]> git.saurik.com Git - wxWidgets.git/blame - src/ribbon/page.cpp
Set popup menu invoking window in wxWindowBase and not in all ports.
[wxWidgets.git] / src / ribbon / page.cpp
CommitLineData
3c3ead1d
PC
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
3c3ead1d
PC
17#if wxUSE_RIBBON
18
4cf018e1 19#include "wx/ribbon/page.h"
3c3ead1d
PC
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
31static 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.
41class wxRibbonPageScrollButton : public wxRibbonControl
42{
43public:
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
52protected:
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
69IMPLEMENT_CLASS(wxRibbonPageScrollButton, wxRibbonControl)
70
71BEGIN_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)
78END_EVENT_TABLE()
79
80wxRibbonPageScrollButton::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
91wxRibbonPageScrollButton::~wxRibbonPageScrollButton()
92{
93}
94
95void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
96{
97 // Do nothing - all painting done in main paint handler
98}
99
100void 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
109void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent& WXUNUSED(evt))
110{
111 m_flags |= wxRIBBON_SCROLL_BTN_HOVERED;
112 Refresh(false);
113}
114
115void 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
122void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent& WXUNUSED(evt))
123{
124 m_flags |= wxRIBBON_SCROLL_BTN_ACTIVE;
125 Refresh(false);
126}
127
128void 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
150IMPLEMENT_CLASS(wxRibbonPage, wxRibbonControl)
151
152BEGIN_EVENT_TABLE(wxRibbonPage, wxRibbonControl)
153 EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground)
154 EVT_PAINT(wxRibbonPage::OnPaint)
155 EVT_SIZE(wxRibbonPage::OnSize)
156END_EVENT_TABLE()
157
158wxRibbonPage::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
166wxRibbonPage::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
176wxRibbonPage::~wxRibbonPage()
177{
960615f4 178 delete[] m_size_calc_array;
3c3ead1d
PC
179}
180
181bool 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
195void 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;
960615f4
PC
204 m_size_calc_array = NULL;
205 m_size_calc_array_size = 0;
3c3ead1d
PC
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
214void 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
230void 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
267void wxRibbonPage::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
268{
269 // All painting done in main paint handler to minimise flicker
270}
271
272void 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
282wxOrientation 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
294bool wxRibbonPage::ScrollLines(int lines)
295{
296 return ScrollPixels(lines * 8);
297}
298
299bool 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
339void 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 }
cffda692
PC
376 if (width < 0) width = 0;
377 if (height < 0) height = 0;
3c3ead1d
PC
378 SetSize(x, y, width, height);
379}
380
381void 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)
960615f4 389 {
3c3ead1d 390 m_size_in_major_axis_for_children = width;
960615f4
PC
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 }
3c3ead1d 399 else
960615f4 400 {
3c3ead1d 401 m_size_in_major_axis_for_children = height;
960615f4
PC
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 }
3c3ead1d
PC
410
411 wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags);
412}
413
414void wxRibbonPage::OnSize(wxSizeEvent& evt)
415{
416 wxSize new_size = evt.GetSize();
417
418 wxMemoryDC temp_dc;
419 wxRect invalid_rect = m_art->GetPageBackgroundRedrawArea(temp_dc, this, m_old_size, new_size);
420 Refresh(true, &invalid_rect);
421
422 m_old_size = new_size;
423
424 if(new_size.GetX() > 0 && new_size.GetY() > 0)
425 {
426 Layout();
427 }
428 else
429 {
430 // Simplify other calculations by pretending new size is zero in both
431 // X and Y
432 new_size.Set(0, 0);
433 // When size == 0, no point in doing any layout
434 }
435
436 evt.Skip();
437}
438
439void wxRibbonPage::RemoveChild(wxWindowBase *child)
440{
441 // Remove all references to the child from the collapse stack
442 size_t count = m_collapse_stack.GetCount();
443 size_t src, dst;
444 for(src = 0, dst = 0; src < count; ++src, ++dst)
445 {
446 wxRibbonControl *item = m_collapse_stack.Item(src);
447 if(item == child)
448 {
449 ++src;
450 if(src == count)
451 {
452 break;
453 }
454 }
455 if(src != dst)
456 {
457 m_collapse_stack.Item(dst) = item;
458 }
459 }
460 if(src > dst)
461 {
462 m_collapse_stack.RemoveAt(dst, src - dst);
463 }
464
465 // ... and then proceed as normal
466 wxRibbonControl::RemoveChild(child);
467}
468
469bool wxRibbonPage::Realize()
470{
471 bool status = true;
472
473 m_collapse_stack.Clear();
474 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
475 node;
476 node = node->GetNext())
477 {
478 wxRibbonControl* child = wxDynamicCast(node->GetData(), wxRibbonControl);
479 if(child == NULL)
480 {
481 continue;
482 }
483 if(!child->Realize())
484 {
485 status = false;
486 }
3c3ead1d 487 }
960615f4 488 PopulateSizeCalcArray(&wxWindow::GetMinSize);
3c3ead1d 489
960615f4
PC
490 return DoActualLayout() && status;
491}
492
493void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size)(void) const)
494{
495 if(m_size_calc_array_size != GetChildren().GetCount())
3c3ead1d 496 {
960615f4
PC
497 delete[] m_size_calc_array;
498 m_size_calc_array_size = GetChildren().GetCount();
499 m_size_calc_array = new wxSize[m_size_calc_array_size];
500 }
501 wxSize* node_size = m_size_calc_array;
502 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
503 node;
504 node = node->GetNext(), ++node_size )
505 {
506 wxWindow* child = node->GetData();
507 *node_size = (child->*get_size)();
3c3ead1d 508 }
3c3ead1d
PC
509}
510
511bool wxRibbonPage::Layout()
512{
513 if(GetChildren().GetCount() == 0)
514 {
515 return true;
516 }
960615f4 517 else
3c3ead1d 518 {
960615f4
PC
519 PopulateSizeCalcArray(&wxWindow::GetSize);
520 return DoActualLayout();
3c3ead1d 521 }
960615f4
PC
522}
523
524bool wxRibbonPage::DoActualLayout()
525{
526 wxPoint origin(m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE), m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE));
527 wxOrientation major_axis = GetMajorAxis();
3c3ead1d
PC
528 int gap;
529 int minor_axis_size;
960615f4 530 int available_space;
3c3ead1d
PC
531 if(major_axis == wxHORIZONTAL)
532 {
533 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
534 minor_axis_size = GetSize().GetHeight() - origin.y - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
960615f4 535 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE) - origin.x;
3c3ead1d
PC
536 }
537 else
538 {
539 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
540 minor_axis_size = GetSize().GetWidth() - origin.x - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
960615f4 541 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE) - origin.y;
3c3ead1d 542 }
16eac072 543 if (minor_axis_size < 0) minor_axis_size = 0;
960615f4
PC
544 size_t size_index;
545 for(size_index = 0; size_index < m_size_calc_array_size; ++size_index)
3c3ead1d 546 {
960615f4 547 if(major_axis == wxHORIZONTAL)
3c3ead1d 548 {
960615f4
PC
549 available_space -= m_size_calc_array[size_index].GetWidth();
550 m_size_calc_array[size_index].SetHeight(minor_axis_size);
3c3ead1d 551 }
960615f4 552 else
3c3ead1d 553 {
960615f4
PC
554 available_space -= m_size_calc_array[size_index].GetHeight();
555 m_size_calc_array[size_index].SetWidth(minor_axis_size);
556 }
557 if(size_index != 0)
558 available_space -= gap;
559 }
560 bool todo_hide_scroll_buttons = false;
561 bool todo_show_scroll_buttons = false;
562 if(available_space >= 0)
563 {
564 if(m_scroll_buttons_visible)
565 todo_hide_scroll_buttons = true;
566 if(available_space > 0)
567 ExpandPanels(major_axis, available_space);
568 }
569 else
570 {
571 if(m_scroll_buttons_visible)
572 {
573 // Scroll buttons already visible - not going to be able to downsize any more
574 m_scroll_amount_limit = -available_space;
575 if(m_scroll_amount > m_scroll_amount_limit)
3c3ead1d 576 {
960615f4
PC
577 m_scroll_amount = m_scroll_amount_limit;
578 todo_show_scroll_buttons = true;
3c3ead1d 579 }
960615f4
PC
580 }
581 else
582 {
583 if(!CollapsePanels(major_axis, -available_space))
3c3ead1d 584 {
960615f4
PC
585 m_scroll_amount = 0;
586 m_scroll_amount_limit = -available_space;
587 todo_show_scroll_buttons = true;
3c3ead1d 588 }
960615f4
PC
589 }
590 }
591 if(m_scroll_buttons_visible)
592 {
593 if(major_axis == wxHORIZONTAL)
594 {
595 origin.x -= m_scroll_amount;
596 if(m_scroll_left_btn)
597 origin.x -= m_scroll_left_btn->GetSize().GetWidth();
598 }
599 else
600 {
601 origin.y -= m_scroll_amount;
602 if(m_scroll_left_btn)
603 origin.y -= m_scroll_left_btn->GetSize().GetHeight();
604 }
605 }
606 size_index = 0;
607 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
608 node;
609 node = node->GetNext(), ++size_index )
610 {
611 wxWindow* child = node->GetData();
612 int w = m_size_calc_array[size_index].GetWidth();
613 int h = m_size_calc_array[size_index].GetHeight();
614 child->SetSize(origin.x, origin.y, w, h);
615 if(major_axis == wxHORIZONTAL)
616 {
617 origin.x += w + gap;
618 }
619 else
620 {
621 origin.y += h + gap;
3c3ead1d
PC
622 }
623 }
624
960615f4
PC
625 if(todo_show_scroll_buttons)
626 ShowScrollButtons();
627 else if(todo_hide_scroll_buttons)
628 HideScrollButtons();
629
630 Refresh();
3c3ead1d
PC
631 return true;
632}
633
634bool wxRibbonPage::Show(bool show)
635{
636 if(m_scroll_left_btn)
637 m_scroll_left_btn->Show(show);
638 if(m_scroll_right_btn)
639 m_scroll_right_btn->Show(show);
640 return wxRibbonControl::Show(show);
641}
642
643void wxRibbonPage::HideScrollButtons()
644{
645 m_scroll_amount = 0;
646 m_scroll_amount_limit = 0;
647 ShowScrollButtons();
648}
649
650void wxRibbonPage::ShowScrollButtons()
651{
652 bool show_left = true;
653 bool show_right = true;
654 bool reposition = false;
655 if(m_scroll_amount == 0)
656 {
657 show_left = false;
658 }
659 if(m_scroll_amount >= m_scroll_amount_limit)
660 {
661 show_right = false;
662 m_scroll_amount = m_scroll_amount_limit;
663 }
664 m_scroll_buttons_visible = show_left || show_right;
665
666 if(show_left)
667 {
668 if(m_scroll_left_btn == NULL)
669 {
670 wxMemoryDC temp_dc;
671 wxSize size;
672 long direction;
673 if(GetMajorAxis() == wxHORIZONTAL)
674 {
675 direction = wxRIBBON_SCROLL_BTN_LEFT;
676 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
677 size.SetHeight(GetSize().GetHeight());
678 }
679 else
680 {
681 direction = wxRIBBON_SCROLL_BTN_UP;
682 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
683 size.SetWidth(GetSize().GetWidth());
684 }
685 m_scroll_left_btn = new wxRibbonPageScrollButton(this, wxID_ANY, GetPosition(), size, direction);
686 if(!IsShown())
687 {
688 m_scroll_left_btn->Hide();
689 }
690 reposition = true;
691 }
692 }
693 else
694 {
695 if(m_scroll_left_btn != NULL)
696 {
697 m_scroll_left_btn->Destroy();
698 m_scroll_left_btn = NULL;
699 reposition = true;
700 }
701 }
702
703 if(show_right)
704 {
705 if(m_scroll_right_btn == NULL)
706 {
707 wxMemoryDC temp_dc;
708 wxSize size;
709 long direction;
710 if(GetMajorAxis() == wxHORIZONTAL)
711 {
712 direction = wxRIBBON_SCROLL_BTN_RIGHT;
713 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
714 size.SetHeight(GetSize().GetHeight());
715 }
716 else
717 {
718 direction = wxRIBBON_SCROLL_BTN_DOWN;
719 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
720 size.SetWidth(GetSize().GetWidth());
721 }
722 wxPoint initial_pos = GetPosition() + GetSize() - size;
723 m_scroll_right_btn = new wxRibbonPageScrollButton(this, wxID_ANY, initial_pos, size, direction);
724 if(!IsShown())
725 {
726 m_scroll_right_btn->Hide();
727 }
728 reposition = true;
729 }
730 }
731 else
732 {
733 if(m_scroll_right_btn != NULL)
734 {
735 m_scroll_right_btn->Destroy();
736 m_scroll_right_btn = NULL;
737 reposition = true;
738 }
739 }
740
741 if(reposition)
742 {
743 wxDynamicCast(GetParent(), wxRibbonBar)->RepositionPage(this);
744 }
745}
746
747static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
748{
749 switch(orientation)
750 {
751 case wxHORIZONTAL: return size.GetWidth();
752 case wxVERTICAL: return size.GetHeight();
753 case wxBOTH: return size.GetWidth() * size.GetHeight();
754 default: return 0;
755 }
756}
757
758bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
759{
760 bool expanded_something = false;
761 while(maximum_amount > 0)
762 {
763 int smallest_size = INT_MAX;
764 wxRibbonPanel* smallest_panel = NULL;
960615f4
PC
765 wxSize* smallest_panel_size = NULL;
766 wxSize* panel_size = m_size_calc_array;
3c3ead1d
PC
767 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
768 node;
960615f4 769 node = node->GetNext(), ++panel_size )
3c3ead1d
PC
770 {
771 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
772 if(panel == NULL)
773 {
774 continue;
775 }
776 if(panel->IsSizingContinuous())
777 {
960615f4 778 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
779 if(size < smallest_size)
780 {
781 smallest_size = size;
782 smallest_panel = panel;
960615f4 783 smallest_panel_size = panel_size;
3c3ead1d
PC
784 }
785 }
786 else
787 {
960615f4 788 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
789 if(size < smallest_size)
790 {
960615f4
PC
791 wxSize larger = panel->GetNextLargerSize(direction, *panel_size);
792 if(larger != (*panel_size) && GetSizeInOrientation(larger, direction) > size)
3c3ead1d
PC
793 {
794 smallest_size = size;
795 smallest_panel = panel;
960615f4 796 smallest_panel_size = panel_size;
3c3ead1d
PC
797 }
798 }
799 }
800 }
801 if(smallest_panel != NULL)
802 {
803 if(smallest_panel->IsSizingContinuous())
804 {
3c3ead1d
PC
805 int amount = maximum_amount;
806 if(amount > 32)
807 {
808 // For "large" growth, grow this panel a bit, and then re-allocate
809 // the remainder (which may come to this panel again anyway)
810 amount = 32;
811 }
812 if(direction & wxHORIZONTAL)
813 {
960615f4 814 smallest_panel_size->x += amount;
3c3ead1d
PC
815 }
816 if(direction & wxVERTICAL)
817 {
960615f4 818 smallest_panel_size->y += amount;
3c3ead1d 819 }
3c3ead1d
PC
820 maximum_amount -= amount;
821 m_collapse_stack.Add(smallest_panel);
822 expanded_something = true;
823 }
824 else
825 {
960615f4
PC
826 wxSize larger = smallest_panel->GetNextLargerSize(direction, *smallest_panel_size);
827 wxSize delta = larger - (*smallest_panel_size);
3c3ead1d
PC
828 if(GetSizeInOrientation(delta, direction) <= maximum_amount)
829 {
960615f4 830 *smallest_panel_size = larger;
3c3ead1d
PC
831 maximum_amount -= GetSizeInOrientation(delta, direction);
832 m_collapse_stack.Add(smallest_panel);
833 expanded_something = true;
834 }
835 else
836 {
837 break;
838 }
839 }
840 }
841 else
842 {
843 break;
844 }
845 }
960615f4 846 return expanded_something;
3c3ead1d
PC
847}
848
849bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
850{
851 bool collapsed_something = false;
852 while(minimum_amount > 0)
853 {
854 int largest_size = 0;
855 wxRibbonPanel* largest_panel = NULL;
960615f4
PC
856 wxSize* largest_panel_size = NULL;
857 wxSize* panel_size = m_size_calc_array;
3c3ead1d
PC
858 if(!m_collapse_stack.IsEmpty())
859 {
860 // For a more consistent panel layout, try to collapse panels which
861 // were recently expanded.
862 largest_panel = wxDynamicCast(m_collapse_stack.Last(), wxRibbonPanel);
863 m_collapse_stack.RemoveAt(m_collapse_stack.GetCount() - 1);
960615f4
PC
864 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
865 node;
866 node = node->GetNext(), ++panel_size )
867 {
868 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
869 if(panel == largest_panel)
870 {
871 largest_panel_size = panel_size;
872 break;
873 }
874 }
3c3ead1d
PC
875 }
876 else
877 {
878 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
879 node;
960615f4 880 node = node->GetNext(), ++panel_size )
3c3ead1d
PC
881 {
882 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
883 if(panel == NULL)
884 {
885 continue;
886 }
887 if(panel->IsSizingContinuous())
888 {
960615f4 889 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
890 if(size > largest_size)
891 {
892 largest_size = size;
893 largest_panel = panel;
960615f4 894 largest_panel_size = panel_size;
3c3ead1d
PC
895 }
896 }
897 else
898 {
960615f4 899 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
900 if(size > largest_size)
901 {
960615f4
PC
902 wxSize smaller = panel->GetNextSmallerSize(direction, *panel_size);
903 if(smaller != (*panel_size) &&
3c3ead1d
PC
904 GetSizeInOrientation(smaller, direction) < size)
905 {
906 largest_size = size;
907 largest_panel = panel;
960615f4 908 largest_panel_size = panel_size;
3c3ead1d
PC
909 }
910 }
911 }
912 }
913 }
914 if(largest_panel != NULL)
915 {
916 if(largest_panel->IsSizingContinuous())
917 {
3c3ead1d
PC
918 int amount = minimum_amount;
919 if(amount > 32)
920 {
921 // For "large" contraction, reduce this panel a bit, and
922 // then re-allocate the remainder of the quota (which may
923 // come to this panel again anyway)
924 amount = 32;
925 }
926 if(direction & wxHORIZONTAL)
927 {
960615f4 928 largest_panel_size->x -= amount;
3c3ead1d
PC
929 }
930 if(direction & wxVERTICAL)
931 {
960615f4 932 largest_panel_size->y -= amount;
3c3ead1d 933 }
3c3ead1d
PC
934 minimum_amount -= amount;
935 collapsed_something = true;
936 }
937 else
938 {
960615f4
PC
939 wxSize smaller = largest_panel->GetNextSmallerSize(direction, *largest_panel_size);
940 wxSize delta = (*largest_panel_size) - smaller;
941 *largest_panel_size = smaller;
3c3ead1d
PC
942 minimum_amount -= GetSizeInOrientation(delta, direction);
943 collapsed_something = true;
944 }
945 }
946 else
947 {
948 break;
949 }
950 }
960615f4 951 return collapsed_something;
3c3ead1d
PC
952}
953
954bool wxRibbonPage::DismissExpandedPanel()
955{
956 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
957 node;
958 node = node->GetNext() )
959 {
960 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
961 if(panel == NULL)
962 {
963 continue;
964 }
965 if(panel->GetExpandedPanel() != NULL)
966 {
967 return panel->HideExpanded();
968 }
969 }
970 return false;
971}
972
973wxSize wxRibbonPage::GetMinSize() const
974{
975 wxSize min(wxDefaultCoord, wxDefaultCoord);
976
977 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
978 node;
979 node = node->GetNext() )
980 {
981 wxWindow* child = node->GetData();
982 wxSize child_min(child->GetMinSize());
983
984 min.x = wxMax(min.x, child_min.x);
985 min.y = wxMax(min.y, child_min.y);
986 }
987
988 if(GetMajorAxis() == wxHORIZONTAL)
989 {
990 min.x = wxDefaultCoord;
991 if(min.y != wxDefaultCoord)
992 {
993 min.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
994 }
995 }
996 else
997 {
998 if(min.x != wxDefaultCoord)
999 {
1000 min.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1001 }
1002 min.y = wxDefaultCoord;
1003 }
1004
1005 return min;
1006}
1007
1008wxSize wxRibbonPage::DoGetBestSize() const
1009{
1010 wxSize best(0, 0);
1011 size_t count = 0;
1012
1013 if(GetMajorAxis() == wxHORIZONTAL)
1014 {
1015 best.y = wxDefaultCoord;
1016
1017 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1018 node;
1019 node = node->GetNext() )
1020 {
1021 wxWindow* child = node->GetData();
1022 wxSize child_best(child->GetBestSize());
1023
1024 if(child_best.x != wxDefaultCoord)
1025 {
1026 best.IncBy(child_best.x, 0);
1027 }
1028 best.y = wxMax(best.y, child_best.y);
1029
1030 ++count;
1031 }
1032
1033 if(count > 1)
1034 {
1035 best.IncBy((count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE), 0);
1036 }
1037 }
1038 else
1039 {
1040 best.x = wxDefaultCoord;
1041
1042 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1043 node;
1044 node = node->GetNext() )
1045 {
1046 wxWindow* child = node->GetData();
1047 wxSize child_best(child->GetBestSize());
1048
1049 best.x = wxMax(best.x, child_best.x);
1050 if(child_best.y != wxDefaultCoord)
1051 {
1052 best.IncBy(0, child_best.y);
1053 }
1054
1055 ++count;
1056 }
1057
1058 if(count > 1)
1059 {
1060 best.IncBy(0, (count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE));
1061 }
1062 }
1063
1064 if(best.x != wxDefaultCoord)
1065 {
1066 best.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1067 }
1068 if(best.y != wxDefaultCoord)
1069 {
1070 best.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
1071 }
1072 return best;
1073}
1074
1075#endif // wxUSE_RIBBON