зеркало из https://github.com/DeGsoft/maui-linux.git
Implemented Editor Placeholder and PlaceholderColor in GTK (#3135)
This commit is contained in:
Родитель
295bcdfe5e
Коммит
673cffb1ab
|
@ -2,45 +2,134 @@
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.GTK.Controls
|
namespace Xamarin.Forms.Platform.GTK.Controls
|
||||||
{
|
{
|
||||||
public class ScrolledTextView : ScrolledWindow
|
public class ScrolledTextView : EventBox
|
||||||
{
|
{
|
||||||
private TextView _textView;
|
private Table _table;
|
||||||
private int _maxLength;
|
private ScrolledWindow _scrolledWindow;
|
||||||
|
private Gtk.Label _placeholder;
|
||||||
|
private EventBox _placeholderContainer;
|
||||||
|
private int _maxLength;
|
||||||
|
|
||||||
public ScrolledTextView()
|
public ScrolledTextView()
|
||||||
{
|
{
|
||||||
ShadowType = ShadowType.In;
|
_table = new Table(1, 1, true);
|
||||||
HscrollbarPolicy = PolicyType.Never;
|
|
||||||
VscrollbarPolicy = PolicyType.Always;
|
|
||||||
|
|
||||||
_textView = new TextView
|
TextView = new TextView
|
||||||
{
|
{
|
||||||
AcceptsTab = false,
|
AcceptsTab = false,
|
||||||
WrapMode = WrapMode.WordChar
|
WrapMode = WrapMode.WordChar
|
||||||
};
|
};
|
||||||
|
|
||||||
_textView.Buffer.InsertText += InsertText;
|
TextView.Buffer.InsertText += InsertText;
|
||||||
Add(_textView);
|
TextView.FocusOutEvent += FocusedOut;
|
||||||
}
|
|
||||||
|
|
||||||
public TextView TextView => _textView;
|
_scrolledWindow = new ScrolledWindow
|
||||||
|
{
|
||||||
|
ShadowType = ShadowType.In,
|
||||||
|
HscrollbarPolicy = PolicyType.Never,
|
||||||
|
VscrollbarPolicy = PolicyType.Automatic
|
||||||
|
};
|
||||||
|
|
||||||
public void SetMaxLength(int maxLength)
|
_scrolledWindow.Add(TextView);
|
||||||
{
|
|
||||||
_maxLength = maxLength;
|
|
||||||
|
|
||||||
if (_textView.Buffer.CharCount > maxLength)
|
_placeholder = new Gtk.Label();
|
||||||
_textView.Buffer.Text = _textView.Buffer.Text.Substring(0, maxLength);
|
_placeholder.SetAlignment(0, 0);
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnFocusGrabbed()
|
_placeholderContainer = new EventBox
|
||||||
{
|
{
|
||||||
_textView?.GrabFocus();
|
BorderWidth = 2
|
||||||
}
|
};
|
||||||
|
|
||||||
void InsertText(object o, InsertTextArgs args)
|
_placeholderContainer.Add(_placeholder);
|
||||||
{
|
|
||||||
args.RetVal = args.Length <= _maxLength;
|
_placeholderContainer.ButtonPressEvent += PlaceHolderContainerPressed;
|
||||||
}
|
|
||||||
}
|
SetBackgroundColor(TextView.Style.BaseColors[(int)StateType.Normal]);
|
||||||
|
|
||||||
|
Add(_table);
|
||||||
|
|
||||||
|
_table.Attach(_placeholderContainer, 0, 1, 0, 1, AttachOptions.Fill, AttachOptions.Fill, 0, 0);
|
||||||
|
_table.Attach(_scrolledWindow, 0, 1, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView TextView { get; }
|
||||||
|
|
||||||
|
public string PlaceholderText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _placeholder.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_placeholder.Text = GLib.Markup.EscapeText(value ?? string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBackgroundColor(Gdk.Color color)
|
||||||
|
{
|
||||||
|
ModifyBg(StateType.Normal, color);
|
||||||
|
TextView.ModifyBase(StateType.Normal, color);
|
||||||
|
_placeholderContainer.ModifyBg(StateType.Normal, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPlaceholderTextColor(Gdk.Color color)
|
||||||
|
{
|
||||||
|
_placeholder.ModifyFg(StateType.Normal, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMaxLength(int maxLength)
|
||||||
|
{
|
||||||
|
_maxLength = maxLength;
|
||||||
|
|
||||||
|
if (TextView.Buffer.CharCount > maxLength)
|
||||||
|
TextView.Buffer.Text = TextView.Buffer.Text.Substring(0, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFocusGrabbed()
|
||||||
|
{
|
||||||
|
TextView?.GrabFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSizeAllocated(Gdk.Rectangle allocation)
|
||||||
|
{
|
||||||
|
base.OnSizeAllocated(allocation);
|
||||||
|
|
||||||
|
TextView.SetSizeRequest(allocation.Width, allocation.Height);
|
||||||
|
|
||||||
|
ShowPlaceholderIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InsertText(object o, InsertTextArgs args)
|
||||||
|
{
|
||||||
|
args.RetVal = args.Length <= _maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FocusedOut(object o, FocusOutEventArgs args)
|
||||||
|
{
|
||||||
|
ShowPlaceholderIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowPlaceholderIfNeeded()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(TextView.Buffer.Text) && !string.IsNullOrEmpty(_placeholder.Text))
|
||||||
|
{
|
||||||
|
_placeholderContainer.VisibleWindow = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_placeholderContainer.VisibleWindow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaceHolderContainerPressed(object o, ButtonPressEventArgs args)
|
||||||
|
{
|
||||||
|
if (Sensitive)
|
||||||
|
{
|
||||||
|
TextView.Sensitive = true;
|
||||||
|
TextView.HasFocus = true;
|
||||||
|
TextView.GdkWindow?.Raise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,158 +8,182 @@ using Xamarin.Forms.Platform.GTK.Helpers;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.GTK.Renderers
|
namespace Xamarin.Forms.Platform.GTK.Renderers
|
||||||
{
|
{
|
||||||
public class EditorRenderer : ViewRenderer<Editor, ScrolledTextView>
|
public class EditorRenderer : ViewRenderer<Editor, ScrolledTextView>
|
||||||
{
|
{
|
||||||
private const string TextColorTagName = "text-color";
|
private const string TextColorTagName = "text-color";
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
protected IEditorController EditorController => Element as IEditorController;
|
protected IEditorController EditorController => Element as IEditorController;
|
||||||
|
|
||||||
protected override void UpdateBackgroundColor()
|
protected override void UpdateBackgroundColor()
|
||||||
{
|
{
|
||||||
if (!Element.BackgroundColor.IsDefaultOrTransparent())
|
if (!Element.BackgroundColor.IsDefaultOrTransparent())
|
||||||
{
|
{
|
||||||
var color = Element.BackgroundColor.ToGtkColor();
|
var backgroundColor = Element.BackgroundColor.ToGtkColor();
|
||||||
|
|
||||||
Control.TextView.ModifyBg(StateType.Normal, color);
|
Control.SetBackgroundColor(backgroundColor);
|
||||||
Control.TextView.ModifyBase(StateType.Normal, color);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
||||||
{
|
{
|
||||||
if (Control == null)
|
if (Control == null)
|
||||||
{
|
{
|
||||||
var scrolled = new ScrolledTextView();
|
var scrolled = new ScrolledTextView();
|
||||||
|
|
||||||
scrolled.TextView.Buffer.TagTable.Add(new TextTag(TextColorTagName));
|
scrolled.TextView.Buffer.TagTable.Add(new TextTag(TextColorTagName));
|
||||||
scrolled.TextView.Buffer.Changed += TextViewBufferChanged;
|
|
||||||
scrolled.TextView.Focused += TextViewFocused;
|
|
||||||
scrolled.TextView.FocusOutEvent += TextViewFocusedOut;
|
|
||||||
|
|
||||||
SetNativeControl(scrolled);
|
scrolled.TextView.Buffer.Changed += TextViewBufferChanged;
|
||||||
AdjustMinimumHeight(scrolled.TextView);
|
scrolled.TextView.Focused += TextViewFocused;
|
||||||
}
|
scrolled.TextView.FocusOutEvent += TextViewFocusedOut;
|
||||||
|
|
||||||
if (e.NewElement != null)
|
SetNativeControl(scrolled);
|
||||||
{
|
AdjustMinimumHeight(scrolled.TextView);
|
||||||
UpdateText();
|
}
|
||||||
UpdateFont();
|
|
||||||
UpdateTextColor();
|
|
||||||
UpdateMaxLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnElementChanged(e);
|
if (e.NewElement != null)
|
||||||
}
|
{
|
||||||
|
UpdateText();
|
||||||
|
UpdateFont();
|
||||||
|
UpdateTextColor();
|
||||||
|
UpdatePlaceholder();
|
||||||
|
UpdatePlaceholderColor();
|
||||||
|
UpdateMaxLength();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
base.OnElementChanged(e);
|
||||||
{
|
}
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Editor.TextProperty.PropertyName)
|
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
UpdateText();
|
{
|
||||||
else if (e.PropertyName == Editor.TextColorProperty.PropertyName)
|
base.OnElementPropertyChanged(sender, e);
|
||||||
UpdateTextColor();
|
|
||||||
else if (e.PropertyName == Editor.FontAttributesProperty.PropertyName)
|
|
||||||
UpdateFont();
|
|
||||||
else if (e.PropertyName == Editor.FontFamilyProperty.PropertyName)
|
|
||||||
UpdateFont();
|
|
||||||
else if (e.PropertyName == Editor.FontSizeProperty.PropertyName)
|
|
||||||
UpdateFont();
|
|
||||||
else if (e.PropertyName == InputView.MaxLengthProperty.PropertyName)
|
|
||||||
UpdateMaxLength();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
if (e.PropertyName == Editor.TextProperty.PropertyName)
|
||||||
{
|
UpdateText();
|
||||||
if (disposing && !_disposed)
|
else if (e.PropertyName == Editor.TextColorProperty.PropertyName)
|
||||||
{
|
UpdateTextColor();
|
||||||
_disposed = true;
|
else if (e.PropertyName == Editor.PlaceholderProperty.PropertyName)
|
||||||
|
UpdatePlaceholder();
|
||||||
|
else if (e.PropertyName == Editor.PlaceholderColorProperty.PropertyName)
|
||||||
|
UpdatePlaceholderColor();
|
||||||
|
else if (e.PropertyName == Editor.FontAttributesProperty.PropertyName)
|
||||||
|
UpdateFont();
|
||||||
|
else if (e.PropertyName == Editor.FontFamilyProperty.PropertyName)
|
||||||
|
UpdateFont();
|
||||||
|
else if (e.PropertyName == Editor.FontSizeProperty.PropertyName)
|
||||||
|
UpdateFont();
|
||||||
|
else if (e.PropertyName == InputView.MaxLengthProperty.PropertyName)
|
||||||
|
UpdateMaxLength();
|
||||||
|
}
|
||||||
|
|
||||||
if (Control != null)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Control.TextView.Buffer.Changed -= TextViewBufferChanged;
|
if (disposing && !_disposed)
|
||||||
Control.TextView.Focused -= TextViewFocused;
|
{
|
||||||
Control.TextView.FocusOutEvent += TextViewFocusedOut;
|
_disposed = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
if (Control != null)
|
||||||
}
|
{
|
||||||
|
Control.TextView.Buffer.Changed -= TextViewBufferChanged;
|
||||||
|
Control.TextView.Focused -= TextViewFocused;
|
||||||
|
Control.TextView.FocusOutEvent += TextViewFocusedOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateText()
|
base.Dispose(disposing);
|
||||||
{
|
}
|
||||||
TextBuffer buffer = Control.TextView.Buffer;
|
|
||||||
|
|
||||||
if (buffer.Text != Element.Text)
|
private void UpdateText()
|
||||||
{
|
{
|
||||||
buffer.Text = Element.Text ?? string.Empty;
|
TextBuffer buffer = Control.TextView.Buffer;
|
||||||
UpdateTextColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateFont()
|
if (buffer.Text != Element.Text)
|
||||||
{
|
{
|
||||||
FontDescription fontDescription = FontDescriptionHelper.CreateFontDescription(
|
buffer.Text = Element.Text ?? string.Empty;
|
||||||
Element.FontSize, Element.FontFamily, Element.FontAttributes);
|
UpdateTextColor();
|
||||||
Control.TextView.ModifyFont(fontDescription);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AdjustMinimumHeight(Control.TextView, fontDescription);
|
private void UpdateFont()
|
||||||
}
|
{
|
||||||
|
FontDescription fontDescription = FontDescriptionHelper.CreateFontDescription(
|
||||||
|
Element.FontSize, Element.FontFamily, Element.FontAttributes);
|
||||||
|
Control.TextView.ModifyFont(fontDescription);
|
||||||
|
|
||||||
private void UpdateTextColor()
|
AdjustMinimumHeight(Control.TextView, fontDescription);
|
||||||
{
|
}
|
||||||
if (!Element.TextColor.IsDefaultOrTransparent())
|
|
||||||
{
|
|
||||||
var textColor = Element.TextColor.ToGtkColor();
|
|
||||||
|
|
||||||
TextBuffer buffer = Control.TextView.Buffer;
|
private void UpdateTextColor()
|
||||||
TextTag tag = buffer.TagTable.Lookup(TextColorTagName);
|
{
|
||||||
tag.ForegroundGdk = Element.IsEnabled ? textColor : Control.Style.Foregrounds[(int)StateType.Normal];
|
if (!Element.TextColor.IsDefaultOrTransparent())
|
||||||
Control.TextView.Buffer.ApplyTag(tag, buffer.StartIter, buffer.EndIter);
|
{
|
||||||
}
|
var textColor = Element.TextColor.ToGtkColor();
|
||||||
}
|
|
||||||
|
|
||||||
private void TextViewBufferChanged(object sender, EventArgs e)
|
TextBuffer buffer = Control.TextView.Buffer;
|
||||||
{
|
TextTag tag = buffer.TagTable.Lookup(TextColorTagName);
|
||||||
TextBuffer buffer = Control.TextView.Buffer;
|
tag.ForegroundGdk = Element.IsEnabled ? textColor : Control.Style.Foregrounds[(int)StateType.Normal];
|
||||||
|
Control.TextView.Buffer.ApplyTag(tag, buffer.StartIter, buffer.EndIter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Element.Text != buffer.Text)
|
private void TextViewBufferChanged(object sender, EventArgs e)
|
||||||
ElementController.SetValueFromRenderer(Editor.TextProperty, buffer.Text);
|
{
|
||||||
|
TextBuffer buffer = Control.TextView.Buffer;
|
||||||
|
|
||||||
UpdateTextColor();
|
if (Element.Text != buffer.Text)
|
||||||
}
|
ElementController.SetValueFromRenderer(Editor.TextProperty, buffer.Text);
|
||||||
|
|
||||||
private void TextViewFocused(object o, FocusedArgs args)
|
UpdateTextColor();
|
||||||
{
|
}
|
||||||
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextViewFocusedOut(object o, FocusOutEventArgs args)
|
private void TextViewFocused(object o, FocusedArgs args)
|
||||||
{
|
{
|
||||||
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
|
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
|
||||||
EditorController.SendCompleted();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static void AdjustMinimumHeight(TextView textView, FontDescription font = null)
|
private void TextViewFocusedOut(object o, FocusOutEventArgs args)
|
||||||
{
|
{
|
||||||
var fDescr = font != null ? font : textView.Style.FontDescription;
|
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
|
||||||
var metrics = textView.PangoContext.GetMetrics(font, Language.Default);
|
EditorController.SendCompleted();
|
||||||
var pangoUnits = (metrics.Ascent + metrics.Descent) / Pango.Scale.PangoScale;
|
}
|
||||||
|
|
||||||
var resolution = textView.Screen.Resolution;
|
private static void AdjustMinimumHeight(TextView textView, FontDescription font = null)
|
||||||
var minHeight = (int)(pangoUnits * (resolution / 72.0));
|
{
|
||||||
|
var fDescr = font != null ? font : textView.Style.FontDescription;
|
||||||
|
var metrics = textView.PangoContext.GetMetrics(font, Language.Default);
|
||||||
|
var pangoUnits = (metrics.Ascent + metrics.Descent) / Pango.Scale.PangoScale;
|
||||||
|
|
||||||
if (textView.HeightRequest < minHeight)
|
var resolution = textView.Screen.Resolution;
|
||||||
{
|
var minHeight = (int)(pangoUnits * (resolution / 72.0));
|
||||||
textView.HeightRequest = minHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateMaxLength()
|
if (textView.HeightRequest < minHeight)
|
||||||
{
|
{
|
||||||
Control.SetMaxLength(Element.MaxLength);
|
textView.HeightRequest = minHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateMaxLength()
|
||||||
|
{
|
||||||
|
Control.SetMaxLength(Element.MaxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePlaceholder()
|
||||||
|
{
|
||||||
|
if (Element.Placeholder != Control.PlaceholderText)
|
||||||
|
{
|
||||||
|
Control.PlaceholderText = Element.Placeholder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePlaceholderColor()
|
||||||
|
{
|
||||||
|
if (!Element.PlaceholderColor.IsDefaultOrTransparent())
|
||||||
|
{
|
||||||
|
var placeholderColor = Element.PlaceholderColor.ToGtkColor();
|
||||||
|
|
||||||
|
Control.SetPlaceholderTextColor(placeholderColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Загрузка…
Ссылка в новой задаче