Newer
Older
DungeonShooting / DungeonShooting_Godot / editor / src / CodeHintPanel.cs
@小李xl 小李xl on 26 Sep 2022 6 KB 代码提示组件开发
  1. using System.Collections.Generic;
  2. using System.Text.RegularExpressions;
  3. using Godot;
  4.  
  5. namespace DScript.GodotEditor
  6. {
  7. /// <summary>
  8. /// 代码补全提示
  9. /// </summary>
  10. public class CodeHintPanel : Popup
  11. {
  12. private class CodeHintItemData
  13. {
  14. public CodeHintItem CodeHintItem;
  15. public bool VisibleFlag;
  16. }
  17. //补全选项
  18. [Export] private PackedScene CodeHintItem;
  19.  
  20. /// <summary>
  21. /// 获取实例
  22. /// </summary>
  23. public static CodeHintPanel Instance { get; private set; }
  24.  
  25. /// <summary>
  26. /// 当前选提示组件活动的项
  27. /// </summary>
  28. public int ActiveIndex
  29. {
  30. get => _activeIndex;
  31. set => SetActiveIndex(value);
  32. }
  33. private int _activeIndex = -1;
  34.  
  35. //滑动容器
  36. private ScrollContainer _scrollContainer;
  37. //提示项父容器
  38. private VBoxContainer _itemContainer;
  39.  
  40. //包含提示数据
  41. private List<CodeHintData> _hintDataList = new List<CodeHintData>();
  42. //当前已启用项的列表
  43. private List<CodeHintItemData> _activeItemList = new List<CodeHintItemData>();
  44. //长按计时器
  45. private float _clickTimer = 0;
  46. private bool _continuousFlag = false;
  47.  
  48. //当前的文本编辑器对象
  49. private CodeTextEdit _textEdit;
  50. private int startLine;
  51. private int startcColumn;
  52. public CodeHintPanel()
  53. {
  54. Instance = this;
  55. }
  56.  
  57. public override void _Ready()
  58. {
  59. _scrollContainer = GetNode<ScrollContainer>("ScrollContainer");
  60. _itemContainer = _scrollContainer.GetNode<VBoxContainer>("VBoxContainer");
  61.  
  62. for (int i = 0; i < CodeTextEdit.KeyCodes.Length; i++)
  63. {
  64. _hintDataList.Add(new CodeHintData() { Text = CodeTextEdit.KeyCodes[i] });
  65. // var item = CreateItem();
  66. // item.CodeHintItem.CodeText = CodeTextEdit.KeyCodes[i];
  67. }
  68. }
  69.  
  70. public override void _Process(float delta)
  71. {
  72. if (!Visible) return;
  73. if (_textEdit == null)
  74. {
  75. Visible = false;
  76. _textEdit = null;
  77. return;
  78. }
  79. //长按判定
  80. var down = Input.IsActionPressed("ui_down");
  81. var up = Input.IsActionPressed("ui_up");
  82. //是否触发选项移动
  83. bool clickFlag = false;
  84. if (down || up)
  85. {
  86. _clickTimer += delta;
  87. if ((!_continuousFlag && _clickTimer > 0.5f) || (_continuousFlag && _clickTimer > 0.06f))
  88. {
  89. _continuousFlag = true;
  90. _clickTimer %= 0.06f;
  91. clickFlag = true;
  92. }
  93. }
  94. else
  95. {
  96. _clickTimer = 0;
  97. _continuousFlag = false;
  98. }
  99. //选项移动判定
  100. if ((Input.IsActionJustPressed("ui_down") || (clickFlag && down)) && _activeItemList.Count > 1) //按下下键
  101. {
  102. var index = ActiveIndex;
  103. index += 1;
  104. if (index >= _activeItemList.Count)
  105. {
  106. index = 0;
  107. }
  108.  
  109. ActiveIndex = index;
  110. }
  111. else if ((Input.IsActionJustPressed("ui_up") || (clickFlag && up)) && _activeItemList.Count > 1) //按下上键
  112. {
  113. var index = ActiveIndex;
  114. index -= 1;
  115. if (index < 0)
  116. {
  117. index = _activeItemList.Count - 1;
  118. }
  119.  
  120. ActiveIndex = index;
  121. }
  122. }
  123.  
  124. public override void _Input(InputEvent @event)
  125. {
  126. if (!Visible) return;
  127. if (@event is InputEventKey eventKey)
  128. {
  129. if (eventKey.IsPressed())
  130. {
  131. //按下左,右,空格时隐藏提示框
  132. if (eventKey.Scancode == (int)KeyList.Left || eventKey.Scancode == (int)KeyList.Right ||
  133. eventKey.Scancode == (int)KeyList.Space)
  134. {
  135. HidePanel();
  136. }
  137. //按下 enter 或者 tab 确认输入
  138. else if (eventKey.Scancode == (int)KeyList.Enter || eventKey.Scancode == (int)KeyList.Tab)
  139. {
  140. ConfirmInput(ActiveIndex);
  141. }
  142. }
  143. }
  144. }
  145.  
  146. /// <summary>
  147. /// 确认输入选中的项, 补全代码
  148. /// </summary>
  149. internal void ConfirmInput(int index)
  150. {
  151. if (index >= 0 && _activeItemList.Count > 0 && index < _activeItemList.Count && _textEdit != null)
  152. {
  153. var line = _textEdit.CursorGetLine();
  154. var column = _textEdit.CursorGetColumn();
  155. var lineStr = _textEdit.GetLine(line);
  156.  
  157. var beforeStr = lineStr.Substring(0, column);
  158.  
  159. var result = Regex.Match(beforeStr, "[\\w]+$");
  160. if (result.Success)
  161. {
  162. var item = _activeItemList[index];
  163. var text = item.CodeHintItem.CodeText;
  164. lineStr = beforeStr.Substring(0,
  165. result.Index) + text + lineStr.Substring(column);
  166. _textEdit.SetLine(line, lineStr);
  167. _textEdit.CursorSetColumn(result.Index + text.Length);
  168. _textEdit.TriggerTextChanged();
  169. }
  170. else
  171. {
  172. var item = _activeItemList[index];
  173. _textEdit.InsertTextAtCursor(item.CodeHintItem.CodeText);
  174. }
  175. }
  176.  
  177. Hide();
  178. CodeHintManager.EnterInput = true;
  179. }
  180.  
  181. /// <summary>
  182. /// 显示提示面板
  183. /// </summary>
  184. public void ShowPanel(CodeTextEdit textEdit, Vector2 pos)
  185. {
  186. _textEdit = textEdit;
  187. RectPosition = pos;
  188. if (!Visible)
  189. {
  190. GD.Print("call ShowPanel()");
  191. Popup_();
  192. _textEdit.GrabFocus();
  193. ActiveIndex = 0;
  194. }
  195. }
  196.  
  197. /// <summary>
  198. /// 隐藏面板
  199. /// </summary>
  200. public void HidePanel()
  201. {
  202. GD.Print("call HidePanel()");
  203. Hide();
  204. _textEdit = null;
  205. }
  206. /// <summary>
  207. /// 设置活动项
  208. /// </summary>
  209. private void SetActiveIndex(int index)
  210. {
  211. //禁用之前的
  212. if (_activeIndex >= 0 && _activeIndex < _activeItemList.Count)
  213. {
  214. var item = _activeItemList[_activeIndex];
  215. item.CodeHintItem.SetActive(false);
  216. }
  217.  
  218. _activeIndex = index;
  219.  
  220. //启用现在的
  221. if (index >= 0 && index < _activeItemList.Count)
  222. {
  223. var item = _activeItemList[index];
  224. item.CodeHintItem.SetActive(true);
  225.  
  226. //矫正滑动组件y轴值, 使其选中项不会跑到视野外
  227. var vertical = _scrollContainer.ScrollVertical;
  228. var scrollSize = _scrollContainer.GetVScrollbar().RectSize;
  229. var itemPos = item.CodeHintItem.RectPosition;
  230. var itemSize = item.CodeHintItem.RectSize;
  231. itemPos.y -= vertical;
  232. if (itemPos.y < 0)
  233. {
  234. _scrollContainer.ScrollVertical = (int)(index * itemSize.y);
  235. }
  236. else if (itemPos.y + itemSize.y > scrollSize.y)
  237. {
  238. _scrollContainer.ScrollVertical = (int)((index + 1) * itemSize.y - scrollSize.y);
  239. }
  240. }
  241. }
  242.  
  243. /// <summary>
  244. /// 创建提示项
  245. /// </summary>
  246. private CodeHintItemData CreateItem()
  247. {
  248. var codeHintItem = CodeHintItem.Instance<CodeHintItem>();
  249. _itemContainer.AddChild(codeHintItem);
  250. codeHintItem.Index = _activeItemList.Count;
  251. var item = new CodeHintItemData();
  252. item.CodeHintItem = codeHintItem;
  253. _activeItemList.Add(item);
  254. return item;
  255. }
  256. }
  257. }