1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/ribbon/page.cpp
3 // Purpose: Container for ribbon-bar-style interface panels
4 // Author: Peter Cawley
7 // Copyright: (C) Peter Cawley
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
18 #include "wx/ribbon/page.h"
19 #include "wx/ribbon/art.h"
20 #include "wx/ribbon/bar.h"
21 #include "wx/dcbuffer.h"
27 #include "wx/msw/private.h"
30 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
);
32 // As scroll buttons need to be rendered on top of a page's child windows, the
33 // buttons themselves have to be proper child windows (rather than just painted
34 // onto the page). In order to get proper clipping of a page's children (with
35 // regard to the scroll button), the scroll buttons are created as children of
36 // the ribbon bar rather than children of the page. This could not have been
37 // achieved by creating buttons as children of the page and then doing some Z-order
38 // manipulation, as this causes problems on win32 due to ribbon panels having the
39 // transparent flag set.
40 class wxRibbonPageScrollButton
: public wxRibbonControl
43 wxRibbonPageScrollButton(wxRibbonPage
* sibling
,
44 wxWindowID id
= wxID_ANY
,
45 const wxPoint
& pos
= wxDefaultPosition
,
46 const wxSize
& size
= wxDefaultSize
,
49 virtual ~wxRibbonPageScrollButton();
52 virtual wxBorder
GetDefaultBorder() const { return wxBORDER_NONE
; }
54 void OnEraseBackground(wxEraseEvent
& evt
);
55 void OnPaint(wxPaintEvent
& evt
);
56 void OnMouseEnter(wxMouseEvent
& evt
);
57 void OnMouseLeave(wxMouseEvent
& evt
);
58 void OnMouseDown(wxMouseEvent
& evt
);
59 void OnMouseUp(wxMouseEvent
& evt
);
61 wxRibbonPage
* m_sibling
;
64 DECLARE_CLASS(wxRibbonPageScrollButton
)
68 IMPLEMENT_CLASS(wxRibbonPageScrollButton
, wxRibbonControl
)
70 BEGIN_EVENT_TABLE(wxRibbonPageScrollButton
, wxRibbonControl
)
71 EVT_ENTER_WINDOW(wxRibbonPageScrollButton::OnMouseEnter
)
72 EVT_ERASE_BACKGROUND(wxRibbonPageScrollButton::OnEraseBackground
)
73 EVT_LEAVE_WINDOW(wxRibbonPageScrollButton::OnMouseLeave
)
74 EVT_LEFT_DOWN(wxRibbonPageScrollButton::OnMouseDown
)
75 EVT_LEFT_UP(wxRibbonPageScrollButton::OnMouseUp
)
76 EVT_PAINT(wxRibbonPageScrollButton::OnPaint
)
79 wxRibbonPageScrollButton::wxRibbonPageScrollButton(wxRibbonPage
* sibling
,
83 long style
) : wxRibbonControl(sibling
->GetParent(), id
, pos
, size
, wxBORDER_NONE
)
85 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
87 m_flags
= (style
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
) | wxRIBBON_SCROLL_BTN_FOR_PAGE
;
90 wxRibbonPageScrollButton::~wxRibbonPageScrollButton()
94 void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
96 // Do nothing - all painting done in main paint handler
99 void wxRibbonPageScrollButton::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
101 wxAutoBufferedPaintDC
dc(this);
104 m_art
->DrawScrollButton(dc
, this, GetSize(), m_flags
);
108 void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent
& WXUNUSED(evt
))
110 m_flags
|= wxRIBBON_SCROLL_BTN_HOVERED
;
114 void wxRibbonPageScrollButton::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
116 m_flags
&= ~wxRIBBON_SCROLL_BTN_HOVERED
;
117 m_flags
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
;
121 void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent
& WXUNUSED(evt
))
123 m_flags
|= wxRIBBON_SCROLL_BTN_ACTIVE
;
127 void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent
& WXUNUSED(evt
))
129 if(m_flags
& wxRIBBON_SCROLL_BTN_ACTIVE
)
131 m_flags
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
;
133 switch(m_flags
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
)
135 case wxRIBBON_SCROLL_BTN_DOWN
:
136 case wxRIBBON_SCROLL_BTN_RIGHT
:
137 m_sibling
->ScrollSections(1);
139 case wxRIBBON_SCROLL_BTN_UP
:
140 case wxRIBBON_SCROLL_BTN_LEFT
:
141 m_sibling
->ScrollSections(-1);
149 IMPLEMENT_CLASS(wxRibbonPage
, wxRibbonControl
)
151 BEGIN_EVENT_TABLE(wxRibbonPage
, wxRibbonControl
)
152 EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground
)
153 EVT_PAINT(wxRibbonPage::OnPaint
)
154 EVT_SIZE(wxRibbonPage::OnSize
)
157 wxRibbonPage::wxRibbonPage()
159 m_scroll_left_btn
= NULL
;
160 m_scroll_right_btn
= NULL
;
162 m_scroll_buttons_visible
= false;
165 wxRibbonPage::wxRibbonPage(wxRibbonBar
* parent
,
167 const wxString
& label
,
168 const wxBitmap
& icon
,
169 long WXUNUSED(style
))
170 : wxRibbonControl(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
)
172 CommonInit(label
, icon
);
175 wxRibbonPage::~wxRibbonPage()
177 delete[] m_size_calc_array
;
180 bool wxRibbonPage::Create(wxRibbonBar
* parent
,
182 const wxString
& label
,
183 const wxBitmap
& icon
,
184 long WXUNUSED(style
))
186 if(!wxRibbonControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
))
189 CommonInit(label
, icon
);
194 void wxRibbonPage::CommonInit(const wxString
& label
, const wxBitmap
& icon
)
199 m_old_size
= wxSize(0, 0);
201 m_scroll_left_btn
= NULL
;
202 m_scroll_right_btn
= NULL
;
203 m_size_calc_array
= NULL
;
204 m_size_calc_array_size
= 0;
206 m_scroll_buttons_visible
= false;
208 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
210 wxDynamicCast(GetParent(), wxRibbonBar
)->AddPage(this);
213 void wxRibbonPage::SetArtProvider(wxRibbonArtProvider
* art
)
216 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
218 node
= node
->GetNext() )
220 wxWindow
* child
= node
->GetData();
221 wxRibbonControl
* ribbon_child
= wxDynamicCast(child
, wxRibbonControl
);
224 ribbon_child
->SetArtProvider(art
);
229 void wxRibbonPage::AdjustRectToIncludeScrollButtons(wxRect
* rect
) const
231 if(m_scroll_buttons_visible
)
233 if(GetMajorAxis() == wxVERTICAL
)
235 if(m_scroll_left_btn
)
237 rect
->SetY(rect
->GetY() -
238 m_scroll_left_btn
->GetSize().GetHeight());
239 rect
->SetHeight(rect
->GetHeight() +
240 m_scroll_left_btn
->GetSize().GetHeight());
242 if(m_scroll_right_btn
)
244 rect
->SetHeight(rect
->GetHeight() +
245 m_scroll_right_btn
->GetSize().GetHeight());
250 if(m_scroll_left_btn
)
252 rect
->SetX(rect
->GetX() -
253 m_scroll_left_btn
->GetSize().GetWidth());
254 rect
->SetWidth(rect
->GetWidth() +
255 m_scroll_left_btn
->GetSize().GetWidth());
257 if(m_scroll_right_btn
)
259 rect
->SetWidth(rect
->GetWidth() +
260 m_scroll_right_btn
->GetSize().GetWidth());
266 void wxRibbonPage::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
268 // All painting done in main paint handler to minimise flicker
271 void wxRibbonPage::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
273 // No foreground painting done by the page itself, but a paint DC
274 // must be created anyway.
275 wxAutoBufferedPaintDC
dc(this);
276 wxRect
rect(GetSize());
277 AdjustRectToIncludeScrollButtons(&rect
);
278 m_art
->DrawPageBackground(dc
, this, rect
);
281 wxOrientation
wxRibbonPage::GetMajorAxis() const
283 if(m_art
&& (m_art
->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL
))
293 bool wxRibbonPage::ScrollLines(int lines
)
295 return ScrollPixels(lines
* 8);
298 bool wxRibbonPage::ScrollPixels(int pixels
)
302 if(m_scroll_amount
== 0)
304 if(m_scroll_amount
< -pixels
)
305 pixels
= -m_scroll_amount
;
309 if(m_scroll_amount
== m_scroll_amount_limit
)
311 if(m_scroll_amount
+ pixels
> m_scroll_amount_limit
)
312 pixels
= m_scroll_amount_limit
- m_scroll_amount
;
317 m_scroll_amount
+= pixels
;
319 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
321 node
= node
->GetNext() )
323 wxWindow
* child
= node
->GetData();
325 child
->GetPosition(&x
, &y
);
326 if(GetMajorAxis() == wxHORIZONTAL
)
330 child
->SetPosition(wxPoint(x
, y
));
338 bool wxRibbonPage::ScrollSections(int sections
)
340 // Currently the only valid values are -1 and 1 for scrolling left and
341 // right, respectively.
342 const bool scrollForward
= sections
>= 1;
344 // Determine by how many pixels to scroll. If something on the page
345 // is partially visible, scroll to make it fully visible. Otherwise
346 // find the next item that will become visible and scroll to make it
347 // fully visible. The ScrollPixel call will correct if we scroll too
348 // much if the available width is smaller than the items.
350 // Scroll at minimum the same amount as ScrollLines(1):
351 int minscroll
= sections
* 8;
352 // How many pixels to scroll:
355 // Determine the scroll position, that is, the page border where items
359 wxOrientation major_axis
= GetMajorAxis();
366 GetSize(&width
, &height
);
368 if(major_axis
== wxHORIZONTAL
)
370 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
);
373 scrollpos
= width
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
377 scrollpos
= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
);
382 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
);
385 scrollpos
= width
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
389 scrollpos
= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
);
393 // Find the child that is partially shown or just beyond the scroll position
394 for(wxWindowList::compatibility_iterator
395 node
= scrollForward
? GetChildren().GetFirst()
396 : GetChildren().GetLast();
398 node
= scrollForward
? node
->GetNext()
399 : node
->GetPrevious())
401 wxWindow
* child
= node
->GetData();
402 child
->GetSize(&width
, &height
);
403 child
->GetPosition(&x
, &y
);
406 if (major_axis
== wxHORIZONTAL
)
409 pos1
= x
+ width
+ gap
;
414 pos1
= y
+ height
+ gap
;
416 if (scrollpos
>= pos0
&& scrollpos
<= pos1
)
418 // This section is partially visible, scroll to make it fully visible.
421 pixels
+= pos1
- scrollpos
;
425 pixels
+= pos0
- scrollpos
;
427 if (abs(pixels
) >= abs(minscroll
))
430 if (scrollpos
<= pos0
&& scrollForward
)
432 // This section is next, scroll the entire section width
433 pixels
+= (pos1
- pos0
);
436 if (scrollpos
>= pos1
&& !scrollForward
)
438 // This section is next, scroll the entire section width
439 pixels
+= (pos0
- pos1
);
443 // Do a final safety sanity check, should not be necessary, but will not hurt either.
448 if (pixels
* minscroll
< 0)
453 return ScrollPixels(pixels
);
456 void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x
, int y
, int width
, int height
)
458 if(m_scroll_buttons_visible
)
460 if(GetMajorAxis() == wxHORIZONTAL
)
462 if(m_scroll_left_btn
)
464 int w
= m_scroll_left_btn
->GetSize().GetWidth();
465 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
));
469 if(m_scroll_right_btn
)
471 int w
= m_scroll_right_btn
->GetSize().GetWidth();
473 m_scroll_right_btn
->SetPosition(wxPoint(x
+ width
, y
));
478 if(m_scroll_left_btn
)
480 int h
= m_scroll_left_btn
->GetSize().GetHeight();
481 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
));
485 if(m_scroll_right_btn
)
487 int h
= m_scroll_right_btn
->GetSize().GetHeight();
489 m_scroll_right_btn
->SetPosition(wxPoint(x
, y
+ height
));
493 if (width
< 0) width
= 0;
494 if (height
< 0) height
= 0;
495 SetSize(x
, y
, width
, height
);
498 void wxRibbonPage::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
500 // When a resize triggers the scroll buttons to become visible, the page is resized.
501 // This resize from within a resize event can cause (MSW) wxWidgets some confusion,
502 // and report the 1st size to the 2nd size event. Hence the most recent size is
503 // remembered internally and used in Layout() where appropriate.
505 if(GetMajorAxis() == wxHORIZONTAL
)
507 m_size_in_major_axis_for_children
= width
;
508 if(m_scroll_buttons_visible
)
510 if(m_scroll_left_btn
)
511 m_size_in_major_axis_for_children
+= m_scroll_left_btn
->GetSize().GetWidth();
512 if(m_scroll_right_btn
)
513 m_size_in_major_axis_for_children
+= m_scroll_right_btn
->GetSize().GetWidth();
518 m_size_in_major_axis_for_children
= height
;
519 if(m_scroll_buttons_visible
)
521 if(m_scroll_left_btn
)
522 m_size_in_major_axis_for_children
+= m_scroll_left_btn
->GetSize().GetHeight();
523 if(m_scroll_right_btn
)
524 m_size_in_major_axis_for_children
+= m_scroll_right_btn
->GetSize().GetHeight();
528 wxRibbonControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
531 void wxRibbonPage::OnSize(wxSizeEvent
& evt
)
533 wxSize new_size
= evt
.GetSize();
538 wxRect invalid_rect
= m_art
->GetPageBackgroundRedrawArea(temp_dc
, this, m_old_size
, new_size
);
539 Refresh(true, &invalid_rect
);
542 m_old_size
= new_size
;
544 if(new_size
.GetX() > 0 && new_size
.GetY() > 0)
550 // Simplify other calculations by pretending new size is zero in both
553 // When size == 0, no point in doing any layout
559 void wxRibbonPage::RemoveChild(wxWindowBase
*child
)
561 // Remove all references to the child from the collapse stack
562 size_t count
= m_collapse_stack
.GetCount();
564 for(src
= 0, dst
= 0; src
< count
; ++src
, ++dst
)
566 wxRibbonControl
*item
= m_collapse_stack
.Item(src
);
577 m_collapse_stack
.Item(dst
) = item
;
582 m_collapse_stack
.RemoveAt(dst
, src
- dst
);
585 // ... and then proceed as normal
586 wxRibbonControl::RemoveChild(child
);
589 bool wxRibbonPage::Realize()
593 m_collapse_stack
.Clear();
594 for (wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
596 node
= node
->GetNext())
598 wxRibbonControl
* child
= wxDynamicCast(node
->GetData(), wxRibbonControl
);
603 if(!child
->Realize())
608 PopulateSizeCalcArray(&wxWindow::GetMinSize
);
610 return DoActualLayout() && status
;
613 void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size
)(void) const)
615 wxSize parentSize
= GetSize();
616 parentSize
.x
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
);
617 parentSize
.x
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
618 parentSize
.y
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
);
619 parentSize
.y
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
621 if(m_size_calc_array_size
!= GetChildren().GetCount())
623 delete[] m_size_calc_array
;
624 m_size_calc_array_size
= GetChildren().GetCount();
625 m_size_calc_array
= new wxSize
[m_size_calc_array_size
];
628 wxSize
* node_size
= m_size_calc_array
;
629 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
631 node
= node
->GetNext(), ++node_size
)
633 wxWindow
* child
= node
->GetData();
634 wxRibbonPanel
* panel
= wxDynamicCast(child
, wxRibbonPanel
);
635 if (panel
&& panel
->GetFlags() & wxRIBBON_PANEL_FLEXIBLE
)
636 *node_size
= panel
->GetBestSizeForParentSize(parentSize
);
638 *node_size
= (child
->*get_size
)();
642 bool wxRibbonPage::Layout()
644 if(GetChildren().GetCount() == 0)
650 PopulateSizeCalcArray(&wxWindow::GetSize
);
651 return DoActualLayout();
655 bool wxRibbonPage::DoActualLayout()
657 wxPoint
origin(m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
), m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
));
658 wxOrientation major_axis
= GetMajorAxis();
662 if(major_axis
== wxHORIZONTAL
)
664 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
);
665 minor_axis_size
= GetSize().GetHeight() - origin
.y
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
666 available_space
= m_size_in_major_axis_for_children
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
) - origin
.x
;
670 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
);
671 minor_axis_size
= GetSize().GetWidth() - origin
.x
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
672 available_space
= m_size_in_major_axis_for_children
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
) - origin
.y
;
674 if (minor_axis_size
< 0) minor_axis_size
= 0;
676 for(size_index
= 0; size_index
< m_size_calc_array_size
; ++size_index
)
678 if(major_axis
== wxHORIZONTAL
)
680 available_space
-= m_size_calc_array
[size_index
].GetWidth();
681 m_size_calc_array
[size_index
].SetHeight(minor_axis_size
);
685 available_space
-= m_size_calc_array
[size_index
].GetHeight();
686 m_size_calc_array
[size_index
].SetWidth(minor_axis_size
);
689 available_space
-= gap
;
691 bool todo_hide_scroll_buttons
= false;
692 bool todo_show_scroll_buttons
= false;
693 if(available_space
>= 0)
695 if(m_scroll_buttons_visible
)
696 todo_hide_scroll_buttons
= true;
697 if(available_space
> 0)
698 ExpandPanels(major_axis
, available_space
);
702 if(m_scroll_buttons_visible
)
704 // Scroll buttons already visible - not going to be able to downsize any more
705 m_scroll_amount_limit
= -available_space
;
706 if(m_scroll_amount
> m_scroll_amount_limit
)
708 m_scroll_amount
= m_scroll_amount_limit
;
709 todo_show_scroll_buttons
= true;
714 if(!CollapsePanels(major_axis
, -available_space
))
717 m_scroll_amount_limit
= -available_space
;
718 todo_show_scroll_buttons
= true;
722 if(m_scroll_buttons_visible
)
724 if(major_axis
== wxHORIZONTAL
)
726 origin
.x
-= m_scroll_amount
;
727 if(m_scroll_left_btn
)
728 origin
.x
-= m_scroll_left_btn
->GetSize().GetWidth();
732 origin
.y
-= m_scroll_amount
;
733 if(m_scroll_left_btn
)
734 origin
.y
-= m_scroll_left_btn
->GetSize().GetHeight();
738 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
740 node
= node
->GetNext(), ++size_index
)
742 wxWindow
* child
= node
->GetData();
743 int w
= m_size_calc_array
[size_index
].GetWidth();
744 int h
= m_size_calc_array
[size_index
].GetHeight();
745 child
->SetSize(origin
.x
, origin
.y
, w
, h
);
746 if(major_axis
== wxHORIZONTAL
)
756 if(todo_show_scroll_buttons
)
758 else if(todo_hide_scroll_buttons
)
760 else if(m_scroll_buttons_visible
)
767 bool wxRibbonPage::Show(bool show
)
769 if(m_scroll_left_btn
)
770 m_scroll_left_btn
->Show(show
);
771 if(m_scroll_right_btn
)
772 m_scroll_right_btn
->Show(show
);
773 return wxRibbonControl::Show(show
);
776 void wxRibbonPage::HideScrollButtons()
779 m_scroll_amount_limit
= 0;
783 void wxRibbonPage::ShowScrollButtons()
785 bool show_left
= true;
786 bool show_right
= true;
787 bool reposition
= false;
788 if(m_scroll_amount
== 0)
792 if(m_scroll_amount
>= m_scroll_amount_limit
)
795 m_scroll_amount
= m_scroll_amount_limit
;
797 m_scroll_buttons_visible
= show_left
|| show_right
;
804 if(GetMajorAxis() == wxHORIZONTAL
)
806 direction
= wxRIBBON_SCROLL_BTN_LEFT
;
807 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
808 size
.SetHeight(GetSize().GetHeight());
812 direction
= wxRIBBON_SCROLL_BTN_UP
;
813 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
814 size
.SetWidth(GetSize().GetWidth());
816 if (m_scroll_left_btn
)
818 m_scroll_left_btn
->SetSize(size
);
822 m_scroll_left_btn
= new wxRibbonPageScrollButton(this, wxID_ANY
, GetPosition(), size
, direction
);
827 m_scroll_left_btn
->Hide();
832 if(m_scroll_left_btn
!= NULL
)
834 m_scroll_left_btn
->Destroy();
835 m_scroll_left_btn
= NULL
;
845 if(GetMajorAxis() == wxHORIZONTAL
)
847 direction
= wxRIBBON_SCROLL_BTN_RIGHT
;
848 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
849 size
.SetHeight(GetSize().GetHeight());
853 direction
= wxRIBBON_SCROLL_BTN_DOWN
;
854 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
855 size
.SetWidth(GetSize().GetWidth());
857 wxPoint initial_pos
= GetPosition() + GetSize() - size
;
858 if (m_scroll_right_btn
)
860 m_scroll_right_btn
->SetSize(size
);
864 m_scroll_right_btn
= new wxRibbonPageScrollButton(this, wxID_ANY
, initial_pos
, size
, direction
);
869 m_scroll_right_btn
->Hide();
874 if(m_scroll_right_btn
!= NULL
)
876 m_scroll_right_btn
->Destroy();
877 m_scroll_right_btn
= NULL
;
884 wxDynamicCast(GetParent(), wxRibbonBar
)->RepositionPage(this);
888 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
)
892 case wxHORIZONTAL
: return size
.GetWidth();
893 case wxVERTICAL
: return size
.GetHeight();
894 case wxBOTH
: return size
.GetWidth() * size
.GetHeight();
899 bool wxRibbonPage::ExpandPanels(wxOrientation direction
, int maximum_amount
)
901 bool expanded_something
= false;
902 while(maximum_amount
> 0)
904 int smallest_size
= INT_MAX
;
905 wxRibbonPanel
* smallest_panel
= NULL
;
906 wxSize
* smallest_panel_size
= NULL
;
907 wxSize
* panel_size
= m_size_calc_array
;
908 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
910 node
= node
->GetNext(), ++panel_size
)
912 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
917 if (panel
->GetFlags() & wxRIBBON_PANEL_FLEXIBLE
)
919 // Don't change if it's flexible since we already calculated the
920 // correct size for the panel.
922 else if(panel
->IsSizingContinuous())
924 int size
= GetSizeInOrientation(*panel_size
, direction
);
925 if(size
< smallest_size
)
927 smallest_size
= size
;
928 smallest_panel
= panel
;
929 smallest_panel_size
= panel_size
;
934 int size
= GetSizeInOrientation(*panel_size
, direction
);
935 if(size
< smallest_size
)
937 wxSize larger
= panel
->GetNextLargerSize(direction
, *panel_size
);
938 if(larger
!= (*panel_size
) && GetSizeInOrientation(larger
, direction
) > size
)
940 smallest_size
= size
;
941 smallest_panel
= panel
;
942 smallest_panel_size
= panel_size
;
947 if(smallest_panel
!= NULL
)
949 if(smallest_panel
->IsSizingContinuous())
951 int amount
= maximum_amount
;
954 // For "large" growth, grow this panel a bit, and then re-allocate
955 // the remainder (which may come to this panel again anyway)
958 if(direction
& wxHORIZONTAL
)
960 smallest_panel_size
->x
+= amount
;
962 if(direction
& wxVERTICAL
)
964 smallest_panel_size
->y
+= amount
;
966 maximum_amount
-= amount
;
967 m_collapse_stack
.Add(smallest_panel
);
968 expanded_something
= true;
972 wxSize larger
= smallest_panel
->GetNextLargerSize(direction
, *smallest_panel_size
);
973 wxSize delta
= larger
- (*smallest_panel_size
);
974 if(GetSizeInOrientation(delta
, direction
) <= maximum_amount
)
976 *smallest_panel_size
= larger
;
977 maximum_amount
-= GetSizeInOrientation(delta
, direction
);
978 m_collapse_stack
.Add(smallest_panel
);
979 expanded_something
= true;
992 return expanded_something
;
995 bool wxRibbonPage::CollapsePanels(wxOrientation direction
, int minimum_amount
)
997 bool collapsed_something
= false;
998 while(minimum_amount
> 0)
1000 int largest_size
= 0;
1001 wxRibbonPanel
* largest_panel
= NULL
;
1002 wxSize
* largest_panel_size
= NULL
;
1003 wxSize
* panel_size
= m_size_calc_array
;
1004 if(!m_collapse_stack
.IsEmpty())
1006 // For a more consistent panel layout, try to collapse panels which
1007 // were recently expanded.
1008 largest_panel
= wxDynamicCast(m_collapse_stack
.Last(), wxRibbonPanel
);
1009 m_collapse_stack
.RemoveAt(m_collapse_stack
.GetCount() - 1);
1010 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1012 node
= node
->GetNext(), ++panel_size
)
1014 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1015 if(panel
== largest_panel
)
1017 largest_panel_size
= panel_size
;
1024 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1026 node
= node
->GetNext(), ++panel_size
)
1028 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1033 if(panel
->IsSizingContinuous())
1035 int size
= GetSizeInOrientation(*panel_size
, direction
);
1036 if(size
> largest_size
)
1038 largest_size
= size
;
1039 largest_panel
= panel
;
1040 largest_panel_size
= panel_size
;
1045 int size
= GetSizeInOrientation(*panel_size
, direction
);
1046 if(size
> largest_size
)
1048 wxSize smaller
= panel
->GetNextSmallerSize(direction
, *panel_size
);
1049 if(smaller
!= (*panel_size
) &&
1050 GetSizeInOrientation(smaller
, direction
) < size
)
1052 largest_size
= size
;
1053 largest_panel
= panel
;
1054 largest_panel_size
= panel_size
;
1060 if(largest_panel
!= NULL
)
1062 if(largest_panel
->IsSizingContinuous())
1064 int amount
= minimum_amount
;
1067 // For "large" contraction, reduce this panel a bit, and
1068 // then re-allocate the remainder of the quota (which may
1069 // come to this panel again anyway)
1072 if(direction
& wxHORIZONTAL
)
1074 largest_panel_size
->x
-= amount
;
1076 if(direction
& wxVERTICAL
)
1078 largest_panel_size
->y
-= amount
;
1080 minimum_amount
-= amount
;
1081 collapsed_something
= true;
1085 wxSize smaller
= largest_panel
->GetNextSmallerSize(direction
, *largest_panel_size
);
1086 wxSize delta
= (*largest_panel_size
) - smaller
;
1087 *largest_panel_size
= smaller
;
1088 minimum_amount
-= GetSizeInOrientation(delta
, direction
);
1089 collapsed_something
= true;
1097 return collapsed_something
;
1100 bool wxRibbonPage::DismissExpandedPanel()
1102 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1104 node
= node
->GetNext() )
1106 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1111 if(panel
->GetExpandedPanel() != NULL
)
1113 return panel
->HideExpanded();
1119 wxSize
wxRibbonPage::GetMinSize() const
1121 wxSize
min(wxDefaultCoord
, wxDefaultCoord
);
1123 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1125 node
= node
->GetNext() )
1127 wxWindow
* child
= node
->GetData();
1128 wxSize
child_min(child
->GetMinSize());
1130 min
.x
= wxMax(min
.x
, child_min
.x
);
1131 min
.y
= wxMax(min
.y
, child_min
.y
);
1134 if(GetMajorAxis() == wxHORIZONTAL
)
1136 min
.x
= wxDefaultCoord
;
1137 if(min
.y
!= wxDefaultCoord
)
1139 min
.y
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
1144 if(min
.x
!= wxDefaultCoord
)
1146 min
.x
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
1148 min
.y
= wxDefaultCoord
;
1154 wxSize
wxRibbonPage::DoGetBestSize() const
1159 if(GetMajorAxis() == wxHORIZONTAL
)
1161 best
.y
= wxDefaultCoord
;
1163 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1165 node
= node
->GetNext() )
1167 wxWindow
* child
= node
->GetData();
1168 wxSize
child_best(child
->GetBestSize());
1170 if(child_best
.x
!= wxDefaultCoord
)
1172 best
.IncBy(child_best
.x
, 0);
1174 best
.y
= wxMax(best
.y
, child_best
.y
);
1181 best
.IncBy((count
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
), 0);
1186 best
.x
= wxDefaultCoord
;
1188 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1190 node
= node
->GetNext() )
1192 wxWindow
* child
= node
->GetData();
1193 wxSize
child_best(child
->GetBestSize());
1195 best
.x
= wxMax(best
.x
, child_best
.x
);
1196 if(child_best
.y
!= wxDefaultCoord
)
1198 best
.IncBy(0, child_best
.y
);
1206 best
.IncBy(0, (count
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
));
1210 if(best
.x
!= wxDefaultCoord
)
1212 best
.x
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
1214 if(best
.y
!= wxDefaultCoord
)
1216 best
.y
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
1221 void wxRibbonPage::HideIfExpanded()
1223 wxStaticCast(m_parent
, wxRibbonBar
)->HideIfExpanded();
1226 #endif // wxUSE_RIBBON