1
2
3
4
5
6 using System;
7 using System.Collections;
8
9 namespace System.Windows
10 {
11 public class delegate void TabPageSelectedEventHandler();
12
13 public nothrow Color DefaultTabControlFrameColor()
14 {
15 return Color(204u, 206u, 219u);
16 }
17
18 public nothrow Color DefaultTabTextColor()
19 {
20 return Color.Black();
21 }
22
23 public nothrow Color DefaultTabNormalBackgroundColor()
24 {
25 return Color.White();
26 }
27
28 public nothrow Color DefaultTabSelectedBackgroundColor()
29 {
30 return Color(255u, 255u, 215u);
31 }
32
33 public nothrow Color DefaultTabCloseBoxSelectedColor()
34 {
35 return Color(222u, 238u, 245u);
36 }
37
38 public inline nothrow int DefaultTabLeadingWidth()
39 {
40 return 0;
41 }
42
43 public inline nothrow int DefaultTabControlTopMarginHeight()
44 {
45 return 4;
46 }
47
48 public nothrow Padding DefaultTabPadding()
49 {
50 return Padding(8, 2, 8, 2);
51 }
52
53 public nothrow Padding DefaultTabCloseBoxPadding()
54 {
55 return Padding(8, 6, 8, 0);
56 }
57
58 public inline nothrow int DefaultTabOverlapWidth()
59 {
60 return 2;
61 }
62
63 public inline nothrow float DefaultTabRoundingRadius()
64 {
65 return 8;
66 }
67
68 public inline nothrow float DefaultTabCloseBoxPenWidth()
69 {
70 return 1.0f;
71 }
72
73 internal class Tab
74 {
75 public enum State
76 {
77 normal, closeBoxSelected
78 }
79 public bool visible;
80 public State state;
81 public float textHeight;
82 public float textWidth;
83 public float closeBoxWidth;
84 public int height;
85 public int width;
86 public int left;
87 public RectF leftRoundingRect;
88 public RectF rightRoundingRect;
89 public RectF topRect;
90 public RectF bottomRect;
91 public RectF textRect;
92 public RectF closeBoxRect;
93 public Rect selectRect;
94 public Rect closeRect;
95 }
96
97 public nothrow ControlCreateParams& TabControlControlCreateParams(ControlCreateParams& controlCreateParams)
98 {
99 return controlCreateParams.SetWindowClassName("System.Windows.TabControl");
100 }
101
102 public class TabControlCreateParams
103 {
104 public nothrow TabControlCreateParams(ControlCreateParams& controlCreateParams_) :
105 controlCreateParams(controlCreateParams_),
106 fontFamilyName("Segoe UI"),
107 fontSize(9.0f),
108 frameColor(DefaultTabControlFrameColor()),
109 textColor(DefaultTabTextColor()),
110 leadingWidth(DefaultTabLeadingWidth()),
111 topMarginHeight(DefaultTabControlTopMarginHeight()),
112 headerHeight(0),
113 tabPadding(DefaultTabPadding()),
114 tabCloseBoxPadding(DefaultTabCloseBoxPadding()),
115 overlapWidth(DefaultTabOverlapWidth()),
116 tabNormalBackgroundColor(DefaultTabNormalBackgroundColor()),
117 tabSelectedBackgroundColor(DefaultTabSelectedBackgroundColor()),
118 roundingRadius(DefaultTabRoundingRadius()),
119 closeBoxPenWidth(DefaultTabCloseBoxPenWidth()),
120 closeBoxSelectedColor(DefaultTabCloseBoxSelectedColor())
121 {
122 }
123 public nothrow TabControlCreateParams& Defaults()
124 {
125 return *this;
126 }
127 public nothrow TabControlCreateParams& SetFontFamilyName(const string& fontFamilyName_)
128 {
129 fontFamilyName = fontFamilyName_;
130 return *this;
131 }
132 public nothrow TabControlCreateParams& SetFontSize(float fontSize_)
133 {
134 fontSize = fontSize_;
135 return *this;
136 }
137 public nothrow TabControlCreateParams& SetFrameColor(const Color& frameColor_)
138 {
139 frameColor = frameColor_;
140 return *this;
141 }
142 public nothrow TabControlCreateParams& SetTextColor(const Color& textColor_)
143 {
144 textColor = textColor_;
145 return *this;
146 }
147 public nothrow TabControlCreateParams& SetLeadingWidth(int leadingWidth_)
148 {
149 leadingWidth = leadingWidth_;
150 return *this;
151 }
152 public nothrow TabControlCreateParams& SetTopMarginHeight(int topMarginHeight_)
153 {
154 topMarginHeight = topMarginHeight_;
155 return *this;
156 }
157 public nothrow TabControlCreateParams& SetHeaderHeight(int headerHeight_)
158 {
159 headerHeight = headerHeight_;
160 return *this;
161 }
162 public nothrow TabControlCreateParams& SetTabPadding(const Padding& tabPadding_)
163 {
164 tabPadding = tabPadding_;
165 return *this;
166 }
167 public nothrow TabControlCreateParams& SetTabCloseBoxPadding(const Padding& tabCloseBoxPadding_)
168 {
169 tabCloseBoxPadding = tabCloseBoxPadding_;
170 return *this;
171 }
172 public nothrow TabControlCreateParams& SetOverlapWidth(int overlapWidth_)
173 {
174 overlapWidth = overlapWidth_;
175 return *this;
176 }
177 public nothrow TabControlCreateParams& SetRoundingRadius(float roundingRadius_)
178 {
179 roundingRadius = roundingRadius_;
180 return *this;
181 }
182 public nothrow TabControlCreateParams& SetTabNormalBackgroundColor(const Color& tabNormalBackgroundColor_)
183 {
184 tabNormalBackgroundColor = tabNormalBackgroundColor_;
185 return *this;
186 }
187 public nothrow TabControlCreateParams& SetTabSelectedBackgroundColor(const Color& tabSelectedBackgroundColor_)
188 {
189 tabSelectedBackgroundColor = tabSelectedBackgroundColor_;
190 return *this;
191 }
192 public nothrow TabControlCreateParams& SetCloseBoxPenWidth(float closeBoxPenWidth_)
193 {
194 closeBoxPenWidth = closeBoxPenWidth_;
195 return *this;
196 }
197 public nothrow TabControlCreateParams& SetCloseBoxSelectedColor(const Color& closeBoxSelectedColor_)
198 {
199 closeBoxSelectedColor = closeBoxSelectedColor_;
200 return *this;
201 }
202 public ControlCreateParams& controlCreateParams;
203 public string fontFamilyName;
204 public float fontSize;
205 public Color frameColor;
206 public Color textColor;
207 public int leadingWidth;
208 public int topMarginHeight;
209 public int headerHeight;
210 public Padding tabPadding;
211 public Padding tabCloseBoxPadding;
212 public int overlapWidth;
213 public float roundingRadius;
214 public Color tabNormalBackgroundColor;
215 public Color tabSelectedBackgroundColor;
216 public float closeBoxPenWidth;
217 public Color closeBoxSelectedColor;
218 }
219
220 public class TabControl : Control
221 {
222 private enum Flags : sbyte
223 {
224 none = 0, changed = 1 << 0
225 }
226 public TabControl(const Font& font_, const Color& frameColor_, const Point& location, const Size& size, Dock dock, Anchors anchors) :
227 base("System.Windows.TabControl", DefaultWindowClassStyle(), DefaultChildWindowStyle(), DefaultExtendedWindowStyle(),
228 DefaultControlBackgroundColor(), "tabControl", location, size, dock, anchors), flags(Flags.none), font(font_), frameColor(frameColor_),
229 textColor(DefaultTabTextColor()), tabPages(this), selectedTabPage(null), leadingWidth(DefaultTabLeadingWidth()),
230 topMarginHeight(DefaultTabControlTopMarginHeight()), headerHeight(0), tabPadding(DefaultTabPadding()),
231 tabCloseBoxPadding(DefaultTabCloseBoxPadding()),
232 overlapWidth(DefaultTabOverlapWidth()), roundingRadius(DefaultTabRoundingRadius()), stringFormat(),
233 centerFormat(StringAlignment.center, StringAlignment.center), framePen(frameColor), textBrush(textColor),
234 tabNormalBackgroundColor(DefaultTabNormalBackgroundColor()), tabNormalBackgroundBrush(tabNormalBackgroundColor),
235 tabSelectedBackgroundColor(DefaultTabSelectedBackgroundColor()), tabSelectedBackgroundBrush(tabSelectedBackgroundColor),
236 closeBoxPenWidth(DefaultTabCloseBoxPenWidth()), closeBoxPen(textColor, closeBoxPenWidth), closeStateTabPage(null),
237 closeBoxSelectedColor(DefaultTabCloseBoxSelectedColor()), closeBoxSelectedBrush(closeBoxSelectedColor)
238 {
239 SetChanged();
240 }
241 public TabControl(const Point& location, const Size& size, Dock dock, Anchors anchors) :
242 this(Font(FontFamily("Segoe UI"), 9.0f), DefaultTabControlFrameColor(), location, size, dock, anchors)
243 {
244 }
245 public TabControl(TabControlCreateParams& createParams) :
246 base(createParams.controlCreateParams),
247 flags(Flags.none), font(FontFamily(createParams.fontFamilyName), createParams.fontSize),
248 frameColor(createParams.frameColor),
249 textColor(createParams.textColor),
250 tabPages(this), selectedTabPage(null),
251 leadingWidth(createParams.leadingWidth),
252 topMarginHeight(createParams.topMarginHeight),
253 headerHeight(createParams.headerHeight),
254 tabPadding(createParams.tabPadding),
255 tabCloseBoxPadding(createParams.tabCloseBoxPadding),
256 overlapWidth(createParams.overlapWidth),
257 roundingRadius(createParams.roundingRadius),
258 stringFormat(),
259 centerFormat(StringAlignment.center, StringAlignment.center), framePen(frameColor), textBrush(textColor),
260 tabNormalBackgroundColor(createParams.tabNormalBackgroundColor), tabNormalBackgroundBrush(tabNormalBackgroundColor),
261 tabSelectedBackgroundColor(createParams.tabSelectedBackgroundColor), tabSelectedBackgroundBrush(tabSelectedBackgroundColor),
262 closeBoxPenWidth(createParams.closeBoxPenWidth), closeBoxPen(textColor, closeBoxPenWidth), closeStateTabPage(null),
263 closeBoxSelectedColor(createParams.closeBoxSelectedColor), closeBoxSelectedBrush(closeBoxSelectedColor)
264 {
265 SetChanged();
266 }
267 public void SetTextColor(const Color& textColor_)
268 {
269 if (textColor_ != textColor)
270 {
271 textColor = textColor_;
272 textBrush = SolidBrush(textColor);
273 Invalidate();
274 }
275 }
276 public void SetTabNormalBackgroundColor(const Color& tabNormalBackgroundColor_)
277 {
278 if (tabNormalBackgroundColor_ != tabNormalBackgroundColor)
279 {
280 tabNormalBackgroundColor = tabNormalBackgroundColor_;
281 tabNormalBackgroundBrush = SolidBrush(tabNormalBackgroundColor);
282 Invalidate();
283 }
284 }
285 public void SetTabSelectedBackgroundColor(const Color& tabSelectedBackgroundColor_)
286 {
287 if (tabSelectedBackgroundColor_ != tabSelectedBackgroundColor)
288 {
289 tabSelectedBackgroundColor = tabSelectedBackgroundColor_;
290 tabSelectedBackgroundBrush = SolidBrush(tabSelectedBackgroundColor);
291 }
292 }
293 public const Container& TabPages() const
294 {
295 return tabPages;
296 }
297 public void AddTabPage(TabPage* tabPage)
298 {
299 AddTabPageToTabPageMap(tabPage);
300 tabPages.AddChild(tabPage);
301 SetSelectedTabPage(tabPage);
302 SetChanged();
303 }
304 public void AddTabPage(const string& text, const string& key)
305 {
306 AddTabPage(new TabPage(text, key));
307 }
308 public void AddTabPage(const string& text)
309 {
310 AddTabPage(text, string());
311 }
312 public void CloseTabPage(TabPage* tabPage)
313 {
314 tabPage->Hide();
315 RemoveTabPageFromTabPageMap(tabPage);
316 if (tabPage == selectedTabPage)
317 {
318 if (selectedTabPage->NextSibling() != null)
319 {
320 SetSelectedTabPage(cast<TabPage*>(selectedTabPage->NextSibling()));
321 }
322 else if (selectedTabPage->PrevSibling() != null)
323 {
324 SetSelectedTabPage(cast<TabPage*>(selectedTabPage->PrevSibling()));
325 }
326 else
327 {
328 SetSelectedTabPage(null);
329 }
330 }
331 UniquePtr<Component> component = tabPages.RemoveChild(tabPage);
332 TabPage* tb = cast<TabPage*>(component.Get());
333 ControlEventArgs args(tb);
334 OnControlRemoved(args);
335 SetChanged();
336 Invalidate();
337 }
338 public void CloseAllTabPages()
339 {
340 if (selectedTabPage != null)
341 {
342 selectedTabPage->Hide();
343 selectedTabPage = null;
344 }
345 Component* component = tabPages.FirstChild();
346 while (component != null)
347 {
348 Component* next = component->NextSibling();
349 UniquePtr<Component> comp = tabPages.RemoveChild(component);
350 TabPage* tabPage = cast<TabPage*>(comp.Get());
351 RemoveTabPageFromTabPageMap(tabPage);
352 ControlEventArgs args(tabPage);
353 OnControlRemoved(args);
354 component = next;
355 }
356 SetChanged();
357 Invalidate();
358 }
359 public nothrow int IndexOf(TabPage* tabPage) const
360 {
361 int index = 0;
362 Component* component = tabPages.FirstChild();
363 while (component != null)
364 {
365 if (component == tabPage)
366 {
367 return index;
368 }
369 component = component->NextSibling();
370 ++index;
371 }
372 return -1;
373 }
374 public nothrow TabPage* GetTabPageByKey(const string& key) const
375 {
376 HashMap<string, TabPage*>.ConstIterator it = tabPageMap.CFind(key);
377 if (it != tabPageMap.CEnd())
378 {
379 return it->second;
380 }
381 else
382 {
383 return null;
384 }
385 }
386 protected override void OnPaint(PaintEventArgs& args)
387 {
388 try
389 {
390 if (Debug.Paint())
391 {
392 Rect r(Point(), GetSize());
393 LogView* log = Application.GetLogView();
394 if (log != null)
395 {
396 log->WriteLine("TabControl.OnPaint: " + r.ToString());
397 }
398 }
399 SmoothingMode prevSmoothingMode = args.graphics.GetSmoothingModeChecked();
400 args.graphics.SetSmoothingModeChecked(SmoothingMode.highQuality);
401 if (Changed())
402 {
403 ResetChanged();
404 Measure(args.graphics);
405 }
406 args.graphics.Clear(BackgroundColor());
407 DrawTabs(args.graphics);
408 DrawSelectedTabPage(args.clipRect);
409 DrawFrame(args.graphics);
410 args.graphics.SetSmoothingModeChecked(prevSmoothingMode);
411 base->OnPaint(args);
412 }
413 catch (const Exception& ex)
414 {
415 MessageBox.Show(ex.Message());
416 }
417 }
418 protected override void OnMouseEnter()
419 {
420 base->OnMouseEnter();
421 closeStateTabPage = null;
422 }
423 protected override void OnMouseLeave()
424 {
425 base->OnMouseLeave();
426 if (closeStateTabPage != null)
427 {
428 closeStateTabPage->tab.state = Tab.State.normal;
429 Invalidate(closeStateTabPage->tab.closeRect.ToWinRect());
430 closeStateTabPage = null;
431 }
432 }
433 protected override void OnMouseMove(MouseEventArgs& args)
434 {
435 base->OnMouseMove(args);
436 Component* component = tabPages.FirstChild();
437 while (component != null)
438 {
439 TabPage* tabPage = cast<TabPage*>(component);
440 if (tabPage->tab.closeRect.Contains(args.location))
441 {
442 if (tabPage->tab.state == Tab.State.normal)
443 {
444 tabPage->tab.state = Tab.State.closeBoxSelected;
445 closeStateTabPage = tabPage;
446 Invalidate(tabPage->tab.closeRect.ToWinRect());
447 return;
448 }
449 }
450 else if (closeStateTabPage != null)
451 {
452 if (tabPage->tab.state == Tab.State.closeBoxSelected)
453 {
454 closeStateTabPage->tab.state = Tab.State.normal;
455 Invalidate(closeStateTabPage->tab.closeRect.ToWinRect());
456 closeStateTabPage = null;
457 return;
458 }
459 }
460 component = component->NextSibling();
461 }
462 }
463 protected override void OnMouseDown(MouseEventArgs& args)
464 {
465 base->OnMouseDown(args);
466 Component* component = tabPages.FirstChild();
467 while (component != null)
468 {
469 TabPage* tabPage = cast<TabPage*>(component);
470 if (tabPage->tab.selectRect.Contains(args.location))
471 {
472 tabPage->Select();
473 return;
474 }
475 else if (tabPage->tab.closeRect.Contains(args.location))
476 {
477 tabPage->Close();
478 return;
479 }
480 component = component->NextSibling();
481 }
482 }
483 public inline nothrow TabPage* SelectedTabPage() const
484 {
485 return selectedTabPage;
486 }
487 public void SetSelectedTabPage(TabPage* tabPage)
488 {
489 if (selectedTabPage != tabPage)
490 {
491 if (selectedTabPage != null)
492 {
493 selectedTabPage->Hide();
494 }
495 selectedTabPage = tabPage;
496 if (selectedTabPage != null)
497 {
498 selectedTabPage->Show();
499 Control* control = selectedTabPage->GetFirstEnabledTabStopControl();
500 if (control != null)
501 {
502 control->SetFocus();
503 }
504 OnTabPageSelected();
505 }
506 Invalidate();
507 }
508 }
509 public void SelectNextTabPage()
510 {
511 if (selectedTabPage == null) return;
512 TabPage* nextTabPage = cast<TabPage*>(selectedTabPage->NextSibling());
513 if (nextTabPage != null)
514 {
515 SetSelectedTabPage(nextTabPage);
516 }
517 else
518 {
519 TabPage* firstTabPage = cast<TabPage*>(tabPages.FirstChild());
520 if (firstTabPage != null)
521 {
522 SetSelectedTabPage(firstTabPage);
523 }
524 }
525 }
526 public void SelectPreviousTabPage()
527 {
528 if (selectedTabPage == null) return;
529 TabPage* prevTabPage = cast<TabPage*>(selectedTabPage->PrevSibling());
530 if (prevTabPage != null)
531 {
532 SetSelectedTabPage(prevTabPage);
533 }
534 else
535 {
536 TabPage* lastTabPage = cast<TabPage*>(tabPages.LastChild());
537 if (lastTabPage != null)
538 {
539 SetSelectedTabPage(lastTabPage);
540 }
541 }
542 }
543 protected virtual void OnTabPageSelected()
544 {
545 tabPageSelectedEvent.Fire();
546 }
547 public Event<TabPageSelectedEventHandler>& TabPageSelectedEvent()
548 {
549 return tabPageSelectedEvent;
550 }
551 private void DrawTabs(Graphics& graphics)
552 {
553 Component* component = tabPages.FirstChild();
554 int left = leadingWidth;
555 while (component != null)
556 {
557 TabPage* tabPage = cast<TabPage*>(component);
558 if (tabPage != selectedTabPage)
559 {
560 tabPage->DrawTab(graphics, this);
561 }
562 component = component->NextSibling();
563 }
564 if (selectedTabPage != null)
565 {
566 selectedTabPage->DrawTab(graphics, this);
567 }
568 }
569 protected override void OnLocationChanged()
570 {
571 base->OnLocationChanged();
572 SetSelectedTabPagePos();
573 }
574 protected override void OnSizeChanged(uint windowState)
575 {
576 base->OnSizeChanged(windowState);
577 SetSelectedTabPagePos();
578 }
579 private void SetSelectedTabPagePos()
580 {
581 if (selectedTabPage == null) return;
582 Point loc(1, headerHeight + 1);
583 selectedTabPage->SetLocation(loc);
584 Size size = GetSize();
585 size.w = size.w - 2;
586 size.h = size.h - headerHeight - 2;
587 selectedTabPage->SetSize(size);
588 selectedTabPage->DockChildren();
589 }
590 private void DrawSelectedTabPage(const Rect& clipRect)
591 {
592 if (selectedTabPage == null) return;
593 SetSelectedTabPagePos();
594 Rect r(selectedTabPage->Location(), selectedTabPage->GetSize());
595 if (!r.IntersectsWith(clipRect)) return;
596 selectedTabPage->Invalidate();
597 }
598 private void DrawFrame(Graphics& graphics)
599 {
600 if (selectedTabPage == null) return;
601 Size size = GetSize();
602 graphics.DrawLineChecked(framePen,
603 PointF(0, headerHeight),
604 PointF(selectedTabPage->tab.left, headerHeight));
605 graphics.DrawLineChecked(framePen,
606 PointF(selectedTabPage->tab.left + selectedTabPage->tab.width, headerHeight),
607 PointF(size.w - 1, headerHeight));
608 graphics.DrawLineChecked(framePen,
609 PointF(size.w - 1, headerHeight),
610 PointF(size.w - 1, size.h - 1));
611 graphics.DrawLineChecked(framePen,
612 PointF(size.w - 1, size.h - 1),
613 PointF(0, size.h - 1));
614 graphics.DrawLineChecked(framePen,
615 PointF(0, size.h - 1),
616 PointF(0, headerHeight));
617 }
618 internal nothrow void AddTabPageToTabPageMap(TabPage* tabPage)
619 {
620 if (!tabPage->Key().IsEmpty())
621 {
622 tabPageMap[tabPage->Key()] = tabPage;
623 }
624 }
625 internal nothrow void RemoveTabPageFromTabPageMap(TabPage* tabPage)
626 {
627 if (!tabPage->Key().IsEmpty())
628 {
629 tabPageMap.Remove(tabPage->Key());
630 }
631 }
632 private void Measure(Graphics& graphics)
633 {
634 headerHeight = 0;
635 MeasureWidthsAndHeight(graphics);
636 SetVisibility(graphics);
637 CalculateMetrics(graphics);
638 }
639 private void MeasureWidthsAndHeight(Graphics& graphics)
640 {
641 Component* component = tabPages.FirstChild();
642 while (component != null)
643 {
644 TabPage* tabPage = cast<TabPage*>(component);
645 tabPage->MeasureWidthAndHeight(graphics, this);
646 component = component->NextSibling();
647 }
648 }
649 private void SetVisibility(Graphics& graphics)
650 {
651 Component* component = tabPages.FirstChild();
652 TabPage* firstVisibleTabPage = cast<TabPage*>(component);
653 int width = GetSize().w;
654 int sum = leadingWidth;
655 bool selectedPassed = false;
656 while (component != null)
657 {
658 TabPage* tabPage = cast<TabPage*>(component);
659 int w = tabPage->tab.width;
660 sum = sum + w;
661 if (tabPage == selectedTabPage)
662 {
663 if (sum < width)
664 {
665 firstVisibleTabPage->tab.visible = true;
666 while (firstVisibleTabPage != selectedTabPage)
667 {
668 firstVisibleTabPage = cast<TabPage*>(firstVisibleTabPage->NextSibling());
669 firstVisibleTabPage->tab.visible = true;
670 }
671 selectedPassed = true;
672 }
673 else
674 {
675 sum = sum - firstVisibleTabPage->tab.width;
676 firstVisibleTabPage->tab.visible = false;
677 component = firstVisibleTabPage;
678 }
679 }
680 else if (selectedPassed)
681 {
682 if (sum < width)
683 {
684 tabPage->tab.visible = true;
685 }
686 else
687 {
688 tabPage->tab.visible = false;
689 }
690 }
691 sum = sum - overlapWidth;
692 component = component->NextSibling();
693 }
694 }
695 private void CalculateMetrics(Graphics& graphics)
696 {
697 Component* component = tabPages.FirstChild();
698 int left = leadingWidth;
699 while (component != null)
700 {
701 TabPage* tabPage = cast<TabPage*>(component);
702 tabPage->CalculateMetrics(graphics, this, left);
703 component = component->NextSibling();
704 }
705 }
706 internal inline nothrow const Font& GetFont() const
707 {
708 return font;
709 }
710 internal inline nothrow const Pen& FramePen() const
711 {
712 return framePen;
713 }
714 internal inline nothrow const Pen& CloseBoxPen() const
715 {
716 return closeBoxPen;
717 }
718 internal inline nothrow const SolidBrush& TextBrush() const
719 {
720 return textBrush;
721 }
722 internal inline nothrow const SolidBrush& TabNormalBackgroundBrush() const
723 {
724 return tabNormalBackgroundBrush;
725 }
726 internal inline nothrow const SolidBrush& TabSelectedBackgroundBrush() const
727 {
728 return tabSelectedBackgroundBrush;
729 }
730 internal inline nothrow const SolidBrush& CloseBoxSelectedBrush() const
731 {
732 return closeBoxSelectedBrush;
733 }
734 internal inline nothrow int LeadingWidth() const
735 {
736 return leadingWidth;
737 }
738 internal inline nothrow int TopMarginHeight() const
739 {
740 return topMarginHeight;
741 }
742 internal inline nothrow int HeaderHeight() const
743 {
744 return headerHeight;
745 }
746 internal nothrow void SetHeaderHeight(int headerHeight_)
747 {
748 headerHeight = headerHeight_;
749 }
750 internal inline nothrow const Padding& TabPadding() const
751 {
752 return tabPadding;
753 }
754 internal inline nothrow const Padding& TabCloseBoxPadding() const
755 {
756 return tabCloseBoxPadding;
757 }
758 internal inline nothrow int OverlapWidth() const
759 {
760 return overlapWidth;
761 }
762 internal inline nothrow float RoundingRadius() const
763 {
764 return roundingRadius;
765 }
766 internal inline nothrow const StringFormat& GetStringFormat() const
767 {
768 return stringFormat;
769 }
770 internal inline nothrow const StringFormat& CenterFormat() const
771 {
772 return centerFormat;
773 }
774 private inline nothrow bool Changed() const
775 {
776 return (flags & Flags.changed) != Flags.none;
777 }
778 internal inline nothrow void SetChanged()
779 {
780 flags = cast<Flags>(flags | Flags.changed);
781 }
782 private inline nothrow void ResetChanged()
783 {
784 flags = cast<Flags>(flags & ~Flags.changed);
785 }
786 private Flags flags;
787 private Font font;
788 private Color frameColor;
789 private Color textColor;
790 private Container tabPages;
791 private HashMap<string, TabPage*> tabPageMap;
792 private TabPage* selectedTabPage;
793 private int leadingWidth;
794 private int topMarginHeight;
795 private int headerHeight;
796 private Padding tabPadding;
797 private Padding tabCloseBoxPadding;
798 private int overlapWidth;
799 private float roundingRadius;
800 private StringFormat stringFormat;
801 private StringFormat centerFormat;
802 private Color tabNormalBackgroundColor;
803 private Color tabSelectedBackgroundColor;
804 private Pen framePen;
805 private float closeBoxPenWidth;
806 private Pen closeBoxPen;
807 private SolidBrush textBrush;
808 private SolidBrush tabNormalBackgroundBrush;
809 private SolidBrush tabSelectedBackgroundBrush;
810 private Color closeBoxSelectedColor;
811 private SolidBrush closeBoxSelectedBrush;
812 private TabPage* closeStateTabPage;
813 private Event<TabPageSelectedEventHandler> tabPageSelectedEvent;
814 }
815
816 public class TabPage : Panel
817 {
818 public TabPage(const string& text, const string& key_) :
819 base("System.Windows.TabPage", text, Point(), Size(), Dock.none, Anchors.none, Color.White()), key(key_), tab()
820 {
821 }
822 public inline nothrow const string& Key() const
823 {
824 return key;
825 }
826 public void SetKey(const string& key_)
827 {
828 TabControl* tabControl = GetTabControl();
829 if (tabControl != null)
830 {
831 tabControl->RemoveTabPageFromTabPageMap(this);
832 }
833 key = key_;
834 if (tabControl != null)
835 {
836 tabControl->AddTabPageToTabPageMap(this);
837 }
838 }
839 public void Select()
840 {
841 TabControl* tabControl = GetTabControl();
842 if (tabControl != null)
843 {
844 tabControl->SetSelectedTabPage(this);
845 }
846 }
847 public void Close()
848 {
849 TabControl* tabControl = GetTabControl();
850 if (tabControl != null)
851 {
852 tabControl->CloseTabPage(this);
853 }
854 }
855 public void SelectNextTabPage()
856 {
857 TabControl* tabControl = GetTabControl();
858 if (tabControl != null)
859 {
860 tabControl->SelectNextTabPage();
861 }
862 }
863 public void SelectPreviousTabPage()
864 {
865 TabControl* tabControl = GetTabControl();
866 if (tabControl != null)
867 {
868 tabControl->SelectPreviousTabPage();
869 }
870 }
871 public nothrow TabControl* GetTabControl() const
872 {
873 Control* parentControl = ParentControl();
874 if (parentControl != null && parentControl is TabControl*)
875 {
876 return cast<TabControl*>(parentControl);
877 }
878 return null;
879 }
880 protected override void OnLocationChanged()
881 {
882 base->OnLocationChanged();
883 }
884 protected override void OnSizeChanged(uint windowState)
885 {
886 base->OnSizeChanged(windowState);
887 }
888 protected override void OnTextChanged()
889 {
890 base->OnTextChanged();
891 tab.width = 0;
892 TabControl* tabControl = GetTabControl();
893 if (tabControl != null)
894 {
895 tabControl->SetChanged();
896 tabControl->Invalidate();
897 }
898 }
899 protected override void OnKeyDown(KeyEventArgs& args)
900 {
901 base->OnKeyDown(args);
902 if (!args.handled)
903 {
904 switch (args.key)
905 {
906 case cast<Keys>(Keys.controlModifier | Keys.f4):
907 {
908 Close();
909 args.handled = true;
910 break;
911 }
912 case cast<Keys>(Keys.controlModifier | Keys.tab):
913 {
914 SelectNextTabPage();
915 args.handled = true;
916 break;
917 }
918 case cast<Keys>(Keys.controlModifier | Keys.shiftModifier | Keys.tab):
919 {
920 SelectPreviousTabPage();
921 args.handled = true;
922 break;
923 }
924 }
925 }
926 }
927 internal void MeasureWidthAndHeight(Graphics& graphics, TabControl* tabControl)
928 {
929 if (tab.width == 0)
930 {
931 RectF textRect = graphics.MeasureStringChecked(Text(), tabControl->GetFont(), PointF(), tabControl->GetStringFormat());
932 RectF closeRect = graphics.MeasureStringChecked("x", tabControl->GetFont(), PointF(), tabControl->GetStringFormat());
933 tab.textHeight = textRect.size.h;
934 tab.textWidth = textRect.size.w;
935 tab.closeBoxWidth = closeRect.size.w;
936 tab.height = cast<int>(tabControl->TabPadding().Vertical() + tabControl->TabCloseBoxPadding().Vertical() + tab.textHeight);
937 tab.width = cast<int>(tabControl->TabPadding().Horizontal() + tab.textWidth + tabControl->OverlapWidth() +
938 tabControl->TabCloseBoxPadding().Horizontal() + tab.closeBoxWidth);
939 }
940 tabControl->SetHeaderHeight(Max(tabControl->HeaderHeight(), tab.height + tabControl->TopMarginHeight()));
941 }
942 internal void CalculateMetrics(Graphics& graphics, TabControl* tabControl, int& left)
943 {
944 if (!tab.visible) return;
945 float roundingRadius = tabControl->RoundingRadius();
946 int topMarginHeight = tabControl->TopMarginHeight();
947 tab.left = left;
948 tab.leftRoundingRect = RectF(PointF(), SizeF(2 * roundingRadius, 2 * roundingRadius));
949 tab.leftRoundingRect.Offset(left, topMarginHeight);
950 tab.rightRoundingRect = RectF(PointF(), SizeF(2 * roundingRadius, 2 * roundingRadius));
951 tab.rightRoundingRect.Offset(left + tab.width - 2 * roundingRadius, topMarginHeight);
952 tab.topRect = RectF(PointF(), SizeF(tab.width - 2 * roundingRadius, roundingRadius));
953 tab.topRect.Offset(left + roundingRadius, topMarginHeight);
954 tab.bottomRect = RectF(PointF(), SizeF(tab.width, tab.height - roundingRadius + 1));
955 tab.bottomRect.Offset(left, topMarginHeight + roundingRadius);
956 tab.textRect = RectF(PointF(), SizeF(tab.width - (tabControl->TabCloseBoxPadding().Horizontal() + tab.closeBoxWidth), tab.height));
957 tab.textRect.Offset(left, topMarginHeight);
958 tab.selectRect = Rect(Point(tab.left, topMarginHeight),
959 Size(cast<int>(tab.width - (tab.closeBoxWidth + tabControl->TabCloseBoxPadding().right)), tab.height));
960 tab.closeBoxRect = RectF(
961 PointF(tab.left + tab.selectRect.size.w,
962 topMarginHeight + tabControl->TabPadding().top + tabControl->TabCloseBoxPadding().top),
963 SizeF(tab.closeBoxWidth, tab.closeBoxWidth));
964 tab.closeRect = Rect(Point(cast<int>(tab.closeBoxRect.location.x), cast<int>(tab.closeBoxRect.location.y)),
965 Size(cast<int>(tab.closeBoxRect.size.w), cast<int>(tab.closeBoxRect.size.h)));
966 tab.closeRect.Inflate(3, 3);
967 tab.closeBoxRect.Inflate(-1, -1);
968 left = left + tab.width - tabControl->OverlapWidth();
969 }
970 internal void DrawTab(Graphics& graphics, TabControl* tabControl)
971 {
972 if (!tab.visible) return;
973 Brush* backgroundBrush = null;
974 if (this == tabControl->SelectedTabPage())
975 {
976 const Brush& brush = tabControl->TabSelectedBackgroundBrush();
977 backgroundBrush = &brush;
978 }
979 else
980 {
981 const Brush& brush = tabControl->TabNormalBackgroundBrush();
982 backgroundBrush = &brush;
983 }
984 const Pen& framePen = tabControl->FramePen();
985 const Pen& closeBoxPen = tabControl->CloseBoxPen();
986 int topMarginHeight = tabControl->TopMarginHeight();
987 float roundingRadius = tabControl->RoundingRadius();
988 graphics.FillEllipseChecked(*backgroundBrush, tab.leftRoundingRect);
989 graphics.FillEllipseChecked(*backgroundBrush, tab.rightRoundingRect);
990 graphics.FillRectangleChecked(*backgroundBrush, tab.topRect);
991 graphics.FillRectangleChecked(*backgroundBrush, tab.bottomRect);
992 graphics.DrawLineChecked(framePen, PointF(tab.left, tab.bottomRect.location.y + tab.bottomRect.size.h), PointF(tab.left, tab.bottomRect.location.y));
993 graphics.DrawArcChecked(framePen, tab.leftRoundingRect, -180.0f, 90.0f);
994 graphics.DrawStringChecked(Text(), tabControl->GetFont(), tab.textRect, tabControl->CenterFormat(), tabControl->TextBrush());
995 graphics.DrawLineChecked(framePen,
996 PointF(tab.leftRoundingRect.location.x + roundingRadius, topMarginHeight),
997 PointF(tab.rightRoundingRect.location.x + roundingRadius, topMarginHeight));
998 graphics.DrawArcChecked(framePen, tab.rightRoundingRect, -90.0f, 90.0f);
999 graphics.DrawLineChecked(framePen,
1000 PointF(tab.left + tab.width, tab.bottomRect.location.y),
1001 PointF(tab.left + tab.width, tab.bottomRect.location.y + tab.bottomRect.size.h - 1));
1002 if (tab.state == Tab.State.normal)
1003 {
1004 RectF r = tab.closeBoxRect;
1005 r.Inflate(3, 3);
1006 graphics.FillRectangleChecked(*backgroundBrush, r);
1007 }
1008 else if (tab.state == Tab.State.closeBoxSelected)
1009 {
1010 RectF r = tab.closeBoxRect;
1011 r.Inflate(3, 3);
1012 const Brush& selectedBrush = tabControl->CloseBoxSelectedBrush();
1013 graphics.FillRectangleChecked(selectedBrush, r);
1014 }
1015 graphics.DrawLineChecked(closeBoxPen,
1016 tab.closeBoxRect.location, PointF(tab.closeBoxRect.location.x + tab.closeBoxRect.size.w, tab.closeBoxRect.location.y + tab.closeBoxRect.size.h));
1017 graphics.DrawLineChecked(closeBoxPen,
1018 PointF(tab.closeBoxRect.location.x, tab.closeBoxRect.location.y + tab.closeBoxRect.size.h),
1019 PointF(tab.closeBoxRect.location.x + tab.closeBoxRect.size.w, tab.closeBoxRect.location.y));
1020 }
1021 private string key;
1022 internal Tab tab;
1023 }
1024 }