PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/controls/ListWidget.cs

https://github.com/moscrif/ide
C# | 703 lines | 451 code | 72 blank | 180 comment | 102 complexity | 74579bbea75e37db2ee8980e0675c97e MD5 | raw file
  1. using Gtk;
  2. using Gdk;
  3. using Pango;
  4. using System;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Collections.Generic;
  8. using Moscrif.IDE.Completion;
  9. namespace Moscrif.IDE.Controls
  10. {
  11. public class ListWidget : Gtk.DrawingArea
  12. {
  13. int margin = 0;
  14. int padding = 4;
  15. int listWidth = 300;
  16. Pango.Layout layout;
  17. ListWindow win;
  18. int selection = 0;
  19. int page = 0;
  20. int rowHeight;
  21. bool buttonPressed;
  22. public event EventHandler SelectionChanged;
  23. string completionString;
  24. public string CompletionString {
  25. get { return completionString; }
  26. set {
  27. if (completionString != value) {
  28. completionString = value;
  29. FilterWords ();
  30. QueueDraw ();
  31. }
  32. }
  33. }
  34. public string DefaultCompletionString {
  35. get;
  36. set;
  37. }
  38. public bool PreviewCompletionString {
  39. get;
  40. set;
  41. }
  42. static bool inCategoryMode;
  43. public bool InCategoryMode {
  44. get { return inCategoryMode; }
  45. set { inCategoryMode = value; this.CalcVisibleRows (); this.UpdatePage (); }
  46. }
  47. public ListWidget (ListWindow win)
  48. {
  49. this.win = win;
  50. this.Events = EventMask.ButtonPressMask | EventMask.ButtonReleaseMask | EventMask.PointerMotionMask;
  51. DefaultCompletionString = "";
  52. layout = new Pango.Layout (this.PangoContext);
  53. layout.Wrap = Pango.WrapMode.Char;
  54. FontDescription des = this.Style.FontDescription.Copy ();
  55. layout.FontDescription = des;
  56. }
  57. public void Reset ()
  58. {
  59. if (win.DataProvider == null) {
  60. selection = -1;
  61. return;
  62. }
  63. selection = win.DataProvider.ItemCount == 0 ? -1 : 0;
  64. page = 0;
  65. AutoSelect = false;
  66. CalcVisibleRows ();
  67. if (SelectionChanged != null)
  68. SelectionChanged (this, EventArgs.Empty);
  69. }
  70. public int SelectionIndex {
  71. get {
  72. if (Selection < 0 || filteredItems.Count <= Selection)
  73. return -1;
  74. return filteredItems[Selection];
  75. }
  76. }
  77. public int Selection {
  78. get { return selection; }
  79. set {
  80. value = Math.Min (filteredItems.Count - 1, Math.Max (0, value));
  81. if (value != selection) {
  82. selection = value;
  83. UpdatePage ();
  84. if (SelectionChanged != null)
  85. SelectionChanged (this, EventArgs.Empty);
  86. this.QueueDraw ();
  87. }
  88. }
  89. }
  90. int GetIndex (bool countCategories, int itemNumber)
  91. {
  92. //if (!InCategoryMode || categories.Count == 1)
  93. // return itemNumber;
  94. int result = -1;
  95. int yPos = 0;
  96. int curItem = 0;
  97. Iterate (false, ref yPos, //delegate (Category category,int ypos) { if (countCategories) curItem++;},
  98. delegate (int item, int ypos) {//Category curCategory,
  99. if (item == itemNumber) {
  100. result = curItem;
  101. return false;
  102. }
  103. curItem++;
  104. return true;
  105. });
  106. return result;
  107. }
  108. int GetItem (bool countCategories, int index)
  109. {
  110. //if (!InCategoryMode || categories.Count == 1)
  111. // return index;
  112. int result = -1;
  113. int curItem = 0;
  114. int yPos = 0;
  115. Iterate (false, ref yPos, //delegate (Category category, int ypos) {if (countCategories) {if (curItem == index) result = category.Items[0];curItem++;} },
  116. delegate ( int item, int ypos) {//Category curCategory,
  117. if (curItem == index) {
  118. result = item;
  119. return false;
  120. }
  121. curItem++;
  122. return true;
  123. });
  124. return result;
  125. }
  126. /*public void MoveToCategory (int relative)
  127. {
  128. int current = CurrentCategory ();
  129. int next = System.Math.Min (categories.Count - 1, System.Math.Max (0, current + relative));
  130. if (next < 0 || next >= categories.Count)
  131. return;
  132. Category newCategory = categories[next];
  133. Selection = newCategory.Items[0];
  134. if (next == 0)
  135. Page = 0;
  136. UpdatePage ();
  137. }*/
  138. /*int CurrentCategory ()
  139. {
  140. for (int i = 0; i < categories.Count; i++) {
  141. if (categories[i].Items.Contains (Selection))
  142. return i;
  143. }
  144. return -1;
  145. }*/
  146. public void MoveCursor (int relative)
  147. {
  148. int newIndex = GetIndex (false, Selection) + relative;
  149. /* if (Math.Abs (relative) == 1) {
  150. if (newIndex < 0)
  151. newIndex = filteredItems.Count - 1;
  152. if (newIndex >= filteredItems.Count)
  153. newIndex = 0;
  154. }*/
  155. int newSelection = GetItem (false, System.Math.Min (filteredItems.Count - 1, System.Math.Max (0, newIndex)));
  156. if (newSelection < 0)
  157. return;
  158. if (Selection == newSelection && relative < 0) {
  159. Page = 0;
  160. } else {
  161. Selection = newSelection;
  162. }
  163. }
  164. public void UpdatePage ()
  165. {
  166. int index = GetIndex (true, Selection);
  167. if (index < page || index >= page + VisibleRows)
  168. page = index - (VisibleRows / 2);
  169. int itemCount = filteredItems.Count;
  170. /*if (InCategoryMode) {
  171. itemCount += categories.Count;
  172. if (categories.Any (cat => cat.CompletionCategory == null))
  173. itemCount--;
  174. }*/
  175. Page = System.Math.Max (0, System.Math.Min (page, itemCount - VisibleRows - 1));
  176. }
  177. bool autoSelect;
  178. public bool AutoSelect {
  179. get { return autoSelect; }
  180. set {
  181. autoSelect = value;
  182. QueueDraw ();
  183. }
  184. }
  185. public bool AutoCompleteEmptyMatch {
  186. get;
  187. set;
  188. }
  189. public bool SelectionEnabled {
  190. get {
  191. return AutoSelect && (AutoCompleteEmptyMatch || !string.IsNullOrEmpty (CompletionString) || !string.IsNullOrEmpty (DefaultCompletionString));
  192. }
  193. }
  194. public int Page {
  195. get { return page; }
  196. set {
  197. if (page != value) {
  198. page = value;
  199. this.QueueDraw ();
  200. }
  201. if (SelectionChanged != null)
  202. SelectionChanged (this, EventArgs.Empty);
  203. }
  204. }
  205. protected override bool OnButtonPressEvent (EventButton e)
  206. {
  207. Selection = GetRowByPosition ((int)e.Y);
  208. buttonPressed = true;
  209. return base.OnButtonPressEvent (e);
  210. }
  211. protected override bool OnButtonReleaseEvent (EventButton e)
  212. {
  213. buttonPressed = false;
  214. return base.OnButtonReleaseEvent (e);
  215. }
  216. protected override void OnRealized ()
  217. {
  218. base.OnRealized ();
  219. this.GdkWindow.Background = this.Style.Base (StateType.Normal);
  220. }
  221. protected override bool OnMotionNotifyEvent (EventMotion e)
  222. {
  223. if (!buttonPressed)
  224. return base.OnMotionNotifyEvent (e);
  225. int winWidth, winHeight;
  226. this.GdkWindow.GetSize (out winWidth, out winHeight);
  227. Selection = GetRowByPosition ((int)e.Y);
  228. return true;
  229. }
  230. protected override bool OnExposeEvent (Gdk.EventExpose args)
  231. {
  232. Gdk.Window window = args.Window;
  233. var alloc = Allocation;
  234. int width = alloc.Width;
  235. int height = alloc.Height;
  236. int lineWidth = width - margin * 2;
  237. int xpos = margin + padding;
  238. int yPos = margin;
  239. if (PreviewCompletionString) {
  240. layout.SetText (string.IsNullOrEmpty (CompletionString) ? MainClass.Languages.Translate("select") : CompletionString);
  241. int wi, he;
  242. layout.GetPixelSize (out wi, out he);
  243. window.DrawRectangle (this.Style.BaseGC (StateType.Insensitive), true, margin, yPos, lineWidth, he + padding);
  244. window.DrawLayout (string.IsNullOrEmpty (CompletionString) ? this.Style.TextGC (StateType.Insensitive) : this.Style.TextGC (StateType.Normal), xpos, yPos, layout);
  245. yPos += rowHeight;
  246. }
  247. if (filteredItems.Count == 0) {
  248. Gdk.GC gc = new Gdk.GC (window);
  249. gc.RgbFgColor = new Gdk.Color (0xff, 0xbc, 0xc1);
  250. window.DrawRectangle (gc, true, 0, yPos, width, height - yPos);
  251. gc.Dispose ();
  252. layout.SetText (MainClass.Languages.Translate("no_suggestions"));
  253. int lWidth, lHeight;
  254. layout.GetPixelSize (out lWidth, out lHeight);
  255. window.DrawLayout (this.Style.TextGC (StateType.Normal), (width - lWidth) / 2, yPos + (height - lHeight - yPos) / 2, layout);
  256. return true;
  257. }
  258. var textGCInsensitive = this.Style.TextGC (StateType.Insensitive);
  259. var textGCNormal = this.Style.TextGC (StateType.Normal);
  260. var fgGCNormal = this.Style.ForegroundGC (StateType.Normal);
  261. Iterate (true, ref yPos, //delegate (Category category, int ypos) {if
  262. //(ypos >= height - margin) return;
  263. // Gdk.Pixbuf icon = MainClass.Tools.GetIconFromStock (category.CompletionCategory.Icon, IconSize.Menu);
  264. //window.DrawPixbuf (fgGCNormal, icon, 0, 0, margin, ypos, icon.Width, icon.Height, Gdk.RgbDither.None, 0, 0);
  265. //layout.SetMarkup ("<span weight='bold'>" + category.CompletionCategory.DisplayText + "</span>");
  266. //window.DrawLayout (textGCInsensitive, icon.Width + 4, ypos, layout);
  267. //layout.SetMarkup ("");
  268. //},
  269. delegate ( int item, int ypos) {//Category curCategory,
  270. if (ypos >= height - margin)
  271. return false;
  272. int itemIndex = filteredItems[item];
  273. //if (InCategoryMode && curCategory != null && curCategory.CompletionCategory != null) {
  274. // xpos = margin + padding + 8;
  275. //} else {
  276. xpos = margin + padding;
  277. //}
  278. string markup = win.DataProvider.HasMarkup (itemIndex) ? (win.DataProvider.GetMarkup (itemIndex) ?? "&lt;null&gt;") : GLib.Markup.EscapeText (win.DataProvider.GetText (itemIndex) ?? "<null>");
  279. string description = win.DataProvider.GetDescription (itemIndex);
  280. if (string.IsNullOrEmpty (description)) {
  281. layout.SetMarkup (markup);
  282. } else {
  283. if (item == selection) {
  284. layout.SetMarkup (markup + " " + description );
  285. } else {
  286. layout.SetMarkup (markup + " <span foreground=\"darkgray\">" + description + "</span>");
  287. }
  288. }
  289. int mw, mh;
  290. layout.GetPixelSize (out mw, out mh);
  291. if (mw > listWidth) {
  292. WidthRequest = listWidth = mw;
  293. win.WidthRequest = win.Allocation.Width + mw - width;
  294. win.QueueResize ();
  295. }
  296. string text = win.DataProvider.GetText (itemIndex);
  297. if ((!SelectionEnabled || item != selection) && !string.IsNullOrEmpty (text)) {
  298. int[] matchIndices = Match (CompletionString, text);
  299. if (matchIndices != null) {
  300. Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList ();
  301. for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++) {
  302. int idx = matchIndices[newSelection];
  303. Pango.AttrForeground fg = new Pango.AttrForeground (0, 0, ushort.MaxValue);
  304. fg.StartIndex = (uint)idx;
  305. fg.EndIndex = (uint)(idx + 1);
  306. attrList.Insert (fg);
  307. }
  308. layout.Attributes = attrList;
  309. }
  310. }
  311. Gdk.Pixbuf icon = win.DataProvider.GetIcon (itemIndex);
  312. int iconHeight, iconWidth;
  313. if (icon != null) {
  314. iconWidth = icon.Width;
  315. iconHeight = icon.Height;
  316. } else if (!Gtk.Icon.SizeLookup (Gtk.IconSize.Menu, out iconWidth, out iconHeight)) {
  317. iconHeight = iconWidth = 24;
  318. }
  319. int wi, he, typos, iypos;
  320. layout.GetPixelSize (out wi, out he);
  321. typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos;
  322. iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos;
  323. if (item == selection) {
  324. if (SelectionEnabled) {
  325. window.DrawRectangle (this.Style.BaseGC (StateType.Selected), true, margin, ypos, lineWidth, he + padding);
  326. window.DrawLayout (this.Style.TextGC (StateType.Selected), xpos + iconWidth + 2, typos, layout);
  327. } else {
  328. window.DrawRectangle (this.Style.DarkGC (StateType.Prelight), false, margin, ypos, lineWidth - 1, he + padding - 1);
  329. window.DrawLayout (textGCNormal, xpos + iconWidth + 2, typos, layout);
  330. }
  331. } else
  332. window.DrawLayout (textGCNormal, xpos + iconWidth + 2, typos, layout);
  333. if (icon != null)
  334. window.DrawPixbuf (fgGCNormal, icon, 0, 0, xpos, iypos, iconWidth, iconHeight, Gdk.RgbDither.None, 0, 0);
  335. layout.SetMarkup ("");
  336. if (layout.Attributes != null) {
  337. layout.Attributes.Dispose ();
  338. layout.Attributes = null;
  339. }
  340. return true;
  341. });
  342. /*
  343. int n = 0;
  344. while (ypos < winHeight - margin && (page + n) < filteredItems.Count) {
  345. bool hasMarkup = win.DataProvider.HasMarkup (filteredItems[page + n]);
  346. if (hasMarkup) {
  347. layout.SetMarkup (win.DataProvider.GetMarkup (filteredItems[page + n]) ?? "&lt;null&gt;");
  348. } else {
  349. layout.SetText (win.DataProvider.GetText (filteredItems[page + n]) ?? "<null>");
  350. }
  351. string text = win.DataProvider.GetText (filteredItems[page + n]);
  352. if ((!SelectionEnabled || page + n != selection) && !string.IsNullOrEmpty (text)) {
  353. int[] matchIndices = Match (CompletionString, text);
  354. if (matchIndices != null) {
  355. Pango.AttrList attrList = layout.Attributes ?? new Pango.AttrList ();
  356. for (int newSelection = 0; newSelection < matchIndices.Length; newSelection++) {
  357. int idx = matchIndices[newSelection];
  358. Pango.AttrForeground fg = new Pango.AttrForeground (0, 0, ushort.MaxValue);
  359. fg.StartIndex = (uint)idx;
  360. fg.EndIndex = (uint)(idx + 1);
  361. attrList.Insert (fg);
  362. }
  363. layout.Attributes = attrList;
  364. }
  365. }
  366. Gdk.Pixbuf icon = win.DataProvider.GetIcon (filteredItems[page + n]);
  367. int iconHeight, iconWidth;
  368. if (icon != null) {
  369. iconWidth = icon.Width;
  370. iconHeight = icon.Height;
  371. } else if (!Gtk.Icon.SizeLookup (Gtk.IconSize.Menu, out iconWidth, out iconHeight)) {
  372. iconHeight = iconWidth = 24;
  373. }
  374. int wi, he, typos, iypos;
  375. layout.GetPixelSize (out wi, out he);
  376. typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos;
  377. iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos;
  378. if (page + n == selection) {
  379. if (SelectionEnabled) {
  380. window.DrawRectangle (this.Style.BaseGC (StateType.Selected), true, margin, ypos, lineWidth, he + padding);
  381. window.DrawLayout (this.Style.TextGC (StateType.Selected), xpos + iconWidth + 2, typos, layout);
  382. } else {
  383. window.DrawRectangle (this.Style.DarkGC (StateType.Prelight), false, margin, ypos, lineWidth - 1, he + padding - 1);
  384. window.DrawLayout (this.Style.TextGC (StateType.Normal), xpos + iconWidth + 2, typos, layout);
  385. }
  386. } else
  387. window.DrawLayout (this.Style.TextGC (StateType.Normal), xpos + iconWidth + 2, typos, layout);
  388. if (icon != null)
  389. window.DrawPixbuf (this.Style.ForegroundGC (StateType.Normal), icon, 0, 0, xpos, iypos, iconWidth, iconHeight, Gdk.RgbDither.None, 0, 0);
  390. ypos += rowHeight;
  391. n++;
  392. if (hasMarkup)
  393. layout.SetMarkup (string.Empty);
  394. if (layout.Attributes != null) {
  395. layout.Attributes.Dispose ();
  396. layout.Attributes = null;
  397. }
  398. }
  399. */
  400. return true;
  401. }
  402. public int TextOffset {
  403. get {
  404. int iconWidth, iconHeight;
  405. if (!Gtk.Icon.SizeLookup (Gtk.IconSize.Menu, out iconWidth, out iconHeight))
  406. iconHeight = iconWidth = 24;
  407. return iconWidth + margin + padding + 2;
  408. }
  409. }
  410. internal List<int> filteredItems = new List<int> ();
  411. internal static bool Match2 (string filterText, string text){
  412. return text.StartsWith(filterText);
  413. /*if (text.IndexOf(filterText) > -1) return true;
  414. else return false;*/
  415. }
  416. internal static int[] Match (string filterText, string text)
  417. {
  418. //Console.WriteLine("filterText->"+filterText);
  419. //Console.WriteLine("text->"+text);
  420. if (string.IsNullOrEmpty (filterText))
  421. return new int[0];
  422. if (string.IsNullOrEmpty (text))
  423. return null;
  424. List<int> matchIndices = new List<int> ();
  425. bool wasMatch = false;
  426. int itemIndex = 0;
  427. for (int newSelection = 0; newSelection < text.Length && itemIndex < filterText.Length; newSelection++) {
  428. char ch1 = char.ToUpper (text[newSelection]);
  429. char ch2 = char.ToUpper (filterText[itemIndex]);
  430. bool ch1IsUpper = char.IsUpper (text[newSelection]);
  431. bool ch2IsUpper = char.IsUpper (filterText[itemIndex]);
  432. if (ch1 == ch2 && !(!ch1IsUpper && ch2IsUpper)) {
  433. itemIndex++;
  434. matchIndices.Add (newSelection);
  435. wasMatch = true;
  436. continue;
  437. } else {
  438. for (; newSelection < text.Length; newSelection++) {
  439. if (char.IsUpper (text[newSelection]) /*&& newSelection + 1 < text.Length && (!char.IsUpper (text[newSelection + 1]) || !char.IsLetter (text[newSelection + 1]))*/ && ch2 == text[newSelection]) {
  440. matchIndices.Add (newSelection);
  441. itemIndex++;
  442. wasMatch = true;
  443. break;
  444. }
  445. }
  446. if (wasMatch)
  447. continue;
  448. }
  449. if ((char.IsPunctuation (ch2) || char.IsWhiteSpace (ch2))) {
  450. wasMatch = false;
  451. break;
  452. }
  453. if (wasMatch) {
  454. wasMatch = false;
  455. bool match = false;
  456. for (; newSelection < text.Length; newSelection++) {
  457. if (ch2 == text[newSelection]) {
  458. newSelection--;
  459. match = true;
  460. break;
  461. }
  462. }
  463. if (match)
  464. continue;
  465. }
  466. break;
  467. }
  468. return itemIndex == filterText.Length ? matchIndices.ToArray () : null;
  469. }
  470. public static bool Matches (string filterText, string text)
  471. {
  472. /*int[] intpole =Match (filterText, text);
  473. if(intpole != null){
  474. foreach (int i in intpole)
  475. Console.WriteLine( "Match->"+ i);
  476. }*/
  477. return Match2(filterText, text);
  478. //return Match (filterText, text) != null;
  479. }
  480. /* Category GetCategory (CompletionCategory completionCategory)
  481. {
  482. foreach (Category cat in categories) {
  483. if (cat.CompletionCategory == completionCategory)
  484. return cat;
  485. }
  486. Category result = new Category ();
  487. result.CompletionCategory = completionCategory;
  488. if (completionCategory == null) {
  489. categories.Add (result);
  490. } else {
  491. categories.Insert (0, result);
  492. }
  493. return result;
  494. }
  495. */
  496. public void FilterWords ()
  497. {
  498. filteredItems.Clear ();
  499. //categories.Clear ();
  500. for (int newSelection = 0; newSelection < win.DataProvider.ItemCount; newSelection++) {
  501. if (string.IsNullOrEmpty (CompletionString) || Matches (CompletionString, win.DataProvider.GetText (newSelection))) {
  502. //CompletionCategory completionCategory = win.DataProvider.GetCompletionCategory (newSelection);
  503. //GetCategory (completionCategory).Items.Add (filteredItems.Count);
  504. filteredItems.Add (newSelection);
  505. }
  506. }
  507. /*categories.Sort (delegate (Category left, Category right) {
  508. return right.CompletionCategory != null ? right.CompletionCategory.CompareTo (left.CompletionCategory) : -1;
  509. });*/
  510. CalcVisibleRows ();
  511. UpdatePage ();
  512. OnWordsFiltered (EventArgs.Empty);
  513. }
  514. protected virtual void OnWordsFiltered (EventArgs e)
  515. {
  516. EventHandler handler = this.WordsFiltered;
  517. if (handler != null)
  518. handler (this, e);
  519. }
  520. public event EventHandler WordsFiltered;
  521. int GetRowByPosition (int ypos)
  522. {
  523. return GetItem (true, page + (ypos - margin) / rowHeight - (PreviewCompletionString ? 1 : 0));
  524. }
  525. public Gdk.Rectangle GetRowArea (int row)
  526. {
  527. if (this.GdkWindow == null)
  528. return Gdk.Rectangle.Zero;
  529. row -= page;
  530. int winWidth, winHeight;
  531. this.GdkWindow.GetSize (out winWidth, out winHeight);
  532. return new Gdk.Rectangle (margin, margin + rowHeight * row, winWidth, rowHeight);
  533. }
  534. public int VisibleRows {
  535. get {
  536. int rowWidth;
  537. layout.GetPixelSize (out rowWidth, out rowHeight);
  538. rowHeight += padding;
  539. return Allocation.Height / rowHeight;
  540. }
  541. }
  542. protected override void OnSizeAllocated (Gdk.Rectangle allocation)
  543. {
  544. base.OnSizeAllocated (allocation);
  545. UpdatePage ();
  546. }
  547. /* protected override void OnSizeRequested (ref Requisition requisition)
  548. {
  549. base.OnSizeRequested (ref requisition);
  550. requisition.Height += requisition.Height % rowHeight;
  551. }
  552. */
  553. void CalcVisibleRows ()
  554. {
  555. int winHeight = 200;
  556. int lvWidth, lvHeight;
  557. this.GetSizeRequest (out lvWidth, out lvHeight);
  558. int rowWidth;
  559. layout.GetPixelSize (out rowWidth, out rowHeight);
  560. rowHeight += padding;
  561. int requestedVisibleRows = (winHeight + padding - margin * 2) / rowHeight;
  562. int viewableCats =0;// InCategoryMode ? categories.Count: 0;
  563. //if (InCategoryMode && categories.Any (cat => cat.CompletionCategory == null))
  564. // viewableCats--;
  565. int newHeight = (rowHeight * Math.Max (1, Math.Min (requestedVisibleRows, filteredItems.Count + viewableCats))) + margin * 2;
  566. if (PreviewCompletionString) {
  567. newHeight += rowHeight;
  568. }
  569. if (lvWidth != listWidth || lvHeight != newHeight)
  570. this.SetSizeRequest (listWidth, newHeight);
  571. }
  572. const int spacing = 2;
  573. // delegate void CategoryAction (Category category, int yPos);
  574. delegate bool ItemAction (int item, int yPos);//Category curCategory,
  575. void Iterate (bool startAtPage, ref int ypos, ItemAction action)//CategoryAction catAction,
  576. {
  577. int curItem = 0;
  578. /*if (InCategoryMode) {
  579. foreach (Category category in this.categories) {
  580. if (category.CompletionCategory != null) {
  581. if (!startAtPage || curItem >= page) {
  582. if (catAction != null)
  583. catAction (category, ypos);
  584. ypos += rowHeight;
  585. }
  586. curItem++;
  587. }
  588. bool result = IterateItems (category, startAtPage,ref ypos, ref curItem, action);
  589. if (!result)
  590. break;
  591. }
  592. } else {*/
  593. int startItem = 0;
  594. if (startAtPage)
  595. startItem = curItem = page;
  596. if (action != null) {
  597. for (int item = startItem; item < filteredItems.Count; item++) {
  598. bool result = action ( item, ypos);//null,
  599. if (!result)
  600. break;
  601. ypos += rowHeight;
  602. curItem++;
  603. }
  604. } else {
  605. int itemCount = (filteredItems.Count - startItem);
  606. ypos += rowHeight * itemCount;
  607. curItem += itemCount;
  608. }
  609. //}
  610. }
  611. /*bool IterateItems ( bool startAtPage, ref int ypos, ref int curItem, ItemAction action)//Category category,
  612. {
  613. foreach (int item in category.Items) {
  614. if (!startAtPage || curItem >= page) {
  615. if (action != null) {
  616. bool result = action (category, item, ypos);
  617. if (!result)
  618. return false;
  619. }
  620. ypos += rowHeight;
  621. }
  622. curItem++;
  623. }
  624. return true;
  625. }*/
  626. }
  627. }