Add Resize support for TextArea

This commit is contained in:
chinboy
2025-11-13 17:15:43 +08:00
parent 7824e89b7b
commit 7bc98762ba
14 changed files with 427 additions and 115 deletions
@@ -392,6 +392,8 @@ namespace AtomUI.Controls.DesignTokens
public static readonly TokenResourceKey FontSize = new TokenResourceKey("TextArea.FontSize");
public static readonly TokenResourceKey FontSizeLG = new TokenResourceKey("TextArea.FontSizeLG");
public static readonly TokenResourceKey FontSizeSM = new TokenResourceKey("TextArea.FontSizeSM");
public static readonly TokenResourceKey ResizeHandleSize = new TokenResourceKey("TextArea.ResizeHandleSize");
public static readonly TokenResourceKey ResizeIndicatorLineColor = new TokenResourceKey("TextArea.ResizeIndicatorLineColor");
}
public static class ListTokenKey
+52
View File
@@ -0,0 +1,52 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
namespace AtomUI.Controls;
internal class ResizeHandle : TemplatedControl
{
internal TextArea? Owner { get; set; }
private Point? _lastPoint;
private bool _dragging;
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
e.Handled = true;
_lastPoint = e.GetPosition(TopLevel.GetTopLevel(this));
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
if (_lastPoint.HasValue)
{
Owner?.NotifyResizeCompleted();
e.Handled = true;
_lastPoint = null;
_dragging = false;
}
}
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
if (_lastPoint.HasValue && e.Properties.IsLeftButtonPressed)
{
var delta = e.GetPosition(TopLevel.GetTopLevel(this)) - _lastPoint.Value;
var manhattanDistance = Math.Abs(delta.X) + Math.Abs(delta.Y);
if (manhattanDistance > Constants.DragThreshold)
{
if (!_dragging)
{
Owner?.NotifyAboutToResize();
_dragging = true;
}
Owner?.NotifyResizing(delta);
}
}
}
}
+96
View File
@@ -6,6 +6,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
@@ -25,7 +26,13 @@ public class TextArea : AvaloniaTextBox,
public static readonly StyledProperty<bool> IsAutoSizeProperty =
AvaloniaProperty.Register<TextArea, bool>(nameof(IsAutoSize), false);
public static readonly StyledProperty<bool> IsShowCountProperty =
AvaloniaProperty.Register<TextArea, bool>(nameof(IsShowCount));
public static readonly StyledProperty<bool> IsResizableProperty =
AvaloniaProperty.Register<TextArea, bool>(nameof(IsResizable));
public static readonly StyledProperty<AddOnDecoratedVariant> StyleVariantProperty =
AddOnDecoratedBox.StyleVariantProperty.AddOwner<TextArea>();
@@ -65,6 +72,18 @@ public class TextArea : AvaloniaTextBox,
get => GetValue(IsAutoSizeProperty);
set => SetValue(IsAutoSizeProperty, value);
}
public bool IsShowCount
{
get => GetValue(IsShowCountProperty);
set => SetValue(IsShowCountProperty, value);
}
public bool IsResizable
{
get => GetValue(IsResizableProperty);
set => SetValue(IsResizableProperty, value);
}
public AddOnDecoratedVariant StyleVariant
{
@@ -122,6 +141,11 @@ public class TextArea : AvaloniaTextBox,
AvaloniaProperty.RegisterDirect<TextArea, bool>(nameof(IsEffectiveShowClearButton),
o => o.IsEffectiveShowClearButton,
(o, v) => o.IsEffectiveShowClearButton = v);
internal static readonly DirectProperty<TextArea, string?> CountTextProperty =
AvaloniaProperty.RegisterDirect<TextArea, string?>(nameof(CountText),
o => o.CountText,
(o, v) => o.CountText = v);
private bool _isEffectiveShowClearButton;
@@ -130,7 +154,15 @@ public class TextArea : AvaloniaTextBox,
get => _isEffectiveShowClearButton;
set => SetAndRaise(IsEffectiveShowClearButtonProperty, ref _isEffectiveShowClearButton, value);
}
private string? _countText;
internal string? CountText
{
get => _countText;
set => SetAndRaise(CountTextProperty, ref _countText, value);
}
Control IControlSharedTokenResourcesHost.HostControl => this;
string IControlSharedTokenResourcesHost.TokenId => LineEditToken.ID;
Control IMotionAwareControl.PropertyBindTarget => this;
@@ -139,6 +171,8 @@ public class TextArea : AvaloniaTextBox,
private ScrollViewer? _scrollViewer;
private IconButton? _clearButton;
private ResizeHandle? _resizeHandle;
private double? _originHeight; // 拖动改变高度的初始值
static TextArea()
{
@@ -174,6 +208,10 @@ public class TextArea : AvaloniaTextBox,
{
ConfigureEffectiveShowClearButton();
}
else if (change.Property == IsShowCountProperty)
{
HandleInputChanged(Text);
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@@ -190,8 +228,16 @@ public class TextArea : AvaloniaTextBox,
{
_clearButton.Click += (sender, args) => { NotifyClearButtonClicked(); };
}
_resizeHandle = e.NameScope.Find<ResizeHandle>(TextAreaThemeConstants.ResizeHandle);
if (_resizeHandle is not null)
{
_resizeHandle.Owner = this;
}
UpdatePseudoClasses();
ConfigureEffectiveShowClearButton();
HandleInputChanged(Text);
}
internal void NotifyScrollViewerCreated(ScrollViewer scrollViewer)
@@ -274,4 +320,54 @@ public class TextArea : AvaloniaTextBox,
{
Clear();
}
protected override void OnTextInput(TextInputEventArgs e)
{
base.OnTextInput(e);
HandleInputChanged(Text);
}
private void HandleInputChanged(string? text)
{
if (IsShowCount)
{
SetCurrentValue(CountTextProperty, $"{text?.Length ?? 0} / {MaxLength}");
}
}
internal void NotifyAboutToResize()
{
if (_scrollViewer != null)
{
if (!double.IsNaN(Height))
{
_scrollViewer.SetCurrentValue(HeightProperty, _scrollViewer.Bounds.Height);
}
var minHeight = _scrollViewer.MinHeight;
var height = _scrollViewer.Height;
if (double.IsNaN(height))
{
height = minHeight;
}
_originHeight = height;
SetCurrentValue(HeightProperty, double.NaN);
}
}
internal void NotifyResizing(Point delta)
{
if (_scrollViewer != null && _originHeight != null)
{
var minHeight = _scrollViewer.MinHeight;
var maxHeight = _scrollViewer.MaxHeight;
var height = _originHeight.Value + delta.Y;
height = Math.Max(minHeight, Math.Min(height, maxHeight));
_scrollViewer.SetCurrentValue(HeightProperty, height);
}
}
internal void NotifyResizeCompleted()
{
_originHeight = null;
}
}
@@ -2,6 +2,7 @@ using AtomUI.Controls.Themes;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
namespace AtomUI.Controls;
@@ -25,6 +26,10 @@ internal class TextAreaDecoratedBox : AddOnDecoratedBox
AvaloniaProperty.Register<TextAreaDecoratedBox, bool>(
nameof(IsScrollChainingEnabled), true);
public static readonly StyledProperty<IBrush?> ResizeIndicatorLineBrushProperty =
AvaloniaProperty.Register<TextAreaDecoratedBox, IBrush?>(
nameof(ResizeIndicatorLineBrush));
public bool IsAllowAutoHide
{
get => GetValue(IsAllowAutoHideProperty);
@@ -48,7 +53,35 @@ internal class TextAreaDecoratedBox : AddOnDecoratedBox
get => GetValue(IsScrollChainingEnabledProperty);
set => SetValue(IsScrollChainingEnabledProperty, value);
}
public IBrush? ResizeIndicatorLineBrush
{
get => GetValue(ResizeIndicatorLineBrushProperty);
set => SetValue(ResizeIndicatorLineBrushProperty, value);
}
#endregion
#region 内部属性定义
internal static readonly DirectProperty<TextAreaDecoratedBox, bool> IsResizableProperty =
AvaloniaProperty.RegisterDirect<TextAreaDecoratedBox, bool>(nameof(IsResizable),
o => o.IsResizable,
(o, v) => o.IsResizable = v);
private bool _isResizable;
internal bool IsResizable
{
get => _isResizable;
set => SetAndRaise(IsResizableProperty, ref _isResizable, value);
}
#endregion
static TextAreaDecoratedBox()
{
AffectsRender<TextAreaDecoratedBox>(ResizeIndicatorLineBrushProperty, IsResizableProperty);
}
internal ScrollViewer? ScrollViewer { get; set; }
internal TextArea? Owner { get; set; }
@@ -62,4 +95,29 @@ internal class TextAreaDecoratedBox : AddOnDecoratedBox
Owner?.NotifyScrollViewerCreated(ScrollViewer);
}
}
public override void Render(DrawingContext context)
{
if (IsResizable)
{
var bounds = Bounds.Deflate(new Thickness(2));
var sideLength = 7d;
var (line1Start, line1End) = CalculateResizeLine(bounds, sideLength);
var (line2Start, line2End) = CalculateResizeLine(bounds, sideLength - 3);
var pen = new Pen(ResizeIndicatorLineBrush);
context.DrawLine(pen, line1Start, line1End);
context.DrawLine(pen, line2Start, line2End);
}
}
private (Point, Point) CalculateResizeLine(Rect bounds, double sideLength)
{
double right = bounds.Right;
double bottom = bounds.Bottom;
Point rightSidePoint = new Point(right, bottom - sideLength);
Point bottomSidePoint = new Point(right - sideLength, bottom);
return (rightSidePoint, bottomSidePoint);
}
}
+16 -3
View File
@@ -1,4 +1,5 @@
using AtomUI.Theme.TokenSystem;
using Avalonia.Media;
namespace AtomUI.Controls;
@@ -26,12 +27,24 @@ internal class TextAreaToken : AbstractControlDesignToken
/// 小号字体大小
/// </summary>
public double FontSizeSM { get; set; }
/// <summary>
/// Resize 指示器颜色
/// </summary>
public Color ResizeIndicatorLineColor { get; set; }
/// <summary>
/// Resize 指示器大小
/// </summary>
public double ResizeHandleSize { get; set; }
public override void CalculateTokenValues()
{
base.CalculateTokenValues();
FontSize = SharedToken.FontSize;
FontSizeLG = SharedToken.FontSizeLG;
FontSizeSM = SharedToken.FontSizeSM;
FontSize = SharedToken.FontSize;
FontSizeLG = SharedToken.FontSizeLG;
FontSizeSM = SharedToken.FontSizeSM;
ResizeIndicatorLineColor = SharedToken.ColorTextDescription;
ResizeHandleSize = SharedToken.SizeXS;
}
}
+42
View File
@@ -4,6 +4,7 @@ using AtomUI.Theme.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;
namespace AtomUI.Controls;
@@ -29,6 +30,9 @@ public class TextBox : AvaloniaTextBox,
public static readonly StyledProperty<bool> IsCustomFontSizeProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsCustomFontSize));
public static readonly StyledProperty<bool> IsShowCountProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsShowCount));
public static readonly StyledProperty<IBrush?> WatermarkForegroundProperty =
AvaloniaProperty.Register<TextBox, IBrush?>(nameof(WatermarkForeground));
@@ -58,6 +62,12 @@ public class TextBox : AvaloniaTextBox,
get => GetValue(IsCustomFontSizeProperty);
set => SetValue(IsCustomFontSizeProperty, value);
}
public bool IsShowCount
{
get => GetValue(IsShowCountProperty);
set => SetValue(IsShowCountProperty, value);
}
public IBrush? WatermarkForeground
{
@@ -78,6 +88,11 @@ public class TextBox : AvaloniaTextBox,
AvaloniaProperty.RegisterDirect<TextBox, bool>(nameof(IsEffectiveShowClearButton),
o => o.IsEffectiveShowClearButton,
(o, v) => o.IsEffectiveShowClearButton = v);
internal static readonly DirectProperty<TextBox, string?> CountTextProperty =
AvaloniaProperty.RegisterDirect<TextBox, string?>(nameof(CountText),
o => o.CountText,
(o, v) => o.CountText = v);
private bool _isEffectiveShowClearButton;
@@ -87,6 +102,14 @@ public class TextBox : AvaloniaTextBox,
set => SetAndRaise(IsEffectiveShowClearButtonProperty, ref _isEffectiveShowClearButton, value);
}
private string? _countText;
internal string? CountText
{
get => _countText;
set => SetAndRaise(CountTextProperty, ref _countText, value);
}
Control IControlSharedTokenResourcesHost.HostControl => this;
string IControlSharedTokenResourcesHost.TokenId => LineEditToken.ID;
Control IMotionAwareControl.PropertyBindTarget => this;
@@ -110,6 +133,10 @@ public class TextBox : AvaloniaTextBox,
{
ConfigureEffectiveShowClearButton();
}
else if (change.Property == IsShowCountProperty)
{
HandleInputChanged(Text);
}
}
private void ConfigureEffectiveShowClearButton()
@@ -132,10 +159,25 @@ public class TextBox : AvaloniaTextBox,
_clearButton.Click += (sender, args) => { NotifyClearButtonClicked(); };
}
ConfigureEffectiveShowClearButton();
HandleInputChanged(Text);
}
protected virtual void NotifyClearButtonClicked()
{
Clear();
}
protected override void OnTextInput(TextInputEventArgs e)
{
base.OnTextInput(e);
HandleInputChanged(Text);
}
private void HandleInputChanged(string? text)
{
if (IsShowCount)
{
SetCurrentValue(CountTextProperty, $"{text?.Length ?? 0} / {MaxLength}");
}
}
}
@@ -8,6 +8,7 @@ internal static class TextBoxThemeConstants
internal static class TextAreaThemeConstants
{
public const string ResizeHandle = "PART_ResizeHandle";
public const string ScrollViewerPart = "PART_ScrollViewer";
public const string ClearButtonPart = "PART_ClearButton";
}
}
@@ -7,6 +7,7 @@
<ResourceInclude Source="SearchEditDecoratedBoxTheme.axaml" />
<ResourceInclude Source="TextAreaDecoratedBoxTheme.axaml" />
<ResourceInclude Source="SearchEditTheme.axaml" />
<ResourceInclude Source="ResizeHandleTheme.axaml" />
</ResourceDictionary.MergedDictionaries>
<themes:TextBoxTheme x:Key="{x:Type atom:TextBox}" TargetType="atom:TextBox"/>
<themes:LineEditTheme x:Key="{x:Type atom:LineEdit}" TargetType="atom:LineEdit"/>
@@ -53,6 +53,11 @@
Focusable="False"
Content="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:LineEdit}}"
IsVisible="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:LineEdit}, Converter={x:Static ObjectConverters.IsNotNull}}" />
<atom:TextBlock Name="TextCountIndicator"
VerticalAlignment="Center"
Foreground="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextPlaceholder}}"
Text="{Binding CountText, RelativeSource={RelativeSource AncestorType=atom:LineEdit}}"
IsVisible="{Binding IsShowCount, RelativeSource={RelativeSource AncestorType=atom:LineEdit}}"/>
</StackPanel>
</atom:AddOnDecoratedBox.ContentRightAddOn>
@@ -128,7 +133,5 @@
</Style>
</Style>
</Style>
</Style>
</ControlTheme>
@@ -0,0 +1,18 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:atom="https://atomui.net"
x:ClassModifier="internal">
<ControlTheme x:Key="{x:Type atom:ResizeHandle}" TargetType="atom:ResizeHandle">
<Setter Property="Template">
<ControlTemplate>
<Border Name="Frame" Background="{TemplateBinding Background}"/>
</ControlTemplate>
</Setter>
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="8" />
<Setter Property="Width" Value="8" />
</ControlTheme>
</ResourceDictionary>
@@ -16,49 +16,52 @@
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BackgroundSizing="OuterBorderEdge">
<ScrollViewer
Name="{x:Static atom:TextAreaThemeConstants.ScrollViewerPart}"
AllowAutoHide="{TemplateBinding IsAllowAutoHide}"
HorizontalScrollBarVisibility="{TemplateBinding HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
IsScrollChainingEnabled="{TemplateBinding IsScrollChainingEnabled}">
<Border Name="ScrollViewerContent">
<DockPanel Name="ContentLayout" LastChildFill="True">
<ContentPresenter
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentLeftAddOnPart}"
DockPanel.Dock="Left"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
HorizontalAlignment="Left"
Focusable="False"
Content="{TemplateBinding ContentLeftAddOn}"
ContentTemplate="{TemplateBinding ContentLeftAddOnTemplate}"
IsVisible="{TemplateBinding ContentLeftAddOn, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ScrollViewer
Name="{x:Static atom:TextAreaThemeConstants.ScrollViewerPart}"
AllowAutoHide="{TemplateBinding IsAllowAutoHide}"
HorizontalScrollBarVisibility="{TemplateBinding HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding VerticalScrollBarVisibility}"
IsScrollChainingEnabled="{TemplateBinding IsScrollChainingEnabled}">
<Border Name="ScrollViewerContent">
<DockPanel Name="ContentLayout" LastChildFill="True">
<ContentPresenter
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentLeftAddOnPart}"
DockPanel.Dock="Left"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
HorizontalAlignment="Left"
Focusable="False"
Content="{TemplateBinding ContentLeftAddOn}"
ContentTemplate="{TemplateBinding ContentLeftAddOnTemplate}"
IsVisible="{TemplateBinding ContentLeftAddOn, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ContentPresenter
DockPanel.Dock="Right"
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentRightAddOnPart}"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
HorizontalAlignment="Right"
Focusable="False"
Content="{TemplateBinding ContentRightAddOn}"
ContentTemplate="{TemplateBinding ContentRightAddOnTemplate}"
IsVisible="{TemplateBinding ContentRightAddOn, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ContentPresenter
DockPanel.Dock="Right"
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentRightAddOnPart}"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
HorizontalAlignment="Right"
Focusable="False"
Content="{TemplateBinding ContentRightAddOn}"
ContentTemplate="{TemplateBinding ContentRightAddOnTemplate}"
IsVisible="{TemplateBinding ContentRightAddOn, Converter={x:Static ObjectConverters.IsNotNull}}" />
<ContentPresenter
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentPresenterPart}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</DockPanel>
</Border>
</ScrollViewer>
<ContentPresenter
Name="{x:Static atom:AddOnDecoratedBoxThemeConstants.ContentPresenterPart}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</DockPanel>
</Border>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:is(atom|TextAreaDecoratedBox)">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="ClipToBounds" Value="True" />
<Setter Property="ResizeIndicatorLineBrush"
Value="{DynamicResource {x:Static atom:TextAreaTokenKey.ResizeIndicatorLineColor}}" />
<Style Selector="^[SizeType=Large]">
<Style Selector="^ /template/ Border#PART_ContentFrame">
<Setter Property="Padding" Value="0" />
@@ -7,71 +7,87 @@
<Setter Property="Template">
<ControlTemplate TargetType="atom:TextArea">
<atom:TextAreaDecoratedBox
Name="{x:Static atom:AddOnDecoratedBox.AddOnDecoratedBoxPart}"
ContentLeftAddOn="{TemplateBinding InnerLeftContent}"
ContentLeftAddOnTemplate="{TemplateBinding InnerLeftContentTemplate}"
StyleVariant="{TemplateBinding StyleVariant}"
SizeType="{TemplateBinding SizeType}"
Status="{TemplateBinding Status}"
Focusable="True"
IsAllowAutoHide="{TemplateBinding ScrollViewer.AllowAutoHide}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
IsScrollChainingEnabled="{TemplateBinding ScrollViewer.IsScrollChainingEnabled}">
<atom:TextAreaDecoratedBox.ContentRightAddOn>
<StackPanel Orientation="Horizontal"
Spacing="{DynamicResource {x:Static atom:SharedTokenKey.UniformlyPaddingXXS}}">
<atom:IconButton
Name="{x:Static atom:TextAreaThemeConstants.ClearButtonPart}"
Icon="{atom:IconProvider CloseCircleFilled}"
IconWidth="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}"
IconHeight="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}"
NormalIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextQuaternary}}"
ActiveIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextTertiary}}"
SelectedIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorText}}"
IsMotionEnabled="{Binding IsMotionEnabled, RelativeSource={RelativeSource AncestorType=atom:TextArea}}"
IsVisible="{Binding IsEffectiveShowClearButton, RelativeSource={RelativeSource AncestorType=atom:TextArea}}" />
<ContentPresenter
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalAlignment="Right"
Focusable="False"
Content="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:TextArea}}"
IsVisible="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:TextArea}, Converter={x:Static ObjectConverters.IsNotNull}}" />
</StackPanel>
</atom:TextAreaDecoratedBox.ContentRightAddOn>
<DockPanel LastChildFill="True"
Height="{TemplateBinding Height}">
<atom:TextBlock Name="TextCountIndicator"
DockPanel.Dock="Bottom"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Text="{TemplateBinding CountText}"
IsVisible="{TemplateBinding IsShowCount}" />
<Panel>
<atom:TextAreaDecoratedBox
Name="{x:Static atom:AddOnDecoratedBox.AddOnDecoratedBoxPart}"
ContentLeftAddOn="{TemplateBinding InnerLeftContent}"
ContentLeftAddOnTemplate="{TemplateBinding InnerLeftContentTemplate}"
StyleVariant="{TemplateBinding StyleVariant}"
SizeType="{TemplateBinding SizeType}"
Status="{TemplateBinding Status}"
Focusable="True"
IsResizable="{TemplateBinding IsResizable}"
IsAllowAutoHide="{TemplateBinding ScrollViewer.AllowAutoHide}"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
IsScrollChainingEnabled="{TemplateBinding ScrollViewer.IsScrollChainingEnabled}">
<atom:TextAreaDecoratedBox.ContentRightAddOn>
<StackPanel Orientation="Horizontal"
Spacing="{DynamicResource {x:Static atom:SharedTokenKey.UniformlyPaddingXXS}}">
<atom:IconButton
Name="{x:Static atom:TextAreaThemeConstants.ClearButtonPart}"
Icon="{atom:IconProvider CloseCircleFilled}"
IconWidth="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}"
IconHeight="{DynamicResource {x:Static atom:SharedTokenKey.IconSize}}"
NormalIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextQuaternary}}"
ActiveIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextTertiary}}"
SelectedIconBrush="{DynamicResource {x:Static atom:SharedTokenKey.ColorText}}"
IsMotionEnabled="{Binding IsMotionEnabled, RelativeSource={RelativeSource AncestorType=atom:TextArea}}"
IsVisible="{Binding IsEffectiveShowClearButton, RelativeSource={RelativeSource AncestorType=atom:TextArea}}" />
<ContentPresenter
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalAlignment="Right"
Focusable="False"
Content="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:TextArea}}"
IsVisible="{Binding InnerRightContent, RelativeSource={RelativeSource AncestorType=atom:TextArea}, Converter={x:Static ObjectConverters.IsNotNull}}" />
</StackPanel>
</atom:TextAreaDecoratedBox.ContentRightAddOn>
<Panel Name="ContentLayout">
<atom:TextBlock
Name="Watermark"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding Watermark}"
Foreground="{TemplateBinding WatermarkForeground}"
LineHeight="{TemplateBinding LineHeight}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}"
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}" />
<TextPresenter
Name="PART_TextPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="{TemplateBinding Text, Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
<Panel Name="ContentLayout">
<atom:TextBlock
Name="Watermark"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding Watermark}"
Foreground="{TemplateBinding WatermarkForeground}"
LineHeight="{TemplateBinding LineHeight}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}"
IsVisible="{TemplateBinding Text, Converter={x:Static StringConverters.IsNullOrEmpty}}" />
<TextPresenter
Name="PART_TextPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
CaretBlinkInterval="{TemplateBinding CaretBlinkInterval}"
CaretBrush="{TemplateBinding CaretBrush}"
CaretIndex="{TemplateBinding CaretIndex}"
LineHeight="{TemplateBinding LineHeight}"
PasswordChar="{TemplateBinding PasswordChar}"
RevealPassword="{TemplateBinding RevealPassword}"
SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionStart="{TemplateBinding SelectionStart}"
SelectionEnd="{TemplateBinding SelectionEnd}"
SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="{TemplateBinding Text, Mode=TwoWay}"
TextAlignment="{TemplateBinding TextAlignment}"
TextWrapping="{TemplateBinding TextWrapping}" />
</Panel>
</atom:TextAreaDecoratedBox>
<atom:ResizeHandle Name="{x:Static atom:TextAreaThemeConstants.ResizeHandle}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Cursor="SizeNorthSouth" />
</Panel>
</atom:TextAreaDecoratedBox>
</DockPanel>
</ControlTemplate>
</Setter>
@@ -166,6 +182,10 @@
<Setter Property="SelectedIconBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorText}}" />
</Style>
<Style Selector="^ /template/ atom|TextBlock#TextCountIndicator">
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextPlaceholder}}" />
</Style>
<Style Selector="^:disabled">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextDisabled}}" />
@@ -47,8 +47,11 @@
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
HorizontalAlignment="Right"
Focusable="False"
Content="{TemplateBinding InnerRightContent}"/>
<atom:TextBlock Name="TextCountIndicator"
VerticalAlignment="Center"
Text="{TemplateBinding CountText}"
IsVisible="{TemplateBinding IsShowCount}"/>
</StackPanel>
<ScrollViewer
@@ -159,6 +162,10 @@
<Setter Property="SelectedIconBrush" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorText}}" />
</Style>
<Style Selector="^ /template/ atom|TextBlock#TextCountIndicator">
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextPlaceholder}}" />
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ ScrollViewer#PART_ScrollViewer">
<Setter Property="Foreground" Value="{DynamicResource {x:Static atom:SharedTokenKey.ColorTextDisabled}}" />
@@ -1,4 +1,5 @@
using System.Reactive.Disposables;
using System.Diagnostics;
using System.Reactive.Disposables;
using AtomUI.Data;
using Avalonia;
using Avalonia.Controls;
@@ -66,6 +67,8 @@ internal class TimePickerFlyout : Flyout
protected override Control CreatePresenter()
{
var flyoutPresenter = base.CreatePresenter() as FlyoutPresenter;
Debug.Assert(flyoutPresenter != null);
TimePickerPresenter = new TimePickerPresenter();
_presenterBindingDisposables?.Dispose();
_presenterBindingDisposables = new CompositeDisposable(8);
@@ -77,14 +80,7 @@ internal class TimePickerFlyout : Flyout
_presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsNeedConfirmProperty, TimePickerPresenter, TimePickerPresenter.IsNeedConfirmProperty));
_presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowNowProperty, TimePickerPresenter, TimePickerPresenter.IsShowNowProperty));
var flyoutPresenter = new FlyoutPresenter
{
Content = TimePickerPresenter
};
_presenterBindingDisposables.Add(BindUtils.RelayBind(this, IsShowArrowEffectiveProperty, flyoutPresenter, IsShowArrowProperty));
ConfigureShowArrowEffective();
// SetupArrowPosition(flyoutPresenter);
flyoutPresenter.Content = TimePickerPresenter;
return flyoutPresenter;
}
}