1
2
3
4
5
6 using System;
7 using System.Collections;
8 using System.Windows;
9 using System.Windows.API;
10
11 namespace System.Windows
12 {
13 public System.Windows.Color DefaultIconListViewTextColor()
14 {
15 return System.Windows.Color.Black();
16 }
17
18 public System.Windows.Color DefaultIconListViewIconSelectedColor()
19 {
20 return System.Windows.Color(64u, 96u, 156u, 210u);
21 }
22
23 public Padding DefaultIconListViewIconPadding()
24 {
25 return Padding(8, 8, 8, 8);
26 }
27
28 public Padding DefaultIconListViewTextPadding()
29 {
30 return Padding(4, 4, 4, 4);
31 }
32
33 public Padding DefaultIconListViewInternalPadding()
34 {
35 return Padding(4, 4, 4, 4);
36 }
37
38 public string DefaultIconListViewFontFamilyName()
39 {
40 return "Segoe UI";
41 }
42
43 public float DefaultIconListViewFontSize()
44 {
45 return 9.000000f;
46 }
47
48 public class delegate void IconListViewSelectedIndexChangedEventHandler();
49 public class delegate void IconListViewIconDoubleClickedEventHandler();
50
51 public class IconListViewItem : Component
52 {
53 public enum Flags : sbyte
54 {
55 none = 0, selected = 1 << 0
56 }
57 public IconListViewItem(const string& iconName_, const string& itemName_) : index(-1), iconName(iconName_), itemName(itemName_), location(), size()
58 {
59 }
60 [nodiscard]
61 public Result<bool> Measure(Graphics& graphics, const Padding& iconPadding, const Padding& textPadding, const Font& font)
62 {
63 iconSize = Size(cast<int>(bitmap->GetWidth()), cast<int>(bitmap->GetHeight()));
64 PointF origin;
65 StringFormat format(StringAlignment.near, StringAlignment.near);
66 if (format.Error())
67 {
68 return Result<bool>(ErrorId(format.GetErrorId()));
69 }
70 auto measureResult = graphics.MeasureStringRectF(itemName, font, origin, format);
71 if (measureResult.Error())
72 {
73 return Result<bool>(ErrorId(measureResult.GetErrorId()));
74 }
75 RectF textRect = measureResult.Value();
76 textSize = textRect.size;
77 size.w = Max(cast<int>(iconSize.w + iconPadding.Horizontal()), cast<int>(textSize.w + textPadding.Horizontal()));
78 size.h = cast<int>(iconSize.h + iconPadding.Vertical() + textSize.h + textPadding.Vertical());
79 return Result<bool>(true);
80 }
81 public void SetLocations(const Point& loc, const Padding& iconPadding, const Padding& textPadding)
82 {
83 location = loc;
84 if (textSize.w > iconSize.w)
85 {
86 iconLocation = Point(cast<int>(location.x + iconPadding.left + ((textSize.w + textPadding.Horizontal()) - (iconSize.w + iconPadding.Horizontal())) / 2), location.y + iconPadding.top);
87 textLocation = PointF(location.x + textPadding.left, location.y + (size.h - textSize.h - textPadding.Vertical()) + textPadding.top);
88 }
89 else
90 {
91 iconLocation = Point(location.x + iconPadding.left, location.y + iconPadding.top);
92 textLocation = PointF(location.x + textPadding.left + ((iconSize.w + iconPadding.Horizontal()) - (textSize.w + textPadding.Horizontal())) / 2, location.y + (size.h - textSize.h - textPadding.Vertical()) + textPadding.top);
93 }
94 }
95 [nodiscard]
96 public Result<bool> Draw(Graphics& graphics, IconListView& iconListView)
97 {
98 if (IsSelected())
99 {
100 auto selectedBrushResult = iconListView.GetSelectedBrush();
101 if (selectedBrushResult.Error())
102 {
103 return Result<bool>(ErrorId(selectedBrushResult.GetErrorId()));
104 }
105 SolidBrush* selectedBrush = selectedBrushResult.Value();
106 RectF rect(PointF(location.x, location.y), SizeF(size.w, size.h));
107 auto result = graphics.FillRectangle(*selectedBrush, rect);
108 if (result.Error())
109 {
110 return Result<bool>(ErrorId(result.GetErrorId()));
111 }
112 }
113 Rect r(iconLocation, iconSize);
114 auto result = graphics.DrawImage(*bitmap, r, 0, 0, iconSize.w, iconSize.h, Unit.pixel, iconListView.GetImageAttributes());
115 if (result.Error())
116 {
117 return Result<bool>(ErrorId(result.GetErrorId()));
118 }
119 RectF textRect(textLocation, textSize);
120 auto textBrushResult = iconListView.GetTextBrush();
121 if (textBrushResult.Error())
122 {
123 return Result<bool>(ErrorId(textBrushResult.GetErrorId()));
124 }
125 result = graphics.DrawString(itemName, iconListView.GetFont(), textRect, iconListView.GetStringFormat(), *textBrushResult.Value());
126 if (result.Error())
127 {
128 return Result<bool>(ErrorId(result.GetErrorId()));
129 }
130 return Result<bool>(true);
131 }
132 public void SetSelected()
133 {
134 flags = cast<Flags>(flags | Flags.selected);
135 }
136 public void ResetSelected()
137 {
138 flags = cast<Flags>(flags & ~Flags.selected);
139 }
140 public bool IsSelected() const
141 {
142 return (flags & Flags.selected) != Flags.none;
143 }
144 private Flags flags;
145 public int index;
146 public string iconName;
147 public string itemName;
148 public Point location;
149 public Size size;
150 public Point iconLocation;
151 public Size iconSize;
152 public PointF textLocation;
153 public SizeF textSize;
154 public Bitmap* bitmap;
155 }
156
157 public ControlCreateParams& IconListViewControlCreateParams(ControlCreateParams& controlCreateParams)
158 {
159 controlCreateParams.SetWindowClassName("System.Windows.IconListView");
160 controlCreateParams.SetWindowClassStyle(DoubleClickWindowClassStyle());
161 controlCreateParams.SetWindowClassBackgroundColor(SystemColor.COLOR_WINDOW);
162 controlCreateParams.SetBackgroundColor(Color.White());
163 return controlCreateParams;
164 }
165
166 public class IconListViewCreateParams
167 {
168 public IconListViewCreateParams(ControlCreateParams& controlCreateParams_) :
169 controlCreateParams(controlCreateParams_),
170 fontFamilyName(DefaultIconListViewFontFamilyName()),
171 fontSize(DefaultIconListViewFontSize()),
172 textColor(DefaultIconListViewTextColor()),
173 iconSelectedColor(DefaultIconListViewIconSelectedColor()),
174 bitmapTransparentColor(System.Windows.Color.DefaultBitmapTransparent()),
175 iconPadding(DefaultIconListViewIconPadding()),
176 textPadding(DefaultIconListViewTextPadding()),
177 internalPadding(DefaultIconListViewInternalPadding())
178 {
179 }
180 public IconListViewCreateParams& SetFontFamilyName(const string& fontFamilyName_)
181 {
182 fontFamilyName = fontFamilyName_;
183 return *this;
184 }
185 public IconListViewCreateParams& SetFontSize(float fontSize_)
186 {
187 fontSize = fontSize_;
188 return *this;
189 }
190 public IconListViewCreateParams& SetTextColor(const Color& textColor_)
191 {
192 textColor = textColor_;
193 return *this;
194 }
195 public IconListViewCreateParams& SetIconSelectedColor(const Color& iconSelectedColor_)
196 {
197 iconSelectedColor = iconSelectedColor_;
198 return *this;
199 }
200 public IconListViewCreateParams& SetIconPadding(const Padding& iconPadding_)
201 {
202 iconPadding = iconPadding_;
203 return *this;
204 }
205 public IconListViewCreateParams& SetTextPadding(const Padding& textPadding_)
206 {
207 textPadding = textPadding_;
208 return *this;
209 }
210 public IconListViewCreateParams& SetInternalPadding(const Padding& internalPadding_)
211 {
212 internalPadding = internalPadding_;
213 return *this;
214 }
215 public ControlCreateParams& controlCreateParams;
216 public string fontFamilyName;
217 public float fontSize;
218 public Color textColor;
219 public Color iconSelectedColor;
220 public Color bitmapTransparentColor;
221 public Padding iconPadding;
222 public Padding textPadding;
223 public Padding internalPadding;
224 }
225
226 public class IconListView : Control
227 {
228 private enum Flags : sbyte
229 {
230 none = 0, changed = 1 << 0
231 }
232
233 public IconListView(const System.Windows.Color& backgroundColor, const Point& location, const Size& size, Dock dock, Anchors anchors) :
234 base("System.Windows.IconListView", DoubleClickWindowClassStyle(), DefaultChildWindowStyle(), DefaultExtendedWindowStyle(),
235 backgroundColor, "iconListView", location, size, dock, anchors), items(this), numberOfItems(0),
236 fontFamily(DefaultIconListViewFontFamilyName()),
237 fontSize(DefaultIconListViewFontSize()),
238 font(fontFamily, fontSize),
239 bitmapTransparentColor(System.Windows.Color.DefaultBitmapTransparent()),
240 iconSelectedColor(DefaultIconListViewIconSelectedColor()),
241 textColor(DefaultIconListViewTextColor()),
242 iconPadding(DefaultIconListViewIconPadding()),
243 textPadding(DefaultIconListViewTextPadding()),
244 internalPadding(DefaultIconListViewInternalPadding()),
245 imageAttributes(), stringFormat(StringAlignment.center, StringAlignment.center), selectedItem(null)
246 {
247 if (imageAttributes.Error())
248 {
249 SetErrorId(imageAttributes.GetErrorId());
250 return;
251 }
252 if (stringFormat.Error())
253 {
254 SetErrorId(stringFormat.GetErrorId());
255 return;
256 }
257 auto result = imageAttributes.SetColorKey(bitmapTransparentColor, bitmapTransparentColor, ColorAdjustType.default_);
258 if (result.Error())
259 {
260 SetErrorId(result.GetErrorId());
261 return;
262 }
263 SetChanged();
264 }
265 public IconListView(const Point& location, const Size& size, Dock dock, Anchors anchors) :
266 this(System.Windows.Color.White(), location, size, dock, anchors)
267 {
268 }
269 public IconListView(IconListViewCreateParams& createParams) :
270 base(createParams.controlCreateParams),
271 items(this), numberOfItems(0),
272 fontFamily(createParams.fontFamilyName),
273 fontSize(createParams.fontSize),
274 font(fontFamily, fontSize),
275 bitmapTransparentColor(createParams.bitmapTransparentColor),
276 iconSelectedColor(createParams.iconSelectedColor),
277 textColor(createParams.textColor),
278 iconPadding(createParams.iconPadding),
279 textPadding(createParams.textPadding),
280 internalPadding(createParams.internalPadding),
281 imageAttributes(), stringFormat(StringAlignment.center, StringAlignment.center), selectedItem(null)
282 {
283 if (imageAttributes.Error())
284 {
285 SetErrorId(imageAttributes.GetErrorId());
286 return;
287 }
288 if (stringFormat.Error())
289 {
290 SetErrorId(stringFormat.GetErrorId());
291 return;
292 }
293 auto result = imageAttributes.SetColorKey(bitmapTransparentColor, bitmapTransparentColor, ColorAdjustType.default_);
294 if (result.Error())
295 {
296 SetErrorId(result.GetErrorId());
297 return;
298 }
299 SetChanged();
300 }
301 [nodiscard]
302 public Result<bool> AddItem(const string& iconName, const string& itemName)
303 {
304 UniquePtr<IconListViewItem> item(new IconListViewItem(iconName, itemName));
305 if (item->Error())
306 {
307 return Result<bool>(ErrorId(item->GetErrorId()));
308 }
309 item->index = numberOfItems;
310 auto insertResult = GetOrInsertBitmap(iconName);
311 if (insertResult.Error())
312 {
313 return Result<bool>(ErrorId(insertResult.GetErrorId()));
314 }
315 item->bitmap = insertResult.Value();
316 auto result = items.AddChild(item.Release());
317 if (result.Error())
318 {
319 return Result<bool>(ErrorId(result.GetErrorId()));
320 }
321 ++numberOfItems;
322 SetChanged();
323 result = Invalidate();
324 if (result.Error()) return result;
325 return Result<bool>(true);
326 }
327 [nodiscard]
328 protected override Result<bool> OnMouseDown(MouseEventArgs& args)
329 {
330 if (selectedItem != null)
331 {
332 selectedItem->ResetSelected();
333 }
334 Point loc = args.location;
335 Component* component = items.FirstChild();
336 while (component != null)
337 {
338 if (component is IconListViewItem*)
339 {
340 IconListViewItem* item = cast<IconListViewItem*>(component);
341 Rect rect(item->location, item->size);
342 if (rect.Contains(loc))
343 {
344 item->SetSelected();
345 selectedItem = item;
346 OnSelectedIndexChanged();
347 break;
348 }
349 }
350 component = component->NextSibling();
351 }
352 return Invalidate();
353 }
354 [nodiscard]
355 protected override Result<bool> OnMouseDoubleClick(MouseEventArgs& args)
356 {
357 Point loc = args.location;
358 Component* component = items.FirstChild();
359 while (component != null)
360 {
361 if (component is IconListViewItem*)
362 {
363 IconListViewItem* item = cast<IconListViewItem*>(component);
364 Rect rect(item->location, item->size);
365 if (rect.Contains(loc))
366 {
367 item->SetSelected();
368 selectedItem = item;
369 OnDoubleClicked();
370 break;
371 }
372 }
373 component = component->NextSibling();
374 }
375 return Invalidate();
376 }
377 [nodiscard]
378 public Result<bool> SetBitmapTransparentColor(const System.Windows.Color& bitmapTransparentColor_)
379 {
380 bitmapTransparentColor = bitmapTransparentColor_;
381 auto result = imageAttributes.SetColorKey(bitmapTransparentColor, bitmapTransparentColor, ColorAdjustType.default_);
382 if (result.Error())
383 {
384 return Result<bool>(ErrorId(result.GetErrorId()));
385 }
386 return Result<bool>(true);
387 }
388 public void SetIconSelectedColor(const System.Windows.Color& iconSelectedColor_)
389 {
390 iconSelectedColor = iconSelectedColor_;
391 }
392 public void SetTextColor(const System.Windows.Color& textColor_)
393 {
394 textColor = textColor_;
395 }
396 public void SetIconPadding(const Padding& iconPadding_)
397 {
398 iconPadding = iconPadding_;
399 }
400 public void SetTextPadding(const Padding& textPadding_)
401 {
402 textPadding = textPadding_;
403 }
404 public void SetInternalPadding(const Padding& internalPadding_)
405 {
406 internalPadding = internalPadding_;
407 }
408 public void SetFont(const Font& font_)
409 {
410 font = font_;
411 SetChanged();
412 }
413 internal const Font& GetFont() const
414 {
415 return font;
416 }
417 internal const StringFormat& GetStringFormat() const
418 {
419 return stringFormat;
420 }
421 public Event<IconListViewSelectedIndexChangedEventHandler>& SelectedIndexChangedEvent()
422 {
423 return selectedIndexChangedEvent;
424 }
425 public Event<IconListViewIconDoubleClickedEventHandler>& IconDoubleClickedEvent()
426 {
427 return iconDoubleClickedEvent;
428 }
429 protected virtual void OnSelectedIndexChanged()
430 {
431 selectedIndexChangedEvent.Fire();
432 }
433 protected virtual void OnDoubleClicked()
434 {
435 iconDoubleClickedEvent.Fire();
436 }
437 public int GetSelectedIndex() const
438 {
439 if (selectedItem != null)
440 {
441 return selectedItem->index;
442 }
443 else
444 {
445 return -1;
446 }
447 }
448 [nodiscard]
449 protected override Result<bool> OnPaint(PaintEventArgs& args)
450 {
451 if (Changed())
452 {
453 ResetChanged();
454 auto result = Measure(args.graphics);
455 if (result.Error())
456 {
457 return Result<bool>(ErrorId(result.GetErrorId()));
458 }
459 }
460 auto result = args.graphics.Clear(BackgroundColor());
461 if (result.Error())
462 {
463 return Result<bool>(ErrorId(result.GetErrorId()));
464 }
465 Component* component = items.FirstChild();
466 while (component != null)
467 {
468 if (component is IconListViewItem*)
469 {
470 IconListViewItem* item = cast<IconListViewItem*>(component);
471 result = item->Draw(args.graphics, *this);
472 if (result.Error())
473 {
474 return Result<bool>(ErrorId(result.GetErrorId()));
475 }
476 }
477 component = component->NextSibling();
478 }
479 return base->OnPaint(args);
480 }
481 private Result<bool> Measure(Graphics& graphics)
482 {
483 Point loc(internalPadding.left, internalPadding.top);
484 Size size;
485 Component* component = items.FirstChild();
486 while (component != null)
487 {
488 if (component is IconListViewItem*)
489 {
490 IconListViewItem* item = cast<IconListViewItem*>(component);
491 auto result = item->Measure(graphics, iconPadding, textPadding, font);
492 if (result.Error())
493 {
494 return Result<bool>(ErrorId(result.GetErrorId()));
495 }
496 item->SetLocations(loc, iconPadding, textPadding);
497 loc.x = loc.x + item->size.w;
498 size.w = size.w + item->size.w;
499 size.h = Max(size.h, item->size.h);
500 }
501 component = component->NextSibling();
502 }
503 size.w = size.w + internalPadding.Horizontal();
504 size.h = size.h + internalPadding.Vertical();
505 auto result = SetSize(size);
506 if (result.Error()) return result;
507 return Result<bool>(true);
508 }
509 internal ImageAttributes& GetImageAttributes()
510 {
511 return imageAttributes;
512 }
513 internal Result<SolidBrush*> GetTextBrush()
514 {
515 return GetOrInsertSolidBrush(textColor);
516 }
517 internal Result<SolidBrush*> GetSelectedBrush()
518 {
519 return GetOrInsertSolidBrush(iconSelectedColor);
520 }
521 private Result<Bitmap*> GetOrInsertBitmap(const string& bitmapName)
522 {
523 auto it = bitmapMap.Find(bitmapName);
524 if (it != bitmapMap.End())
525 {
526 return it->second;
527 }
528 auto bitmapResult = Bitmap.FromResource(bitmapName);
529 if (bitmapResult.Error())
530 {
531 return Result<Bitmap*>(ErrorId(bitmapResult.GetErrorId()));
532 }
533 UniquePtr<Bitmap> bitmapPtr(new Bitmap(Rvalue(bitmapResult.Value())));
534 if (bitmapPtr->Error())
535 {
536 return Result<Bitmap*>(ErrorId(bitmapPtr->GetErrorId()));
537 }
538 Bitmap* bitmap = bitmapPtr.Get();
539 bitmapMap[bitmapName] = bitmap;
540 bitmaps.Add(Rvalue(bitmapPtr));
541 return Result<Bitmap*>(bitmap);
542 }
543 private Result<SolidBrush*> GetOrInsertSolidBrush(const System.Windows.Color& color)
544 {
545 auto it = brushMap.Find(color);
546 if (it != brushMap.End())
547 {
548 return it->second;
549 }
550 else
551 {
552 UniquePtr<SolidBrush> solidBrushPtr(new SolidBrush(color));
553 if (solidBrushPtr->Error())
554 {
555 return Result<SolidBrush*>(ErrorId(solidBrushPtr->GetErrorId()));
556 }
557 SolidBrush* solidBrush = solidBrushPtr.Get();
558 brushMap[color] = solidBrush;
559 brushes.Add(Rvalue(solidBrushPtr));
560 return Result<SolidBrush*>(solidBrush);
561 }
562 }
563 private void SetChanged()
564 {
565 flags = cast<Flags>(flags | Flags.changed);
566 }
567 private void ResetChanged()
568 {
569 flags = cast<Flags>(flags & ~Flags.changed);
570 }
571 private bool Changed() const
572 {
573 return (flags & Flags.changed) != Flags.none;
574 }
575 private Flags flags;
576 private ComponentContainer items;
577 private int numberOfItems;
578 private FontFamily fontFamily;
579 private float fontSize;
580 private Font font;
581 private List<UniquePtr<Bitmap>> bitmaps;
582 private HashMap<string, Bitmap*> bitmapMap;
583 private System.Windows.Color bitmapTransparentColor;
584 private System.Windows.Color iconSelectedColor;
585 private System.Windows.Color textColor;
586 private List<UniquePtr<SolidBrush>> brushes;
587 private HashMap<System.Windows.Color, SolidBrush*> brushMap;
588 private Padding iconPadding;
589 private Padding textPadding;
590 private Padding internalPadding;
591 private ImageAttributes imageAttributes;
592 private StringFormat stringFormat;
593 private IconListViewItem* selectedItem;
594 private Event<IconListViewSelectedIndexChangedEventHandler> selectedIndexChangedEvent;
595 private Event<IconListViewIconDoubleClickedEventHandler> iconDoubleClickedEvent;
596 }