1 // =================================
   2 // Copyright (c) 2021 Seppo Laakko
   3 // Distributed under the MIT license
   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(204u206u219u);
  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(255u255u215u);
  31     }
  32 
  33     public nothrow Color DefaultTabCloseBoxSelectedColor()
  34     {
  35         return Color(222u238u245u);
  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(8282);
  51     }
  52 
  53     public nothrow Padding DefaultTabCloseBoxPadding()
  54     {
  55         return Padding(8680);
  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             normalcloseBoxSelected
  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 = 0changed = 1 << 0
 225         }
 226         public TabControl(const Font& font_const Color& frameColor_const Point& locationconst Size& sizeDock dockAnchors anchors) : 
 227             base("System.Windows.TabControl"DefaultWindowClassStyle()DefaultChildWindowStyle()DefaultExtendedWindowStyle()
 228             DefaultControlBackgroundColor()"tabControl"locationsizedockanchors)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.centerStringAlignment.center)framePen(frameColor)textBrush(textColor)
 234             tabNormalBackgroundColor(DefaultTabNormalBackgroundColor())tabNormalBackgroundBrush(tabNormalBackgroundColor)
 235             tabSelectedBackgroundColor(DefaultTabSelectedBackgroundColor())tabSelectedBackgroundBrush(tabSelectedBackgroundColor)
 236             closeBoxPenWidth(DefaultTabCloseBoxPenWidth())closeBoxPen(textColorcloseBoxPenWidth)closeStateTabPage(null)
 237             closeBoxSelectedColor(DefaultTabCloseBoxSelectedColor())closeBoxSelectedBrush(closeBoxSelectedColor)
 238         {
 239             SetChanged();
 240         }
 241         public TabControl(const Point& locationconst Size& sizeDock dockAnchors anchors) : 
 242             this(Font(FontFamily("Segoe UI")9.0f)DefaultTabControlFrameColor()locationsizedockanchors)
 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.centerStringAlignment.center)framePen(frameColor)textBrush(textColor)
 260             tabNormalBackgroundColor(createParams.tabNormalBackgroundColor)tabNormalBackgroundBrush(tabNormalBackgroundColor)
 261             tabSelectedBackgroundColor(createParams.tabSelectedBackgroundColor)tabSelectedBackgroundBrush(tabSelectedBackgroundColor)
 262             closeBoxPenWidth(createParams.closeBoxPenWidth)closeBoxPen(textColorcloseBoxPenWidth)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& textconst string& key)
 305         {
 306             AddTabPage(new TabPage(textkey));
 307         }
 308         public void AddTabPage(const string& text)
 309         {
 310             AddTabPage(textstring());
 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<stringTabPage*>.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(graphicsthis);
 561                 }
 562                 component = component->NextSibling();
 563             }
 564             if (selectedTabPage != null)
 565             {
 566                 selectedTabPage->DrawTab(graphicsthis);
 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(1headerHeight + 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(0headerHeight)
 604                 PointF(selectedTabPage->tab.leftheaderHeight));
 605             graphics.DrawLineChecked(framePen
 606                 PointF(selectedTabPage->tab.left + selectedTabPage->tab.widthheaderHeight)
 607                 PointF(size.w - 1headerHeight));
 608             graphics.DrawLineChecked(framePen
 609                 PointF(size.w - 1headerHeight)
 610                 PointF(size.w - 1size.h - 1));
 611             graphics.DrawLineChecked(framePen
 612                 PointF(size.w - 1size.h - 1)
 613                 PointF(0size.h - 1));
 614             graphics.DrawLineChecked(framePen
 615                 PointF(0size.h - 1)
 616                 PointF(0headerHeight));
 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(graphicsthis);
 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(graphicsthisleft);
 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<stringTabPage*> 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& textconst string& key_) : 
 819             base("System.Windows.TabPage"textPoint()Size()Dock.noneAnchors.noneColor.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& graphicsTabControl* 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& graphicsTabControl* tabControlint& 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 * roundingRadius2 * roundingRadius));
 949             tab.leftRoundingRect.Offset(lefttopMarginHeight);
 950             tab.rightRoundingRect = RectF(PointF()SizeF(2 * roundingRadius2 * roundingRadius));
 951             tab.rightRoundingRect.Offset(left + tab.width - 2 * roundingRadiustopMarginHeight);
 952             tab.topRect = RectF(PointF()SizeF(tab.width - 2 * roundingRadiusroundingRadius));
 953             tab.topRect.Offset(left + roundingRadiustopMarginHeight);
 954             tab.bottomRect = RectF(PointF()SizeF(tab.widthtab.height - roundingRadius + 1));
 955             tab.bottomRect.Offset(lefttopMarginHeight + roundingRadius);
 956             tab.textRect = RectF(PointF()SizeF(tab.width - (tabControl->TabCloseBoxPadding().Horizontal() + tab.closeBoxWidth)tab.height));
 957             tab.textRect.Offset(lefttopMarginHeight);
 958             tab.selectRect = Rect(Point(tab.lefttopMarginHeight)
 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.closeBoxWidthtab.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(33);
 967             tab.closeBoxRect.Inflate(-1-1);
 968             left = left + tab.width - tabControl->OverlapWidth();
 969         }
 970         internal void DrawTab(Graphics& graphicsTabControl* 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(*backgroundBrushtab.leftRoundingRect);
 989             graphics.FillEllipseChecked(*backgroundBrushtab.rightRoundingRect);
 990             graphics.FillRectangleChecked(*backgroundBrushtab.topRect);
 991             graphics.FillRectangleChecked(*backgroundBrushtab.bottomRect);
 992             graphics.DrawLineChecked(framePenPointF(tab.lefttab.bottomRect.location.y + tab.bottomRect.size.h)PointF(tab.lefttab.bottomRect.location.y));
 993             graphics.DrawArcChecked(framePentab.leftRoundingRect-180.0f90.0f);
 994             graphics.DrawStringChecked(Text()tabControl->GetFont()tab.textRecttabControl->CenterFormat()tabControl->TextBrush());
 995             graphics.DrawLineChecked(framePen
 996                 PointF(tab.leftRoundingRect.location.x + roundingRadiustopMarginHeight)
 997                 PointF(tab.rightRoundingRect.location.x + roundingRadiustopMarginHeight));
 998                 graphics.DrawArcChecked(framePentab.rightRoundingRect-90.0f90.0f);
 999             graphics.DrawLineChecked(framePen
1000                 PointF(tab.left + tab.widthtab.bottomRect.location.y)
1001                 PointF(tab.left + tab.widthtab.bottomRect.location.y + tab.bottomRect.size.h - 1));
1002             if (tab.state == Tab.State.normal)
1003             {
1004                 RectF r = tab.closeBoxRect;
1005                 r.Inflate(33);
1006                 graphics.FillRectangleChecked(*backgroundBrushr);
1007             }
1008             else if (tab.state == Tab.State.closeBoxSelected)
1009             {
1010                 RectF r = tab.closeBoxRect;
1011                 r.Inflate(33);
1012                 const Brush& selectedBrush = tabControl->CloseBoxSelectedBrush();
1013                 graphics.FillRectangleChecked(selectedBrushr);
1014             }
1015             graphics.DrawLineChecked(closeBoxPen
1016                 tab.closeBoxRect.locationPointF(tab.closeBoxRect.location.x + tab.closeBoxRect.size.wtab.closeBoxRect.location.y + tab.closeBoxRect.size.h));
1017             graphics.DrawLineChecked(closeBoxPen
1018                 PointF(tab.closeBoxRect.location.xtab.closeBoxRect.location.y + tab.closeBoxRect.size.h)
1019                 PointF(tab.closeBoxRect.location.x + tab.closeBoxRect.size.wtab.closeBoxRect.location.y));
1020         }
1021         private string key;
1022         internal Tab tab;
1023     }
1024 }