/contrib/ICSharpCode.TextEditor/Project/Src/Gui/CompletionWindow/CodeCompletionListView.cs

https://github.com/Ziaw/npad · C# · 293 lines · 242 code · 30 blank · 21 comment · 67 complexity · d7f8ca48fabda0c64f42057a48662068 MD5 · raw file

  1. // <file>
  2. // <copyright see="prj:///doc/copyright.txt"/>
  3. // <license see="prj:///doc/license.txt"/>
  4. // <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
  5. // <version>$Revision$</version>
  6. // </file>
  7. using System;
  8. using System.Drawing;
  9. using System.Windows.Forms;
  10. namespace ICSharpCode.TextEditor.Gui.CompletionWindow
  11. {
  12. /// <summary>
  13. /// Description of CodeCompletionListView.
  14. /// </summary>
  15. public class CodeCompletionListView : System.Windows.Forms.UserControl
  16. {
  17. ICompletionData[] completionData;
  18. int firstItem = 0;
  19. int selectedItem = -1;
  20. ImageList imageList;
  21. public ImageList ImageList {
  22. get {
  23. return imageList;
  24. }
  25. set {
  26. imageList = value;
  27. }
  28. }
  29. public int FirstItem {
  30. get {
  31. return firstItem;
  32. }
  33. set {
  34. if (firstItem != value) {
  35. firstItem = value;
  36. OnFirstItemChanged(EventArgs.Empty);
  37. }
  38. }
  39. }
  40. public ICompletionData SelectedCompletionData {
  41. get {
  42. if (selectedItem < 0) {
  43. return null;
  44. }
  45. return completionData[selectedItem];
  46. }
  47. }
  48. public int ItemHeight {
  49. get {
  50. return Math.Max(imageList.ImageSize.Height, (int)(Font.Height * 1.25));
  51. }
  52. }
  53. public int MaxVisibleItem {
  54. get {
  55. return Height / ItemHeight;
  56. }
  57. }
  58. public CodeCompletionListView(ICompletionData[] completionData)
  59. {
  60. Array.Sort(completionData, DefaultCompletionData.Compare);
  61. this.completionData = completionData;
  62. // this.KeyDown += new System.Windows.Forms.KeyEventHandler(OnKey);
  63. // SetStyle(ControlStyles.Selectable, false);
  64. // SetStyle(ControlStyles.UserPaint, true);
  65. // SetStyle(ControlStyles.DoubleBuffer, false);
  66. }
  67. public void Close()
  68. {
  69. if (completionData != null) {
  70. Array.Clear(completionData, 0, completionData.Length);
  71. }
  72. base.Dispose();
  73. }
  74. public void SelectIndex(int index)
  75. {
  76. int oldSelectedItem = selectedItem;
  77. int oldFirstItem = firstItem;
  78. index = Math.Max(0, index);
  79. selectedItem = Math.Max(0, Math.Min(completionData.Length - 1, index));
  80. if (selectedItem < firstItem) {
  81. FirstItem = selectedItem;
  82. }
  83. if (firstItem + MaxVisibleItem <= selectedItem) {
  84. FirstItem = selectedItem - MaxVisibleItem + 1;
  85. }
  86. if (oldSelectedItem != selectedItem) {
  87. if (firstItem != oldFirstItem) {
  88. Invalidate();
  89. } else {
  90. int min = Math.Min(selectedItem, oldSelectedItem) - firstItem;
  91. int max = Math.Max(selectedItem, oldSelectedItem) - firstItem;
  92. Invalidate(new Rectangle(0, 1 + min * ItemHeight, Width, (max - min + 1) * ItemHeight));
  93. }
  94. OnSelectedItemChanged(EventArgs.Empty);
  95. }
  96. }
  97. public void CenterViewOn(int index)
  98. {
  99. int oldFirstItem = this.FirstItem;
  100. int firstItem = index - MaxVisibleItem / 2;
  101. if (firstItem < 0)
  102. this.FirstItem = 0;
  103. else if (firstItem >= completionData.Length - MaxVisibleItem)
  104. this.FirstItem = completionData.Length - MaxVisibleItem;
  105. else
  106. this.FirstItem = firstItem;
  107. if (this.FirstItem != oldFirstItem) {
  108. Invalidate();
  109. }
  110. }
  111. public void ClearSelection()
  112. {
  113. if (selectedItem < 0)
  114. return;
  115. int itemNum = selectedItem - firstItem;
  116. selectedItem = -1;
  117. Invalidate(new Rectangle(0, itemNum * ItemHeight, Width, (itemNum + 1) * ItemHeight + 1));
  118. Update();
  119. OnSelectedItemChanged(EventArgs.Empty);
  120. }
  121. public void PageDown()
  122. {
  123. SelectIndex(selectedItem + MaxVisibleItem);
  124. }
  125. public void PageUp()
  126. {
  127. SelectIndex(selectedItem - MaxVisibleItem);
  128. }
  129. public void SelectNextItem()
  130. {
  131. SelectIndex(selectedItem + 1);
  132. }
  133. public void SelectPrevItem()
  134. {
  135. SelectIndex(selectedItem - 1);
  136. }
  137. public void SelectItemWithStart(string startText)
  138. {
  139. if (startText == null || startText.Length == 0) return;
  140. string originalStartText = startText;
  141. startText = startText.ToLower();
  142. int bestIndex = -1;
  143. int bestQuality = -1;
  144. // Qualities: 0 = match start
  145. // 1 = match start case sensitive
  146. // 2 = full match
  147. // 3 = full match case sensitive
  148. double bestPriority = 0;
  149. for (int i = 0; i < completionData.Length; ++i) {
  150. string itemText = completionData[i].Text;
  151. string lowerText = itemText.ToLower();
  152. if (lowerText.StartsWith(startText)) {
  153. double priority = completionData[i].Priority;
  154. int quality;
  155. if (lowerText == startText) {
  156. if (itemText == originalStartText)
  157. quality = 3;
  158. else
  159. quality = 2;
  160. } else if (itemText.StartsWith(originalStartText)) {
  161. quality = 1;
  162. } else {
  163. quality = 0;
  164. }
  165. bool useThisItem;
  166. if (bestQuality < quality) {
  167. useThisItem = true;
  168. } else {
  169. if (bestIndex == selectedItem) {
  170. useThisItem = false;
  171. } else if (i == selectedItem) {
  172. useThisItem = bestQuality == quality;
  173. } else {
  174. useThisItem = bestQuality == quality && bestPriority < priority;
  175. }
  176. }
  177. if (useThisItem) {
  178. bestIndex = i;
  179. bestPriority = priority;
  180. bestQuality = quality;
  181. }
  182. }
  183. }
  184. if (bestIndex < 0) {
  185. ClearSelection();
  186. } else {
  187. if (bestIndex < firstItem || firstItem + MaxVisibleItem <= bestIndex) {
  188. SelectIndex(bestIndex);
  189. CenterViewOn(bestIndex);
  190. } else {
  191. SelectIndex(bestIndex);
  192. }
  193. }
  194. }
  195. protected override void OnPaint(PaintEventArgs pe)
  196. {
  197. float yPos = 1;
  198. float itemHeight = ItemHeight;
  199. // Maintain aspect ratio
  200. int imageWidth = (int)(itemHeight * imageList.ImageSize.Width / imageList.ImageSize.Height);
  201. int curItem = firstItem;
  202. Graphics g = pe.Graphics;
  203. while (curItem < completionData.Length && yPos < Height) {
  204. RectangleF drawingBackground = new RectangleF(1, yPos, Width - 2, itemHeight);
  205. if (drawingBackground.IntersectsWith(pe.ClipRectangle)) {
  206. // draw Background
  207. if (curItem == selectedItem) {
  208. g.FillRectangle(SystemBrushes.Highlight, drawingBackground);
  209. } else {
  210. g.FillRectangle(SystemBrushes.Window, drawingBackground);
  211. }
  212. // draw Icon
  213. int xPos = 0;
  214. if (imageList != null && completionData[curItem].ImageIndex < imageList.Images.Count) {
  215. g.DrawImage(imageList.Images[completionData[curItem].ImageIndex], new RectangleF(1, yPos, imageWidth, itemHeight));
  216. xPos = imageWidth;
  217. }
  218. // draw text
  219. if (curItem == selectedItem) {
  220. g.DrawString(completionData[curItem].Text, Font, SystemBrushes.HighlightText, xPos, yPos);
  221. } else {
  222. g.DrawString(completionData[curItem].Text, Font, SystemBrushes.WindowText, xPos, yPos);
  223. }
  224. }
  225. yPos += itemHeight;
  226. ++curItem;
  227. }
  228. g.DrawRectangle(SystemPens.Control, new Rectangle(0, 0, Width - 1, Height - 1));
  229. }
  230. protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
  231. {
  232. float yPos = 1;
  233. int curItem = firstItem;
  234. float itemHeight = ItemHeight;
  235. while (curItem < completionData.Length && yPos < Height) {
  236. RectangleF drawingBackground = new RectangleF(1, yPos, Width - 2, itemHeight);
  237. if (drawingBackground.Contains(e.X, e.Y)) {
  238. SelectIndex(curItem);
  239. break;
  240. }
  241. yPos += itemHeight;
  242. ++curItem;
  243. }
  244. }
  245. protected override void OnPaintBackground(PaintEventArgs pe)
  246. {
  247. }
  248. protected virtual void OnSelectedItemChanged(EventArgs e)
  249. {
  250. if (SelectedItemChanged != null) {
  251. SelectedItemChanged(this, e);
  252. }
  253. }
  254. protected virtual void OnFirstItemChanged(EventArgs e)
  255. {
  256. if (FirstItemChanged != null) {
  257. FirstItemChanged(this, e);
  258. }
  259. }
  260. public event EventHandler SelectedItemChanged;
  261. public event EventHandler FirstItemChanged;
  262. }
  263. }