1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/ribbon/page.cpp 
   3 // Purpose:     Container for ribbon-bar-style interface panels 
   4 // Author:      Peter Cawley 
   8 // Copyright:   (C) Peter Cawley 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  11 #include "wx/wxprec.h" 
  17 #include "wx/ribbon/page.h" 
  21 #include "wx/ribbon/art.h" 
  22 #include "wx/ribbon/bar.h" 
  23 #include "wx/dcbuffer.h" 
  29 #include "wx/msw/private.h" 
  32 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
); 
  34 // As scroll buttons need to be rendered on top of a page's child windows, the 
  35 // buttons themselves have to be proper child windows (rather than just painted 
  36 // onto the page). In order to get proper clipping of a page's children (with 
  37 // regard to the scroll button), the scroll buttons are created as children of 
  38 // the ribbon bar rather than children of the page. This could not have been 
  39 // achieved by creating buttons as children of the page and then doing some Z-order 
  40 // manipulation, as this causes problems on win32 due to ribbon panels having the 
  41 // transparent flag set. 
  42 class wxRibbonPageScrollButton 
: public wxRibbonControl
 
  45     wxRibbonPageScrollButton(wxRibbonPage
* sibling
, 
  46                  wxWindowID id 
= wxID_ANY
, 
  47                  const wxPoint
& pos 
= wxDefaultPosition
, 
  48                  const wxSize
& size 
= wxDefaultSize
, 
  51     virtual ~wxRibbonPageScrollButton(); 
  54     virtual wxBorder 
GetDefaultBorder() const { return wxBORDER_NONE
; } 
  56     void OnEraseBackground(wxEraseEvent
& evt
); 
  57     void OnPaint(wxPaintEvent
& evt
); 
  58     void OnMouseEnter(wxMouseEvent
& evt
); 
  59     void OnMouseLeave(wxMouseEvent
& evt
); 
  60     void OnMouseDown(wxMouseEvent
& evt
); 
  61     void OnMouseUp(wxMouseEvent
& evt
); 
  63     wxRibbonPage
* m_sibling
; 
  66     DECLARE_CLASS(wxRibbonPageScrollButton
) 
  70 IMPLEMENT_CLASS(wxRibbonPageScrollButton
, wxRibbonControl
) 
  72 BEGIN_EVENT_TABLE(wxRibbonPageScrollButton
, wxRibbonControl
) 
  73     EVT_ENTER_WINDOW(wxRibbonPageScrollButton::OnMouseEnter
) 
  74     EVT_ERASE_BACKGROUND(wxRibbonPageScrollButton::OnEraseBackground
) 
  75     EVT_LEAVE_WINDOW(wxRibbonPageScrollButton::OnMouseLeave
) 
  76     EVT_LEFT_DOWN(wxRibbonPageScrollButton::OnMouseDown
) 
  77     EVT_LEFT_UP(wxRibbonPageScrollButton::OnMouseUp
) 
  78     EVT_PAINT(wxRibbonPageScrollButton::OnPaint
) 
  81 wxRibbonPageScrollButton::wxRibbonPageScrollButton(wxRibbonPage
* sibling
, 
  85                  long style
) : wxRibbonControl(sibling
->GetParent(), id
, pos
, size
, wxBORDER_NONE
) 
  87     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
  89     m_flags 
= (style 
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
) | wxRIBBON_SCROLL_BTN_FOR_PAGE
; 
  92 wxRibbonPageScrollButton::~wxRibbonPageScrollButton() 
  96 void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
)) 
  98     // Do nothing - all painting done in main paint handler 
 101 void wxRibbonPageScrollButton::OnPaint(wxPaintEvent
& WXUNUSED(evt
)) 
 103     wxAutoBufferedPaintDC 
dc(this); 
 106         m_art
->DrawScrollButton(dc
, this, GetSize(), m_flags
); 
 110 void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent
& WXUNUSED(evt
)) 
 112     m_flags 
|= wxRIBBON_SCROLL_BTN_HOVERED
; 
 116 void wxRibbonPageScrollButton::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
)) 
 118     m_flags 
&= ~wxRIBBON_SCROLL_BTN_HOVERED
; 
 119     m_flags 
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
; 
 123 void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent
& WXUNUSED(evt
)) 
 125     m_flags 
|= wxRIBBON_SCROLL_BTN_ACTIVE
; 
 129 void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent
& WXUNUSED(evt
)) 
 131     if(m_flags 
& wxRIBBON_SCROLL_BTN_ACTIVE
) 
 133         m_flags 
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
; 
 135         switch(m_flags 
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
) 
 137         case wxRIBBON_SCROLL_BTN_DOWN
: 
 138         case wxRIBBON_SCROLL_BTN_RIGHT
: 
 139             m_sibling
->ScrollLines(1); 
 141         case wxRIBBON_SCROLL_BTN_UP
: 
 142         case wxRIBBON_SCROLL_BTN_LEFT
: 
 143             m_sibling
->ScrollLines(-1); 
 151 IMPLEMENT_CLASS(wxRibbonPage
, wxRibbonControl
) 
 153 BEGIN_EVENT_TABLE(wxRibbonPage
, wxRibbonControl
) 
 154     EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground
) 
 155     EVT_PAINT(wxRibbonPage::OnPaint
) 
 156     EVT_SIZE(wxRibbonPage::OnSize
) 
 159 wxRibbonPage::wxRibbonPage() 
 161     m_scroll_left_btn 
= NULL
; 
 162     m_scroll_right_btn 
= NULL
; 
 164     m_scroll_buttons_visible 
= false; 
 167 wxRibbonPage::wxRibbonPage(wxRibbonBar
* parent
, 
 169                    const wxString
& label
, 
 170                    const wxBitmap
& icon
, 
 171                    long WXUNUSED(style
)) 
 172     : wxRibbonControl(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
) 
 174     CommonInit(label
, icon
); 
 177 wxRibbonPage::~wxRibbonPage() 
 179     delete[] m_size_calc_array
; 
 182 bool wxRibbonPage::Create(wxRibbonBar
* parent
, 
 184                 const wxString
& label
, 
 185                 const wxBitmap
& icon
, 
 186                 long WXUNUSED(style
)) 
 188     if(!wxRibbonControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
)) 
 191     CommonInit(label
, icon
); 
 196 void wxRibbonPage::CommonInit(const wxString
& label
, const wxBitmap
& icon
) 
 201     m_old_size 
= wxSize(0, 0); 
 203     m_scroll_left_btn 
= NULL
; 
 204     m_scroll_right_btn 
= NULL
; 
 205     m_size_calc_array 
= NULL
; 
 206     m_size_calc_array_size 
= 0; 
 208     m_scroll_buttons_visible 
= false; 
 210     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 212     wxDynamicCast(GetParent(), wxRibbonBar
)->AddPage(this); 
 215 void wxRibbonPage::SetArtProvider(wxRibbonArtProvider
* art
) 
 218     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 220           node 
= node
->GetNext() ) 
 222         wxWindow
* child 
= node
->GetData(); 
 223         wxRibbonControl
* ribbon_child 
= wxDynamicCast(child
, wxRibbonControl
); 
 226             ribbon_child
->SetArtProvider(art
); 
 231 void wxRibbonPage::AdjustRectToIncludeScrollButtons(wxRect
* rect
) const 
 233     if(m_scroll_buttons_visible
) 
 235         if(GetMajorAxis() == wxVERTICAL
) 
 237             if(m_scroll_left_btn
) 
 239                 rect
->SetY(rect
->GetY() - 
 240                     m_scroll_left_btn
->GetSize().GetHeight()); 
 241                 rect
->SetHeight(rect
->GetHeight() + 
 242                     m_scroll_left_btn
->GetSize().GetHeight()); 
 244             if(m_scroll_right_btn
) 
 246                 rect
->SetHeight(rect
->GetHeight() + 
 247                     m_scroll_right_btn
->GetSize().GetHeight()); 
 252             if(m_scroll_left_btn
) 
 254                 rect
->SetX(rect
->GetX() - 
 255                     m_scroll_left_btn
->GetSize().GetWidth()); 
 256                 rect
->SetWidth(rect
->GetWidth() + 
 257                     m_scroll_left_btn
->GetSize().GetWidth()); 
 259             if(m_scroll_right_btn
) 
 261                 rect
->SetWidth(rect
->GetWidth() + 
 262                     m_scroll_right_btn
->GetSize().GetWidth()); 
 268 void wxRibbonPage::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
)) 
 270     // All painting done in main paint handler to minimise flicker 
 273 void wxRibbonPage::OnPaint(wxPaintEvent
& WXUNUSED(evt
)) 
 275     // No foreground painting done by the page itself, but a paint DC 
 276     // must be created anyway. 
 277     wxAutoBufferedPaintDC 
dc(this); 
 278     wxRect 
rect(GetSize()); 
 279     AdjustRectToIncludeScrollButtons(&rect
); 
 280     m_art
->DrawPageBackground(dc
, this, rect
); 
 283 wxOrientation 
wxRibbonPage::GetMajorAxis() const 
 285     if(m_art 
&& (m_art
->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL
)) 
 295 bool wxRibbonPage::ScrollLines(int lines
) 
 297     return ScrollPixels(lines 
* 8); 
 300 bool wxRibbonPage::ScrollPixels(int pixels
) 
 304         if(m_scroll_amount 
== 0) 
 306         if(m_scroll_amount 
< -pixels
) 
 307             pixels 
= -m_scroll_amount
; 
 311         if(m_scroll_amount 
== m_scroll_amount_limit
) 
 313         if(m_scroll_amount 
+ pixels 
> m_scroll_amount_limit
) 
 314             pixels 
= m_scroll_amount_limit 
- m_scroll_amount
; 
 319     m_scroll_amount 
+= pixels
; 
 321     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 323               node 
= node
->GetNext() ) 
 325         wxWindow
* child 
= node
->GetData(); 
 327         child
->GetPosition(&x
, &y
); 
 328         if(GetMajorAxis() == wxHORIZONTAL
) 
 332         child
->SetPosition(wxPoint(x
, y
)); 
 340 void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x
, int y
, int width
, int height
) 
 342     if(m_scroll_buttons_visible
) 
 344         if(GetMajorAxis() == wxHORIZONTAL
) 
 346             if(m_scroll_left_btn
) 
 348                 int w 
= m_scroll_left_btn
->GetSize().GetWidth(); 
 349                 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
)); 
 353             if(m_scroll_right_btn
) 
 355                 int w 
= m_scroll_right_btn
->GetSize().GetWidth(); 
 357                 m_scroll_right_btn
->SetPosition(wxPoint(x 
+ width
, y
)); 
 362             if(m_scroll_left_btn
) 
 364                 int h 
= m_scroll_left_btn
->GetSize().GetHeight(); 
 365                 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
)); 
 369             if(m_scroll_right_btn
) 
 371                 int h 
= m_scroll_right_btn
->GetSize().GetHeight(); 
 373                 m_scroll_right_btn
->SetPosition(wxPoint(x
, y 
+ height
)); 
 377     SetSize(x
, y
, width
, height
); 
 380 void wxRibbonPage::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
) 
 382     // When a resize triggers the scroll buttons to become visible, the page is resized. 
 383     // This resize from within a resize event can cause (MSW) wxWidgets some confusion, 
 384     // and report the 1st size to the 2nd size event. Hence the most recent size is 
 385     // remembered internally and used in Layout() where appropiate. 
 387     if(GetMajorAxis() == wxHORIZONTAL
) 
 389         m_size_in_major_axis_for_children 
= width
; 
 390         if(m_scroll_buttons_visible
) 
 392             if(m_scroll_left_btn
) 
 393                 m_size_in_major_axis_for_children 
+= m_scroll_left_btn
->GetSize().GetWidth(); 
 394             if(m_scroll_right_btn
) 
 395                 m_size_in_major_axis_for_children 
+= m_scroll_right_btn
->GetSize().GetWidth(); 
 400         m_size_in_major_axis_for_children 
= height
; 
 401         if(m_scroll_buttons_visible
) 
 403             if(m_scroll_left_btn
) 
 404                 m_size_in_major_axis_for_children 
+= m_scroll_left_btn
->GetSize().GetHeight(); 
 405             if(m_scroll_right_btn
) 
 406                 m_size_in_major_axis_for_children 
+= m_scroll_right_btn
->GetSize().GetHeight(); 
 410     wxRibbonControl::DoSetSize(x
, y
, width
, height
, sizeFlags
); 
 413 void wxRibbonPage::OnSize(wxSizeEvent
& evt
) 
 415     wxSize new_size 
= evt
.GetSize(); 
 418     wxRect invalid_rect 
= m_art
->GetPageBackgroundRedrawArea(temp_dc
, this, m_old_size
, new_size
); 
 419     Refresh(true, &invalid_rect
); 
 421     m_old_size 
= new_size
; 
 423     if(new_size
.GetX() > 0 && new_size
.GetY() > 0) 
 429         // Simplify other calculations by pretending new size is zero in both 
 432         // When size == 0, no point in doing any layout 
 438 void wxRibbonPage::RemoveChild(wxWindowBase 
*child
) 
 440     // Remove all references to the child from the collapse stack 
 441     size_t count 
= m_collapse_stack
.GetCount(); 
 443     for(src 
= 0, dst 
= 0; src 
< count
; ++src
, ++dst
) 
 445         wxRibbonControl 
*item 
= m_collapse_stack
.Item(src
); 
 456             m_collapse_stack
.Item(dst
) = item
; 
 461         m_collapse_stack
.RemoveAt(dst
, src 
- dst
); 
 464     // ... and then proceed as normal 
 465     wxRibbonControl::RemoveChild(child
); 
 468 bool wxRibbonPage::Realize() 
 472     m_collapse_stack
.Clear(); 
 473     for (wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 475                   node 
= node
->GetNext()) 
 477         wxRibbonControl
* child 
= wxDynamicCast(node
->GetData(), wxRibbonControl
); 
 482         if(!child
->Realize()) 
 487     PopulateSizeCalcArray(&wxWindow::GetMinSize
); 
 489     return DoActualLayout() && status
; 
 492 void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size
)(void) const) 
 494     if(m_size_calc_array_size 
!= GetChildren().GetCount()) 
 496         delete[] m_size_calc_array
; 
 497         m_size_calc_array_size 
= GetChildren().GetCount(); 
 498         m_size_calc_array 
= new wxSize
[m_size_calc_array_size
]; 
 500     wxSize
* node_size 
= m_size_calc_array
; 
 501     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 503           node 
= node
->GetNext(), ++node_size 
) 
 505         wxWindow
* child 
= node
->GetData(); 
 506         *node_size 
= (child
->*get_size
)(); 
 510 bool wxRibbonPage::Layout() 
 512     if(GetChildren().GetCount() == 0) 
 518         PopulateSizeCalcArray(&wxWindow::GetSize
); 
 519         return DoActualLayout(); 
 523 bool wxRibbonPage::DoActualLayout() 
 525     wxPoint 
origin(m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
), m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
)); 
 526     wxOrientation major_axis 
= GetMajorAxis(); 
 530     if(major_axis 
== wxHORIZONTAL
) 
 532         gap 
= m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
); 
 533         minor_axis_size 
= GetSize().GetHeight() - origin
.y 
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
); 
 534         available_space 
= m_size_in_major_axis_for_children 
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
) - origin
.x
; 
 538         gap 
= m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
); 
 539         minor_axis_size 
= GetSize().GetWidth() - origin
.x 
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
); 
 540         available_space 
= m_size_in_major_axis_for_children 
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
) - origin
.y
; 
 543     for(size_index 
= 0; size_index 
< m_size_calc_array_size
; ++size_index
) 
 545         if(major_axis 
== wxHORIZONTAL
) 
 547             available_space 
-= m_size_calc_array
[size_index
].GetWidth(); 
 548             m_size_calc_array
[size_index
].SetHeight(minor_axis_size
); 
 552             available_space 
-= m_size_calc_array
[size_index
].GetHeight(); 
 553             m_size_calc_array
[size_index
].SetWidth(minor_axis_size
); 
 556             available_space 
-= gap
; 
 558     bool todo_hide_scroll_buttons 
= false; 
 559     bool todo_show_scroll_buttons 
= false; 
 560     if(available_space 
>= 0) 
 562         if(m_scroll_buttons_visible
) 
 563             todo_hide_scroll_buttons 
= true; 
 564         if(available_space 
> 0) 
 565             ExpandPanels(major_axis
, available_space
); 
 569         if(m_scroll_buttons_visible
) 
 571             // Scroll buttons already visible - not going to be able to downsize any more 
 572             m_scroll_amount_limit 
= -available_space
; 
 573             if(m_scroll_amount 
> m_scroll_amount_limit
) 
 575                 m_scroll_amount 
= m_scroll_amount_limit
; 
 576                 todo_show_scroll_buttons 
= true; 
 581             if(!CollapsePanels(major_axis
, -available_space
)) 
 584                 m_scroll_amount_limit 
= -available_space
; 
 585                 todo_show_scroll_buttons 
= true; 
 589     if(m_scroll_buttons_visible
) 
 591         if(major_axis 
== wxHORIZONTAL
) 
 593             origin
.x 
-= m_scroll_amount
; 
 594             if(m_scroll_left_btn
) 
 595                 origin
.x 
-= m_scroll_left_btn
->GetSize().GetWidth(); 
 599             origin
.y 
-= m_scroll_amount
; 
 600             if(m_scroll_left_btn
) 
 601                 origin
.y 
-= m_scroll_left_btn
->GetSize().GetHeight(); 
 605     for(wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 607         node 
= node
->GetNext(), ++size_index 
) 
 609         wxWindow
* child 
= node
->GetData(); 
 610         int w 
= m_size_calc_array
[size_index
].GetWidth(); 
 611         int h 
= m_size_calc_array
[size_index
].GetHeight(); 
 612         child
->SetSize(origin
.x
, origin
.y
, w
, h
); 
 613         if(major_axis 
== wxHORIZONTAL
) 
 623     if(todo_show_scroll_buttons
) 
 625     else if(todo_hide_scroll_buttons
) 
 632 bool wxRibbonPage::Show(bool show
) 
 634     if(m_scroll_left_btn
) 
 635         m_scroll_left_btn
->Show(show
); 
 636     if(m_scroll_right_btn
) 
 637         m_scroll_right_btn
->Show(show
); 
 638     return wxRibbonControl::Show(show
); 
 641 void wxRibbonPage::HideScrollButtons() 
 644     m_scroll_amount_limit 
= 0; 
 648 void wxRibbonPage::ShowScrollButtons() 
 650     bool show_left 
= true; 
 651     bool show_right 
= true; 
 652     bool reposition 
= false; 
 653     if(m_scroll_amount 
== 0) 
 657     if(m_scroll_amount 
>= m_scroll_amount_limit
) 
 660         m_scroll_amount 
= m_scroll_amount_limit
; 
 662     m_scroll_buttons_visible 
= show_left 
|| show_right
; 
 666         if(m_scroll_left_btn 
== NULL
) 
 671             if(GetMajorAxis() == wxHORIZONTAL
) 
 673                 direction 
= wxRIBBON_SCROLL_BTN_LEFT
; 
 674                 size 
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
); 
 675                 size
.SetHeight(GetSize().GetHeight()); 
 679                 direction 
= wxRIBBON_SCROLL_BTN_UP
; 
 680                 size 
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
); 
 681                 size
.SetWidth(GetSize().GetWidth()); 
 683             m_scroll_left_btn 
= new wxRibbonPageScrollButton(this, wxID_ANY
, GetPosition(), size
, direction
); 
 686                 m_scroll_left_btn
->Hide(); 
 693         if(m_scroll_left_btn 
!= NULL
) 
 695             m_scroll_left_btn
->Destroy(); 
 696             m_scroll_left_btn 
= NULL
; 
 703         if(m_scroll_right_btn 
== NULL
) 
 708             if(GetMajorAxis() == wxHORIZONTAL
) 
 710                 direction 
= wxRIBBON_SCROLL_BTN_RIGHT
; 
 711                 size 
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
); 
 712                 size
.SetHeight(GetSize().GetHeight()); 
 716                 direction 
= wxRIBBON_SCROLL_BTN_DOWN
; 
 717                 size 
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
); 
 718                 size
.SetWidth(GetSize().GetWidth()); 
 720             wxPoint initial_pos 
= GetPosition() + GetSize() - size
; 
 721             m_scroll_right_btn 
= new wxRibbonPageScrollButton(this, wxID_ANY
, initial_pos
, size
, direction
); 
 724                 m_scroll_right_btn
->Hide(); 
 731         if(m_scroll_right_btn 
!= NULL
) 
 733             m_scroll_right_btn
->Destroy(); 
 734             m_scroll_right_btn 
= NULL
; 
 741         wxDynamicCast(GetParent(), wxRibbonBar
)->RepositionPage(this); 
 745 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
) 
 749     case wxHORIZONTAL
: return size
.GetWidth(); 
 750     case wxVERTICAL
: return size
.GetHeight(); 
 751     case wxBOTH
: return size
.GetWidth() * size
.GetHeight(); 
 756 bool wxRibbonPage::ExpandPanels(wxOrientation direction
, int maximum_amount
) 
 758     bool expanded_something 
= false; 
 759     while(maximum_amount 
> 0) 
 761         int smallest_size 
= INT_MAX
; 
 762         wxRibbonPanel
* smallest_panel 
= NULL
; 
 763         wxSize
* smallest_panel_size 
= NULL
; 
 764         wxSize
* panel_size 
= m_size_calc_array
; 
 765         for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 767                   node 
= node
->GetNext(), ++panel_size 
) 
 769             wxRibbonPanel
* panel 
= wxDynamicCast(node
->GetData(), wxRibbonPanel
); 
 774             if(panel
->IsSizingContinuous()) 
 776                 int size 
= GetSizeInOrientation(*panel_size
, direction
); 
 777                 if(size 
< smallest_size
) 
 779                     smallest_size 
= size
; 
 780                     smallest_panel 
= panel
; 
 781                     smallest_panel_size 
= panel_size
; 
 786                 int size 
= GetSizeInOrientation(*panel_size
, direction
); 
 787                 if(size 
< smallest_size
) 
 789                     wxSize larger 
= panel
->GetNextLargerSize(direction
, *panel_size
); 
 790                     if(larger 
!= (*panel_size
) && GetSizeInOrientation(larger
, direction
) > size
) 
 792                         smallest_size 
= size
; 
 793                         smallest_panel 
= panel
; 
 794                         smallest_panel_size 
= panel_size
; 
 799         if(smallest_panel 
!= NULL
) 
 801             if(smallest_panel
->IsSizingContinuous()) 
 803                 int amount 
= maximum_amount
; 
 806                     // For "large" growth, grow this panel a bit, and then re-allocate 
 807                     // the remainder (which may come to this panel again anyway) 
 810                 if(direction 
& wxHORIZONTAL
) 
 812                     smallest_panel_size
->x 
+= amount
; 
 814                 if(direction 
& wxVERTICAL
) 
 816                     smallest_panel_size
->y 
+= amount
; 
 818                 maximum_amount 
-= amount
; 
 819                 m_collapse_stack
.Add(smallest_panel
); 
 820                 expanded_something 
= true; 
 824                 wxSize larger 
= smallest_panel
->GetNextLargerSize(direction
, *smallest_panel_size
); 
 825                 wxSize delta 
= larger 
- (*smallest_panel_size
); 
 826                 if(GetSizeInOrientation(delta
, direction
) <= maximum_amount
) 
 828                     *smallest_panel_size 
= larger
; 
 829                     maximum_amount 
-= GetSizeInOrientation(delta
, direction
); 
 830                     m_collapse_stack
.Add(smallest_panel
); 
 831                     expanded_something 
= true; 
 844     return expanded_something
; 
 847 bool wxRibbonPage::CollapsePanels(wxOrientation direction
, int minimum_amount
) 
 849     bool collapsed_something 
= false; 
 850     while(minimum_amount 
> 0) 
 852         int largest_size 
= 0; 
 853         wxRibbonPanel
* largest_panel 
= NULL
; 
 854         wxSize
* largest_panel_size 
= NULL
; 
 855         wxSize
* panel_size 
= m_size_calc_array
; 
 856         if(!m_collapse_stack
.IsEmpty()) 
 858             // For a more consistent panel layout, try to collapse panels which 
 859             // were recently expanded. 
 860             largest_panel 
= wxDynamicCast(m_collapse_stack
.Last(), wxRibbonPanel
); 
 861             m_collapse_stack
.RemoveAt(m_collapse_stack
.GetCount() - 1); 
 862             for(wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 864                       node 
= node
->GetNext(), ++panel_size 
) 
 866                 wxRibbonPanel
* panel 
= wxDynamicCast(node
->GetData(), wxRibbonPanel
); 
 867                 if(panel 
== largest_panel
) 
 869                     largest_panel_size 
= panel_size
; 
 876             for(wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 878                       node 
= node
->GetNext(), ++panel_size 
) 
 880                 wxRibbonPanel
* panel 
= wxDynamicCast(node
->GetData(), wxRibbonPanel
); 
 885                 if(panel
->IsSizingContinuous()) 
 887                     int size 
= GetSizeInOrientation(*panel_size
, direction
); 
 888                     if(size 
> largest_size
) 
 891                         largest_panel 
= panel
; 
 892                         largest_panel_size 
= panel_size
; 
 897                     int size 
= GetSizeInOrientation(*panel_size
, direction
); 
 898                     if(size 
> largest_size
) 
 900                         wxSize smaller 
= panel
->GetNextSmallerSize(direction
, *panel_size
); 
 901                         if(smaller 
!= (*panel_size
) && 
 902                             GetSizeInOrientation(smaller
, direction
) < size
) 
 905                             largest_panel 
= panel
; 
 906                             largest_panel_size 
= panel_size
; 
 912         if(largest_panel 
!= NULL
) 
 914             if(largest_panel
->IsSizingContinuous()) 
 916                 int amount 
= minimum_amount
; 
 919                     // For "large" contraction, reduce this panel a bit, and 
 920                     // then re-allocate the remainder of the quota (which may 
 921                     // come to this panel again anyway) 
 924                 if(direction 
& wxHORIZONTAL
) 
 926                     largest_panel_size
->x 
-= amount
; 
 928                 if(direction 
& wxVERTICAL
) 
 930                     largest_panel_size
->y 
-= amount
; 
 932                 minimum_amount 
-= amount
; 
 933                 collapsed_something 
= true; 
 937                 wxSize smaller 
= largest_panel
->GetNextSmallerSize(direction
, *largest_panel_size
); 
 938                 wxSize delta 
= (*largest_panel_size
) - smaller
; 
 939                 *largest_panel_size 
= smaller
; 
 940                 minimum_amount 
-= GetSizeInOrientation(delta
, direction
); 
 941                 collapsed_something 
= true; 
 949     return collapsed_something
; 
 952 bool wxRibbonPage::DismissExpandedPanel() 
 954     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 956               node 
= node
->GetNext() ) 
 958         wxRibbonPanel
* panel 
= wxDynamicCast(node
->GetData(), wxRibbonPanel
); 
 963         if(panel
->GetExpandedPanel() != NULL
) 
 965             return panel
->HideExpanded(); 
 971 wxSize 
wxRibbonPage::GetMinSize() const 
 973     wxSize 
min(wxDefaultCoord
, wxDefaultCoord
); 
 975     for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
 977           node 
= node
->GetNext() ) 
 979         wxWindow
* child 
= node
->GetData(); 
 980         wxSize 
child_min(child
->GetMinSize()); 
 982         min
.x 
= wxMax(min
.x
, child_min
.x
); 
 983         min
.y 
= wxMax(min
.y
, child_min
.y
); 
 986     if(GetMajorAxis() == wxHORIZONTAL
) 
 988         min
.x 
= wxDefaultCoord
; 
 989         if(min
.y 
!= wxDefaultCoord
) 
 991             min
.y 
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
); 
 996         if(min
.x 
!= wxDefaultCoord
) 
 998             min
.x 
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
); 
1000         min
.y 
= wxDefaultCoord
; 
1006 wxSize 
wxRibbonPage::DoGetBestSize() const 
1011     if(GetMajorAxis() == wxHORIZONTAL
) 
1013         best
.y 
= wxDefaultCoord
; 
1015         for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
1017           node 
= node
->GetNext() ) 
1019             wxWindow
* child 
= node
->GetData(); 
1020             wxSize 
child_best(child
->GetBestSize()); 
1022             if(child_best
.x 
!= wxDefaultCoord
) 
1024                 best
.IncBy(child_best
.x
, 0); 
1026             best
.y 
= wxMax(best
.y
, child_best
.y
); 
1033             best
.IncBy((count 
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
), 0); 
1038         best
.x 
= wxDefaultCoord
; 
1040         for ( wxWindowList::compatibility_iterator node 
= GetChildren().GetFirst(); 
1042           node 
= node
->GetNext() ) 
1044             wxWindow
* child 
= node
->GetData(); 
1045             wxSize 
child_best(child
->GetBestSize()); 
1047             best
.x 
= wxMax(best
.x
, child_best
.x
); 
1048             if(child_best
.y 
!= wxDefaultCoord
) 
1050                 best
.IncBy(0, child_best
.y
); 
1058             best
.IncBy(0, (count 
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
)); 
1062     if(best
.x 
!= wxDefaultCoord
) 
1064         best
.x 
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
); 
1066     if(best
.y 
!= wxDefaultCoord
) 
1068         best
.y 
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
); 
1073 #endif // wxUSE_RIBBON