]> git.saurik.com Git - wxWidgets.git/blob - src/ribbon/page.cpp
Always provide wxMenuItem bitmap-related methods in wxMSW.
[wxWidgets.git] / src / ribbon / page.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/ribbon/page.cpp
3 // Purpose: Container for ribbon-bar-style interface panels
4 // Author: Peter Cawley
5 // Modified by:
6 // Created: 2009-05-25
7 // RCS-ID: $Id$
8 // Copyright: (C) Peter Cawley
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #if wxUSE_RIBBON
18
19 #include "wx/ribbon/page.h"
20 #include "wx/ribbon/art.h"
21 #include "wx/ribbon/bar.h"
22 #include "wx/dcbuffer.h"
23
24 #ifndef WX_PRECOMP
25 #endif
26
27 #ifdef __WXMSW__
28 #include "wx/msw/private.h"
29 #endif
30
31 static int GetSizeInOrientation(wxSize size, wxOrientation orientation);
32
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
42 {
43 public:
44 wxRibbonPageScrollButton(wxRibbonPage* sibling,
45 wxWindowID id = wxID_ANY,
46 const wxPoint& pos = wxDefaultPosition,
47 const wxSize& size = wxDefaultSize,
48 long style = 0);
49
50 virtual ~wxRibbonPageScrollButton();
51
52 protected:
53 virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
54
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);
61
62 wxRibbonPage* m_sibling;
63 long m_flags;
64
65 DECLARE_CLASS(wxRibbonPageScrollButton)
66 DECLARE_EVENT_TABLE()
67 };
68
69 IMPLEMENT_CLASS(wxRibbonPageScrollButton, wxRibbonControl)
70
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)
78 END_EVENT_TABLE()
79
80 wxRibbonPageScrollButton::wxRibbonPageScrollButton(wxRibbonPage* sibling,
81 wxWindowID id,
82 const wxPoint& pos,
83 const wxSize& size,
84 long style) : wxRibbonControl(sibling->GetParent(), id, pos, size, wxBORDER_NONE)
85 {
86 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
87 m_sibling = sibling;
88 m_flags = (style & wxRIBBON_SCROLL_BTN_DIRECTION_MASK) | wxRIBBON_SCROLL_BTN_FOR_PAGE;
89 }
90
91 wxRibbonPageScrollButton::~wxRibbonPageScrollButton()
92 {
93 }
94
95 void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
96 {
97 // Do nothing - all painting done in main paint handler
98 }
99
100 void wxRibbonPageScrollButton::OnPaint(wxPaintEvent& WXUNUSED(evt))
101 {
102 wxAutoBufferedPaintDC dc(this);
103 if(m_art)
104 {
105 m_art->DrawScrollButton(dc, this, GetSize(), m_flags);
106 }
107 }
108
109 void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent& WXUNUSED(evt))
110 {
111 m_flags |= wxRIBBON_SCROLL_BTN_HOVERED;
112 Refresh(false);
113 }
114
115 void wxRibbonPageScrollButton::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
116 {
117 m_flags &= ~wxRIBBON_SCROLL_BTN_HOVERED;
118 m_flags &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
119 Refresh(false);
120 }
121
122 void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent& WXUNUSED(evt))
123 {
124 m_flags |= wxRIBBON_SCROLL_BTN_ACTIVE;
125 Refresh(false);
126 }
127
128 void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent& WXUNUSED(evt))
129 {
130 if(m_flags & wxRIBBON_SCROLL_BTN_ACTIVE)
131 {
132 m_flags &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
133 Refresh(false);
134 switch(m_flags & wxRIBBON_SCROLL_BTN_DIRECTION_MASK)
135 {
136 case wxRIBBON_SCROLL_BTN_DOWN:
137 case wxRIBBON_SCROLL_BTN_RIGHT:
138 m_sibling->ScrollLines(1);
139 break;
140 case wxRIBBON_SCROLL_BTN_UP:
141 case wxRIBBON_SCROLL_BTN_LEFT:
142 m_sibling->ScrollLines(-1);
143 break;
144 default:
145 break;
146 }
147 }
148 }
149
150 IMPLEMENT_CLASS(wxRibbonPage, wxRibbonControl)
151
152 BEGIN_EVENT_TABLE(wxRibbonPage, wxRibbonControl)
153 EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground)
154 EVT_PAINT(wxRibbonPage::OnPaint)
155 EVT_SIZE(wxRibbonPage::OnSize)
156 END_EVENT_TABLE()
157
158 wxRibbonPage::wxRibbonPage()
159 {
160 m_scroll_left_btn = NULL;
161 m_scroll_right_btn = NULL;
162 m_scroll_amount = 0;
163 m_scroll_buttons_visible = false;
164 }
165
166 wxRibbonPage::wxRibbonPage(wxRibbonBar* parent,
167 wxWindowID id,
168 const wxString& label,
169 const wxBitmap& icon,
170 long WXUNUSED(style))
171 : wxRibbonControl(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
172 {
173 CommonInit(label, icon);
174 }
175
176 wxRibbonPage::~wxRibbonPage()
177 {
178 delete[] m_size_calc_array;
179 }
180
181 bool wxRibbonPage::Create(wxRibbonBar* parent,
182 wxWindowID id,
183 const wxString& label,
184 const wxBitmap& icon,
185 long WXUNUSED(style))
186 {
187 if(!wxRibbonControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE))
188 return false;
189
190 CommonInit(label, icon);
191
192 return true;
193 }
194
195 void wxRibbonPage::CommonInit(const wxString& label, const wxBitmap& icon)
196 {
197 SetName(label);
198
199 SetLabel(label);
200 m_old_size = wxSize(0, 0);
201 m_icon = icon;
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;
206 m_scroll_amount = 0;
207 m_scroll_buttons_visible = false;
208
209 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
210
211 wxDynamicCast(GetParent(), wxRibbonBar)->AddPage(this);
212 }
213
214 void wxRibbonPage::SetArtProvider(wxRibbonArtProvider* art)
215 {
216 m_art = art;
217 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
218 node;
219 node = node->GetNext() )
220 {
221 wxWindow* child = node->GetData();
222 wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
223 if(ribbon_child)
224 {
225 ribbon_child->SetArtProvider(art);
226 }
227 }
228 }
229
230 void wxRibbonPage::AdjustRectToIncludeScrollButtons(wxRect* rect) const
231 {
232 if(m_scroll_buttons_visible)
233 {
234 if(GetMajorAxis() == wxVERTICAL)
235 {
236 if(m_scroll_left_btn)
237 {
238 rect->SetY(rect->GetY() -
239 m_scroll_left_btn->GetSize().GetHeight());
240 rect->SetHeight(rect->GetHeight() +
241 m_scroll_left_btn->GetSize().GetHeight());
242 }
243 if(m_scroll_right_btn)
244 {
245 rect->SetHeight(rect->GetHeight() +
246 m_scroll_right_btn->GetSize().GetHeight());
247 }
248 }
249 else
250 {
251 if(m_scroll_left_btn)
252 {
253 rect->SetX(rect->GetX() -
254 m_scroll_left_btn->GetSize().GetWidth());
255 rect->SetWidth(rect->GetWidth() +
256 m_scroll_left_btn->GetSize().GetWidth());
257 }
258 if(m_scroll_right_btn)
259 {
260 rect->SetWidth(rect->GetWidth() +
261 m_scroll_right_btn->GetSize().GetWidth());
262 }
263 }
264 }
265 }
266
267 void wxRibbonPage::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
268 {
269 // All painting done in main paint handler to minimise flicker
270 }
271
272 void wxRibbonPage::OnPaint(wxPaintEvent& WXUNUSED(evt))
273 {
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);
280 }
281
282 wxOrientation wxRibbonPage::GetMajorAxis() const
283 {
284 if(m_art && (m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL))
285 {
286 return wxVERTICAL;
287 }
288 else
289 {
290 return wxHORIZONTAL;
291 }
292 }
293
294 bool wxRibbonPage::ScrollLines(int lines)
295 {
296 return ScrollPixels(lines * 8);
297 }
298
299 bool wxRibbonPage::ScrollPixels(int pixels)
300 {
301 if(pixels < 0)
302 {
303 if(m_scroll_amount == 0)
304 return false;
305 if(m_scroll_amount < -pixels)
306 pixels = -m_scroll_amount;
307 }
308 else if(pixels > 0)
309 {
310 if(m_scroll_amount == m_scroll_amount_limit)
311 return false;
312 if(m_scroll_amount + pixels > m_scroll_amount_limit)
313 pixels = m_scroll_amount_limit - m_scroll_amount;
314 }
315 else
316 return false;
317
318 m_scroll_amount += pixels;
319
320 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
321 node;
322 node = node->GetNext() )
323 {
324 wxWindow* child = node->GetData();
325 int x, y;
326 child->GetPosition(&x, &y);
327 if(GetMajorAxis() == wxHORIZONTAL)
328 x -= pixels;
329 else
330 y -= pixels;
331 child->SetPosition(wxPoint(x, y));
332 }
333
334 ShowScrollButtons();
335 Refresh();
336 return true;
337 }
338
339 void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x, int y, int width, int height)
340 {
341 if(m_scroll_buttons_visible)
342 {
343 if(GetMajorAxis() == wxHORIZONTAL)
344 {
345 if(m_scroll_left_btn)
346 {
347 int w = m_scroll_left_btn->GetSize().GetWidth();
348 m_scroll_left_btn->SetPosition(wxPoint(x, y));
349 x += w;
350 width -= w;
351 }
352 if(m_scroll_right_btn)
353 {
354 int w = m_scroll_right_btn->GetSize().GetWidth();
355 width -= w;
356 m_scroll_right_btn->SetPosition(wxPoint(x + width, y));
357 }
358 }
359 else
360 {
361 if(m_scroll_left_btn)
362 {
363 int h = m_scroll_left_btn->GetSize().GetHeight();
364 m_scroll_left_btn->SetPosition(wxPoint(x, y));
365 y += h;
366 height -= h;
367 }
368 if(m_scroll_right_btn)
369 {
370 int h = m_scroll_right_btn->GetSize().GetHeight();
371 height -= h;
372 m_scroll_right_btn->SetPosition(wxPoint(x, y + height));
373 }
374 }
375 }
376 if (width < 0) width = 0;
377 if (height < 0) height = 0;
378 SetSize(x, y, width, height);
379 }
380
381 void wxRibbonPage::DoSetSize(int x, int y, int width, int height, int sizeFlags)
382 {
383 // When a resize triggers the scroll buttons to become visible, the page is resized.
384 // This resize from within a resize event can cause (MSW) wxWidgets some confusion,
385 // and report the 1st size to the 2nd size event. Hence the most recent size is
386 // remembered internally and used in Layout() where appropiate.
387
388 if(GetMajorAxis() == wxHORIZONTAL)
389 {
390 m_size_in_major_axis_for_children = width;
391 if(m_scroll_buttons_visible)
392 {
393 if(m_scroll_left_btn)
394 m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetWidth();
395 if(m_scroll_right_btn)
396 m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetWidth();
397 }
398 }
399 else
400 {
401 m_size_in_major_axis_for_children = height;
402 if(m_scroll_buttons_visible)
403 {
404 if(m_scroll_left_btn)
405 m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetHeight();
406 if(m_scroll_right_btn)
407 m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetHeight();
408 }
409 }
410
411 wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags);
412 }
413
414 void wxRibbonPage::OnSize(wxSizeEvent& evt)
415 {
416 wxSize new_size = evt.GetSize();
417
418 if (m_art)
419 {
420 wxMemoryDC temp_dc;
421 wxRect invalid_rect = m_art->GetPageBackgroundRedrawArea(temp_dc, this, m_old_size, new_size);
422 Refresh(true, &invalid_rect);
423 }
424
425 m_old_size = new_size;
426
427 if(new_size.GetX() > 0 && new_size.GetY() > 0)
428 {
429 Layout();
430 }
431 else
432 {
433 // Simplify other calculations by pretending new size is zero in both
434 // X and Y
435 new_size.Set(0, 0);
436 // When size == 0, no point in doing any layout
437 }
438
439 evt.Skip();
440 }
441
442 void wxRibbonPage::RemoveChild(wxWindowBase *child)
443 {
444 // Remove all references to the child from the collapse stack
445 size_t count = m_collapse_stack.GetCount();
446 size_t src, dst;
447 for(src = 0, dst = 0; src < count; ++src, ++dst)
448 {
449 wxRibbonControl *item = m_collapse_stack.Item(src);
450 if(item == child)
451 {
452 ++src;
453 if(src == count)
454 {
455 break;
456 }
457 }
458 if(src != dst)
459 {
460 m_collapse_stack.Item(dst) = item;
461 }
462 }
463 if(src > dst)
464 {
465 m_collapse_stack.RemoveAt(dst, src - dst);
466 }
467
468 // ... and then proceed as normal
469 wxRibbonControl::RemoveChild(child);
470 }
471
472 bool wxRibbonPage::Realize()
473 {
474 bool status = true;
475
476 m_collapse_stack.Clear();
477 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
478 node;
479 node = node->GetNext())
480 {
481 wxRibbonControl* child = wxDynamicCast(node->GetData(), wxRibbonControl);
482 if(child == NULL)
483 {
484 continue;
485 }
486 if(!child->Realize())
487 {
488 status = false;
489 }
490 }
491 PopulateSizeCalcArray(&wxWindow::GetMinSize);
492
493 return DoActualLayout() && status;
494 }
495
496 void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size)(void) const)
497 {
498 if(m_size_calc_array_size != GetChildren().GetCount())
499 {
500 delete[] m_size_calc_array;
501 m_size_calc_array_size = GetChildren().GetCount();
502 m_size_calc_array = new wxSize[m_size_calc_array_size];
503 }
504 wxSize* node_size = m_size_calc_array;
505 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
506 node;
507 node = node->GetNext(), ++node_size )
508 {
509 wxWindow* child = node->GetData();
510 *node_size = (child->*get_size)();
511 }
512 }
513
514 bool wxRibbonPage::Layout()
515 {
516 if(GetChildren().GetCount() == 0)
517 {
518 return true;
519 }
520 else
521 {
522 PopulateSizeCalcArray(&wxWindow::GetSize);
523 return DoActualLayout();
524 }
525 }
526
527 bool wxRibbonPage::DoActualLayout()
528 {
529 wxPoint origin(m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE), m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE));
530 wxOrientation major_axis = GetMajorAxis();
531 int gap;
532 int minor_axis_size;
533 int available_space;
534 if(major_axis == wxHORIZONTAL)
535 {
536 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
537 minor_axis_size = GetSize().GetHeight() - origin.y - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
538 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE) - origin.x;
539 }
540 else
541 {
542 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
543 minor_axis_size = GetSize().GetWidth() - origin.x - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
544 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE) - origin.y;
545 }
546 if (minor_axis_size < 0) minor_axis_size = 0;
547 size_t size_index;
548 for(size_index = 0; size_index < m_size_calc_array_size; ++size_index)
549 {
550 if(major_axis == wxHORIZONTAL)
551 {
552 available_space -= m_size_calc_array[size_index].GetWidth();
553 m_size_calc_array[size_index].SetHeight(minor_axis_size);
554 }
555 else
556 {
557 available_space -= m_size_calc_array[size_index].GetHeight();
558 m_size_calc_array[size_index].SetWidth(minor_axis_size);
559 }
560 if(size_index != 0)
561 available_space -= gap;
562 }
563 bool todo_hide_scroll_buttons = false;
564 bool todo_show_scroll_buttons = false;
565 if(available_space >= 0)
566 {
567 if(m_scroll_buttons_visible)
568 todo_hide_scroll_buttons = true;
569 if(available_space > 0)
570 ExpandPanels(major_axis, available_space);
571 }
572 else
573 {
574 if(m_scroll_buttons_visible)
575 {
576 // Scroll buttons already visible - not going to be able to downsize any more
577 m_scroll_amount_limit = -available_space;
578 if(m_scroll_amount > m_scroll_amount_limit)
579 {
580 m_scroll_amount = m_scroll_amount_limit;
581 todo_show_scroll_buttons = true;
582 }
583 }
584 else
585 {
586 if(!CollapsePanels(major_axis, -available_space))
587 {
588 m_scroll_amount = 0;
589 m_scroll_amount_limit = -available_space;
590 todo_show_scroll_buttons = true;
591 }
592 }
593 }
594 if(m_scroll_buttons_visible)
595 {
596 if(major_axis == wxHORIZONTAL)
597 {
598 origin.x -= m_scroll_amount;
599 if(m_scroll_left_btn)
600 origin.x -= m_scroll_left_btn->GetSize().GetWidth();
601 }
602 else
603 {
604 origin.y -= m_scroll_amount;
605 if(m_scroll_left_btn)
606 origin.y -= m_scroll_left_btn->GetSize().GetHeight();
607 }
608 }
609 size_index = 0;
610 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
611 node;
612 node = node->GetNext(), ++size_index )
613 {
614 wxWindow* child = node->GetData();
615 int w = m_size_calc_array[size_index].GetWidth();
616 int h = m_size_calc_array[size_index].GetHeight();
617 child->SetSize(origin.x, origin.y, w, h);
618 if(major_axis == wxHORIZONTAL)
619 {
620 origin.x += w + gap;
621 }
622 else
623 {
624 origin.y += h + gap;
625 }
626 }
627
628 if(todo_show_scroll_buttons)
629 ShowScrollButtons();
630 else if(todo_hide_scroll_buttons)
631 HideScrollButtons();
632
633 Refresh();
634 return true;
635 }
636
637 bool wxRibbonPage::Show(bool show)
638 {
639 if(m_scroll_left_btn)
640 m_scroll_left_btn->Show(show);
641 if(m_scroll_right_btn)
642 m_scroll_right_btn->Show(show);
643 return wxRibbonControl::Show(show);
644 }
645
646 void wxRibbonPage::HideScrollButtons()
647 {
648 m_scroll_amount = 0;
649 m_scroll_amount_limit = 0;
650 ShowScrollButtons();
651 }
652
653 void wxRibbonPage::ShowScrollButtons()
654 {
655 bool show_left = true;
656 bool show_right = true;
657 bool reposition = false;
658 if(m_scroll_amount == 0)
659 {
660 show_left = false;
661 }
662 if(m_scroll_amount >= m_scroll_amount_limit)
663 {
664 show_right = false;
665 m_scroll_amount = m_scroll_amount_limit;
666 }
667 m_scroll_buttons_visible = show_left || show_right;
668
669 if(show_left)
670 {
671 if(m_scroll_left_btn == NULL)
672 {
673 wxMemoryDC temp_dc;
674 wxSize size;
675 long direction;
676 if(GetMajorAxis() == wxHORIZONTAL)
677 {
678 direction = wxRIBBON_SCROLL_BTN_LEFT;
679 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
680 size.SetHeight(GetSize().GetHeight());
681 }
682 else
683 {
684 direction = wxRIBBON_SCROLL_BTN_UP;
685 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
686 size.SetWidth(GetSize().GetWidth());
687 }
688 m_scroll_left_btn = new wxRibbonPageScrollButton(this, wxID_ANY, GetPosition(), size, direction);
689 if(!IsShown())
690 {
691 m_scroll_left_btn->Hide();
692 }
693 reposition = true;
694 }
695 }
696 else
697 {
698 if(m_scroll_left_btn != NULL)
699 {
700 m_scroll_left_btn->Destroy();
701 m_scroll_left_btn = NULL;
702 reposition = true;
703 }
704 }
705
706 if(show_right)
707 {
708 if(m_scroll_right_btn == NULL)
709 {
710 wxMemoryDC temp_dc;
711 wxSize size;
712 long direction;
713 if(GetMajorAxis() == wxHORIZONTAL)
714 {
715 direction = wxRIBBON_SCROLL_BTN_RIGHT;
716 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
717 size.SetHeight(GetSize().GetHeight());
718 }
719 else
720 {
721 direction = wxRIBBON_SCROLL_BTN_DOWN;
722 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
723 size.SetWidth(GetSize().GetWidth());
724 }
725 wxPoint initial_pos = GetPosition() + GetSize() - size;
726 m_scroll_right_btn = new wxRibbonPageScrollButton(this, wxID_ANY, initial_pos, size, direction);
727 if(!IsShown())
728 {
729 m_scroll_right_btn->Hide();
730 }
731 reposition = true;
732 }
733 }
734 else
735 {
736 if(m_scroll_right_btn != NULL)
737 {
738 m_scroll_right_btn->Destroy();
739 m_scroll_right_btn = NULL;
740 reposition = true;
741 }
742 }
743
744 if(reposition)
745 {
746 wxDynamicCast(GetParent(), wxRibbonBar)->RepositionPage(this);
747 }
748 }
749
750 static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
751 {
752 switch(orientation)
753 {
754 case wxHORIZONTAL: return size.GetWidth();
755 case wxVERTICAL: return size.GetHeight();
756 case wxBOTH: return size.GetWidth() * size.GetHeight();
757 default: return 0;
758 }
759 }
760
761 bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
762 {
763 bool expanded_something = false;
764 while(maximum_amount > 0)
765 {
766 int smallest_size = INT_MAX;
767 wxRibbonPanel* smallest_panel = NULL;
768 wxSize* smallest_panel_size = NULL;
769 wxSize* panel_size = m_size_calc_array;
770 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
771 node;
772 node = node->GetNext(), ++panel_size )
773 {
774 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
775 if(panel == NULL)
776 {
777 continue;
778 }
779 if(panel->IsSizingContinuous())
780 {
781 int size = GetSizeInOrientation(*panel_size, direction);
782 if(size < smallest_size)
783 {
784 smallest_size = size;
785 smallest_panel = panel;
786 smallest_panel_size = panel_size;
787 }
788 }
789 else
790 {
791 int size = GetSizeInOrientation(*panel_size, direction);
792 if(size < smallest_size)
793 {
794 wxSize larger = panel->GetNextLargerSize(direction, *panel_size);
795 if(larger != (*panel_size) && GetSizeInOrientation(larger, direction) > size)
796 {
797 smallest_size = size;
798 smallest_panel = panel;
799 smallest_panel_size = panel_size;
800 }
801 }
802 }
803 }
804 if(smallest_panel != NULL)
805 {
806 if(smallest_panel->IsSizingContinuous())
807 {
808 int amount = maximum_amount;
809 if(amount > 32)
810 {
811 // For "large" growth, grow this panel a bit, and then re-allocate
812 // the remainder (which may come to this panel again anyway)
813 amount = 32;
814 }
815 if(direction & wxHORIZONTAL)
816 {
817 smallest_panel_size->x += amount;
818 }
819 if(direction & wxVERTICAL)
820 {
821 smallest_panel_size->y += amount;
822 }
823 maximum_amount -= amount;
824 m_collapse_stack.Add(smallest_panel);
825 expanded_something = true;
826 }
827 else
828 {
829 wxSize larger = smallest_panel->GetNextLargerSize(direction, *smallest_panel_size);
830 wxSize delta = larger - (*smallest_panel_size);
831 if(GetSizeInOrientation(delta, direction) <= maximum_amount)
832 {
833 *smallest_panel_size = larger;
834 maximum_amount -= GetSizeInOrientation(delta, direction);
835 m_collapse_stack.Add(smallest_panel);
836 expanded_something = true;
837 }
838 else
839 {
840 break;
841 }
842 }
843 }
844 else
845 {
846 break;
847 }
848 }
849 return expanded_something;
850 }
851
852 bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
853 {
854 bool collapsed_something = false;
855 while(minimum_amount > 0)
856 {
857 int largest_size = 0;
858 wxRibbonPanel* largest_panel = NULL;
859 wxSize* largest_panel_size = NULL;
860 wxSize* panel_size = m_size_calc_array;
861 if(!m_collapse_stack.IsEmpty())
862 {
863 // For a more consistent panel layout, try to collapse panels which
864 // were recently expanded.
865 largest_panel = wxDynamicCast(m_collapse_stack.Last(), wxRibbonPanel);
866 m_collapse_stack.RemoveAt(m_collapse_stack.GetCount() - 1);
867 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
868 node;
869 node = node->GetNext(), ++panel_size )
870 {
871 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
872 if(panel == largest_panel)
873 {
874 largest_panel_size = panel_size;
875 break;
876 }
877 }
878 }
879 else
880 {
881 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
882 node;
883 node = node->GetNext(), ++panel_size )
884 {
885 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
886 if(panel == NULL)
887 {
888 continue;
889 }
890 if(panel->IsSizingContinuous())
891 {
892 int size = GetSizeInOrientation(*panel_size, direction);
893 if(size > largest_size)
894 {
895 largest_size = size;
896 largest_panel = panel;
897 largest_panel_size = panel_size;
898 }
899 }
900 else
901 {
902 int size = GetSizeInOrientation(*panel_size, direction);
903 if(size > largest_size)
904 {
905 wxSize smaller = panel->GetNextSmallerSize(direction, *panel_size);
906 if(smaller != (*panel_size) &&
907 GetSizeInOrientation(smaller, direction) < size)
908 {
909 largest_size = size;
910 largest_panel = panel;
911 largest_panel_size = panel_size;
912 }
913 }
914 }
915 }
916 }
917 if(largest_panel != NULL)
918 {
919 if(largest_panel->IsSizingContinuous())
920 {
921 int amount = minimum_amount;
922 if(amount > 32)
923 {
924 // For "large" contraction, reduce this panel a bit, and
925 // then re-allocate the remainder of the quota (which may
926 // come to this panel again anyway)
927 amount = 32;
928 }
929 if(direction & wxHORIZONTAL)
930 {
931 largest_panel_size->x -= amount;
932 }
933 if(direction & wxVERTICAL)
934 {
935 largest_panel_size->y -= amount;
936 }
937 minimum_amount -= amount;
938 collapsed_something = true;
939 }
940 else
941 {
942 wxSize smaller = largest_panel->GetNextSmallerSize(direction, *largest_panel_size);
943 wxSize delta = (*largest_panel_size) - smaller;
944 *largest_panel_size = smaller;
945 minimum_amount -= GetSizeInOrientation(delta, direction);
946 collapsed_something = true;
947 }
948 }
949 else
950 {
951 break;
952 }
953 }
954 return collapsed_something;
955 }
956
957 bool wxRibbonPage::DismissExpandedPanel()
958 {
959 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
960 node;
961 node = node->GetNext() )
962 {
963 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
964 if(panel == NULL)
965 {
966 continue;
967 }
968 if(panel->GetExpandedPanel() != NULL)
969 {
970 return panel->HideExpanded();
971 }
972 }
973 return false;
974 }
975
976 wxSize wxRibbonPage::GetMinSize() const
977 {
978 wxSize min(wxDefaultCoord, wxDefaultCoord);
979
980 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
981 node;
982 node = node->GetNext() )
983 {
984 wxWindow* child = node->GetData();
985 wxSize child_min(child->GetMinSize());
986
987 min.x = wxMax(min.x, child_min.x);
988 min.y = wxMax(min.y, child_min.y);
989 }
990
991 if(GetMajorAxis() == wxHORIZONTAL)
992 {
993 min.x = wxDefaultCoord;
994 if(min.y != wxDefaultCoord)
995 {
996 min.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
997 }
998 }
999 else
1000 {
1001 if(min.x != wxDefaultCoord)
1002 {
1003 min.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1004 }
1005 min.y = wxDefaultCoord;
1006 }
1007
1008 return min;
1009 }
1010
1011 wxSize wxRibbonPage::DoGetBestSize() const
1012 {
1013 wxSize best(0, 0);
1014 size_t count = 0;
1015
1016 if(GetMajorAxis() == wxHORIZONTAL)
1017 {
1018 best.y = wxDefaultCoord;
1019
1020 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1021 node;
1022 node = node->GetNext() )
1023 {
1024 wxWindow* child = node->GetData();
1025 wxSize child_best(child->GetBestSize());
1026
1027 if(child_best.x != wxDefaultCoord)
1028 {
1029 best.IncBy(child_best.x, 0);
1030 }
1031 best.y = wxMax(best.y, child_best.y);
1032
1033 ++count;
1034 }
1035
1036 if(count > 1)
1037 {
1038 best.IncBy((count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE), 0);
1039 }
1040 }
1041 else
1042 {
1043 best.x = wxDefaultCoord;
1044
1045 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1046 node;
1047 node = node->GetNext() )
1048 {
1049 wxWindow* child = node->GetData();
1050 wxSize child_best(child->GetBestSize());
1051
1052 best.x = wxMax(best.x, child_best.x);
1053 if(child_best.y != wxDefaultCoord)
1054 {
1055 best.IncBy(0, child_best.y);
1056 }
1057
1058 ++count;
1059 }
1060
1061 if(count > 1)
1062 {
1063 best.IncBy(0, (count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE));
1064 }
1065 }
1066
1067 if(best.x != wxDefaultCoord)
1068 {
1069 best.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1070 }
1071 if(best.y != wxDefaultCoord)
1072 {
1073 best.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
1074 }
1075 return best;
1076 }
1077
1078 #endif // wxUSE_RIBBON