Files
ZuneShell.dll/UIX/Microsoft/Iris/InputHandlers/TextEditingHandler.cs
T

1115 lines
38 KiB
C#

// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.InputHandlers.TextEditingHandler
// Assembly: UIX, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: A56C6C9D-B7F6-46A9-8BDE-B3D9B8D60B11
// Assembly location: C:\Program Files\Zune\UIX.dll
using Microsoft.Iris.Drawing;
using Microsoft.Iris.Input;
using Microsoft.Iris.Layout;
using Microsoft.Iris.Markup;
using Microsoft.Iris.ModelItems;
using Microsoft.Iris.OS;
using Microsoft.Iris.Render;
using Microsoft.Iris.RenderAPI;
using Microsoft.Iris.Session;
using Microsoft.Iris.UI;
using Microsoft.Iris.ViewItems;
using System;
using Range = Microsoft.Iris.ModelItems.Range;
namespace Microsoft.Iris.InputHandlers
{
internal class TextEditingHandler :
InputHandler,
IRichTextCallbacks,
ITextScrollModelCallback,
IImeCallbacks
{
private const uint WM_LBUTTONDOWN = 513;
private const uint WM_LBUTTONUP = 514;
private TextEditingHandler.TextEditingCommand _copyCommand;
private TextEditingHandler.TextEditingCommand _cutCommand;
private TextEditingHandler.TextEditingCommand _deleteCommand;
private TextEditingHandler.TextPasteCommand _pasteCommand;
private TextEditingHandler.TextEditingCommand _selectAllCommand;
private TextEditingHandler.TextEditingCommand _undoCommand;
private uint _bits;
private Range _selection;
private Point _inputOffset;
private int _savedMouseYPositionToWorkAroundRichEditBug;
private EditableTextData _editData;
private EventHandler _maxLengthChangedHandler;
private EventHandler _readOnlyChangedHandler;
private EventHandler _valueChangedHandler;
private EventHandler _activationStateHandler;
private Form _activationStateNotifier;
private Text _textDisplay;
private CaretInfo _caretInfo;
private RichText _editControl;
private CursorID _cursor;
private TextScrollModel.State _pendingHorizontalScrollState;
private TextScrollModel.State _pendingVerticalScrollState;
private TextScrollModel _horizontalScrollModel;
private TextScrollModel _verticalScrollModel;
private SimpleCallback _updateScrollbars;
private InputInfo _pendingPointerDown;
private Color _linkColor;
private string _linkClickedParameter;
private bool _InImeMode;
private uint _ImeCallbackToken;
public TextEditingHandler()
{
_caretInfo = new CaretInfo();
_editControl = new RichText(true, this);
_maxLengthChangedHandler = new EventHandler(OnEditableTextMaxLengthChanged);
_readOnlyChangedHandler = new EventHandler(OnEditableTextReadOnlyChanged);
_valueChangedHandler = new EventHandler(OnEditableTextValueChanged);
_activationStateHandler = new EventHandler(OnActivationChanged);
SetBit(Bits.AcceptsEnter);
}
protected override void OnDispose()
{
base.OnDispose();
RemoveEditableTextEventHandlers();
UnregisterImeMessageHandler();
if (_activationStateNotifier != null)
UpdateActivationStateHandler(false);
HorizontalScrollModel = null;
VerticalScrollModel = null;
_editControl.Dispose();
}
protected override void ConfigureInteractivity()
{
base.ConfigureInteractivity();
if (!HandleDirect)
return;
UI.MouseInteractive = true;
UI.KeyInteractive = true;
}
public override void OnZoneAttached()
{
if (!UI.DirectKeyFocus)
return;
UpdateActivationStateHandler(true);
}
private void OnActivationChanged(object sender, EventArgs ea)
{
WindowIsActivated = _activationStateNotifier.ActivationState;
UpdateCaretVisibility();
}
public EditableTextData EditableTextData
{
get => _editData;
set
{
if (_editData == value)
return;
RemoveEditableTextEventHandlers();
_editData = value;
if (_editData != null)
{
AddEditableTextEventHandlers();
UpdateMaxLengthOnRichEdit();
UpdateReadOnlyOnRichEdit();
UpdateContentOnRichEdit();
}
FireThreadSafeNotification(NotificationID.EditableTextData);
}
}
private void RemoveEditableTextEventHandlers()
{
if (_editData == null)
return;
_editData.MaxLengthChanged -= _maxLengthChangedHandler;
_editData.ReadOnlyChanged -= _readOnlyChangedHandler;
_editData.ValueChanged -= _valueChangedHandler;
}
private void AddEditableTextEventHandlers()
{
_editData.MaxLengthChanged += _maxLengthChangedHandler;
_editData.ReadOnlyChanged += _readOnlyChangedHandler;
_editData.ValueChanged += _valueChangedHandler;
}
private void UnregisterImeMessageHandler() => RendererApi.IFC(NativeApi.SpUnregisterImeCallbacks(_ImeCallbackToken));
private void OnEditableTextMaxLengthChanged(object sender, EventArgs unused) => UpdateMaxLengthOnRichEdit();
private void OnEditableTextReadOnlyChanged(object sender, EventArgs unused) => UpdateReadOnlyOnRichEdit();
private void OnEditableTextValueChanged(object sender, EventArgs unused)
{
if (InsideValueChangeOnEditableTextData)
return;
UpdateContentOnRichEdit();
}
private void UpdateContentOnRichEdit()
{
if (_editData == null)
return;
InsideContentChangeOnRichEdit = true;
_editControl.Content = _editData.Value;
if (_textDisplay != null)
_textDisplay.MarkScaleDirty();
InsideContentChangeOnRichEdit = false;
}
private void UpdateReadOnlyOnRichEdit()
{
_editControl.ReadOnly = _editData.ReadOnly;
UpdateSelectionAndReadOnlyCommands();
}
private void UpdateMaxLengthOnRichEdit() => _editControl.MaxLength = _editData.MaxLength;
public Text TextDisplay
{
get => _textDisplay;
set
{
if (_textDisplay == value)
return;
LayoutCompleteEventHandler completeEventHandler = new LayoutCompleteEventHandler(TextLayoutComplete);
if (_textDisplay != null)
{
_textDisplay.ExternalRasterizer = null;
_textDisplay.ExternalEditingHandler = null;
_textDisplay.LayoutComplete -= completeEventHandler;
}
_textDisplay = value;
if (_textDisplay != null)
{
_textDisplay.ExternalRasterizer = _editControl;
_textDisplay.ExternalEditingHandler = this;
_textDisplay.OnDisplayedContentChange();
_textDisplay.LayoutComplete += completeEventHandler;
InputOffsetDirty = true;
}
FireThreadSafeNotification(NotificationID.TextDisplay);
}
}
private void TextLayoutComplete(object sender) => InputOffsetDirty = true;
private void FireTypingInputRejectedEvent() => FireThreadSafeNotification(NotificationID.TypingInputRejected);
public bool DetectUrls
{
get => GetBit(Bits.DetectUrls);
set
{
if (!ChangeBit(Bits.DetectUrls, value))
return;
_editControl.DetectUrls = value;
FireThreadSafeNotification(NotificationID.DetectUrls);
}
}
public Color LinkColor
{
get => _linkColor;
set
{
if (!(_linkColor != value))
return;
_linkColor = value;
FireThreadSafeNotification(NotificationID.LinkColor);
}
}
private void FireLinkClicked() => FireThreadSafeNotification(NotificationID.LinkClicked);
public string LinkClickedParameter
{
get => _linkClickedParameter;
private set
{
if (!(_linkClickedParameter != value))
return;
_linkClickedParameter = value;
FireThreadSafeNotification(NotificationID.LinkClickedParameter);
}
}
HRESULT IRichTextCallbacks.SetCursor(EditCursorType type)
{
CursorID cursorId = CursorID.NotSpecified;
switch (type)
{
case EditCursorType.IBeam:
cursorId = CursorID.IBeam;
break;
}
if (cursorId != _cursor)
{
_cursor = cursorId;
UpdateCursor();
}
return new HRESULT(0);
}
internal override CursorID GetCursor() => _cursor;
private bool IgnoreReadOnlyChar(char character) => character == '\r' || character == '\t';
protected override void OnKeyDown(UIClass ui, KeyStateInfo info)
{
bool flag = ForwardKeyStateChange(info);
switch (info.Key)
{
case Keys.Back:
if (_editData.ReadOnly)
FireTypingInputRejectedEvent();
info.MarkHandled();
break;
case Keys.Tab:
if (flag)
info.MarkHandled();
HandledTabKeyDown = info.Handled;
break;
case Keys.Enter:
if (!info.Handled && AcceptsEnter && (info.Modifiers == InputModifiers.None && !_editData.ReadOnly))
{
_editData.Submit();
info.MarkHandled();
}
HandledEnterKeyDown = info.Handled;
break;
}
}
protected override void OnKeyCharacter(UIClass ui, KeyCharacterInfo info)
{
if (ForwardKeyCharacter(info) && !info.Handled && (_editData.ReadOnly && !IgnoreReadOnlyChar(info.Character)))
FireTypingInputRejectedEvent();
switch (info.Character)
{
case '\b':
info.MarkHandled();
break;
case '\t':
if (!HandledTabKeyDown)
break;
info.MarkHandled();
break;
case '\r':
if (!HandledEnterKeyDown)
break;
info.MarkHandled();
break;
}
}
protected override void OnKeyUp(UIClass ui, KeyStateInfo info)
{
ForwardKeyStateChange(info);
switch (info.Key)
{
case Keys.Back:
info.MarkHandled();
break;
case Keys.Tab:
if (!HandledTabKeyDown)
break;
info.MarkHandled();
HandledTabKeyDown = false;
break;
case Keys.Enter:
if (!HandledEnterKeyDown)
break;
info.MarkHandled();
HandledEnterKeyDown = false;
break;
}
}
private bool ForwardKeyToRichEdit(KeyStateInfo info)
{
bool flag = true;
switch (info.Key)
{
case Keys.Tab:
flag = info.Action != KeyAction.Down ? HandledTabKeyDown : AcceptsTab;
break;
case Keys.Enter:
flag = info.Action != KeyAction.Down ? HandledEnterKeyDown : AcceptsEnter;
break;
}
return flag;
}
private bool ForwardKeyCharacterToRichEdit(KeyCharacterInfo info)
{
bool flag = true;
switch (info.Character)
{
case '\t':
flag = HandledTabKeyDown;
break;
case '\r':
flag = HandledEnterKeyDown;
break;
}
return flag;
}
private bool ForwardKeyStateChange(KeyStateInfo info)
{
if (!ForwardKeyToRichEdit(info))
return false;
if (_editControl.ForwardKeyStateNotification(info.NativeMessageID, (int)info.Key, info.ScanCode, (int)info.RepeatCount, (uint)info.Modifiers, info.KeyboardFlags))
info.MarkHandled();
return true;
}
private bool ForwardKeyCharacter(KeyCharacterInfo info)
{
if (!ForwardKeyCharacterToRichEdit(info))
return false;
if (_editControl.ForwardKeyCharacterNotification(info.NativeMessageID, info.Character, info.ScanCode, (int)info.RepeatCount, (uint)info.Modifiers, info.KeyboardFlags))
info.MarkHandled();
return true;
}
protected override void OnGainKeyFocus(UIClass ui, KeyFocusInfo info)
{
RendererApi.IFC(NativeApi.SpRegisterImeCallbacks(this, out _ImeCallbackToken));
_editControl.NotifyOfFocusChange(true);
if (Overtype)
SelectAll();
DeliverPendingPointerDown();
if (UI.IsZoned)
UpdateActivationStateHandler(true);
if (!_textDisplay.UsePasswordMask && !_textDisplay.DisableIme)
return;
RendererApi.IFC(NativeApi.SpPostDeferredImeMessage(1032U, new UIntPtr(_ImeCallbackToken), UIntPtr.Zero));
}
protected override void OnLoseKeyFocus(UIClass ui, KeyFocusInfo info)
{
_editControl.NotifyOfFocusChange(false);
HandledEnterKeyDown = false;
HandledTabKeyDown = false;
if (UI.IsZoned)
UpdateActivationStateHandler(false);
ClearPendingPointerDown();
RendererApi.IFC(NativeApi.SpUnregisterImeCallbacks(_ImeCallbackToken));
}
protected override void OnLoseMouseFocus(UIClass ui, MouseFocusInfo info)
{
}
private void UpdateActivationStateHandler(bool add)
{
if (add)
{
_activationStateNotifier = UI.Zone.Form;
_activationStateNotifier.ActivationChange += _activationStateHandler;
OnActivationChanged(null, EventArgs.Empty);
}
else
{
_activationStateNotifier.ActivationChange -= _activationStateHandler;
_activationStateNotifier = null;
}
}
protected override void OnMouseDoubleClick(UIClass ui, MouseButtonInfo info) => ForwardMouseInput(info);
protected override void OnMouseMove(UIClass ui, MouseMoveInfo info) => ForwardMouseInput(info);
protected override void OnMousePrimaryDown(UIClass ui, MouseButtonInfo info)
{
_pendingPointerDown = info;
info.Lock();
if (!UI.DirectKeyFocus && HandlerStage == InputHandlerStage.Direct && UI.KeyFocusOnMouseDown)
return;
DeliverPendingPointerDown();
}
private void DeliverPendingPointerDown()
{
if (_pendingPointerDown == null)
return;
MousePrimaryDown = true;
MouseButtonInfo pendingPointerDown = (MouseButtonInfo)_pendingPointerDown;
_savedMouseYPositionToWorkAroundRichEditBug = pendingPointerDown.Y;
ForwardMouseInput(pendingPointerDown);
ClearPendingPointerDown();
}
private void ClearPendingPointerDown()
{
if (_pendingPointerDown == null)
return;
_pendingPointerDown.Unlock();
_pendingPointerDown = null;
}
protected override void OnMousePrimaryUp(UIClass ui, MouseButtonInfo info)
{
MousePrimaryDown = false;
ForwardMouseInput(info);
}
protected override void OnMouseSecondaryDown(UIClass ui, MouseButtonInfo info) => ForwardMouseInput(info);
protected override void OnMouseSecondaryUp(UIClass ui, MouseButtonInfo info) => ForwardMouseInput(info);
protected override void OnMouseWheel(UIClass ui, MouseWheelInfo info)
{
if (!_textDisplay.WordWrap)
return;
ForwardMouseInput(info);
}
private bool ForwardMouseInput(
uint nativeMessageID,
InputModifiers modifiers,
MouseButtons button,
int inputX,
int inputY,
int wheelDelta)
{
if (InputOffsetDirty)
{
Vector3 parentOffsetPxlVector;
ViewItem.GetAccumulatedOffsetAndScale(_textDisplay, UI.RootItem, out parentOffsetPxlVector, out Vector3 _);
_inputOffset = new Point((int)Math.Floor(parentOffsetPxlVector.X), (int)Math.Floor(parentOffsetPxlVector.Y));
InputOffsetDirty = false;
}
int x = inputX - _inputOffset.X;
int y = inputY - _inputOffset.Y;
if (MousePrimaryDown && _textDisplay != null && !_textDisplay.WordWrap)
y = _savedMouseYPositionToWorkAroundRichEditBug - _inputOffset.Y;
return _editControl.ForwardMouseInput(nativeMessageID, (uint)modifiers, (int)button, x, y, wheelDelta);
}
private void ForwardMouseInput(MouseActionInfo info)
{
if (!ForwardMouseInput(info.NativeMessageID, info.Modifiers, info.Button, info.X, info.Y, info.WheelDelta))
return;
info.MarkHandled();
}
public bool Overtype
{
get => GetBit(Bits.Overtype);
set
{
if (!ChangeBit(Bits.Overtype, value))
return;
FireThreadSafeNotification(NotificationID.Overtype);
}
}
public bool AcceptsTab
{
get => GetBit(Bits.AcceptsTab);
set
{
if (!ChangeBit(Bits.AcceptsTab, value))
return;
FireThreadSafeNotification(NotificationID.AcceptsTab);
}
}
public bool AcceptsEnter
{
get => GetBit(Bits.AcceptsEnter);
set
{
if (!ChangeBit(Bits.AcceptsEnter, value))
return;
FireThreadSafeNotification(NotificationID.AcceptsEnter);
}
}
public bool WordWrap
{
set
{
if (!ChangeBit(Bits.WordWrap, value))
return;
_editControl.SetWordWrap(value);
if (!value)
return;
UpdateContentOnRichEdit();
}
}
public CaretInfo CaretInfo => _caretInfo;
private void CreateCommands()
{
if (GetBit(Bits.CommandsCreated))
return;
SetBit(Bits.CommandsCreated);
_undoCommand = new TextEditingHandler.TextEditingCommand(new SimpleCallback(_editControl.Undo));
_cutCommand = new TextEditingHandler.TextEditingCommand(new SimpleCallback(_editControl.Cut));
_copyCommand = new TextEditingHandler.TextEditingCommand(new SimpleCallback(_editControl.Copy));
_pasteCommand = new TextEditingHandler.TextPasteCommand(new SimpleCallback(_editControl.Paste));
_deleteCommand = new TextEditingHandler.TextEditingCommand(new SimpleCallback(_editControl.Delete));
_selectAllCommand = new TextEditingHandler.TextEditingCommand(new SimpleCallback(SelectAll));
UpdateSelectionAndReadOnlyCommands();
UpdateTextBasedCommandAvailability();
}
public IUICommand UndoCommand
{
get
{
CreateCommands();
return _undoCommand;
}
}
public void Undo() => _editControl.Undo();
public IUICommand CutCommand
{
get
{
CreateCommands();
return _cutCommand;
}
}
public void Cut() => _editControl.Cut();
public IUICommand CopyCommand
{
get
{
CreateCommands();
return _copyCommand;
}
}
public void Copy() => _editControl.Copy();
public IUICommand PasteCommand
{
get
{
CreateCommands();
return _pasteCommand;
}
}
public void Paste() => _editControl.Paste();
public IUICommand DeleteCommand
{
get
{
CreateCommands();
return _deleteCommand;
}
}
public void Delete() => _editControl.Delete();
public IUICommand SelectAllCommand
{
get
{
CreateCommands();
return _selectAllCommand;
}
}
public void SelectAll()
{
string str = _editData != null ? _editData.Value : null;
if (string.IsNullOrEmpty(str))
return;
SelectionRange = new Range(0, str.Length);
}
public Range SelectionRange
{
get => _selection;
set
{
if (_selection.IsEqual(value))
return;
_editControl.SetSelectionRange(value.Begin, value.End);
}
}
private void UpdateTextBasedCommandAvailability()
{
_undoCommand.Available = _editControl.CanUndo;
_selectAllCommand.Available = _editData != null && !string.IsNullOrEmpty(_editData.Value);
}
private void UpdateSelectionAndReadOnlyCommands()
{
if (!GetBit(Bits.CommandsCreated))
return;
bool flag1 = !_selection.IsEmpty;
bool flag2 = _editData == null || _editData.ReadOnly;
_cutCommand.Available = flag1 && !flag2;
_copyCommand.Available = flag1;
_deleteCommand.Available = flag1 && !flag2;
_pasteCommand.TextIsReadOnly = flag2;
}
HRESULT IRichTextCallbacks.TextChanged()
{
if (!Application.IsApplicationThread)
{
Application.DeferredInvoke(args => ((IRichTextCallbacks)args).TextChanged(), this, DeferredInvokePriority.Normal);
return new HRESULT(0);
}
if (GetBit(Bits.CommandsCreated))
UpdateTextBasedCommandAvailability();
if (_editData != null && !InsideContentChangeOnRichEdit)
{
InsideValueChangeOnEditableTextData = true;
_editData.Value = _editControl.SimpleContent;
InsideValueChangeOnEditableTextData = false;
}
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.InvalidateContent()
{
if (!Application.IsApplicationThread)
{
Application.DeferredInvoke(args => ((IRichTextCallbacks)args).InvalidateContent(), this, DeferredInvokePriority.Normal);
return new HRESULT(0);
}
if (_textDisplay != null)
_textDisplay.OnDisplayedContentChange();
RefreshCaretPosition();
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.SelectionChanged(
int selectionStart,
int selectionEnd)
{
_selection = new Range(selectionStart, selectionEnd);
FireThreadSafeNotification(NotificationID.SelectionRange);
UpdateSelectionAndReadOnlyCommands();
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.MaxLengthExceeded()
{
FireTypingInputRejectedEvent();
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.SetTimer(uint id, uint timeout)
{
_editControl.SetTimer(id, timeout);
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.KillTimer(uint id)
{
_editControl.KillTimer(id);
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.CreateCaret(int width, int height)
{
_caretInfo.CreateCaret(new Size(width, height));
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.SetCaretPos(int x, int y)
{
_caretInfo.SetCaretPosition(new Point(x, y));
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.ShowCaret(bool visible)
{
RichEditCaretVisible = visible;
UpdateCaretVisibility();
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.ClientToWindow(Point pt, out Point ppt)
{
ppt = _textDisplay == null ? new Point(0, 0) : _textDisplay.ClientToWindow(pt);
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.ClientToScreen(Point pt, out Point ppt)
{
ppt = _textDisplay.ClientToScreen(pt);
return new HRESULT(0);
}
HRESULT IRichTextCallbacks.LinkClicked(int start, int end)
{
string str = _editData != null ? _editData.Value : string.Empty;
if (string.IsNullOrEmpty(str))
{
LinkClickedParameter = string.Empty;
}
else
{
end = end >= 0 ? Math.Min(str.Length, end) : str.Length;
start = Math.Min(start, end);
LinkClickedParameter = str.Substring(start, end - start);
}
FireLinkClicked();
return new HRESULT(0);
}
HRESULT IImeCallbacks.OnImeMessageReceived(
uint message,
UIntPtr wParam,
UIntPtr lParam)
{
switch (message)
{
case 269:
InImeCompositionMode = true;
break;
case 270:
InImeCompositionMode = false;
break;
}
return _editControl.ForwardImeMessage(message, wParam, lParam);
}
public bool InImeCompositionMode
{
get => _InImeMode;
set
{
if (_InImeMode == value)
return;
CaretInfo.IgnoreIdealWidth = value;
_InImeMode = value;
FireThreadSafeNotification(NotificationID.InImeCompositionMode);
}
}
HRESULT IRichTextCallbacks.SetScrollRange(
int whichBarInt,
int minPosition,
int extent,
int viewExtent,
int scrollPosition)
{
if (whichBarInt == 1 && _verticalScrollModel != null)
{
SetScrollRange(ref _pendingVerticalScrollState, minPosition, extent, viewExtent, scrollPosition);
ScheduleScrollbarUpdate(true);
}
else if (_horizontalScrollModel != null)
{
SetScrollRange(ref _pendingHorizontalScrollState, minPosition, extent, viewExtent, scrollPosition);
ScheduleScrollbarUpdate(false);
}
return new HRESULT(0);
}
private void SetScrollRange(
ref TextScrollModel.State state,
int minPosition,
int extent,
int viewExtent,
int scrollAmount)
{
state.Min = minPosition;
state.Extent = extent;
state.ViewExtent = viewExtent;
state.ScrollAmount = scrollAmount;
}
private bool IsVerticalScrollbar(ScrollbarType whichBar) => whichBar == ScrollbarType.Vertical || whichBar == ScrollbarType.Both;
private bool IsHorizontalScrollbar(ScrollbarType whichBar) => whichBar == ScrollbarType.Horizontal || whichBar == ScrollbarType.Both;
HRESULT IRichTextCallbacks.EnableScrollbar(
int whichBarInt,
ScrollbarEnableFlags flags)
{
ScrollbarType whichBar = (ScrollbarType)whichBarInt;
if (IsVerticalScrollbar(whichBar) && _verticalScrollModel != null)
{
EnableScrollbar(ref _pendingVerticalScrollState, flags);
ScheduleScrollbarUpdate(true);
}
if (IsHorizontalScrollbar(whichBar) && _horizontalScrollModel != null)
{
EnableScrollbar(ref _pendingHorizontalScrollState, flags);
ScheduleScrollbarUpdate(false);
}
return new HRESULT(0);
}
private void EnableScrollbar(ref TextScrollModel.State state, ScrollbarEnableFlags flags)
{
switch (flags)
{
case ScrollbarEnableFlags.EnableBoth:
state.CanScrollUp = true;
state.CanScrollDown = true;
break;
case ScrollbarEnableFlags.DisableNear:
state.CanScrollUp = false;
state.CanScrollDown = true;
break;
case ScrollbarEnableFlags.DisableFar:
state.CanScrollUp = true;
state.CanScrollDown = false;
break;
case ScrollbarEnableFlags.DisableBoth:
state.CanScrollUp = false;
state.CanScrollDown = false;
break;
}
}
private void ScheduleScrollbarUpdate(bool vertical)
{
bool flag = !GetBit(Bits.PendingVerticalScrollbarUpdate) && !GetBit(Bits.PendingHorizontalScrollbarUpdate);
if (vertical)
SetBit(Bits.PendingVerticalScrollbarUpdate);
else
SetBit(Bits.PendingHorizontalScrollbarUpdate);
if (!flag)
return;
if (_updateScrollbars == null)
_updateScrollbars = new SimpleCallback(UpdateScrollbars);
DeferredCall.Post(DispatchPriority.Normal, _updateScrollbars);
}
private void UpdateScrollbars()
{
if (GetBit(Bits.PendingVerticalScrollbarUpdate))
{
ClearBit(Bits.PendingVerticalScrollbarUpdate);
_verticalScrollModel.UpdateState(_pendingVerticalScrollState);
_pendingVerticalScrollState = new TextScrollModel.State();
}
if (!GetBit(Bits.PendingHorizontalScrollbarUpdate))
return;
ClearBit(Bits.PendingHorizontalScrollbarUpdate);
_horizontalScrollModel.UpdateState(_pendingHorizontalScrollState);
_pendingHorizontalScrollState = new TextScrollModel.State();
}
public TextScrollModel HorizontalScrollModel
{
get
{
if (_horizontalScrollModel == null)
StoreScrollModel(ref _horizontalScrollModel, new TextScrollModel());
return _horizontalScrollModel;
}
set
{
if (_horizontalScrollModel == value)
return;
StoreScrollModel(ref _horizontalScrollModel, value);
FireThreadSafeNotification(NotificationID.HorizontalScrollModel);
}
}
public TextScrollModel VerticalScrollModel
{
get
{
if (_verticalScrollModel == null)
StoreScrollModel(ref _verticalScrollModel, new TextScrollModel());
return _verticalScrollModel;
}
set
{
if (_verticalScrollModel == value)
return;
StoreScrollModel(ref _verticalScrollModel, value);
FireThreadSafeNotification(NotificationID.VerticalScrollModel);
}
}
private void StoreScrollModel(ref TextScrollModel storage, TextScrollModel newDude)
{
if (storage != null)
storage.DetachCallbacks();
storage = newDude;
if (storage != null)
storage.AttachCallbacks(this);
_editControl.SetScrollbars(_horizontalScrollModel != null, _verticalScrollModel != null);
}
private ScrollbarType WhichScrollbar(TextScrollModel who) => who != _verticalScrollModel ? ScrollbarType.Horizontal : ScrollbarType.Vertical;
void ITextScrollModelCallback.ScrollUp(TextScrollModel who) => _editControl.ScrollUp(WhichScrollbar(who));
void ITextScrollModelCallback.ScrollDown(TextScrollModel who) => _editControl.ScrollDown(WhichScrollbar(who));
void ITextScrollModelCallback.PageUp(TextScrollModel who) => _editControl.PageUp(WhichScrollbar(who));
void ITextScrollModelCallback.PageDown(TextScrollModel who) => _editControl.PageDown(WhichScrollbar(who));
void ITextScrollModelCallback.ScrollToPosition(
TextScrollModel who,
int whereTo)
{
_editControl.ScrollToPosition(WhichScrollbar(who), whereTo);
}
private void UpdateCaretVisibility() => CaretInfo.SetVisible(RichEditCaretVisible && WindowIsActivated);
private void RefreshCaretPosition()
{
if (!CaretInfo.Visible || MousePrimaryDown || _editControl == null)
return;
_editControl.NotifyOfFocusChange(true);
}
private bool HandledTabKeyDown
{
get => GetBit(Bits.HandledTabKeyDown);
set => SetBit(Bits.HandledTabKeyDown, value);
}
private bool HandledEnterKeyDown
{
get => GetBit(Bits.HandledEnterKeyDown);
set => SetBit(Bits.HandledEnterKeyDown, value);
}
private bool InputOffsetDirty
{
get => GetBit(Bits.InputOffsetDirty);
set => SetBit(Bits.InputOffsetDirty, value);
}
private bool MousePrimaryDown
{
get => GetBit(Bits.MousePrimaryDown);
set => SetBit(Bits.MousePrimaryDown, value);
}
private bool InsideValueChangeOnEditableTextData
{
get => GetBit(Bits.InsideValueChangeOnEditableTextData);
set => SetBit(Bits.InsideValueChangeOnEditableTextData, value);
}
private bool InsideContentChangeOnRichEdit
{
get => GetBit(Bits.InsideContentChangeOnRichEdit);
set => SetBit(Bits.InsideContentChangeOnRichEdit, value);
}
private bool RichEditCaretVisible
{
get => GetBit(Bits.RichEditCaretVisible);
set => SetBit(Bits.RichEditCaretVisible, value);
}
private bool WindowIsActivated
{
get => GetBit(Bits.WindowIsActivated);
set => SetBit(Bits.WindowIsActivated, value);
}
private bool GetBit(TextEditingHandler.Bits lookupBit) => ((TextEditingHandler.Bits)_bits & lookupBit) != 0;
private void SetBit(TextEditingHandler.Bits changeBit)
{
TextEditingHandler textEditingHandler = this;
textEditingHandler._bits = (uint)((TextEditingHandler.Bits)textEditingHandler._bits | changeBit);
}
private void SetBit(TextEditingHandler.Bits changeBit, bool value) => _bits = value ? (uint)((TextEditingHandler.Bits)_bits | changeBit) : (uint)((TextEditingHandler.Bits)_bits & ~changeBit);
private void ClearBit(TextEditingHandler.Bits changeBit)
{
TextEditingHandler textEditingHandler = this;
textEditingHandler._bits = (uint)((TextEditingHandler.Bits)textEditingHandler._bits & ~changeBit);
}
private bool ChangeBit(TextEditingHandler.Bits changeBit, bool value)
{
uint num = value ? (uint)((TextEditingHandler.Bits)_bits | changeBit) : (uint)((TextEditingHandler.Bits)_bits & ~changeBit);
bool flag = (int)num != (int)_bits;
if (flag)
_bits = num;
return flag;
}
private enum Bits
{
AcceptsTab = 1,
AcceptsEnter = 2,
HandledTabKeyDown = 4,
HandledEnterKeyDown = 16, // 0x00000010
InputOffsetDirty = 32, // 0x00000020
MousePrimaryDown = 64, // 0x00000040
Overtype = 128, // 0x00000080
InsideValueChangeOnEditableTextData = 256, // 0x00000100
InsideContentChangeOnRichEdit = 512, // 0x00000200
RichEditCaretVisible = 1024, // 0x00000400
WindowIsActivated = 2048, // 0x00000800
WordWrap = 4096, // 0x00001000
CommandsCreated = 8192, // 0x00002000
PendingHorizontalScrollbarUpdate = 16384, // 0x00004000
PendingVerticalScrollbarUpdate = 32768, // 0x00008000
DetectUrls = 65536, // 0x00010000
}
private class TextEditingCommand : UICommand
{
private SimpleCallback _onInvoked;
public TextEditingCommand(SimpleCallback onInvoked) => _onInvoked = onInvoked;
protected override void OnInvoked()
{
base.OnInvoked();
_onInvoked();
}
}
private class TextPasteCommand : TextEditingHandler.TextEditingCommand, IUICommand
{
private bool _isReadOnly;
public TextPasteCommand(SimpleCallback onInvoked)
: base(onInvoked)
{
}
bool IUICommand.Available
{
get => Clipboard.ContainsText() && !_isReadOnly;
set
{
}
}
public bool TextIsReadOnly
{
get => _isReadOnly;
set => _isReadOnly = value;
}
}
}
}