1
2
3
4
5
6 using System;
7 using System.Collections;
8
9 namespace System.Windows
10 {
11 public class ListViewItemEventArgs
12 {
13 public nothrow ListViewItemEventArgs(ListView* view_, ListViewItem* item_) : view(view_), item(item_), location(), control(false)
14 {
15 }
16 public ListView* view;
17 public ListViewItem* item;
18 public Point location;
19 public bool control;
20 }
21
22 public class ListViewColumnEventArgs
23 {
24 public nothrow ListViewColumnEventArgs(ListView* view_, ListViewColumn* column_) : view(view_), column(column_)
25 {
26 }
27 public ListView* view;
28 public ListViewColumn* column;
29 }
30
31 public class delegate void ListViewItemEventHandler(ListViewItemEventArgs& args);
32 public class delegate void ListViewColumnEventHandler(ListViewColumnEventArgs& args);
33
34 public nothrow Color DefaultListViewBackgroundColor()
35 {
36 return Color.White();
37 }
38
39 public nothrow string DefaultListViewFontFamilyName()
40 {
41 return "Segoe UI";
42 }
43
44 public nothrow float DefaultListViewFontSize()
45 {
46 return 9.0f;
47 }
48
49 public nothrow Color DefaultListViewColumnTextColor()
50 {
51 return Color(76u, 96u, 122u);
52 }
53
54 public nothrow Color DefaultListViewItemTextColor()
55 {
56 return Color.Black();
57 }
58
59 public nothrow Color DefaultListViewDisabledItemTextColor()
60 {
61 return Color(201u, 201u, 201u);
62 }
63
64 public nothrow Color DefaultListViewColumnDividerColor()
65 {
66 return Color(229u, 229u, 229u);
67 }
68
69 public nothrow Color DefaultListViewItemSelectedColor()
70 {
71 return Color(204u, 232u, 255u);
72 }
73
74 public nothrow Padding DefaultListViewColumnHeaderPadding()
75 {
76 return Padding(4, 0, 4, 4);
77 }
78
79 public nothrow Padding DefaultListViewItemPadding()
80 {
81 return Padding(4, 0, 4, 0);
82 }
83
84 public nothrow Padding DefaultListViewItemColumnPadding()
85 {
86 return Padding(4, 0, 4, 0);
87 }
88
89 public nothrow Padding DefaultListViewColumnDividerPadding()
90 {
91 return Padding(1, 0, 1, 0);
92 }
93
94 public nothrow Padding DefaultListViewImagePadding()
95 {
96 return Padding(2, 2, 2, 2);
97 }
98
99 public ControlCreateParams& ListViewControlCreateParams(ControlCreateParams& controlCreateParams)
100 {
101 return controlCreateParams.SetWindowClassName("System.Windows.ListView").SetWindowClassStyle(DoubleClickWindowClassStyle()).
102 SetWindowClassBackgroundColor(SystemColor.COLOR_WINDOW).SetBackgroundColor(DefaultListViewBackgroundColor());
103 }
104
105 public class ListViewCreateParams
106 {
107 public nothrow ListViewCreateParams(ControlCreateParams& controlCreateParams_) :
108 controlCreateParams(controlCreateParams_),
109 allowMultiselect(false),
110 fontFamilyName(DefaultListViewFontFamilyName()),
111 fontSize(DefaultListViewFontSize()),
112 columnTextColor(DefaultListViewColumnTextColor()),
113 itemTextColor(DefaultListViewItemTextColor()),
114 disabledItemTextColor(DefaultListViewDisabledItemTextColor()),
115 columnDividerColor(DefaultListViewColumnDividerColor()),
116 itemSelectedColor(DefaultListViewItemSelectedColor()),
117 columnHeaderPadding(DefaultListViewColumnHeaderPadding()),
118 itemPadding(DefaultListViewItemPadding()),
119 itemColumnPadding(DefaultListViewItemColumnPadding()),
120 columnDividerPadding(DefaultListViewColumnDividerPadding()),
121 imagePadding(DefaultListViewImagePadding())
122 {
123 }
124 public nothrow ListViewCreateParams& Defaults()
125 {
126 return *this;
127 }
128 public nothrow ListViewCreateParams& SetAllowMultiselect(bool allowMultiselect_)
129 {
130 allowMultiselect = allowMultiselect_;
131 return *this;
132 }
133 public nothrow ListViewCreateParams& SetFontFamilyName(const string& fontFamilyName_)
134 {
135 fontFamilyName = fontFamilyName_;
136 return *this;
137 }
138 public nothrow ListViewCreateParams& SetFontSize(float fontSize_)
139 {
140 fontSize = fontSize_;
141 return *this;
142 }
143 public nothrow ListViewCreateParams& SetColumnTextColor(const Color& columnTextColor_)
144 {
145 columnTextColor = columnTextColor_;
146 return *this;
147 }
148 public nothrow ListViewCreateParams& SetItemTextColor(const Color& itemTextColor_)
149 {
150 itemTextColor = itemTextColor_;
151 return *this;
152 }
153 public nothrow ListViewCreateParams& SetDisabledItemTextColor(const Color& disabledItemTextColor_)
154 {
155 disabledItemTextColor = disabledItemTextColor_;
156 return *this;
157 }
158 public nothrow ListViewCreateParams& SetColumnDividerColor(const Color& columnDividerColor_)
159 {
160 columnDividerColor = columnDividerColor_;
161 return *this;
162 }
163 public nothrow ListViewCreateParams& SetItemSelectedColor(const Color& itemSelectedColor_)
164 {
165 itemSelectedColor = itemSelectedColor_;
166 return *this;
167 }
168 public nothrow ListViewCreateParams& SetColumnHeaderPadding(const Padding& columnHeaderPadding_)
169 {
170 columnHeaderPadding = columnHeaderPadding_;
171 return *this;
172 }
173 public nothrow ListViewCreateParams& SetItemPadding(const Padding& itemPadding_)
174 {
175 itemPadding = itemPadding_;
176 return *this;
177 }
178 public nothrow ListViewCreateParams& SetItemColumnPadding(const Padding& itemColumnPadding_)
179 {
180 itemColumnPadding = itemColumnPadding_;
181 return *this;
182 }
183 public nothrow ListViewCreateParams& SetColumnDividerPadding(const Padding& columnDividerPadding_)
184 {
185 columnDividerPadding = columnDividerPadding_;
186 return *this;
187 }
188 public nothrow ListViewCreateParams& SetImagePadding(const Padding& imagePadding_)
189 {
190 imagePadding = imagePadding_;
191 return *this;
192 }
193 public ControlCreateParams& controlCreateParams;
194 public bool allowMultiselect;
195 public string fontFamilyName;
196 public float fontSize;
197 public Color columnTextColor;
198 public Color itemTextColor;
199 public Color disabledItemTextColor;
200 public Color columnDividerColor;
201 public Color itemSelectedColor;
202 public Padding columnHeaderPadding;
203 public Padding itemPadding;
204 public Padding itemColumnPadding;
205 public Padding columnDividerPadding;
206 public Padding imagePadding;
207 }
208
209 public class ListView : Control
210 {
211 public enum Flags : int
212 {
213 none = 0, measured = 1 << 0, allowMultiselect = 1 << 1
214 }
215 public ListView(ListViewCreateParams& createParams) :
216 base(createParams.controlCreateParams),
217 flags(Flags.none), imageList(null),
218 columnHeaderTextBrush(createParams.columnTextColor),
219 itemTextBrush(createParams.itemTextColor),
220 disabledItemTextBrush(createParams.disabledItemTextColor),
221 itemSelectedBrush(createParams.itemSelectedColor),
222 columnDividerPen(createParams.columnDividerColor),
223 stringFormat(),
224 columnHeaderPadding(createParams.columnHeaderPadding),
225 itemPadding(createParams.itemPadding),
226 itemColumnPadding(createParams.itemColumnPadding),
227 columnDividerPadding(createParams.columnDividerPadding),
228 imagePadding(createParams.imagePadding),
229 charWidth(0),
230 charHeight(0),
231 columnDividerWidth(1),
232 ellipsisWidth(0),
233 mouseDownItem(null),
234 mouseEnterItem(null),
235 selectedItem(null),
236 mouseDownColumnDivider(null),
237 data(null),
238 arrowCursor(LoadStandardCursor(StandardCursorId.IDC_ARROW)),
239 columnSizeCursor(Application.GetResourceManager().GetCursor("column.size.system.windows.cursor"))
240 {
241 if (createParams.allowMultiselect)
242 {
243 SetFlag(Flags.allowMultiselect);
244 }
245 SetFont(Font(FontFamily(createParams.fontFamilyName), createParams.fontSize));
246 }
247 public inline nothrow ImageList* GetImageList() const
248 {
249 return imageList;
250 }
251 public nothrow void SetImageList(ImageList* imageList_)
252 {
253 imageList = imageList_;
254 }
255 public const StringFormat& GetStringFormat() const
256 {
257 return stringFormat;
258 }
259 public nothrow const Brush& ColumnHeaderTextBrush() const
260 {
261 return columnHeaderTextBrush;
262 }
263 public nothrow const Brush* ItemTextBrush() const
264 {
265 return &itemTextBrush;
266 }
267 public nothrow const Brush* DisabledItemTextBrush() const
268 {
269 return &disabledItemTextBrush;
270 }
271 public nothrow const Brush& ItemSelectedBrush() const
272 {
273 return itemSelectedBrush;
274 }
275 public nothrow const Pen& ColumnDividerPen() const
276 {
277 return columnDividerPen;
278 }
279 public nothrow const Padding& ColumnHeaderPadding() const
280 {
281 return columnHeaderPadding;
282 }
283 public nothrow const Padding& ItemPadding() const
284 {
285 return itemPadding;
286 }
287 public nothrow const Padding& ItemColumnPadding() const
288 {
289 return itemColumnPadding;
290 }
291 public nothrow const Padding& ColumnDividerPadding() const
292 {
293 return columnDividerPadding;
294 }
295 public nothrow const Padding& ImagePadding() const
296 {
297 return imagePadding;
298 }
299 public inline nothrow bool GetFlag(Flags flag) const
300 {
301 return (flags & flag) != Flags.none;
302 }
303 public nothrow void SetFlag(Flags flag)
304 {
305 flags = cast<Flags>(flags | flag);
306 }
307 public nothrow void ResetFlag(Flags flag)
308 {
309 flags = cast<Flags>(flags & ~flag);
310 }
311 public nothrow int ColumnCount() const
312 {
313 return cast<int>(columns.Count());
314 }
315 public nothrow void AddColumn(const string& name, int width)
316 {
317 ListViewColumn* column = new ListViewColumn(this, name, width);
318 columns.Add(UniquePtr<ListViewColumn>(column));
319 columnDividers.Add(UniquePtr<ListViewColumnDivider>(new ListViewColumnDivider(this, column)));
320 }
321 public const ListViewColumn& GetColumn(int columnIndex) const
322 {
323 if (columnIndex < 0 || columnIndex >= ColumnCount())
324 {
325 throw Exception("invalid column index");
326 }
327 return *columns[columnIndex];
328 }
329 public ListViewColumn& GetColumn(int columnIndex)
330 {
331 if (columnIndex < 0 || columnIndex >= ColumnCount())
332 {
333 throw Exception("invalid column index");
334 }
335 return *columns[columnIndex];
336 }
337 public int ItemCount() const
338 {
339 return cast<int>(items.Count());
340 }
341 public ListViewItem* AddItem()
342 {
343 ListViewItem* item = new ListViewItem(this);
344 items.Add(UniquePtr<ListViewItem>(item));
345 return item;
346 }
347 public const ListViewItem& GetItem(int itemIndex) const
348 {
349 if (itemIndex < 0 || itemIndex >= ItemCount())
350 {
351 throw Exception("invalid item index");
352 }
353 return *items[itemIndex];
354 }
355 public ListViewItem& GetItem(int itemIndex)
356 {
357 if (itemIndex < 0 || itemIndex >= ItemCount())
358 {
359 throw Exception("invalid item index");
360 }
361 return *items[itemIndex];
362 }
363 public inline nothrow ListViewItem* SelectedItem() const
364 {
365 return selectedItem;
366 }
367 public nothrow void SetSelectedItem(ListViewItem* selectedItem_)
368 {
369 if (GetFlag(Flags.allowMultiselect))
370 {
371 ResetSelectedItems();
372 }
373 if (selectedItem != selectedItem_)
374 {
375 if (selectedItem != null)
376 {
377 selectedItem->ResetSelected();
378 }
379 selectedItem = selectedItem_;
380 if (selectedItem != null)
381 {
382 selectedItem->SetSelected();
383 }
384 }
385 }
386 public nothrow List<ListViewItem*> GetSelectedItems() const
387 {
388 List<ListViewItem*> result;
389 for (const UniquePtr<ListViewItem>& item : items)
390 {
391 if (item->IsSelected())
392 {
393 result.Add(item.Get());
394 }
395 }
396 return result;
397 }
398 public nothrow void ResetSelectedItems()
399 {
400 for (const UniquePtr<ListViewItem>& item : items)
401 {
402 if (item.Get() != SelectedItem())
403 {
404 if (item->IsSelected())
405 {
406 item->ResetSelected();
407 }
408 }
409 }
410 }
411 public nothrow ListViewItem* ItemAt(const Point& location) const
412 {
413 for (const UniquePtr<ListViewItem>& item : items)
414 {
415 Rect rect(item->Location(), item->GetSize());
416 if (rect.Contains(location))
417 {
418 return item.Get();
419 }
420 }
421 return null;
422 }
423 public nothrow ListViewColumnDivider* ColumnDividerAt(const Point& location) const
424 {
425 for (const UniquePtr<ListViewColumnDivider>& columnDivider : columnDividers)
426 {
427 Rect rect(columnDivider->Location(), columnDivider->GetSize());
428 if (rect.Contains(location))
429 {
430 return columnDivider.Get();
431 }
432 }
433 return null;
434 }
435 public inline nothrow float TextHeight() const
436 {
437 return charHeight;
438 }
439 public inline nothrow float ColumnDividerWidth() const
440 {
441 return columnDividerWidth;
442 }
443 public nothrow float EllipsisWidth() const
444 {
445 return ellipsisWidth;
446 }
447 public void FireColumnWidthChanged(ListViewColumn* column)
448 {
449 ListViewColumnEventArgs args(this, column);
450 OnColumnWidthChanged(args);
451 }
452 public nothrow void SetData(void* data_)
453 {
454 data = data_;
455 }
456 public inline nothrow void* Data() const
457 {
458 return data;
459 }
460 public nothrow Event<ListViewItemEventHandler, ListViewItemEventArgs>& ItemClickEvent()
461 {
462 return itemClickEvent;
463 }
464 public nothrow Event<ListViewItemEventHandler, ListViewItemEventArgs>& ItemRightClickEvent()
465 {
466 return itemRightClickEvent;
467 }
468 public nothrow Event<ListViewItemEventHandler, ListViewItemEventArgs>& ItemDoubleClickEvent()
469 {
470 return itemDoubleClickEvent;
471 }
472 public nothrow Event<ListViewItemEventHandler, ListViewItemEventArgs>& ItemEnterEvent()
473 {
474 return itemEnterEvent;
475 }
476 public nothrow Event<ListViewItemEventHandler, ListViewItemEventArgs>& ItemLeaveEvent()
477 {
478 return itemLeaveEvent;
479 }
480 public nothrow Event<ListViewColumnEventHandler, ListViewColumnEventArgs>& ColumnWidthChangedEvent()
481 {
482 return columnWidthChangedEvent;
483 }
484 protected override void OnSizeChanged(uint windowState)
485 {
486 base->OnSizeChanged(windowState);
487 SetContentLocation(Point(0, 0));
488 }
489 protected override void OnPaint(PaintEventArgs& args)
490 {
491 try
492 {
493 if (!GetFlag(Flags.measured))
494 {
495 SetFlag(Flags.measured);
496 Measure(args.graphics);
497 }
498 Size contentSize(0, 0);
499 args.graphics.Clear(BackgroundColor());
500 PointF origin;
501 MeasureItems(args.graphics, contentSize);
502 DrawColumnHeader(args.graphics, origin);
503 DrawItems(args.graphics, origin);
504 SetContentSize(contentSize);
505 base->OnPaint(args);
506 }
507 catch (const Exception& ex)
508 {
509 MessageBox.Show(ex.ToString());
510 }
511 }
512 protected override void OnMouseDown(MouseEventArgs& args)
513 {
514 try
515 {
516 mouseDownItem = null;
517 ListViewItem* item = ItemAt(args.location);
518 if (item != null)
519 {
520 mouseDownItem = item;
521 }
522 else
523 {
524 SetSelectedItem(null);
525 }
526 if (args.buttons == MouseButtons.lbutton)
527 {
528 ListViewColumnDivider* columnDivider = ColumnDividerAt(args.location);
529 if (columnDivider != null)
530 {
531 columnDivider->OnLButtonDown(args.location);
532 mouseDownColumnDivider = columnDivider;
533 }
534 }
535 }
536 catch (const Exception& ex)
537 {
538 MessageBox.Show(ex.Message());
539 }
540 }
541 protected override void OnMouseUp(MouseEventArgs& args)
542 {
543 try
544 {
545 ListViewItem* item = ItemAt(args.location);
546 if (item == mouseDownItem)
547 {
548 ListViewItemEventArgs itemArgs(this, item);
549 if ((args.buttons & MouseButtons.lbutton) != MouseButtons.none)
550 {
551 if (GetFlag(Flags.allowMultiselect))
552 {
553 if ((args.buttons & MouseButtons.control) != MouseButtons.none)
554 {
555 itemArgs.control = true;
556 }
557 }
558 itemClickEvent.Fire(itemArgs);
559 }
560 else if (args.buttons == MouseButtons.rbutton)
561 {
562 itemArgs.location = args.location;
563 itemRightClickEvent.Fire(itemArgs);
564 }
565 }
566 mouseDownItem = null;
567 if (args.buttons == MouseButtons.lbutton)
568 {
569 if (mouseDownColumnDivider != null)
570 {
571 mouseDownColumnDivider->OnLButtonUp();
572 mouseDownColumnDivider = null;
573 }
574 }
575 }
576 catch (const Exception& ex)
577 {
578 MessageBox.Show(ex.Message());
579 }
580 }
581 protected override void OnMouseDoubleClick(MouseEventArgs& args)
582 {
583 try
584 {
585 ListViewItem* item = ItemAt(args.location);
586 if (item != null)
587 {
588 ListViewItemEventArgs args(this, item);
589 itemDoubleClickEvent.Fire(args);
590 }
591 mouseDownItem = null;
592 }
593 catch (const Exception& ex)
594 {
595 MessageBox.Show(ex.Message());
596 }
597 }
598 protected override void OnMouseEnter()
599 {
600 try
601 {
602 mouseEnterItem = null;
603 }
604 catch (const Exception& ex)
605 {
606 MessageBox.Show(ex.Message());
607 }
608 }
609 protected override void OnMouseLeave()
610 {
611 try
612 {
613 if (mouseEnterItem != null)
614 {
615 ListViewItemEventArgs leaveItemArgs(this, mouseEnterItem);
616 itemLeaveEvent.Fire(leaveItemArgs);
617 mouseEnterItem = null;
618 }
619 }
620 catch (const Exception& ex)
621 {
622 MessageBox.Show(ex.Message());
623 }
624 }
625 protected override void OnMouseMove(MouseEventArgs& args)
626 {
627 try
628 {
629 if (mouseEnterItem == null)
630 {
631 mouseEnterItem = ItemAt(args.location);
632 if (mouseEnterItem != null)
633 {
634 ListViewItemEventArgs itemArgs(this, mouseEnterItem);
635 itemEnterEvent.Fire(itemArgs);
636 }
637 }
638 else
639 {
640 ListViewItem* item = ItemAt(args.location);
641 if (item != mouseEnterItem)
642 {
643 ListViewItemEventArgs leaveItemArgs(this, mouseEnterItem);
644 itemLeaveEvent.Fire(leaveItemArgs);
645 mouseEnterItem = item;
646 if (mouseEnterItem != null)
647 {
648 ListViewItemEventArgs enterItemArgs(this, mouseEnterItem);
649 itemEnterEvent.Fire(enterItemArgs);
650 }
651 }
652 }
653 if (args.buttons == MouseButtons.lbutton)
654 {
655 if (mouseDownColumnDivider != null)
656 {
657 if (mouseDownColumnDivider->HasMouseCapture())
658 {
659 mouseDownColumnDivider->OnMouseMove(args.location);
660 }
661 }
662 }
663 }
664 catch (const Exception& ex)
665 {
666 MessageBox.Show(ex.Message());
667 }
668 }
669 protected virtual void OnColumnWidthChanged(ListViewColumnEventArgs& args)
670 {
671 columnWidthChangedEvent.Fire(args);
672 }
673 protected override void SetCursor()
674 {
675 Point pt;
676 GetCursorPos(pt.x, pt.y);
677 Point cursorPos = ScreenToClient(pt);
678 bool cursorSet = false;
679 for (const UniquePtr<ListViewColumnDivider>& columnDivider : columnDividers)
680 {
681 Rect r(columnDivider->Location(), columnDivider->GetSize());
682 if (r.Contains(cursorPos))
683 {
684 System.Windows.SetCursor(columnSizeCursor);
685 cursorSet = true;
686 break;
687 }
688 }
689 if (!cursorSet)
690 {
691 System.Windows.SetCursor(arrowCursor);
692 }
693 }
694 private void Measure(Graphics& graphics)
695 {
696 RectF charRect = graphics.MeasureStringChecked("This is test string", GetFont(), PointF(0, 0), stringFormat);
697 charHeight = charRect.size.h;
698 charWidth = charRect.size.w;
699 SetScrollUnits(cast<int>(charHeight + 0.5), cast<int>(2 * (charWidth + 0.5)));
700 RectF ellipsisRect = graphics.MeasureStringChecked("...", GetFont(), PointF(0, 0), stringFormat);
701 ellipsisWidth = ellipsisRect.size.w;
702 }
703 private void MeasureItems(Graphics& graphics, Size& contentSize)
704 {
705 int maxWidth = 0;
706 Point loc(itemPadding.left, cast<int>(charHeight + 0.5 + columnHeaderPadding.Vertical()));
707 for (const UniquePtr<ListViewItem>& item : items)
708 {
709 item->SetLocation(loc);
710 item->Measure(graphics);
711 Size itemSize = item->GetSize();
712 loc.y = loc.y + itemSize.h;
713 maxWidth = Max(maxWidth, itemSize.w);
714 }
715 contentSize.w = Max(contentSize.w, maxWidth);
716 contentSize.h = Max(contentSize.h, loc.y);
717 }
718 private void DrawColumnHeader(Graphics& graphics, PointF& origin)
719 {
720 PointF headerOrigin = origin;
721 headerOrigin.x = headerOrigin.x + columnHeaderPadding.left;
722 headerOrigin.y = headerOrigin.y + columnHeaderPadding.top;
723 long n = columns.Count();
724 for (long i = 0; i < n; ++i;)
725 {
726 ListViewColumn* column = columns[i].Get();
727 column->Draw(graphics, headerOrigin);
728 headerOrigin.x = headerOrigin.x + column->Width() + columnHeaderPadding.Horizontal();
729 ListViewColumnDivider* divider = columnDividers[i].Get();
730 headerOrigin.x = headerOrigin.x + columnDividerPadding.left;
731 divider->Draw(graphics, headerOrigin);
732 headerOrigin.x = headerOrigin.x + columnDividerWidth + columnDividerPadding.right;
733 }
734 origin.y = origin.y + charHeight + columnHeaderPadding.Vertical();
735 }
736 private void DrawItems(Graphics& graphics, PointF& origin)
737 {
738 for (const UniquePtr<ListViewItem>& item : items)
739 {
740 PointF itemOrigin = origin;
741 itemOrigin.y = itemOrigin.y + itemPadding.top;
742 itemOrigin.x = itemOrigin.x + itemPadding.left;
743 item->Draw(graphics, itemOrigin);
744 Size sz = item->GetSize();
745 origin.y = origin.y + sz.h;
746 }
747 }
748 private Flags flags;
749 private ImageList* imageList;
750 private SolidBrush columnHeaderTextBrush;
751 private SolidBrush itemTextBrush;
752 private SolidBrush disabledItemTextBrush;
753 private SolidBrush itemSelectedBrush;
754 private Pen columnDividerPen;
755 private StringFormat stringFormat;
756 private Padding columnHeaderPadding;
757 private Padding itemPadding;
758 private Padding itemColumnPadding;
759 private Padding columnDividerPadding;
760 private Padding imagePadding;
761 private float charWidth;
762 private float charHeight;
763 private float columnDividerWidth;
764 private float ellipsisWidth;
765 private ListViewItem* mouseDownItem;
766 private ListViewItem* mouseEnterItem;
767 private ListViewItem* selectedItem;
768 private ListViewColumnDivider* mouseDownColumnDivider;
769 private void* data;
770 private Cursor arrowCursor;
771 private Cursor& columnSizeCursor;
772 private List<UniquePtr<ListViewColumn>> columns;
773 private List<UniquePtr<ListViewColumnDivider>> columnDividers;
774 private List<UniquePtr<ListViewItem>> items;
775 private Event<ListViewItemEventHandler, ListViewItemEventArgs> itemClickEvent;
776 private Event<ListViewItemEventHandler, ListViewItemEventArgs> itemRightClickEvent;
777 private Event<ListViewItemEventHandler, ListViewItemEventArgs> itemDoubleClickEvent;
778 private Event<ListViewItemEventHandler, ListViewItemEventArgs> itemEnterEvent;
779 private Event<ListViewItemEventHandler, ListViewItemEventArgs> itemLeaveEvent;
780 private Event<ListViewColumnEventHandler, ListViewColumnEventArgs> columnWidthChangedEvent;
781 }
782
783 public class ListViewColumn
784 {
785 public nothrow ListViewColumn(ListView* view_, const string& name_, int width_) :
786 view(view_), name(name_), width(width_), minWidth(0)
787 {
788 }
789 public inline nothrow const string& Name() const
790 {
791 return name;
792 }
793 public inline nothrow int Width() const
794 {
795 return width;
796 }
797 public nothrow void SetWidth(int width_)
798 {
799 if (width != width_)
800 {
801 width = width_;
802 view->FireColumnWidthChanged(this);
803 view->Invalidate();
804 }
805 }
806 public inline nothrow int MinWidth() const
807 {
808 return minWidth;
809 }
810 public nothrow void SetMinWidth(int minWidth_)
811 {
812 minWidth = minWidth_;
813 }
814 public void Draw(Graphics& graphics, const PointF& origin)
815 {
816 graphics.DrawStringChecked(name, view->GetFont(), origin, view->ColumnHeaderTextBrush());
817 }
818 private ListView* view;
819 private string name;
820 private int width;
821 private int minWidth;
822 }
823
824 public class ListViewColumnDivider
825 {
826 public nothrow ListViewColumnDivider(ListView* view_, ListViewColumn* column_) :
827 view(view_), column(column_), location(), startCapturePos(), startColumnWidth(0), hasMouseCapture(false)
828 {
829 }
830 public inline nothrow const Point& Location() const
831 {
832 return location;
833 }
834 public nothrow Size GetSize() const
835 {
836 return Size(cast<int>(view->ColumnDividerWidth() + 4 * view->ColumnDividerPadding().Horizontal() + 0.5f), cast<int>(view->TextHeight() + 0.5f));
837 }
838 public inline nothrow bool HasMouseCapture() const
839 {
840 return hasMouseCapture;
841 }
842 public void OnLButtonDown(const Point& pos)
843 {
844 WinSetCapture(view->Handle());
845 startCapturePos = pos;
846 startColumnWidth = column->Width();
847 hasMouseCapture = true;
848 }
849 public void OnMouseMove(const Point& pos)
850 {
851 column->SetWidth(Max(column->MinWidth(), startColumnWidth + pos.x - startCapturePos.x));
852 }
853 public void OnLButtonUp()
854 {
855 WinReleaseCapture();
856 hasMouseCapture = false;
857 }
858 public void Draw(Graphics& graphics, const PointF& origin)
859 {
860 const Pen& pen = view->ColumnDividerPen();
861 Size sz = GetSize();
862 location = Point(cast<int>(origin.x - sz.w / 2), cast<int>(origin.y));
863 PointF end = origin;
864 end.y = end.y + view->TextHeight();
865 graphics.DrawLine(pen, origin, end);
866 }
867 private ListView* view;
868 private ListViewColumn* column;
869 private Point location;
870 private Point startCapturePos;
871 private int startColumnWidth;
872 private bool hasMouseCapture;
873 }
874
875 public class ListViewItem
876 {
877 public enum Flags : int
878 {
879 none = 0, disabled = 1 << 0, selected = 1 << 1
880 }
881 public enum State : int
882 {
883 enabled, disabled
884 }
885 public nothrow ListViewItem(ListView* view_) : view(view_), flags(Flags.none), imageIndex(-1), disabledImageIndex(-1), data(null)
886 {
887 }
888 public void SetColumnValue(int columnIndex, const string& columnValue)
889 {
890 if (columnIndex < 0)
891 {
892 throw Exception("invalid column index");
893 }
894 while (columnIndex >= columnValues.Count())
895 {
896 columnValues.Add(string());
897 }
898 columnValues[columnIndex] = columnValue;
899 }
900 public string GetColumnValue(int columnIndex) const
901 {
902 if (columnIndex < 0)
903 {
904 throw Exception("invalid column index");
905 }
906 if (columnIndex >= columnValues.Count())
907 {
908 return string();
909 }
910 return columnValues[columnIndex];
911 }
912 public void Draw(Graphics& graphics, PointF& origin)
913 {
914 if (IsSelected())
915 {
916 const Brush& selectedBrush = view->ItemSelectedBrush();
917 Rect rect(location, size);
918 graphics.FillRectangleChecked(selectedBrush, rect);
919 }
920 PointF itemOrigin = origin;
921 int imageSpace = 0;
922 DrawImage(graphics, itemOrigin, imageSpace);
923 for (int index = 0; index < view->ColumnCount(); ++index;)
924 {
925 int imgSpc = 0;
926 if (index == 0)
927 {
928 imgSpc = imageSpace;
929 }
930 imgSpc = imageSpace;
931 bool clipped = false;
932 Region prevClip;
933 if (index < textWidths.Count() && textWidths[index] > view->GetColumn(index).Width())
934 {
935 prevClip = graphics.GetClipChecked();
936 clipped = true;
937 Size itemSize(Size(cast<int>(view->GetColumn(index).Width() - view->EllipsisWidth() - imgSpc), cast<int>(view->TextHeight())));
938 Rect clip(Point(cast<int>(itemOrigin.x), cast<int>(itemOrigin.y)), itemSize);
939 graphics.SetClipChecked(clip);
940 }
941 const Brush* brush = view->ItemTextBrush();
942 if (GetState() == State.disabled)
943 {
944 brush = view->DisabledItemTextBrush();
945 }
946 graphics.DrawStringChecked(GetColumnValue(index), view->GetFont(), itemOrigin, *brush);
947 itemOrigin.x = itemOrigin.x + view->GetColumn(index).Width();
948 if (clipped)
949 {
950 graphics.SetClipChecked(prevClip);
951 PointF ellipsisOrigin(itemOrigin.x - view->EllipsisWidth() - imgSpc, itemOrigin.y);
952 graphics.DrawStringChecked("...", view->GetFont(), ellipsisOrigin, *brush);
953 }
954 itemOrigin.x = itemOrigin.x + view->ColumnDividerPadding().Horizontal() + view->ColumnDividerWidth() - imgSpc;
955 itemOrigin.x = itemOrigin.x + view->ItemColumnPadding().Horizontal();
956 }
957 }
958 public void Measure(Graphics& graphics)
959 {
960 float width = 0;
961 float height = 0;
962 Bitmap* image = null;
963 ImageList* imageList = view->GetImageList();
964 if (imageList != null)
965 {
966 if (GetState() == State.enabled)
967 {
968 image = imageList->GetImage(imageIndex);
969 }
970 else
971 {
972 image = imageList->GetImage(disabledImageIndex);
973 }
974 }
975 if (image != null)
976 {
977 int imageWidth = cast<int>(image->GetWidth());
978 int imageHeight = cast<int>(image->GetHeight());
979 Padding padding = view->ImagePadding();
980 if (view->ColumnCount() > 0)
981 {
982 ListViewColumn& firstColumn = view->GetColumn(0);
983 firstColumn.SetMinWidth(Max(firstColumn.MinWidth(), cast<int>(imageWidth + padding.Horizontal() + view->EllipsisWidth() + 0.5f)));
984 }
985 height = imageHeight + padding.Vertical();
986 }
987 for (int index = 0; index < view->ColumnCount(); ++index;)
988 {
989 ListViewColumn& column = view->GetColumn(index);
990 width = width + column.Width();
991 width = width + view->ColumnDividerWidth() + view->ColumnDividerPadding().Horizontal();
992 height = Max(height, view->TextHeight());
993 column.SetMinWidth(Max(column.MinWidth(), cast<int>(view->EllipsisWidth() + 0.5f)));
994 }
995 width = width + view->ItemPadding().Horizontal();
996 size = Size(cast<int>(width + 0.5f), cast<int>(height + 0.5f));
997 textWidths.Clear();
998 for (const string& columnValue : columnValues)
999 {
1000 RectF r = graphics.MeasureStringChecked(columnValue, view->GetFont(), PointF(0, 0), view->GetStringFormat());
1001 textWidths.Add(r.size.w);
1002 }
1003 }
1004 public inline nothrow const Point& Location() const
1005 {
1006 return location;
1007 }
1008 public nothrow void SetLocation(const Point& location_)
1009 {
1010 location = location_;
1011 }
1012 public inline nothrow const Size& GetSize() const
1013 {
1014 return size;
1015 }
1016 public inline nothrow bool GetFlag(Flags flag) const
1017 {
1018 return (flags & flag) != Flags.none;
1019 }
1020 public inline nothrow void SetFlag(Flags flag)
1021 {
1022 flags = cast<Flags>(flags | flag);
1023 }
1024 public inline nothrow void ResetFlag(Flags flag)
1025 {
1026 flags = cast<Flags>(flags & ~flag);
1027 }
1028 public inline nothrow bool IsSelected() const
1029 {
1030 return GetFlag(Flags.selected);
1031 }
1032 public nothrow void SetSelected()
1033 {
1034 if (!IsSelected())
1035 {
1036 SetFlag(Flags.selected);
1037 view->Invalidate();
1038 }
1039 }
1040 public nothrow void ResetSelected()
1041 {
1042 if (IsSelected())
1043 {
1044 ResetFlag(Flags.selected);
1045 view->Invalidate();
1046 }
1047 }
1048 public nothrow State GetState() const
1049 {
1050 if (GetFlag(Flags.disabled))
1051 {
1052 return State.disabled;
1053 }
1054 else
1055 {
1056 return State.enabled;
1057 }
1058 }
1059 public nothrow void SetState(State state)
1060 {
1061 if (state != GetState())
1062 {
1063 if (state == State.disabled)
1064 {
1065 SetFlag(Flags.disabled);
1066 }
1067 else
1068 {
1069 ResetFlag(Flags.disabled);
1070 }
1071 view->Invalidate();
1072 }
1073 }
1074 public inline nothrow ListView* View() const
1075 {
1076 return view;
1077 }
1078 public inline nothrow void* Data() const
1079 {
1080 return data;
1081 }
1082 public nothrow void SetData(void* data_)
1083 {
1084 data = data_;
1085 }
1086 public inline nothrow int ImageIndex() const
1087 {
1088 return imageIndex;
1089 }
1090 public nothrow void SetImageIndex(int imageIndex_)
1091 {
1092 imageIndex = imageIndex_;
1093 }
1094 public inline nothrow int DisabledImageIndex() const
1095 {
1096 return disabledImageIndex;
1097 }
1098 public nothrow void SetDisabledImageIndex(int disabledImageIndex_)
1099 {
1100 disabledImageIndex = disabledImageIndex_;
1101 }
1102 private void DrawImage(Graphics& graphics, PointF& origin, int& imageSpace)
1103 {
1104 imageSpace = 0;
1105 Bitmap* image = null;
1106 ImageList* imageList = view->GetImageList();
1107 if (imageList != null)
1108 {
1109 if (GetState() == State.enabled)
1110 {
1111 image = imageList->GetImage(imageIndex);
1112 }
1113 else
1114 {
1115 image = imageList->GetImage(disabledImageIndex);
1116 }
1117 }
1118 if (image != null)
1119 {
1120 int imageWidth = cast<int>(image->GetWidth());
1121 int imageHeight = cast<int>(image->GetHeight());
1122 Padding padding = view->ImagePadding();
1123 Point imageLoc = Point(cast<int>(origin.x), cast<int>(origin.y));
1124 imageLoc.x = imageLoc.x + padding.left;
1125 imageLoc.y = imageLoc.y + padding.top;
1126 Rect r(imageLoc, Size(imageWidth + padding.Horizontal(), imageHeight + padding.Vertical()));
1127 ImageAttributes attributes;
1128 attributes.SetColorKey(Color.DefaultBitmapTransparent(), Color.DefaultBitmapTransparent(), ColorAdjustType.default_);
1129 graphics.DrawImageChecked(*image, r, 0, 0, imageWidth + padding.Horizontal(), imageHeight + padding.Vertical(), Unit.pixel, attributes);
1130 imageSpace = imageWidth + padding.Horizontal();
1131 origin.x = origin.x + imageSpace;
1132 }
1133 }
1134 private Flags flags;
1135 private Point location;
1136 private Size size;
1137 private ListView* view;
1138 private int imageIndex;
1139 private int disabledImageIndex;
1140 private void* data;
1141 private List<string> columnValues;
1142 private List<float> textWidths;
1143 }
1144 }