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