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
{
public class ScrolledTextView : ScrolledWindow
{
private TextView _textView;
private int _maxLength;
public class ScrolledTextView : EventBox
{
private Table _table;
private ScrolledWindow _scrolledWindow;
private Gtk.Label _placeholder;
private EventBox _placeholderContainer;
private int _maxLength;
public ScrolledTextView()
{
ShadowType = ShadowType.In;
HscrollbarPolicy = PolicyType.Never;
VscrollbarPolicy = PolicyType.Always;
public ScrolledTextView()
{
_table = new Table(1, 1, true);
_textView = new TextView
{
AcceptsTab = false,
WrapMode = WrapMode.WordChar
};
TextView = new TextView
{
AcceptsTab = false,
WrapMode = WrapMode.WordChar
};
_textView.Buffer.InsertText += InsertText;
Add(_textView);
}
TextView.Buffer.InsertText += InsertText;
TextView.FocusOutEvent += FocusedOut;
public TextView TextView => _textView;
_scrolledWindow = new ScrolledWindow
{
ShadowType = ShadowType.In,
HscrollbarPolicy = PolicyType.Never,
VscrollbarPolicy = PolicyType.Automatic
};
public void SetMaxLength(int maxLength)
{
_maxLength = maxLength;
_scrolledWindow.Add(TextView);
if (_textView.Buffer.CharCount > maxLength)
_textView.Buffer.Text = _textView.Buffer.Text.Substring(0, maxLength);
}
_placeholder = new Gtk.Label();
_placeholder.SetAlignment(0, 0);
protected override void OnFocusGrabbed()
{
_textView?.GrabFocus();
}
_placeholderContainer = new EventBox
{
BorderWidth = 2
};
void InsertText(object o, InsertTextArgs args)
{
args.RetVal = args.Length <= _maxLength;
}
}
_placeholderContainer.Add(_placeholder);
_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
{
public class EditorRenderer : ViewRenderer<Editor, ScrolledTextView>
{
private const string TextColorTagName = "text-color";
public class EditorRenderer : ViewRenderer<Editor, ScrolledTextView>
{
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()
{
if (!Element.BackgroundColor.IsDefaultOrTransparent())
{
var color = Element.BackgroundColor.ToGtkColor();
protected override void UpdateBackgroundColor()
{
if (!Element.BackgroundColor.IsDefaultOrTransparent())
{
var backgroundColor = Element.BackgroundColor.ToGtkColor();
Control.TextView.ModifyBg(StateType.Normal, color);
Control.TextView.ModifyBase(StateType.Normal, color);
}
}
Control.SetBackgroundColor(backgroundColor);
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
if (Control == null)
{
var scrolled = new ScrolledTextView();
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
if (Control == null)
{
var scrolled = new ScrolledTextView();
scrolled.TextView.Buffer.TagTable.Add(new TextTag(TextColorTagName));
scrolled.TextView.Buffer.Changed += TextViewBufferChanged;
scrolled.TextView.Focused += TextViewFocused;
scrolled.TextView.FocusOutEvent += TextViewFocusedOut;
scrolled.TextView.Buffer.TagTable.Add(new TextTag(TextColorTagName));
SetNativeControl(scrolled);
AdjustMinimumHeight(scrolled.TextView);
}
scrolled.TextView.Buffer.Changed += TextViewBufferChanged;
scrolled.TextView.Focused += TextViewFocused;
scrolled.TextView.FocusOutEvent += TextViewFocusedOut;
if (e.NewElement != null)
{
UpdateText();
UpdateFont();
UpdateTextColor();
UpdateMaxLength();
}
SetNativeControl(scrolled);
AdjustMinimumHeight(scrolled.TextView);
}
base.OnElementChanged(e);
}
if (e.NewElement != null)
{
UpdateText();
UpdateFont();
UpdateTextColor();
UpdatePlaceholder();
UpdatePlaceholderColor();
UpdateMaxLength();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
base.OnElementChanged(e);
}
if (e.PropertyName == Editor.TextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Editor.TextColorProperty.PropertyName)
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 OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
_disposed = true;
if (e.PropertyName == Editor.TextProperty.PropertyName)
UpdateText();
else if (e.PropertyName == Editor.TextColorProperty.PropertyName)
UpdateTextColor();
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)
{
Control.TextView.Buffer.Changed -= TextViewBufferChanged;
Control.TextView.Focused -= TextViewFocused;
Control.TextView.FocusOutEvent += TextViewFocusedOut;
}
}
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
_disposed = true;
base.Dispose(disposing);
}
if (Control != null)
{
Control.TextView.Buffer.Changed -= TextViewBufferChanged;
Control.TextView.Focused -= TextViewFocused;
Control.TextView.FocusOutEvent += TextViewFocusedOut;
}
}
private void UpdateText()
{
TextBuffer buffer = Control.TextView.Buffer;
base.Dispose(disposing);
}
if (buffer.Text != Element.Text)
{
buffer.Text = Element.Text ?? string.Empty;
UpdateTextColor();
}
}
private void UpdateText()
{
TextBuffer buffer = Control.TextView.Buffer;
private void UpdateFont()
{
FontDescription fontDescription = FontDescriptionHelper.CreateFontDescription(
Element.FontSize, Element.FontFamily, Element.FontAttributes);
Control.TextView.ModifyFont(fontDescription);
if (buffer.Text != Element.Text)
{
buffer.Text = Element.Text ?? string.Empty;
UpdateTextColor();
}
}
AdjustMinimumHeight(Control.TextView, fontDescription);
}
private void UpdateFont()
{
FontDescription fontDescription = FontDescriptionHelper.CreateFontDescription(
Element.FontSize, Element.FontFamily, Element.FontAttributes);
Control.TextView.ModifyFont(fontDescription);
private void UpdateTextColor()
{
if (!Element.TextColor.IsDefaultOrTransparent())
{
var textColor = Element.TextColor.ToGtkColor();
AdjustMinimumHeight(Control.TextView, fontDescription);
}
TextBuffer buffer = Control.TextView.Buffer;
TextTag tag = buffer.TagTable.Lookup(TextColorTagName);
tag.ForegroundGdk = Element.IsEnabled ? textColor : Control.Style.Foregrounds[(int)StateType.Normal];
Control.TextView.Buffer.ApplyTag(tag, buffer.StartIter, buffer.EndIter);
}
}
private void UpdateTextColor()
{
if (!Element.TextColor.IsDefaultOrTransparent())
{
var textColor = Element.TextColor.ToGtkColor();
private void TextViewBufferChanged(object sender, EventArgs e)
{
TextBuffer buffer = Control.TextView.Buffer;
TextBuffer buffer = Control.TextView.Buffer;
TextTag tag = buffer.TagTable.Lookup(TextColorTagName);
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)
ElementController.SetValueFromRenderer(Editor.TextProperty, buffer.Text);
private void TextViewBufferChanged(object sender, EventArgs e)
{
TextBuffer buffer = Control.TextView.Buffer;
UpdateTextColor();
}
if (Element.Text != buffer.Text)
ElementController.SetValueFromRenderer(Editor.TextProperty, buffer.Text);
private void TextViewFocused(object o, FocusedArgs args)
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
}
UpdateTextColor();
}
private void TextViewFocusedOut(object o, FocusOutEventArgs args)
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
EditorController.SendCompleted();
}
private void TextViewFocused(object o, FocusedArgs args)
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, true);
}
private static void AdjustMinimumHeight(TextView textView, FontDescription font = null)
{
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;
private void TextViewFocusedOut(object o, FocusOutEventArgs args)
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, false);
EditorController.SendCompleted();
}
var resolution = textView.Screen.Resolution;
var minHeight = (int)(pangoUnits * (resolution / 72.0));
private static void AdjustMinimumHeight(TextView textView, FontDescription font = null)
{
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)
{
textView.HeightRequest = minHeight;
}
}
var resolution = textView.Screen.Resolution;
var minHeight = (int)(pangoUnits * (resolution / 72.0));
private void UpdateMaxLength()
{
Control.SetMaxLength(Element.MaxLength);
}
}
if (textView.HeightRequest < minHeight)
{
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);
}
}
}
}