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