- using System.Collections.Generic;
- using System.Text.RegularExpressions;
- using Godot;
- namespace DScript.GodotEditor
- {
- /// <summary>
- /// 代码补全提示
- /// </summary>
- public class CodeHintPanel : Popup
- {
- private class CodeHintItemData
- {
- public CodeHintItem CodeHintItem;
- public bool VisibleFlag;
- }
- //补全选项
- [Export] private PackedScene CodeHintItem;
- /// <summary>
- /// 获取实例
- /// </summary>
- public static CodeHintPanel Instance { get; private set; }
- /// <summary>
- /// 当前选提示组件活动的项
- /// </summary>
- public int ActiveIndex
- {
- get => _activeIndex;
- set => SetActiveIndex(value);
- }
- private int _activeIndex = -1;
- //滑动容器
- private ScrollContainer _scrollContainer;
- //提示项父容器
- private VBoxContainer _itemContainer;
- //包含提示数据
- private List<CodeHintData> _hintDataList = new List<CodeHintData>();
- //当前已启用项的列表
- private List<CodeHintItemData> _activeItemList = new List<CodeHintItemData>();
- //长按计时器
- private float _clickTimer = 0;
- private bool _continuousFlag = false;
- //当前的文本编辑器对象
- private CodeTextEdit _textEdit;
- private int startLine;
- private int startcColumn;
- public CodeHintPanel()
- {
- Instance = this;
- }
- public override void _Ready()
- {
- _scrollContainer = GetNode<ScrollContainer>("ScrollContainer");
- _itemContainer = _scrollContainer.GetNode<VBoxContainer>("VBoxContainer");
- for (int i = 0; i < CodeTextEdit.KeyCodes.Length; i++)
- {
- _hintDataList.Add(new CodeHintData() { Text = CodeTextEdit.KeyCodes[i] });
- // var item = CreateItem();
- // item.CodeHintItem.CodeText = CodeTextEdit.KeyCodes[i];
- }
- }
- public override void _Process(float delta)
- {
- if (!Visible) return;
- if (_textEdit == null)
- {
- Visible = false;
- _textEdit = null;
- return;
- }
- //长按判定
- var down = Input.IsActionPressed("ui_down");
- var up = Input.IsActionPressed("ui_up");
- //是否触发选项移动
- bool clickFlag = false;
- if (down || up)
- {
- _clickTimer += delta;
- if ((!_continuousFlag && _clickTimer > 0.5f) || (_continuousFlag && _clickTimer > 0.06f))
- {
- _continuousFlag = true;
- _clickTimer %= 0.06f;
- clickFlag = true;
- }
- }
- else
- {
- _clickTimer = 0;
- _continuousFlag = false;
- }
- //选项移动判定
- if ((Input.IsActionJustPressed("ui_down") || (clickFlag && down)) && _activeItemList.Count > 1) //按下下键
- {
- var index = ActiveIndex;
- index += 1;
- if (index >= _activeItemList.Count)
- {
- index = 0;
- }
- ActiveIndex = index;
- }
- else if ((Input.IsActionJustPressed("ui_up") || (clickFlag && up)) && _activeItemList.Count > 1) //按下上键
- {
- var index = ActiveIndex;
- index -= 1;
- if (index < 0)
- {
- index = _activeItemList.Count - 1;
- }
- ActiveIndex = index;
- }
- }
- public override void _Input(InputEvent @event)
- {
- if (!Visible) return;
- if (@event is InputEventKey eventKey)
- {
- if (eventKey.IsPressed())
- {
- //按下左,右,空格时隐藏提示框
- if (eventKey.Scancode == (int)KeyList.Left || eventKey.Scancode == (int)KeyList.Right ||
- eventKey.Scancode == (int)KeyList.Space)
- {
- HidePanel();
- }
- //按下 enter 或者 tab 确认输入
- else if (eventKey.Scancode == (int)KeyList.Enter || eventKey.Scancode == (int)KeyList.Tab)
- {
- ConfirmInput(ActiveIndex);
- }
- }
- }
- }
- /// <summary>
- /// 确认输入选中的项, 补全代码
- /// </summary>
- internal void ConfirmInput(int index)
- {
- if (index >= 0 && _activeItemList.Count > 0 && index < _activeItemList.Count && _textEdit != null)
- {
- var line = _textEdit.CursorGetLine();
- var column = _textEdit.CursorGetColumn();
- var lineStr = _textEdit.GetLine(line);
- var beforeStr = lineStr.Substring(0, column);
- var result = Regex.Match(beforeStr, "[\\w]+$");
- if (result.Success)
- {
- var item = _activeItemList[index];
- var text = item.CodeHintItem.CodeText;
- lineStr = beforeStr.Substring(0,
- result.Index) + text + lineStr.Substring(column);
- _textEdit.SetLine(line, lineStr);
- _textEdit.CursorSetColumn(result.Index + text.Length);
- _textEdit.TriggerTextChanged();
- }
- else
- {
- var item = _activeItemList[index];
- _textEdit.InsertTextAtCursor(item.CodeHintItem.CodeText);
- }
- }
- Hide();
- CodeHintManager.EnterInput = true;
- }
- /// <summary>
- /// 显示提示面板
- /// </summary>
- public void ShowPanel(CodeTextEdit textEdit, Vector2 pos)
- {
- _textEdit = textEdit;
- RectPosition = pos;
- if (!Visible)
- {
- GD.Print("call ShowPanel()");
- Popup_();
- _textEdit.GrabFocus();
- ActiveIndex = 0;
- }
- }
- /// <summary>
- /// 隐藏面板
- /// </summary>
- public void HidePanel()
- {
- GD.Print("call HidePanel()");
- Hide();
- _textEdit = null;
- }
- /// <summary>
- /// 设置活动项
- /// </summary>
- private void SetActiveIndex(int index)
- {
- //禁用之前的
- if (_activeIndex >= 0 && _activeIndex < _activeItemList.Count)
- {
- var item = _activeItemList[_activeIndex];
- item.CodeHintItem.SetActive(false);
- }
- _activeIndex = index;
- //启用现在的
- if (index >= 0 && index < _activeItemList.Count)
- {
- var item = _activeItemList[index];
- item.CodeHintItem.SetActive(true);
- //矫正滑动组件y轴值, 使其选中项不会跑到视野外
- var vertical = _scrollContainer.ScrollVertical;
- var scrollSize = _scrollContainer.GetVScrollbar().RectSize;
- var itemPos = item.CodeHintItem.RectPosition;
- var itemSize = item.CodeHintItem.RectSize;
- itemPos.y -= vertical;
- if (itemPos.y < 0)
- {
- _scrollContainer.ScrollVertical = (int)(index * itemSize.y);
- }
- else if (itemPos.y + itemSize.y > scrollSize.y)
- {
- _scrollContainer.ScrollVertical = (int)((index + 1) * itemSize.y - scrollSize.y);
- }
- }
- }
- /// <summary>
- /// 创建提示项
- /// </summary>
- private CodeHintItemData CreateItem()
- {
- var codeHintItem = CodeHintItem.Instance<CodeHintItem>();
- _itemContainer.AddChild(codeHintItem);
- codeHintItem.Index = _activeItemList.Count;
- var item = new CodeHintItemData();
- item.CodeHintItem = codeHintItem;
- _activeItemList.Add(item);
- return item;
- }
- }
- }