Implemented Editor Placeholder and PlaceholderColor in GTK (#3135)

This commit is contained in:
Javier Suárez Ruiz 2018-06-25 11:02:28 +02:00 коммит произвёл Stephane Delcroix
Родитель 295bcdfe5e
Коммит 673cffb1ab
2 изменённых файлов: 271 добавлений и 158 удалений

Просмотреть файл

@ -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);
}
}
}
} }