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"
19 #include "wx/ribbon/page.h"
20 #include "wx/ribbon/art.h"
21 #include "wx/ribbon/bar.h"
22 #include "wx/dcbuffer.h"
28 #include "wx/msw/private.h"
31 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
);
33 // As scroll buttons need to be rendered on top of a page's child windows, the
34 // buttons themselves have to be proper child windows (rather than just painted
35 // onto the page). In order to get proper clipping of a page's children (with
36 // regard to the scroll button), the scroll buttons are created as children of
37 // the ribbon bar rather than children of the page. This could not have been
38 // achieved by creating buttons as children of the page and then doing some Z-order
39 // manipulation, as this causes problems on win32 due to ribbon panels having the
40 // transparent flag set.
41 class wxRibbonPageScrollButton
: public wxRibbonControl
44 wxRibbonPageScrollButton(wxRibbonPage
* sibling
,
45 wxWindowID id
= wxID_ANY
,
46 const wxPoint
& pos
= wxDefaultPosition
,
47 const wxSize
& size
= wxDefaultSize
,
50 virtual ~wxRibbonPageScrollButton();
53 virtual wxBorder
GetDefaultBorder() const { return wxBORDER_NONE
; }
55 void OnEraseBackground(wxEraseEvent
& evt
);
56 void OnPaint(wxPaintEvent
& evt
);
57 void OnMouseEnter(wxMouseEvent
& evt
);
58 void OnMouseLeave(wxMouseEvent
& evt
);
59 void OnMouseDown(wxMouseEvent
& evt
);
60 void OnMouseUp(wxMouseEvent
& evt
);
62 wxRibbonPage
* m_sibling
;
65 DECLARE_CLASS(wxRibbonPageScrollButton
)
69 IMPLEMENT_CLASS(wxRibbonPageScrollButton
, wxRibbonControl
)
71 BEGIN_EVENT_TABLE(wxRibbonPageScrollButton
, wxRibbonControl
)
72 EVT_ENTER_WINDOW(wxRibbonPageScrollButton::OnMouseEnter
)
73 EVT_ERASE_BACKGROUND(wxRibbonPageScrollButton::OnEraseBackground
)
74 EVT_LEAVE_WINDOW(wxRibbonPageScrollButton::OnMouseLeave
)
75 EVT_LEFT_DOWN(wxRibbonPageScrollButton::OnMouseDown
)
76 EVT_LEFT_UP(wxRibbonPageScrollButton::OnMouseUp
)
77 EVT_PAINT(wxRibbonPageScrollButton::OnPaint
)
80 wxRibbonPageScrollButton::wxRibbonPageScrollButton(wxRibbonPage
* sibling
,
84 long style
) : wxRibbonControl(sibling
->GetParent(), id
, pos
, size
, wxBORDER_NONE
)
86 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
88 m_flags
= (style
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
) | wxRIBBON_SCROLL_BTN_FOR_PAGE
;
91 wxRibbonPageScrollButton::~wxRibbonPageScrollButton()
95 void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
97 // Do nothing - all painting done in main paint handler
100 void wxRibbonPageScrollButton::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
102 wxAutoBufferedPaintDC
dc(this);
105 m_art
->DrawScrollButton(dc
, this, GetSize(), m_flags
);
109 void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent
& WXUNUSED(evt
))
111 m_flags
|= wxRIBBON_SCROLL_BTN_HOVERED
;
115 void wxRibbonPageScrollButton::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
117 m_flags
&= ~wxRIBBON_SCROLL_BTN_HOVERED
;
118 m_flags
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
;
122 void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent
& WXUNUSED(evt
))
124 m_flags
|= wxRIBBON_SCROLL_BTN_ACTIVE
;
128 void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent
& WXUNUSED(evt
))
130 if(m_flags
& wxRIBBON_SCROLL_BTN_ACTIVE
)
132 m_flags
&= ~wxRIBBON_SCROLL_BTN_ACTIVE
;
134 switch(m_flags
& wxRIBBON_SCROLL_BTN_DIRECTION_MASK
)
136 case wxRIBBON_SCROLL_BTN_DOWN
:
137 case wxRIBBON_SCROLL_BTN_RIGHT
:
138 m_sibling
->ScrollSections(1);
140 case wxRIBBON_SCROLL_BTN_UP
:
141 case wxRIBBON_SCROLL_BTN_LEFT
:
142 m_sibling
->ScrollSections(-1);
150 IMPLEMENT_CLASS(wxRibbonPage
, wxRibbonControl
)
152 BEGIN_EVENT_TABLE(wxRibbonPage
, wxRibbonControl
)
153 EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground
)
154 EVT_PAINT(wxRibbonPage::OnPaint
)
155 EVT_SIZE(wxRibbonPage::OnSize
)
158 wxRibbonPage::wxRibbonPage()
160 m_scroll_left_btn
= NULL
;
161 m_scroll_right_btn
= NULL
;
163 m_scroll_buttons_visible
= false;
166 wxRibbonPage::wxRibbonPage(wxRibbonBar
* parent
,
168 const wxString
& label
,
169 const wxBitmap
& icon
,
170 long WXUNUSED(style
))
171 : wxRibbonControl(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
)
173 CommonInit(label
, icon
);
176 wxRibbonPage::~wxRibbonPage()
178 delete[] m_size_calc_array
;
181 bool wxRibbonPage::Create(wxRibbonBar
* parent
,
183 const wxString
& label
,
184 const wxBitmap
& icon
,
185 long WXUNUSED(style
))
187 if(!wxRibbonControl::Create(parent
, id
, wxDefaultPosition
, wxDefaultSize
, wxBORDER_NONE
))
190 CommonInit(label
, icon
);
195 void wxRibbonPage::CommonInit(const wxString
& label
, const wxBitmap
& icon
)
200 m_old_size
= wxSize(0, 0);
202 m_scroll_left_btn
= NULL
;
203 m_scroll_right_btn
= NULL
;
204 m_size_calc_array
= NULL
;
205 m_size_calc_array_size
= 0;
207 m_scroll_buttons_visible
= false;
209 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
211 wxDynamicCast(GetParent(), wxRibbonBar
)->AddPage(this);
214 void wxRibbonPage::SetArtProvider(wxRibbonArtProvider
* art
)
217 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
219 node
= node
->GetNext() )
221 wxWindow
* child
= node
->GetData();
222 wxRibbonControl
* ribbon_child
= wxDynamicCast(child
, wxRibbonControl
);
225 ribbon_child
->SetArtProvider(art
);
230 void wxRibbonPage::AdjustRectToIncludeScrollButtons(wxRect
* rect
) const
232 if(m_scroll_buttons_visible
)
234 if(GetMajorAxis() == wxVERTICAL
)
236 if(m_scroll_left_btn
)
238 rect
->SetY(rect
->GetY() -
239 m_scroll_left_btn
->GetSize().GetHeight());
240 rect
->SetHeight(rect
->GetHeight() +
241 m_scroll_left_btn
->GetSize().GetHeight());
243 if(m_scroll_right_btn
)
245 rect
->SetHeight(rect
->GetHeight() +
246 m_scroll_right_btn
->GetSize().GetHeight());
251 if(m_scroll_left_btn
)
253 rect
->SetX(rect
->GetX() -
254 m_scroll_left_btn
->GetSize().GetWidth());
255 rect
->SetWidth(rect
->GetWidth() +
256 m_scroll_left_btn
->GetSize().GetWidth());
258 if(m_scroll_right_btn
)
260 rect
->SetWidth(rect
->GetWidth() +
261 m_scroll_right_btn
->GetSize().GetWidth());
267 void wxRibbonPage::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
269 // All painting done in main paint handler to minimise flicker
272 void wxRibbonPage::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
274 // No foreground painting done by the page itself, but a paint DC
275 // must be created anyway.
276 wxAutoBufferedPaintDC
dc(this);
277 wxRect
rect(GetSize());
278 AdjustRectToIncludeScrollButtons(&rect
);
279 m_art
->DrawPageBackground(dc
, this, rect
);
282 wxOrientation
wxRibbonPage::GetMajorAxis() const
284 if(m_art
&& (m_art
->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL
))
294 bool wxRibbonPage::ScrollLines(int lines
)
296 return ScrollPixels(lines
* 8);
299 bool wxRibbonPage::ScrollPixels(int pixels
)
303 if(m_scroll_amount
== 0)
305 if(m_scroll_amount
< -pixels
)
306 pixels
= -m_scroll_amount
;
310 if(m_scroll_amount
== m_scroll_amount_limit
)
312 if(m_scroll_amount
+ pixels
> m_scroll_amount_limit
)
313 pixels
= m_scroll_amount_limit
- m_scroll_amount
;
318 m_scroll_amount
+= pixels
;
320 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
322 node
= node
->GetNext() )
324 wxWindow
* child
= node
->GetData();
326 child
->GetPosition(&x
, &y
);
327 if(GetMajorAxis() == wxHORIZONTAL
)
331 child
->SetPosition(wxPoint(x
, y
));
339 bool wxRibbonPage::ScrollSections(int sections
)
341 // Currently the only valid values are -1 and 1 for scrolling left and
342 // right, respectively.
343 const bool scrollForward
= sections
>= 1;
345 // Determine by how many pixels to scroll. If something on the page
346 // is partially visible, scroll to make it fully visible. Otherwise
347 // find the next item that will become visible and scroll to make it
348 // fully visible. The ScrollPixel call will correct if we scroll too
349 // much if the available width is smaller than the items.
351 // Scroll at minimum the same amount as ScrollLines(1):
352 int minscroll
= sections
* 8;
353 // How many pixels to scroll:
356 // Determine the scroll position, that is, the page border where items
360 wxOrientation major_axis
= GetMajorAxis();
367 GetSize(&width
, &height
);
369 if(major_axis
== wxHORIZONTAL
)
371 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
);
374 scrollpos
= width
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
378 scrollpos
= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
);
383 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
);
386 scrollpos
= width
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
390 scrollpos
= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
);
394 // Find the child that is partially shown or just beyond the scroll position
395 for(wxWindowList::compatibility_iterator
396 node
= scrollForward
? GetChildren().GetFirst()
397 : GetChildren().GetLast();
399 node
= scrollForward
? node
->GetNext()
400 : node
->GetPrevious())
402 wxWindow
* child
= node
->GetData();
403 child
->GetSize(&width
, &height
);
404 child
->GetPosition(&x
, &y
);
407 if (major_axis
== wxHORIZONTAL
)
410 pos1
= x
+ width
+ gap
;
415 pos1
= y
+ height
+ gap
;
417 if (scrollpos
>= pos0
&& scrollpos
<= pos1
)
419 // This section is partially visible, scroll to make it fully visible.
422 pixels
+= pos1
- scrollpos
;
426 pixels
+= pos0
- scrollpos
;
428 if (abs(pixels
) >= abs(minscroll
))
431 if (scrollpos
<= pos0
&& scrollForward
)
433 // This section is next, scroll the entire section width
434 pixels
+= (pos1
- pos0
);
437 if (scrollpos
>= pos1
&& !scrollForward
)
439 // This section is next, scroll the entire section width
440 pixels
+= (pos0
- pos1
);
444 // Do a final safety sanity check, should not be necessary, but will not hurt either.
449 if (pixels
* minscroll
< 0)
454 return ScrollPixels(pixels
);
457 void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x
, int y
, int width
, int height
)
459 if(m_scroll_buttons_visible
)
461 if(GetMajorAxis() == wxHORIZONTAL
)
463 if(m_scroll_left_btn
)
465 int w
= m_scroll_left_btn
->GetSize().GetWidth();
466 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
));
470 if(m_scroll_right_btn
)
472 int w
= m_scroll_right_btn
->GetSize().GetWidth();
474 m_scroll_right_btn
->SetPosition(wxPoint(x
+ width
, y
));
479 if(m_scroll_left_btn
)
481 int h
= m_scroll_left_btn
->GetSize().GetHeight();
482 m_scroll_left_btn
->SetPosition(wxPoint(x
, y
));
486 if(m_scroll_right_btn
)
488 int h
= m_scroll_right_btn
->GetSize().GetHeight();
490 m_scroll_right_btn
->SetPosition(wxPoint(x
, y
+ height
));
494 if (width
< 0) width
= 0;
495 if (height
< 0) height
= 0;
496 SetSize(x
, y
, width
, height
);
499 void wxRibbonPage::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
501 // When a resize triggers the scroll buttons to become visible, the page is resized.
502 // This resize from within a resize event can cause (MSW) wxWidgets some confusion,
503 // and report the 1st size to the 2nd size event. Hence the most recent size is
504 // remembered internally and used in Layout() where appropriate.
506 if(GetMajorAxis() == wxHORIZONTAL
)
508 m_size_in_major_axis_for_children
= width
;
509 if(m_scroll_buttons_visible
)
511 if(m_scroll_left_btn
)
512 m_size_in_major_axis_for_children
+= m_scroll_left_btn
->GetSize().GetWidth();
513 if(m_scroll_right_btn
)
514 m_size_in_major_axis_for_children
+= m_scroll_right_btn
->GetSize().GetWidth();
519 m_size_in_major_axis_for_children
= height
;
520 if(m_scroll_buttons_visible
)
522 if(m_scroll_left_btn
)
523 m_size_in_major_axis_for_children
+= m_scroll_left_btn
->GetSize().GetHeight();
524 if(m_scroll_right_btn
)
525 m_size_in_major_axis_for_children
+= m_scroll_right_btn
->GetSize().GetHeight();
529 wxRibbonControl::DoSetSize(x
, y
, width
, height
, sizeFlags
);
532 void wxRibbonPage::OnSize(wxSizeEvent
& evt
)
534 wxSize new_size
= evt
.GetSize();
539 wxRect invalid_rect
= m_art
->GetPageBackgroundRedrawArea(temp_dc
, this, m_old_size
, new_size
);
540 Refresh(true, &invalid_rect
);
543 m_old_size
= new_size
;
545 if(new_size
.GetX() > 0 && new_size
.GetY() > 0)
551 // Simplify other calculations by pretending new size is zero in both
554 // When size == 0, no point in doing any layout
560 void wxRibbonPage::RemoveChild(wxWindowBase
*child
)
562 // Remove all references to the child from the collapse stack
563 size_t count
= m_collapse_stack
.GetCount();
565 for(src
= 0, dst
= 0; src
< count
; ++src
, ++dst
)
567 wxRibbonControl
*item
= m_collapse_stack
.Item(src
);
578 m_collapse_stack
.Item(dst
) = item
;
583 m_collapse_stack
.RemoveAt(dst
, src
- dst
);
586 // ... and then proceed as normal
587 wxRibbonControl::RemoveChild(child
);
590 bool wxRibbonPage::Realize()
594 m_collapse_stack
.Clear();
595 for (wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
597 node
= node
->GetNext())
599 wxRibbonControl
* child
= wxDynamicCast(node
->GetData(), wxRibbonControl
);
604 if(!child
->Realize())
609 PopulateSizeCalcArray(&wxWindow::GetMinSize
);
611 return DoActualLayout() && status
;
614 void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size
)(void) const)
616 wxSize parentSize
= GetSize();
617 parentSize
.x
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
);
618 parentSize
.x
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
619 parentSize
.y
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
);
620 parentSize
.y
-= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
622 if(m_size_calc_array_size
!= GetChildren().GetCount())
624 delete[] m_size_calc_array
;
625 m_size_calc_array_size
= GetChildren().GetCount();
626 m_size_calc_array
= new wxSize
[m_size_calc_array_size
];
629 wxSize
* node_size
= m_size_calc_array
;
630 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
632 node
= node
->GetNext(), ++node_size
)
634 wxWindow
* child
= node
->GetData();
635 wxRibbonPanel
* panel
= wxDynamicCast(child
, wxRibbonPanel
);
636 if (panel
&& panel
->GetFlags() & wxRIBBON_PANEL_FLEXIBLE
)
637 *node_size
= panel
->GetBestSizeForParentSize(parentSize
);
639 *node_size
= (child
->*get_size
)();
643 bool wxRibbonPage::Layout()
645 if(GetChildren().GetCount() == 0)
651 PopulateSizeCalcArray(&wxWindow::GetSize
);
652 return DoActualLayout();
656 bool wxRibbonPage::DoActualLayout()
658 wxPoint
origin(m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
), m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
));
659 wxOrientation major_axis
= GetMajorAxis();
663 if(major_axis
== wxHORIZONTAL
)
665 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
);
666 minor_axis_size
= GetSize().GetHeight() - origin
.y
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
667 available_space
= m_size_in_major_axis_for_children
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
) - origin
.x
;
671 gap
= m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
);
672 minor_axis_size
= GetSize().GetWidth() - origin
.x
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
673 available_space
= m_size_in_major_axis_for_children
- m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
) - origin
.y
;
675 if (minor_axis_size
< 0) minor_axis_size
= 0;
677 for(size_index
= 0; size_index
< m_size_calc_array_size
; ++size_index
)
679 if(major_axis
== wxHORIZONTAL
)
681 available_space
-= m_size_calc_array
[size_index
].GetWidth();
682 m_size_calc_array
[size_index
].SetHeight(minor_axis_size
);
686 available_space
-= m_size_calc_array
[size_index
].GetHeight();
687 m_size_calc_array
[size_index
].SetWidth(minor_axis_size
);
690 available_space
-= gap
;
692 bool todo_hide_scroll_buttons
= false;
693 bool todo_show_scroll_buttons
= false;
694 if(available_space
>= 0)
696 if(m_scroll_buttons_visible
)
697 todo_hide_scroll_buttons
= true;
698 if(available_space
> 0)
699 ExpandPanels(major_axis
, available_space
);
703 if(m_scroll_buttons_visible
)
705 // Scroll buttons already visible - not going to be able to downsize any more
706 m_scroll_amount_limit
= -available_space
;
707 if(m_scroll_amount
> m_scroll_amount_limit
)
709 m_scroll_amount
= m_scroll_amount_limit
;
710 todo_show_scroll_buttons
= true;
715 if(!CollapsePanels(major_axis
, -available_space
))
718 m_scroll_amount_limit
= -available_space
;
719 todo_show_scroll_buttons
= true;
723 if(m_scroll_buttons_visible
)
725 if(major_axis
== wxHORIZONTAL
)
727 origin
.x
-= m_scroll_amount
;
728 if(m_scroll_left_btn
)
729 origin
.x
-= m_scroll_left_btn
->GetSize().GetWidth();
733 origin
.y
-= m_scroll_amount
;
734 if(m_scroll_left_btn
)
735 origin
.y
-= m_scroll_left_btn
->GetSize().GetHeight();
739 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
741 node
= node
->GetNext(), ++size_index
)
743 wxWindow
* child
= node
->GetData();
744 int w
= m_size_calc_array
[size_index
].GetWidth();
745 int h
= m_size_calc_array
[size_index
].GetHeight();
746 child
->SetSize(origin
.x
, origin
.y
, w
, h
);
747 if(major_axis
== wxHORIZONTAL
)
757 if(todo_show_scroll_buttons
)
759 else if(todo_hide_scroll_buttons
)
761 else if(m_scroll_buttons_visible
)
768 bool wxRibbonPage::Show(bool show
)
770 if(m_scroll_left_btn
)
771 m_scroll_left_btn
->Show(show
);
772 if(m_scroll_right_btn
)
773 m_scroll_right_btn
->Show(show
);
774 return wxRibbonControl::Show(show
);
777 void wxRibbonPage::HideScrollButtons()
780 m_scroll_amount_limit
= 0;
784 void wxRibbonPage::ShowScrollButtons()
786 bool show_left
= true;
787 bool show_right
= true;
788 bool reposition
= false;
789 if(m_scroll_amount
== 0)
793 if(m_scroll_amount
>= m_scroll_amount_limit
)
796 m_scroll_amount
= m_scroll_amount_limit
;
798 m_scroll_buttons_visible
= show_left
|| show_right
;
805 if(GetMajorAxis() == wxHORIZONTAL
)
807 direction
= wxRIBBON_SCROLL_BTN_LEFT
;
808 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
809 size
.SetHeight(GetSize().GetHeight());
813 direction
= wxRIBBON_SCROLL_BTN_UP
;
814 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
815 size
.SetWidth(GetSize().GetWidth());
817 if (m_scroll_left_btn
)
819 m_scroll_left_btn
->SetSize(size
);
823 m_scroll_left_btn
= new wxRibbonPageScrollButton(this, wxID_ANY
, GetPosition(), size
, direction
);
828 m_scroll_left_btn
->Hide();
833 if(m_scroll_left_btn
!= NULL
)
835 m_scroll_left_btn
->Destroy();
836 m_scroll_left_btn
= NULL
;
846 if(GetMajorAxis() == wxHORIZONTAL
)
848 direction
= wxRIBBON_SCROLL_BTN_RIGHT
;
849 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
850 size
.SetHeight(GetSize().GetHeight());
854 direction
= wxRIBBON_SCROLL_BTN_DOWN
;
855 size
= m_art
->GetScrollButtonMinimumSize(temp_dc
, GetParent(), direction
);
856 size
.SetWidth(GetSize().GetWidth());
858 wxPoint initial_pos
= GetPosition() + GetSize() - size
;
859 if (m_scroll_right_btn
)
861 m_scroll_right_btn
->SetSize(size
);
865 m_scroll_right_btn
= new wxRibbonPageScrollButton(this, wxID_ANY
, initial_pos
, size
, direction
);
870 m_scroll_right_btn
->Hide();
875 if(m_scroll_right_btn
!= NULL
)
877 m_scroll_right_btn
->Destroy();
878 m_scroll_right_btn
= NULL
;
885 wxDynamicCast(GetParent(), wxRibbonBar
)->RepositionPage(this);
889 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
)
893 case wxHORIZONTAL
: return size
.GetWidth();
894 case wxVERTICAL
: return size
.GetHeight();
895 case wxBOTH
: return size
.GetWidth() * size
.GetHeight();
900 bool wxRibbonPage::ExpandPanels(wxOrientation direction
, int maximum_amount
)
902 bool expanded_something
= false;
903 while(maximum_amount
> 0)
905 int smallest_size
= INT_MAX
;
906 wxRibbonPanel
* smallest_panel
= NULL
;
907 wxSize
* smallest_panel_size
= NULL
;
908 wxSize
* panel_size
= m_size_calc_array
;
909 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
911 node
= node
->GetNext(), ++panel_size
)
913 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
918 if (panel
->GetFlags() & wxRIBBON_PANEL_FLEXIBLE
)
920 // Don't change if it's flexible since we already calculated the
921 // correct size for the panel.
923 else if(panel
->IsSizingContinuous())
925 int size
= GetSizeInOrientation(*panel_size
, direction
);
926 if(size
< smallest_size
)
928 smallest_size
= size
;
929 smallest_panel
= panel
;
930 smallest_panel_size
= panel_size
;
935 int size
= GetSizeInOrientation(*panel_size
, direction
);
936 if(size
< smallest_size
)
938 wxSize larger
= panel
->GetNextLargerSize(direction
, *panel_size
);
939 if(larger
!= (*panel_size
) && GetSizeInOrientation(larger
, direction
) > size
)
941 smallest_size
= size
;
942 smallest_panel
= panel
;
943 smallest_panel_size
= panel_size
;
948 if(smallest_panel
!= NULL
)
950 if(smallest_panel
->IsSizingContinuous())
952 int amount
= maximum_amount
;
955 // For "large" growth, grow this panel a bit, and then re-allocate
956 // the remainder (which may come to this panel again anyway)
959 if(direction
& wxHORIZONTAL
)
961 smallest_panel_size
->x
+= amount
;
963 if(direction
& wxVERTICAL
)
965 smallest_panel_size
->y
+= amount
;
967 maximum_amount
-= amount
;
968 m_collapse_stack
.Add(smallest_panel
);
969 expanded_something
= true;
973 wxSize larger
= smallest_panel
->GetNextLargerSize(direction
, *smallest_panel_size
);
974 wxSize delta
= larger
- (*smallest_panel_size
);
975 if(GetSizeInOrientation(delta
, direction
) <= maximum_amount
)
977 *smallest_panel_size
= larger
;
978 maximum_amount
-= GetSizeInOrientation(delta
, direction
);
979 m_collapse_stack
.Add(smallest_panel
);
980 expanded_something
= true;
993 return expanded_something
;
996 bool wxRibbonPage::CollapsePanels(wxOrientation direction
, int minimum_amount
)
998 bool collapsed_something
= false;
999 while(minimum_amount
> 0)
1001 int largest_size
= 0;
1002 wxRibbonPanel
* largest_panel
= NULL
;
1003 wxSize
* largest_panel_size
= NULL
;
1004 wxSize
* panel_size
= m_size_calc_array
;
1005 if(!m_collapse_stack
.IsEmpty())
1007 // For a more consistent panel layout, try to collapse panels which
1008 // were recently expanded.
1009 largest_panel
= wxDynamicCast(m_collapse_stack
.Last(), wxRibbonPanel
);
1010 m_collapse_stack
.RemoveAt(m_collapse_stack
.GetCount() - 1);
1011 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1013 node
= node
->GetNext(), ++panel_size
)
1015 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1016 if(panel
== largest_panel
)
1018 largest_panel_size
= panel_size
;
1025 for(wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1027 node
= node
->GetNext(), ++panel_size
)
1029 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1034 if(panel
->IsSizingContinuous())
1036 int size
= GetSizeInOrientation(*panel_size
, direction
);
1037 if(size
> largest_size
)
1039 largest_size
= size
;
1040 largest_panel
= panel
;
1041 largest_panel_size
= panel_size
;
1046 int size
= GetSizeInOrientation(*panel_size
, direction
);
1047 if(size
> largest_size
)
1049 wxSize smaller
= panel
->GetNextSmallerSize(direction
, *panel_size
);
1050 if(smaller
!= (*panel_size
) &&
1051 GetSizeInOrientation(smaller
, direction
) < size
)
1053 largest_size
= size
;
1054 largest_panel
= panel
;
1055 largest_panel_size
= panel_size
;
1061 if(largest_panel
!= NULL
)
1063 if(largest_panel
->IsSizingContinuous())
1065 int amount
= minimum_amount
;
1068 // For "large" contraction, reduce this panel a bit, and
1069 // then re-allocate the remainder of the quota (which may
1070 // come to this panel again anyway)
1073 if(direction
& wxHORIZONTAL
)
1075 largest_panel_size
->x
-= amount
;
1077 if(direction
& wxVERTICAL
)
1079 largest_panel_size
->y
-= amount
;
1081 minimum_amount
-= amount
;
1082 collapsed_something
= true;
1086 wxSize smaller
= largest_panel
->GetNextSmallerSize(direction
, *largest_panel_size
);
1087 wxSize delta
= (*largest_panel_size
) - smaller
;
1088 *largest_panel_size
= smaller
;
1089 minimum_amount
-= GetSizeInOrientation(delta
, direction
);
1090 collapsed_something
= true;
1098 return collapsed_something
;
1101 bool wxRibbonPage::DismissExpandedPanel()
1103 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1105 node
= node
->GetNext() )
1107 wxRibbonPanel
* panel
= wxDynamicCast(node
->GetData(), wxRibbonPanel
);
1112 if(panel
->GetExpandedPanel() != NULL
)
1114 return panel
->HideExpanded();
1120 wxSize
wxRibbonPage::GetMinSize() const
1122 wxSize
min(wxDefaultCoord
, wxDefaultCoord
);
1124 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1126 node
= node
->GetNext() )
1128 wxWindow
* child
= node
->GetData();
1129 wxSize
child_min(child
->GetMinSize());
1131 min
.x
= wxMax(min
.x
, child_min
.x
);
1132 min
.y
= wxMax(min
.y
, child_min
.y
);
1135 if(GetMajorAxis() == wxHORIZONTAL
)
1137 min
.x
= wxDefaultCoord
;
1138 if(min
.y
!= wxDefaultCoord
)
1140 min
.y
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
1145 if(min
.x
!= wxDefaultCoord
)
1147 min
.x
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
1149 min
.y
= wxDefaultCoord
;
1155 wxSize
wxRibbonPage::DoGetBestSize() const
1160 if(GetMajorAxis() == wxHORIZONTAL
)
1162 best
.y
= wxDefaultCoord
;
1164 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1166 node
= node
->GetNext() )
1168 wxWindow
* child
= node
->GetData();
1169 wxSize
child_best(child
->GetBestSize());
1171 if(child_best
.x
!= wxDefaultCoord
)
1173 best
.IncBy(child_best
.x
, 0);
1175 best
.y
= wxMax(best
.y
, child_best
.y
);
1182 best
.IncBy((count
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE
), 0);
1187 best
.x
= wxDefaultCoord
;
1189 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
1191 node
= node
->GetNext() )
1193 wxWindow
* child
= node
->GetData();
1194 wxSize
child_best(child
->GetBestSize());
1196 best
.x
= wxMax(best
.x
, child_best
.x
);
1197 if(child_best
.y
!= wxDefaultCoord
)
1199 best
.IncBy(0, child_best
.y
);
1207 best
.IncBy(0, (count
- 1) * m_art
->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE
));
1211 if(best
.x
!= wxDefaultCoord
)
1213 best
.x
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE
);
1215 if(best
.y
!= wxDefaultCoord
)
1217 best
.y
+= m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE
) + m_art
->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE
);
1222 void wxRibbonPage::HideIfExpanded()
1224 wxStaticCast(m_parent
, wxRibbonBar
)->HideIfExpanded();
1227 #endif // wxUSE_RIBBON