// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Design; using System.Linq; using System.Windows.Forms; namespace AntdUI { /// /// Input 输入框 /// /// 通过鼠标或键盘输入内容,是最基础的表单域的包装。 [Description("Input 输入框")] [ToolboxItem(true)] [DefaultProperty("Text")] [DefaultEvent("TextChanged")] public partial class Input : IControl { public Input() { base.BackColor = Color.Transparent; SetStyle(ControlStyles.Selectable, true); UpdateStyles(); CurrentCaret.Width = (int)(1 * Config.Dpi); } #region 属性 internal Color? fore; /// /// 文字颜色 /// [Description("文字颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public new Color? ForeColor { get => fore; set { if (fore == value) fore = value; fore = value; Invalidate(); } } #region 背景 Color? back; /// /// 背景颜色 /// [Description("背景颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public new Color? BackColor { get => back; set { if (back == value) return; back = value; Invalidate(); } } string? backExtend = null; /// /// 背景渐变色 /// [Description("背景渐变色"), Category("外观"), DefaultValue(null)] public string? BackExtend { get => backExtend; set { if (backExtend == value) return; backExtend = value; Invalidate(); } } Image? backImage = null; /// /// 背景图片 /// [Description("背景图片"), Category("外观"), DefaultValue(null)] public new Image? BackgroundImage { get => backImage; set { if (backImage == value) return; backImage = value; Invalidate(); } } TFit backFit = TFit.Fill; /// /// 背景图片布局 /// [Description("背景图片布局"), Category("外观"), DefaultValue(TFit.Fill)] public new TFit BackgroundImageLayout { get => backFit; set { if (backFit == value) return; backFit = value; Invalidate(); } } #endregion Color selection = Color.FromArgb(102, 0, 127, 255); /// /// 选中颜色 /// [Description("选中颜色"), Category("外观"), DefaultValue(typeof(Color), "102, 0, 127, 255")] public Color SelectionColor { get => selection; set { if (selection == value) return; selection = value; Invalidate(); } } #region 光标 /// /// 光标颜色 /// [Description("光标颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? CaretColor { get; set; } /// /// 光标速度 /// [Description("光标速度"), Category("外观"), DefaultValue(1000)] public int CaretSpeed { get; set; } = 1000; #endregion #region 边框 internal float borderWidth = 1F; /// /// 边框宽度 /// [Description("边框宽度"), Category("边框"), DefaultValue(1F)] public float BorderWidth { get => borderWidth; set { if (borderWidth == value) return; borderWidth = value; Invalidate(); } } /// /// 边框颜色 /// internal Color? borderColor; [Description("边框颜色"), Category("边框"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? BorderColor { get => borderColor; set { if (borderColor == value) return; borderColor = value; Invalidate(); } } /// /// 悬停边框颜色 /// [Description("悬停边框颜色"), Category("边框"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? BorderHover { get; set; } /// /// 激活边框颜色 /// [Description("激活边框颜色"), Category("边框"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? BorderActive { get; set; } #endregion /// /// 波浪大小 /// [Description("波浪大小"), Category("外观"), DefaultValue(4)] public int WaveSize { get; set; } = 4; internal int radius = 6; /// /// 圆角 /// [Description("圆角"), Category("外观"), DefaultValue(6)] public int Radius { get => radius; set { if (radius == value) return; radius = value; Invalidate(); } } internal bool round = false; /// /// 圆角样式 /// [Description("圆角样式"), Category("外观"), DefaultValue(false)] public bool Round { get => round; set { if (round == value) return; round = value; CalculateRect(); Invalidate(); } } TType status = TType.None; /// /// 设置校验状态 /// [Description("设置校验状态"), Category("外观"), DefaultValue(TType.None)] public TType Status { get => status; set { if (status == value) return; status = value; Invalidate(); } } #region 图标 float iconratio = .7F; /// /// 图标比例 /// [Description("图标比例"), Category("外观"), DefaultValue(.7F)] public float IconRatio { get => iconratio; set { if (iconratio == value) return; iconratio = value; CalculateRect(); Invalidate(); } } Image? prefix = null; /// /// 前缀 /// [Description("前缀"), Category("外观"), DefaultValue(null)] public Image? Prefix { get => prefix; set { if (prefix == value) return; prefix = value; CalculateRect(); Invalidate(); } } string? prefixSvg = null; /// /// 前缀SVG /// [Description("前缀SVG"), Category("外观"), DefaultValue(null)] public string? PrefixSvg { get => prefixSvg; set { if (prefixSvg == value) return; prefixSvg = value; CalculateRect(); Invalidate(); } } /// /// 是否包含前缀 /// public bool HasPrefix => prefixSvg != null || prefix != null; Image? suffix = null; /// /// 后缀 /// [Description("后缀"), Category("外观"), DefaultValue(null)] public Image? Suffix { get => suffix; set { if (suffix == value) return; suffix = value; CalculateRect(); Invalidate(); } } string? suffixSvg = null; /// /// 后缀SVG /// [Description("后缀SVG"), Category("外观"), DefaultValue(null)] public string? SuffixSvg { get => suffixSvg; set { if (suffixSvg == value) return; suffixSvg = value; CalculateRect(); Invalidate(); } } /// /// 是否包含后缀 /// public virtual bool HasSuffix => suffixSvg != null || suffix != null; string? prefixText = null; [Description("前缀文本"), Category("外观"), DefaultValue(null)] public string? PrefixText { get => prefixText; set { if (prefixText == value) return; prefixText = value; CalculateRect(); Invalidate(); } } string? suffixText = null; [Description("后缀文本"), Category("外观"), DefaultValue(null)] public string? SuffixText { get => suffixText; set { if (suffixText == value) return; suffixText = value; CalculateRect(); Invalidate(); } } #endregion /// /// 连接左边 /// [Description("连接左边"), Category("外观"), DefaultValue(false)] public bool JoinLeft { get; set; } = false; /// /// 连接右边 /// [Description("连接右边"), Category("外观"), DefaultValue(false)] public bool JoinRight { get; set; } = false; bool allowclear = false, is_clear = false, is_clear_down = false; bool is_prefix_down = false, is_suffix_down = false; /// /// 支持清除 /// [Description("支持清除"), Category("行为"), DefaultValue(false)] public virtual bool AllowClear { get => allowclear; set { if (allowclear == value) return; allowclear = value; OnAllowClear(); } } void OnAllowClear() { bool _is_clear = !ReadOnly && allowclear && _mouseHover && (!isempty || HasValue); if (is_clear == _is_clear) return; is_clear = _is_clear; CalculateRect(); } bool autoscroll = false; [Description("是否显示滚动条"), Category("外观"), DefaultValue(false)] public bool AutoScroll { get => autoscroll; set { if (autoscroll == value) return; autoscroll = value; Invalidate(); } } #endregion #region 原生属性 #region 文本 internal bool isempty = true; string _text = ""; [Description("文本"), Category("外观"), DefaultValue("")] [Editor(typeof(System.ComponentModel.Design.MultilineStringEditor), typeof(UITypeEditor))] public override string Text { get => _text; set { if (value is null) value = ""; if (_text == value) return; _text = value; isempty = string.IsNullOrEmpty(_text); FixFontWidth(); OnAllowClear(); if (isempty) { if (selectionStart > 0) SelectionStart = 0; } else if (cache_font != null) { if (selectionStart > cache_font.Length) SelectionStart = cache_font.Length; } Invalidate(); OnTextChanged(EventArgs.Empty); } } #endregion [Description("Emoji字体"), Category("外观"), DefaultValue("Segoe UI Emoji")] public string EmojiFont { get; set; } = "Segoe UI Emoji"; #region 原生文本框 int selectionStart = 0, selectionStartTemp = 0, selectionLength = 0; /// /// 所选文本的起点 /// [Browsable(false), DefaultValue(0)] public int SelectionStart { get => selectionStart; set { if (value < 0) value = 0; else if (value > 0) { if (cache_font == null) value = 0; else if (value > cache_font.Length) value = cache_font.Length; } if (selectionStart == value) return; selectionStart = selectionStartTemp = value; SetCaretPostion(value); } } /// /// 所选文本的长度 /// [Browsable(false), DefaultValue(0)] public int SelectionLength { get => selectionLength; set { if (selectionLength == value) return; selectionLength = value; Invalidate(); } } #endregion /// /// 多行编辑是否允许输入制表符 /// [Description("多行编辑是否允许输入制表符"), Category("行为"), DefaultValue(false)] public bool AcceptsTab { get; set; } = false; /// /// 焦点离开清空选中 /// [Description("焦点离开清空选中"), Category("行为"), DefaultValue(true)] public bool LostFocusClearSelection { get; set; } = true; /// /// 只读 /// [Description("只读"), Category("行为"), DefaultValue(false)] public bool ReadOnly { get; set; } bool multiline = false; /// /// 多行文本 /// [Description("多行文本"), Category("行为"), DefaultValue(false)] public bool Multiline { get => multiline; set { if (multiline == value) return; multiline = value; if (multiline) { sf_placeholder.FormatFlags &= ~StringFormatFlags.NoWrap; sf_placeholder.LineAlignment = StringAlignment.Near; } else { sf_placeholder.FormatFlags |= StringFormatFlags.NoWrap; sf_placeholder.LineAlignment = StringAlignment.Center; } CalculateRect(); Invalidate(); } } int lineheight = 0; [Description("多行行高"), Category("行为"), DefaultValue(0)] public int LineHeight { get => lineheight; set { if (lineheight == value) return; lineheight = value; CalculateRect(); Invalidate(); } } HorizontalAlignment textalign = HorizontalAlignment.Left; /// /// 文本对齐方向 /// [Description("文本对齐方向"), Category("外观"), DefaultValue(HorizontalAlignment.Left)] public HorizontalAlignment TextAlign { get => textalign; set { if (textalign == value) return; textalign = value; textalign.SetAlignment(ref sf_placeholder); CalculateRect(); Invalidate(); } } #region 水印 string? placeholderText = null; /// /// 水印文本 /// [Description("水印文本"), Category("行为"), DefaultValue(null)] public virtual string? PlaceholderText { get => placeholderText; set { if (placeholderText == value) return; placeholderText = value; if (isempty && ShowPlaceholder) Invalidate(); } } Color? placeholderColor = null; /// /// 水印颜色 /// [Description("水印颜色"), Category("外观"), DefaultValue(null)] [Editor(typeof(Design.ColorEditor), typeof(UITypeEditor))] public Color? PlaceholderColor { get => placeholderColor; set { if (placeholderColor == value) return; placeholderColor = value; if (isempty && ShowPlaceholder) Invalidate(); } } string? placeholderColorExtend = null; /// /// 水印渐变色 /// [Description("水印渐变色"), Category("外观"), DefaultValue(null)] public string? PlaceholderColorExtend { get => placeholderColorExtend; set { if (placeholderColorExtend == value) return; placeholderColorExtend = value; if (isempty && ShowPlaceholder) Invalidate(); } } #endregion /// /// 文本最大长度 /// [Description("文本最大长度"), Category("行为"), DefaultValue(32767)] public int MaxLength { get; set; } = 32767; #region 密码框 bool IsPassWord = false; string PassWordChar = "●"; bool useSystemPasswordChar = false; /// /// 使用密码框 /// [Description("使用密码框"), Category("行为"), DefaultValue(false)] public bool UseSystemPasswordChar { get => useSystemPasswordChar; set { if (useSystemPasswordChar == value) return; useSystemPasswordChar = value; SetPassWord(); } } char passwordChar = '\0'; /// /// 自定义密码字符 /// [Description("自定义密码字符"), Category("行为"), DefaultValue((char)0)] public char PasswordChar { get => passwordChar; set { if (passwordChar == value) return; passwordChar = value; SetPassWord(); } } /// /// 密码可以复制 /// [Description("密码可以复制"), Category("行为"), DefaultValue(false)] public bool PasswordCopy { get; set; } /// /// 密码可以粘贴 /// [Description("密码可以粘贴"), Category("行为"), DefaultValue(true)] public bool PasswordPaste { get; set; } = true; void SetPassWord() { if (passwordChar != '\0') { PassWordChar = passwordChar.ToString(); IsPassWord = true; } else if (useSystemPasswordChar) { PassWordChar = "●"; IsPassWord = true; } else IsPassWord = false; FixFontWidth(true); Invalidate(); } #endregion #endregion #region 方法 /// /// 将文本追加到当前文本中 /// /// 追加的文本 public void AppendText(string text) { var tmp = _text + text; Text = tmp; CurrentPosIndex = tmp.Length; } /// /// 清除所有文本 /// public void Clear() { Text = ""; } /// /// 清除撤消缓冲区信息 /// public void ClearUndo() { history_Log.Clear(); } /// /// 复制 /// public void Copy() { if (IsPassWord && !PasswordCopy) return; var text = GetSelectionText(); if (string.IsNullOrEmpty(text)) return; this.ClipboardSetText(text); } /// /// 剪贴 /// public void Cut() { if (IsPassWord && !PasswordCopy) return; var text = GetSelectionText(); if (string.IsNullOrEmpty(text)) return; this.ClipboardSetText(text); ProcessBackSpaceKey(); } /// /// 粘贴 /// public void Paste() { if (IsPassWord && !PasswordPaste) return; var strText = this.ClipboardGetText(); if (strText == null || string.IsNullOrEmpty(strText)) return; var chars = new List(strText.Length); foreach (char key in strText) { if (Verify(key, out var change)) chars.Add(change ?? key.ToString()); } if (chars.Count > 0) EnterText(string.Join("", chars), false); } /// /// 取消全部选中 /// public void DeselectAll() { SelectionLength = 0; } /// /// 撤消 /// public void Undo() { if (IsPassWord && !PasswordCopy) return; if (history_Log.Count > 0) { int index; if (history_I == -1) { index = history_Log.Count - 1; AddHistoryRecord(); } else index = history_I - 1; if (index > -1) { var it = history_Log[index]; history_I = index; Text = it.Text; SelectionStart = it.SelectionStart; SelectionLength = it.SelectionLength; } } } /// /// 重做 /// public void Redo() { if (IsPassWord && !PasswordCopy) return; if (history_Log.Count > 0 && history_I > -1) { int index = history_I + 1; if (history_Log.Count > index) { var it = history_Log[index]; history_I = index; Text = it.Text; SelectionStart = it.SelectionStart; SelectionLength = it.SelectionLength; } } } /// /// 文本选择范围 /// /// 第一个字符的位置 /// 字符长度 public void Select(int start, int length) { SelectionStart = start; SelectionLength = length; } /// /// 选择所有文本 /// public void SelectAll() { if (cache_font != null) { SelectionStart = 0; SelectionLength = cache_font.Length; } } void EnterText(string text, bool ismax = true) { if (ReadOnly || BanInput) return; AddHistoryRecord(); int len = 0; GraphemeSplitter.Each(text, 0, (str, nStart, nLen) => { len++; return true; }); if (cache_font == null) { if (ismax && text.Length > MaxLength) text = text.Substring(0, MaxLength); Text = text; SelectionStart = len; } else { if (selectionLength > 0) { int start = selectionStartTemp, end = selectionLength; AddHistoryRecord(); int end_temp = start + end; var texts = new List(end); foreach (var it in cache_font) { if (it.i < start || it.i >= end_temp) texts.Add(it.text); } texts.Insert(start, text); var tmp = string.Join("", texts); if (ismax && tmp.Length > MaxLength) tmp = tmp.Substring(0, MaxLength); Text = tmp; SelectionLength = 0; SelectionStart = start + len; } else { int start = selectionStart - 1; var texts = new List(cache_font.Length); foreach (var it in cache_font) texts.Add(it.text); texts.Insert(start + 1, text); var tmp = string.Join("", texts); if (ismax && tmp.Length > MaxLength) tmp = tmp.Substring(0, MaxLength); Text = tmp; SelectionStart = start + 1 + len; } } } string? GetSelectionText() { if (cache_font == null) return null; else { if (selectionLength > 0) { int start = selectionStartTemp, end = selectionLength; int end_temp = start + end; if (end_temp > cache_font.Length) end_temp = cache_font.Length; var texts = new List(end); foreach (var it in cache_font) { if (it.i >= start && end_temp > it.i) texts.Add(it.text); } return string.Join("", texts); } return null; } } /// /// 内容滚动到当前插入符号位置 /// public void ScrollToCaret() { if (cache_font != null) { Rectangle r; if (CurrentPosIndex >= cache_font.Length) r = cache_font[cache_font.Length - 1].rect; else r = cache_font[CurrentPosIndex].rect; ScrollY = r.Bottom; } } /// /// 内容滚动到最下面 /// public void ScrollToEnd() { ScrollY = ScrollYMax; } #endregion #region 重写 protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); FixFontWidth(true); } #region 焦点 bool AnimationFocus = false; int AnimationFocusValue = 0; DateTime HasFocusTime; public bool HasFocus { get; internal set; } protected override void OnGotFocus(EventArgs e) { base.OnGotFocus(e); HasFocusTime = DateTime.Now; HasFocus = true; ShowCaret = true; ExtraMouseDown = true; } protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); HasFocus = false; ShowCaret = false; if (LostFocusClearSelection) SelectionLength = 0; ExtraMouseDown = false; } #endregion #region 系统消息 IntPtr m_hIMC; protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { case Win32.WM_IME_STARTCOMPOSITION: m_hIMC = Win32.ImmGetContext(Handle); OnImeStartPrivate(m_hIMC); break; case Win32.WM_IME_ENDCOMPOSITION: OnImeEndPrivate(m_hIMC); break; case Win32.WM_IME_COMPOSITION: if (((int)m.LParam & Win32.GCS_RESULTSTR) == Win32.GCS_RESULTSTR) { m.Result = (IntPtr)1; OnImeResultStrPrivate(m_hIMC, Win32.ImmGetCompositionString(m_hIMC, Win32.GCS_RESULTSTR)); return; } break; } base.WndProc(ref m); } #endregion #region 虚拟 /// /// 禁止输入 /// protected virtual bool BanInput => false; protected virtual bool HasValue => false; protected virtual bool ModeRange => false; protected virtual void ModeRangeCaretPostion(bool Null) { } /// /// 是否显示水印 /// protected virtual bool ShowPlaceholder => true; protected virtual bool HasLeft() => false; protected virtual int UseLeft(Rectangle rect, bool delgap) => 0; protected virtual void IBackSpaceKey() { } protected virtual bool IMouseDown(Point e) => false; protected virtual bool IMouseMove(Point e) => false; protected virtual bool IMouseUp(Point e) => false; /// /// 清空值 /// protected virtual void OnClearValue() => Text = ""; /// /// 焦点点击 /// /// 是否已经设置过焦点 protected virtual void OnFocusClick(bool SetFocus) { } /// /// 改变鼠标状态 /// /// 移入 /// 焦点 protected virtual void ChangeMouseHover(bool Hover, bool Focus) { } #endregion #endregion #region 光标 internal bool ReadShowCaret = false; bool showCaret = false; bool showCaretFlag = false; internal bool ShowCaret { get => showCaret; set { if (showCaret == value) return; showCaret = value; CaretPrint?.Dispose(); if (IsHandleCreated) { showCaretFlag = true; if (showCaret) { if (ReadShowCaret) { showCaret = false; return; } CaretPrint = new ITask(this, () => { showCaretFlag = !showCaretFlag; Invalidate(); return showCaret; }, CaretSpeed); SetCaretPostion(); } else { CaretPrint = null; Invalidate(); } } } } ITask? CaretPrint; internal Rectangle CurrentCaret = new Rectangle(-1, -1000, 1, 0); internal void SetCaretX(int x) { if (CurrentCaret.X == x && showCaretFlag) return; CurrentCaret.X = x; showCaretFlag = true; Invalidate(); } internal void SetCaretY(int y) { if (CurrentCaret.Y == y && showCaretFlag) return; CurrentCaret.Y = y; showCaretFlag = true; Invalidate(); } internal void SetCaretXY(int x, int y) { if (CurrentCaret.X == x && CurrentCaret.Y == y && showCaretFlag) return; CurrentCaret.X = x; CurrentCaret.Y = y; showCaretFlag = true; Invalidate(); } #region 得到光标位置 /// /// 通过坐标系查找光标位置 /// int GetCaretPostion(int x, int y) { if (cache_font == null) return 0; else { foreach (var it in cache_font) { if (it.rect.X <= x && it.rect.Right >= x && it.rect.Y <= y && it.rect.Bottom >= y) { if (x > it.rect.X + it.rect.Width / 2) return it.i + 1; else return it.i; } } var nearest = FindNearestFont(x, y, cache_font, out bool isold); if (nearest == null) { if (x > cache_font[cache_font.Length - 1].rect.Right) return cache_font.Length; else return 0; } else { if (isold) return nearest.i; else if (x > nearest.rect.X + nearest.rect.Width / 2) return nearest.i + 1; else return nearest.i; } } } /// /// 寻找最近的矩形和距离的辅助方法 /// CacheFont? FindNearestFont(int x, int y, CacheFont[] cache_font, out bool isold) { CacheFont first = cache_font[0], last = cache_font[cache_font.Length - 1]; if (x < first.rect.X && y < first.rect.Y) { isold = false; return first; } else if (x > last.rect.X && y > last.rect.Y) { isold = false; return last; } var findy = FindNearestFontY(y, cache_font, out isold); CacheFont? result = null; if (findy == null) { double minDistance = int.MaxValue; for (int i = 0; i < cache_font.Length; i++) { var it = cache_font[i]; // 计算点到矩形四个边的最近距离,取最小值作为当前矩形的最近距离 int distanceToLeft = Math.Abs(x - (it.rect.X + it.rect.Width / 2)), distanceToTop = Math.Abs(y - (it.rect.Y + it.rect.Height / 2)); double currentMinDistance = new int[] { distanceToLeft, distanceToTop }.Average(); // 如果当前矩形的最近距离比之前找到的最近距离小,更新最近距离和最近矩形信息 if (currentMinDistance < minDistance) { minDistance = currentMinDistance; result = it; } } } else { int ry = isold ? findy.rect_old.Y : findy.rect.Y; int minDistance = int.MaxValue; for (int i = 0; i < cache_font.Length; i++) { var it = cache_font[i]; if (it.rect.Y == ry || (it.ret && it.rect_old.Y == ry)) { // 计算点到矩形四个边的最近距离,取最小值作为当前矩形的最近距离 int currentMinDistance = Math.Abs(x - (it.rect.X + it.rect.Width / 2)); // 如果当前矩形的最近距离比之前找到的最近距离小,更新最近距离和最近矩形信息 if (currentMinDistance < minDistance) { minDistance = currentMinDistance; result = it; } } } } if (result == null) return result; return result; } CacheFont? FindNearestFontY(int y, CacheFont[] cache_font, out bool old) { int minDistance = int.MaxValue; CacheFont? result = null; old = false; for (int i = 0; i < cache_font.Length; i++) { var it = cache_font[i]; // 计算点到矩形四个边的最近距离,取最小值作为当前矩形的最近距离 int currentMinDistance = Math.Abs(y - (it.rect.Y + it.rect.Height / 2)); // 如果当前矩形的最近距离比之前找到的最近距离小,更新最近距离和最近矩形信息 if (currentMinDistance < minDistance) { old = false; minDistance = currentMinDistance; result = it; } if (it.ret) { int currentMinDistance2 = Math.Abs(y - (it.rect_old.Y + it.rect_old.Height / 2)); if (currentMinDistance2 < minDistance) { old = true; minDistance = currentMinDistance2; result = it; } } } return result; } #endregion int CurrentPosIndex = 0; internal void SetCaretPostion() { SetCaretPostion(CurrentPosIndex); } internal void SetCaretPostion(int PosIndex) { CurrentPosIndex = PosIndex; if (showCaret) { if (cache_font == null) { if (ModeRange) ModeRangeCaretPostion(true); else { if (textalign == HorizontalAlignment.Center) SetCaretX(rect_text.X + rect_text.Width / 2); else if (textalign == HorizontalAlignment.Right) SetCaretX(rect_text.Right); } } else { Rectangle r; if (PosIndex >= cache_font.Length) { var it = cache_font[cache_font.Length - 1]; r = it.rect; SetCaretXY(it.ret ? r.X : r.Right, r.Y); } else { var it = cache_font[PosIndex]; if (it.ret) { if (PosIndex > 0) { it = cache_font[PosIndex - 1]; r = it.rect; SetCaretXY(r.Right, r.Y); } else { r = it.rect_old; SetCaretXY(r.X, r.Y); } } else { r = it.rect; SetCaretXY(r.X, r.Y); } } if (ModeRange) ModeRangeCaretPostion(false); ScrollIFTo(r); } showCaretFlag = true; Invalidate(); } } bool SpeedScrollTo = false; void OnImeStartPrivate(IntPtr hIMC) { var point = CurrentCaret.Location; point.Offset(0, -scrolly); var CandidateForm = new Win32.CANDIDATEFORM() { dwStyle = Win32.CFS_CANDIDATEPOS, ptCurrentPos = point, }; Win32.ImmSetCandidateWindow(hIMC, ref CandidateForm); var CompositionForm = new Win32.COMPOSITIONFORM() { dwStyle = Win32.CFS_FORCE_POSITION, ptCurrentPos = point, }; Win32.ImmSetCompositionWindow(hIMC, ref CompositionForm); var logFont = new Win32.LOGFONT() { lfHeight = CurrentCaret.Height, lfFaceName = Font.Name + "\0" }; Win32.ImmSetCompositionFont(hIMC, ref logFont); } void OnImeEndPrivate(IntPtr hIMC) { Win32.ImmReleaseContext(Handle, hIMC); } void OnImeResultStrPrivate(IntPtr hIMC, string? strResult) { var CompositionForm = new Win32.COMPOSITIONFORM() { dwStyle = Win32.CFS_FORCE_POSITION, ptCurrentPos = CurrentCaret.Location }; Win32.ImmSetCompositionWindow(hIMC, ref CompositionForm); if (strResult != null && !string.IsNullOrEmpty(strResult)) { var chars = new List(strResult.Length); foreach (char key in strResult) { if (Verify(key, out var change)) chars.Add(change ?? key.ToString()); } if (chars.Count > 0) EnterText(string.Join("", chars)); } } protected virtual bool Verify(char key, out string? change) { change = null; return true; } #endregion protected override void Dispose(bool disposing) { ThreadFocus?.Dispose(); ThreadHover?.Dispose(); base.Dispose(disposing); } ITask? ThreadHover = null; ITask? ThreadFocus = null; } }