]> git.saurik.com Git - wxWidgets.git/blame - src/ribbon/page.cpp
Use correct extensions in wxDynamicLibrary::CanonicalizeName() on OS X.
[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:
0a72cae7 138 m_sibling->ScrollSections(1);
3c3ead1d
PC
139 break;
140 case wxRIBBON_SCROLL_BTN_UP:
141 case wxRIBBON_SCROLL_BTN_LEFT:
0a72cae7 142 m_sibling->ScrollSections(-1);
3c3ead1d
PC
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
0a72cae7
VZ
339bool wxRibbonPage::ScrollSections(int sections)
340{
341 // Currently the only valid values are -1 and 1 for scrolling left and
342 // right, respectively.
343 const bool scrollForward = sections >= 1;
344
345 // Determine by how many pixels to scroll. If something on the page
346 // is partially visible, scroll to make it fully visible. Otherwise
347 // find the next item that will become visible and scroll to make it
348 // fully visible. The ScrollPixel call will correct if we scroll too
349 // much if the available width is smaller than the items.
350
351 // Scroll at minimum the same amount as ScrollLines(1):
352 int minscroll = sections * 8;
353 // How many pixels to scroll:
354 int pixels = 0;
355
356 // Determine the scroll position, that is, the page border where items
357 // are appearing.
358 int scrollpos = 0;
359
360 wxOrientation major_axis = GetMajorAxis();
361 int gap = 0;
362
363 int width = 0;
364 int height = 0;
365 int x = 0;
366 int y = 0;
367 GetSize(&width, &height);
368 GetPosition(&x, &y);
369 if(major_axis == wxHORIZONTAL)
370 {
371 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
372 if (scrollForward)
373 {
374 scrollpos = width - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
375 }
376 else
377 {
378 scrollpos = m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE);
379 }
380 }
381 else
382 {
383 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
384 if (scrollForward)
385 {
386 scrollpos = width - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
387 }
388 else
389 {
390 scrollpos = m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE);
391 }
392 }
393
394 // Find the child that is partially shown or just beyond the scroll position
395 for(wxWindowList::compatibility_iterator
396 node = scrollForward ? GetChildren().GetFirst()
397 : GetChildren().GetLast();
398 node;
399 node = scrollForward ? node->GetNext()
400 : node->GetPrevious())
401 {
402 wxWindow* child = node->GetData();
403 child->GetSize(&width, &height);
404 child->GetPosition(&x, &y);
405 int pos0 = 0;
406 int pos1 = 0;
407 if (major_axis == wxHORIZONTAL)
408 {
409 pos0 = x;
410 pos1 = x + width + gap;
411 }
412 else
413 {
414 pos0 = y;
415 pos1 = y + height + gap;
416 }
417 if (scrollpos >= pos0 && scrollpos <= pos1)
418 {
419 // This section is partially visible, scroll to make it fully visible.
420 if (scrollForward)
421 {
422 pixels += pos1 - scrollpos;
423 }
424 else
425 {
426 pixels += pos0 - scrollpos;
427 }
428 if (abs(pixels) >= abs(minscroll))
429 break;
430 }
431 if (scrollpos <= pos0 && scrollForward)
432 {
433 // This section is next, scroll the entire section width
434 pixels += (pos1 - pos0);
435 break;
436 }
437 if (scrollpos >= pos1 && !scrollForward)
438 {
439 // This section is next, scroll the entire section width
440 pixels += (pos0 - pos1);
441 break;
442 }
443 }
444 // Do a final safety sanity check, should not be necessary, but will not hurt either.
445 if (pixels == 0)
446 {
447 pixels = minscroll;
448 }
449 if (pixels * minscroll < 0)
450 {
451 pixels = -pixels;
452 }
453
454 return ScrollPixels(pixels);
455}
456
3c3ead1d
PC
457void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x, int y, int width, int height)
458{
459 if(m_scroll_buttons_visible)
460 {
461 if(GetMajorAxis() == wxHORIZONTAL)
462 {
463 if(m_scroll_left_btn)
464 {
465 int w = m_scroll_left_btn->GetSize().GetWidth();
466 m_scroll_left_btn->SetPosition(wxPoint(x, y));
467 x += w;
468 width -= w;
469 }
470 if(m_scroll_right_btn)
471 {
472 int w = m_scroll_right_btn->GetSize().GetWidth();
473 width -= w;
474 m_scroll_right_btn->SetPosition(wxPoint(x + width, y));
475 }
476 }
477 else
478 {
479 if(m_scroll_left_btn)
480 {
481 int h = m_scroll_left_btn->GetSize().GetHeight();
482 m_scroll_left_btn->SetPosition(wxPoint(x, y));
483 y += h;
484 height -= h;
485 }
486 if(m_scroll_right_btn)
487 {
488 int h = m_scroll_right_btn->GetSize().GetHeight();
489 height -= h;
490 m_scroll_right_btn->SetPosition(wxPoint(x, y + height));
491 }
492 }
493 }
cffda692
PC
494 if (width < 0) width = 0;
495 if (height < 0) height = 0;
3c3ead1d
PC
496 SetSize(x, y, width, height);
497}
498
499void wxRibbonPage::DoSetSize(int x, int y, int width, int height, int sizeFlags)
500{
501 // When a resize triggers the scroll buttons to become visible, the page is resized.
502 // This resize from within a resize event can cause (MSW) wxWidgets some confusion,
503 // and report the 1st size to the 2nd size event. Hence the most recent size is
8d598997 504 // remembered internally and used in Layout() where appropriate.
3c3ead1d
PC
505
506 if(GetMajorAxis() == wxHORIZONTAL)
960615f4 507 {
3c3ead1d 508 m_size_in_major_axis_for_children = width;
960615f4
PC
509 if(m_scroll_buttons_visible)
510 {
511 if(m_scroll_left_btn)
512 m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetWidth();
513 if(m_scroll_right_btn)
514 m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetWidth();
515 }
516 }
3c3ead1d 517 else
960615f4 518 {
3c3ead1d 519 m_size_in_major_axis_for_children = height;
960615f4
PC
520 if(m_scroll_buttons_visible)
521 {
522 if(m_scroll_left_btn)
523 m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetHeight();
524 if(m_scroll_right_btn)
525 m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetHeight();
526 }
527 }
3c3ead1d
PC
528
529 wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags);
530}
531
532void wxRibbonPage::OnSize(wxSizeEvent& evt)
533{
534 wxSize new_size = evt.GetSize();
535
fd6e1597
VZ
536 if (m_art)
537 {
538 wxMemoryDC temp_dc;
539 wxRect invalid_rect = m_art->GetPageBackgroundRedrawArea(temp_dc, this, m_old_size, new_size);
540 Refresh(true, &invalid_rect);
541 }
3c3ead1d
PC
542
543 m_old_size = new_size;
544
545 if(new_size.GetX() > 0 && new_size.GetY() > 0)
546 {
547 Layout();
548 }
549 else
550 {
551 // Simplify other calculations by pretending new size is zero in both
552 // X and Y
553 new_size.Set(0, 0);
554 // When size == 0, no point in doing any layout
555 }
556
557 evt.Skip();
558}
559
560void wxRibbonPage::RemoveChild(wxWindowBase *child)
561{
562 // Remove all references to the child from the collapse stack
563 size_t count = m_collapse_stack.GetCount();
564 size_t src, dst;
565 for(src = 0, dst = 0; src < count; ++src, ++dst)
566 {
567 wxRibbonControl *item = m_collapse_stack.Item(src);
568 if(item == child)
569 {
570 ++src;
571 if(src == count)
572 {
573 break;
574 }
575 }
576 if(src != dst)
577 {
578 m_collapse_stack.Item(dst) = item;
579 }
580 }
581 if(src > dst)
582 {
583 m_collapse_stack.RemoveAt(dst, src - dst);
584 }
585
586 // ... and then proceed as normal
587 wxRibbonControl::RemoveChild(child);
588}
589
590bool wxRibbonPage::Realize()
591{
592 bool status = true;
593
594 m_collapse_stack.Clear();
595 for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
596 node;
597 node = node->GetNext())
598 {
599 wxRibbonControl* child = wxDynamicCast(node->GetData(), wxRibbonControl);
600 if(child == NULL)
601 {
602 continue;
603 }
604 if(!child->Realize())
605 {
606 status = false;
607 }
3c3ead1d 608 }
960615f4 609 PopulateSizeCalcArray(&wxWindow::GetMinSize);
3c3ead1d 610
960615f4
PC
611 return DoActualLayout() && status;
612}
613
614void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size)(void) const)
615{
98742322
JS
616 wxSize parentSize = GetSize();
617 parentSize.x -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE);
618 parentSize.x -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
619 parentSize.y -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE);
620 parentSize.y -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
621
960615f4 622 if(m_size_calc_array_size != GetChildren().GetCount())
3c3ead1d 623 {
960615f4
PC
624 delete[] m_size_calc_array;
625 m_size_calc_array_size = GetChildren().GetCount();
626 m_size_calc_array = new wxSize[m_size_calc_array_size];
627 }
98742322 628
960615f4
PC
629 wxSize* node_size = m_size_calc_array;
630 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
631 node;
632 node = node->GetNext(), ++node_size )
633 {
634 wxWindow* child = node->GetData();
98742322
JS
635 wxRibbonPanel* panel = wxDynamicCast(child, wxRibbonPanel);
636 if (panel && panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)
637 *node_size = panel->GetBestSizeForParentSize(parentSize);
638 else
639 *node_size = (child->*get_size)();
3c3ead1d 640 }
3c3ead1d
PC
641}
642
643bool wxRibbonPage::Layout()
644{
645 if(GetChildren().GetCount() == 0)
646 {
647 return true;
648 }
960615f4 649 else
3c3ead1d 650 {
960615f4
PC
651 PopulateSizeCalcArray(&wxWindow::GetSize);
652 return DoActualLayout();
3c3ead1d 653 }
960615f4
PC
654}
655
656bool wxRibbonPage::DoActualLayout()
657{
658 wxPoint origin(m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE), m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE));
659 wxOrientation major_axis = GetMajorAxis();
3c3ead1d
PC
660 int gap;
661 int minor_axis_size;
960615f4 662 int available_space;
3c3ead1d
PC
663 if(major_axis == wxHORIZONTAL)
664 {
665 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
666 minor_axis_size = GetSize().GetHeight() - origin.y - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
960615f4 667 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE) - origin.x;
3c3ead1d
PC
668 }
669 else
670 {
671 gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
672 minor_axis_size = GetSize().GetWidth() - origin.x - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
960615f4 673 available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE) - origin.y;
3c3ead1d 674 }
16eac072 675 if (minor_axis_size < 0) minor_axis_size = 0;
960615f4
PC
676 size_t size_index;
677 for(size_index = 0; size_index < m_size_calc_array_size; ++size_index)
3c3ead1d 678 {
960615f4 679 if(major_axis == wxHORIZONTAL)
3c3ead1d 680 {
960615f4
PC
681 available_space -= m_size_calc_array[size_index].GetWidth();
682 m_size_calc_array[size_index].SetHeight(minor_axis_size);
3c3ead1d 683 }
960615f4 684 else
3c3ead1d 685 {
960615f4
PC
686 available_space -= m_size_calc_array[size_index].GetHeight();
687 m_size_calc_array[size_index].SetWidth(minor_axis_size);
688 }
689 if(size_index != 0)
690 available_space -= gap;
691 }
692 bool todo_hide_scroll_buttons = false;
693 bool todo_show_scroll_buttons = false;
694 if(available_space >= 0)
695 {
696 if(m_scroll_buttons_visible)
697 todo_hide_scroll_buttons = true;
698 if(available_space > 0)
699 ExpandPanels(major_axis, available_space);
700 }
701 else
702 {
703 if(m_scroll_buttons_visible)
704 {
705 // Scroll buttons already visible - not going to be able to downsize any more
706 m_scroll_amount_limit = -available_space;
707 if(m_scroll_amount > m_scroll_amount_limit)
3c3ead1d 708 {
960615f4
PC
709 m_scroll_amount = m_scroll_amount_limit;
710 todo_show_scroll_buttons = true;
3c3ead1d 711 }
960615f4
PC
712 }
713 else
714 {
715 if(!CollapsePanels(major_axis, -available_space))
3c3ead1d 716 {
960615f4
PC
717 m_scroll_amount = 0;
718 m_scroll_amount_limit = -available_space;
719 todo_show_scroll_buttons = true;
3c3ead1d 720 }
960615f4
PC
721 }
722 }
723 if(m_scroll_buttons_visible)
724 {
725 if(major_axis == wxHORIZONTAL)
726 {
727 origin.x -= m_scroll_amount;
728 if(m_scroll_left_btn)
729 origin.x -= m_scroll_left_btn->GetSize().GetWidth();
730 }
731 else
732 {
733 origin.y -= m_scroll_amount;
734 if(m_scroll_left_btn)
735 origin.y -= m_scroll_left_btn->GetSize().GetHeight();
736 }
737 }
738 size_index = 0;
739 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
740 node;
741 node = node->GetNext(), ++size_index )
742 {
743 wxWindow* child = node->GetData();
744 int w = m_size_calc_array[size_index].GetWidth();
745 int h = m_size_calc_array[size_index].GetHeight();
746 child->SetSize(origin.x, origin.y, w, h);
747 if(major_axis == wxHORIZONTAL)
748 {
749 origin.x += w + gap;
750 }
751 else
752 {
753 origin.y += h + gap;
3c3ead1d
PC
754 }
755 }
756
960615f4
PC
757 if(todo_show_scroll_buttons)
758 ShowScrollButtons();
759 else if(todo_hide_scroll_buttons)
760 HideScrollButtons();
b31d6326
VZ
761 else if(m_scroll_buttons_visible)
762 ShowScrollButtons();
960615f4
PC
763
764 Refresh();
3c3ead1d
PC
765 return true;
766}
767
768bool wxRibbonPage::Show(bool show)
769{
770 if(m_scroll_left_btn)
771 m_scroll_left_btn->Show(show);
772 if(m_scroll_right_btn)
773 m_scroll_right_btn->Show(show);
774 return wxRibbonControl::Show(show);
775}
776
777void wxRibbonPage::HideScrollButtons()
778{
779 m_scroll_amount = 0;
780 m_scroll_amount_limit = 0;
781 ShowScrollButtons();
782}
783
784void wxRibbonPage::ShowScrollButtons()
785{
786 bool show_left = true;
787 bool show_right = true;
788 bool reposition = false;
789 if(m_scroll_amount == 0)
790 {
791 show_left = false;
792 }
793 if(m_scroll_amount >= m_scroll_amount_limit)
794 {
795 show_right = false;
796 m_scroll_amount = m_scroll_amount_limit;
797 }
798 m_scroll_buttons_visible = show_left || show_right;
799
800 if(show_left)
801 {
b31d6326
VZ
802 wxMemoryDC temp_dc;
803 wxSize size;
804 long direction;
805 if(GetMajorAxis() == wxHORIZONTAL)
3c3ead1d 806 {
b31d6326
VZ
807 direction = wxRIBBON_SCROLL_BTN_LEFT;
808 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
809 size.SetHeight(GetSize().GetHeight());
810 }
811 else
812 {
813 direction = wxRIBBON_SCROLL_BTN_UP;
814 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
815 size.SetWidth(GetSize().GetWidth());
816 }
817 if (m_scroll_left_btn)
818 {
819 m_scroll_left_btn->SetSize(size);
820 }
821 else
822 {
823 m_scroll_left_btn = new wxRibbonPageScrollButton(this, wxID_ANY, GetPosition(), size, direction);
824 reposition = true;
825 }
826 if(!IsShown())
827 {
828 m_scroll_left_btn->Hide();
3c3ead1d
PC
829 }
830 }
831 else
832 {
833 if(m_scroll_left_btn != NULL)
834 {
835 m_scroll_left_btn->Destroy();
836 m_scroll_left_btn = NULL;
837 reposition = true;
838 }
839 }
840
841 if(show_right)
842 {
b31d6326
VZ
843 wxMemoryDC temp_dc;
844 wxSize size;
845 long direction;
846 if(GetMajorAxis() == wxHORIZONTAL)
3c3ead1d 847 {
b31d6326
VZ
848 direction = wxRIBBON_SCROLL_BTN_RIGHT;
849 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
850 size.SetHeight(GetSize().GetHeight());
851 }
852 else
853 {
854 direction = wxRIBBON_SCROLL_BTN_DOWN;
855 size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
856 size.SetWidth(GetSize().GetWidth());
857 }
858 wxPoint initial_pos = GetPosition() + GetSize() - size;
859 if (m_scroll_right_btn)
860 {
861 m_scroll_right_btn->SetSize(size);
862 }
863 else
864 {
865 m_scroll_right_btn = new wxRibbonPageScrollButton(this, wxID_ANY, initial_pos, size, direction);
866 reposition = true;
867 }
868 if(!IsShown())
869 {
870 m_scroll_right_btn->Hide();
3c3ead1d
PC
871 }
872 }
873 else
874 {
875 if(m_scroll_right_btn != NULL)
876 {
877 m_scroll_right_btn->Destroy();
878 m_scroll_right_btn = NULL;
879 reposition = true;
880 }
881 }
882
883 if(reposition)
884 {
885 wxDynamicCast(GetParent(), wxRibbonBar)->RepositionPage(this);
886 }
887}
888
889static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
890{
891 switch(orientation)
892 {
893 case wxHORIZONTAL: return size.GetWidth();
894 case wxVERTICAL: return size.GetHeight();
895 case wxBOTH: return size.GetWidth() * size.GetHeight();
896 default: return 0;
897 }
898}
899
900bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
901{
902 bool expanded_something = false;
903 while(maximum_amount > 0)
904 {
905 int smallest_size = INT_MAX;
906 wxRibbonPanel* smallest_panel = NULL;
960615f4
PC
907 wxSize* smallest_panel_size = NULL;
908 wxSize* panel_size = m_size_calc_array;
3c3ead1d
PC
909 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
910 node;
960615f4 911 node = node->GetNext(), ++panel_size )
3c3ead1d
PC
912 {
913 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
914 if(panel == NULL)
915 {
916 continue;
917 }
98742322
JS
918 if (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)
919 {
920 // Don't change if it's flexible since we already calculated the
921 // correct size for the panel.
922 }
923 else if(panel->IsSizingContinuous())
3c3ead1d 924 {
960615f4 925 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
926 if(size < smallest_size)
927 {
928 smallest_size = size;
929 smallest_panel = panel;
960615f4 930 smallest_panel_size = panel_size;
3c3ead1d
PC
931 }
932 }
933 else
934 {
960615f4 935 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
936 if(size < smallest_size)
937 {
960615f4
PC
938 wxSize larger = panel->GetNextLargerSize(direction, *panel_size);
939 if(larger != (*panel_size) && GetSizeInOrientation(larger, direction) > size)
3c3ead1d
PC
940 {
941 smallest_size = size;
942 smallest_panel = panel;
960615f4 943 smallest_panel_size = panel_size;
3c3ead1d
PC
944 }
945 }
946 }
947 }
948 if(smallest_panel != NULL)
949 {
950 if(smallest_panel->IsSizingContinuous())
951 {
3c3ead1d
PC
952 int amount = maximum_amount;
953 if(amount > 32)
954 {
955 // For "large" growth, grow this panel a bit, and then re-allocate
956 // the remainder (which may come to this panel again anyway)
957 amount = 32;
958 }
959 if(direction & wxHORIZONTAL)
960 {
960615f4 961 smallest_panel_size->x += amount;
3c3ead1d
PC
962 }
963 if(direction & wxVERTICAL)
964 {
960615f4 965 smallest_panel_size->y += amount;
3c3ead1d 966 }
3c3ead1d
PC
967 maximum_amount -= amount;
968 m_collapse_stack.Add(smallest_panel);
969 expanded_something = true;
970 }
971 else
972 {
960615f4
PC
973 wxSize larger = smallest_panel->GetNextLargerSize(direction, *smallest_panel_size);
974 wxSize delta = larger - (*smallest_panel_size);
3c3ead1d
PC
975 if(GetSizeInOrientation(delta, direction) <= maximum_amount)
976 {
960615f4 977 *smallest_panel_size = larger;
3c3ead1d
PC
978 maximum_amount -= GetSizeInOrientation(delta, direction);
979 m_collapse_stack.Add(smallest_panel);
980 expanded_something = true;
981 }
982 else
983 {
984 break;
985 }
986 }
987 }
988 else
989 {
990 break;
991 }
992 }
960615f4 993 return expanded_something;
3c3ead1d
PC
994}
995
996bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
997{
998 bool collapsed_something = false;
999 while(minimum_amount > 0)
1000 {
1001 int largest_size = 0;
1002 wxRibbonPanel* largest_panel = NULL;
960615f4
PC
1003 wxSize* largest_panel_size = NULL;
1004 wxSize* panel_size = m_size_calc_array;
3c3ead1d
PC
1005 if(!m_collapse_stack.IsEmpty())
1006 {
1007 // For a more consistent panel layout, try to collapse panels which
1008 // were recently expanded.
1009 largest_panel = wxDynamicCast(m_collapse_stack.Last(), wxRibbonPanel);
1010 m_collapse_stack.RemoveAt(m_collapse_stack.GetCount() - 1);
960615f4
PC
1011 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1012 node;
1013 node = node->GetNext(), ++panel_size )
1014 {
1015 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
1016 if(panel == largest_panel)
1017 {
1018 largest_panel_size = panel_size;
1019 break;
1020 }
1021 }
3c3ead1d
PC
1022 }
1023 else
1024 {
1025 for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1026 node;
960615f4 1027 node = node->GetNext(), ++panel_size )
3c3ead1d
PC
1028 {
1029 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
1030 if(panel == NULL)
1031 {
1032 continue;
1033 }
1034 if(panel->IsSizingContinuous())
1035 {
960615f4 1036 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
1037 if(size > largest_size)
1038 {
1039 largest_size = size;
1040 largest_panel = panel;
960615f4 1041 largest_panel_size = panel_size;
3c3ead1d
PC
1042 }
1043 }
1044 else
1045 {
960615f4 1046 int size = GetSizeInOrientation(*panel_size, direction);
3c3ead1d
PC
1047 if(size > largest_size)
1048 {
960615f4
PC
1049 wxSize smaller = panel->GetNextSmallerSize(direction, *panel_size);
1050 if(smaller != (*panel_size) &&
3c3ead1d
PC
1051 GetSizeInOrientation(smaller, direction) < size)
1052 {
1053 largest_size = size;
1054 largest_panel = panel;
960615f4 1055 largest_panel_size = panel_size;
3c3ead1d
PC
1056 }
1057 }
1058 }
1059 }
1060 }
1061 if(largest_panel != NULL)
1062 {
1063 if(largest_panel->IsSizingContinuous())
1064 {
3c3ead1d
PC
1065 int amount = minimum_amount;
1066 if(amount > 32)
1067 {
1068 // For "large" contraction, reduce this panel a bit, and
1069 // then re-allocate the remainder of the quota (which may
1070 // come to this panel again anyway)
1071 amount = 32;
1072 }
1073 if(direction & wxHORIZONTAL)
1074 {
960615f4 1075 largest_panel_size->x -= amount;
3c3ead1d
PC
1076 }
1077 if(direction & wxVERTICAL)
1078 {
960615f4 1079 largest_panel_size->y -= amount;
3c3ead1d 1080 }
3c3ead1d
PC
1081 minimum_amount -= amount;
1082 collapsed_something = true;
1083 }
1084 else
1085 {
960615f4
PC
1086 wxSize smaller = largest_panel->GetNextSmallerSize(direction, *largest_panel_size);
1087 wxSize delta = (*largest_panel_size) - smaller;
1088 *largest_panel_size = smaller;
3c3ead1d
PC
1089 minimum_amount -= GetSizeInOrientation(delta, direction);
1090 collapsed_something = true;
1091 }
1092 }
1093 else
1094 {
1095 break;
1096 }
1097 }
960615f4 1098 return collapsed_something;
3c3ead1d
PC
1099}
1100
1101bool wxRibbonPage::DismissExpandedPanel()
1102{
1103 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1104 node;
1105 node = node->GetNext() )
1106 {
1107 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
1108 if(panel == NULL)
1109 {
1110 continue;
1111 }
1112 if(panel->GetExpandedPanel() != NULL)
1113 {
1114 return panel->HideExpanded();
1115 }
1116 }
1117 return false;
1118}
1119
1120wxSize wxRibbonPage::GetMinSize() const
1121{
1122 wxSize min(wxDefaultCoord, wxDefaultCoord);
1123
1124 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1125 node;
1126 node = node->GetNext() )
1127 {
1128 wxWindow* child = node->GetData();
1129 wxSize child_min(child->GetMinSize());
1130
1131 min.x = wxMax(min.x, child_min.x);
1132 min.y = wxMax(min.y, child_min.y);
1133 }
1134
1135 if(GetMajorAxis() == wxHORIZONTAL)
1136 {
1137 min.x = wxDefaultCoord;
1138 if(min.y != wxDefaultCoord)
1139 {
1140 min.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
1141 }
1142 }
1143 else
1144 {
1145 if(min.x != wxDefaultCoord)
1146 {
1147 min.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1148 }
1149 min.y = wxDefaultCoord;
1150 }
1151
1152 return min;
1153}
1154
1155wxSize wxRibbonPage::DoGetBestSize() const
1156{
1157 wxSize best(0, 0);
1158 size_t count = 0;
1159
1160 if(GetMajorAxis() == wxHORIZONTAL)
1161 {
1162 best.y = wxDefaultCoord;
1163
1164 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1165 node;
1166 node = node->GetNext() )
1167 {
1168 wxWindow* child = node->GetData();
1169 wxSize child_best(child->GetBestSize());
1170
1171 if(child_best.x != wxDefaultCoord)
1172 {
1173 best.IncBy(child_best.x, 0);
1174 }
1175 best.y = wxMax(best.y, child_best.y);
1176
1177 ++count;
1178 }
1179
1180 if(count > 1)
1181 {
1182 best.IncBy((count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE), 0);
1183 }
1184 }
1185 else
1186 {
1187 best.x = wxDefaultCoord;
1188
1189 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1190 node;
1191 node = node->GetNext() )
1192 {
1193 wxWindow* child = node->GetData();
1194 wxSize child_best(child->GetBestSize());
1195
1196 best.x = wxMax(best.x, child_best.x);
1197 if(child_best.y != wxDefaultCoord)
1198 {
1199 best.IncBy(0, child_best.y);
1200 }
1201
1202 ++count;
1203 }
1204
1205 if(count > 1)
1206 {
1207 best.IncBy(0, (count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE));
1208 }
1209 }
1210
1211 if(best.x != wxDefaultCoord)
1212 {
1213 best.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
1214 }
1215 if(best.y != wxDefaultCoord)
1216 {
1217 best.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
1218 }
1219 return best;
1220}
1221
42d73941
VZ
1222void wxRibbonPage::HideIfExpanded()
1223{
1224 wxStaticCast(m_parent, wxRibbonBar)->HideIfExpanded();
1225}
1226
3c3ead1d 1227#endif // wxUSE_RIBBON