1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/ribbon/bar.cpp
3 // Purpose: Top-level component of the ribbon-bar-style interface
4 // Author: Peter Cawley
5 // Modified by:
6 // Created: 2009-05-23
7 // Copyright: (C) Peter Cawley
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13
14 #if wxUSE_RIBBON
15
16 #include "wx/ribbon/bar.h"
17 #include "wx/ribbon/art.h"
18 #include "wx/dcbuffer.h"
19 #include "wx/app.h"
20 #include "wx/vector.h"
21
22 #ifndef WX_PRECOMP
23 #endif
24
25 #ifdef __WXMSW__
26 #include "wx/msw/private.h"
27 #endif
28
29 #include "wx/arrimpl.cpp"
30 #include "wx/imaglist.h"
31
32 WX_DEFINE_USER_EXPORTED_OBJARRAY(wxRibbonPageTabInfoArray)
33
34 wxDEFINE_EVENT(wxEVT_RIBBONBAR_PAGE_CHANGED, wxRibbonBarEvent);
35 wxDEFINE_EVENT(wxEVT_RIBBONBAR_PAGE_CHANGING, wxRibbonBarEvent);
36 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TAB_MIDDLE_DOWN, wxRibbonBarEvent);
37 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TAB_MIDDLE_UP, wxRibbonBarEvent);
38 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TAB_RIGHT_DOWN, wxRibbonBarEvent);
39 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TAB_RIGHT_UP, wxRibbonBarEvent);
40 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TAB_LEFT_DCLICK, wxRibbonBarEvent);
41 wxDEFINE_EVENT(wxEVT_RIBBONBAR_TOGGLED, wxRibbonBarEvent);
42 wxDEFINE_EVENT(wxEVT_RIBBONBAR_HELP_CLICK, wxRibbonBarEvent);
43
44 wxIMPLEMENT_CLASS(wxRibbonBar, wxRibbonControl);
45 wxIMPLEMENT_DYNAMIC_CLASS(wxRibbonBarEvent, wxNotifyEvent);
46
wxBEGIN_EVENT_TABLE(wxRibbonBar,wxRibbonControl)47 wxBEGIN_EVENT_TABLE(wxRibbonBar, wxRibbonControl)
48 EVT_ERASE_BACKGROUND(wxRibbonBar::OnEraseBackground)
49 EVT_LEAVE_WINDOW(wxRibbonBar::OnMouseLeave)
50 EVT_LEFT_DOWN(wxRibbonBar::OnMouseLeftDown)
51 EVT_LEFT_UP(wxRibbonBar::OnMouseLeftUp)
52 EVT_MIDDLE_DOWN(wxRibbonBar::OnMouseMiddleDown)
53 EVT_MIDDLE_UP(wxRibbonBar::OnMouseMiddleUp)
54 EVT_MOTION(wxRibbonBar::OnMouseMove)
55 EVT_PAINT(wxRibbonBar::OnPaint)
56 EVT_RIGHT_DOWN(wxRibbonBar::OnMouseRightDown)
57 EVT_RIGHT_UP(wxRibbonBar::OnMouseRightUp)
58 EVT_LEFT_DCLICK(wxRibbonBar::OnMouseDoubleClick)
59 EVT_SIZE(wxRibbonBar::OnSize)
60 EVT_KILL_FOCUS(wxRibbonBar::OnKillFocus)
61 wxEND_EVENT_TABLE()
62
63 void wxRibbonBar::AddPage(wxRibbonPage *page)
64 {
65 wxRibbonPageTabInfo info;
66
67 info.page = page;
68 info.active = false;
69 info.hovered = false;
70 info.highlight = false;
71 info.shown = true;
72 // info.rect not set (intentional)
73
74 wxClientDC dcTemp(this);
75 wxString label;
76 if(m_flags & wxRIBBON_BAR_SHOW_PAGE_LABELS)
77 label = page->GetLabel();
78 wxBitmap icon;
79 if(m_flags & wxRIBBON_BAR_SHOW_PAGE_ICONS)
80 icon = page->GetIcon();
81 m_art->GetBarTabWidth(dcTemp, this, label, icon,
82 &info.ideal_width,
83 &info.small_begin_need_separator_width,
84 &info.small_must_have_separator_width,
85 &info.minimum_width);
86
87 if(m_pages.IsEmpty())
88 {
89 m_tabs_total_width_ideal = info.ideal_width;
90 m_tabs_total_width_minimum = info.minimum_width;
91 }
92 else
93 {
94 int sep = m_art->GetMetric(wxRIBBON_ART_TAB_SEPARATION_SIZE);
95 m_tabs_total_width_ideal += sep + info.ideal_width;
96 m_tabs_total_width_minimum += sep + info.minimum_width;
97 }
98 m_pages.Add(info);
99
100 page->Hide(); // Most likely case is that this new page is not the active tab
101 page->SetArtProvider(m_art);
102
103 if(m_pages.GetCount() == 1)
104 {
105 SetActivePage((size_t)0);
106 }
107 }
108
DismissExpandedPanel()109 bool wxRibbonBar::DismissExpandedPanel()
110 {
111 if(m_current_page == -1)
112 return false;
113 return m_pages.Item(m_current_page).page->DismissExpandedPanel();
114 }
115
116
ShowPanels(wxRibbonDisplayMode mode)117 void wxRibbonBar::ShowPanels(wxRibbonDisplayMode mode)
118 {
119 switch ( mode )
120 {
121 case wxRIBBON_BAR_PINNED:
122 case wxRIBBON_BAR_EXPANDED:
123 m_arePanelsShown = true;
124 break;
125
126 case wxRIBBON_BAR_MINIMIZED:
127 m_arePanelsShown = false;
128 break;
129 }
130
131 SetMinSize(wxSize(GetSize().GetWidth(), DoGetBestSize().GetHeight()));
132 Realise();
133 GetParent()->Layout();
134
135 m_ribbon_state = mode;
136 }
137
138
ShowPanels(bool show)139 void wxRibbonBar::ShowPanels(bool show)
140 {
141 ShowPanels( show ? wxRIBBON_BAR_PINNED : wxRIBBON_BAR_MINIMIZED );
142 }
143
SetWindowStyleFlag(long style)144 void wxRibbonBar::SetWindowStyleFlag(long style)
145 {
146 m_flags = style;
147 if(m_art)
148 m_art->SetFlags(style);
149 }
150
GetWindowStyleFlag() const151 long wxRibbonBar::GetWindowStyleFlag() const
152 {
153 return m_flags;
154 }
155
Realize()156 bool wxRibbonBar::Realize()
157 {
158 bool status = true;
159
160 wxClientDC dcTemp(this);
161 int sep = m_art->GetMetric(wxRIBBON_ART_TAB_SEPARATION_SIZE);
162 size_t numtabs = m_pages.GetCount();
163 bool firstVisible = true;
164 size_t i;
165 for(i = 0; i < numtabs; ++i)
166 {
167 wxRibbonPageTabInfo& info = m_pages.Item(i);
168 if (!info.shown)
169 continue;
170 RepositionPage(info.page);
171 if(!info.page->Realize())
172 {
173 status = false;
174 }
175 wxString label;
176 if(m_flags & wxRIBBON_BAR_SHOW_PAGE_LABELS)
177 label = info.page->GetLabel();
178 wxBitmap icon;
179 if(m_flags & wxRIBBON_BAR_SHOW_PAGE_ICONS)
180 icon = info.page->GetIcon();
181 m_art->GetBarTabWidth(dcTemp, this, label, icon,
182 &info.ideal_width,
183 &info.small_begin_need_separator_width,
184 &info.small_must_have_separator_width,
185 &info.minimum_width);
186
187 if ( firstVisible )
188 {
189 firstVisible = false;
190
191 m_tabs_total_width_ideal = info.ideal_width;
192 m_tabs_total_width_minimum = info.minimum_width;
193 }
194 else
195 {
196 m_tabs_total_width_ideal += sep + info.ideal_width;
197 m_tabs_total_width_minimum += sep + info.minimum_width;
198 }
199 }
200 m_tab_height = m_art->GetTabCtrlHeight(dcTemp, this, m_pages);
201
202 RecalculateMinSize();
203 RecalculateTabSizes();
204 Refresh();
205
206 return status;
207 }
208
OnMouseMove(wxMouseEvent & evt)209 void wxRibbonBar::OnMouseMove(wxMouseEvent& evt)
210 {
211 int x = evt.GetX();
212 int y = evt.GetY();
213 int hovered_page = -1;
214 bool refresh_tabs = false;
215 if(y < m_tab_height)
216 {
217 // It is quite likely that the mouse moved a small amount and is still over the same tab
218 if(m_current_hovered_page != -1 && m_pages.Item((size_t)m_current_hovered_page).rect.Contains(x, y))
219 {
220 hovered_page = m_current_hovered_page;
221 // But be careful, if tabs can be scrolled, then parts of the tab rect may not be valid
222 if(m_tab_scroll_buttons_shown)
223 {
224 if(x >= m_tab_scroll_right_button_rect.GetX() || x < m_tab_scroll_left_button_rect.GetRight())
225 {
226 hovered_page = -1;
227 }
228 }
229 }
230 else
231 {
232 HitTestTabs(evt.GetPosition(), &hovered_page);
233 }
234 }
235 if(hovered_page != m_current_hovered_page)
236 {
237 if(m_current_hovered_page != -1)
238 {
239 m_pages.Item((int)m_current_hovered_page).hovered = false;
240 }
241 m_current_hovered_page = hovered_page;
242 if(m_current_hovered_page != -1)
243 {
244 m_pages.Item((int)m_current_hovered_page).hovered = true;
245 }
246 refresh_tabs = true;
247 }
248 if(m_tab_scroll_buttons_shown)
249 {
250 #define SET_FLAG(variable, flag) \
251 { if(((variable) & (flag)) != (flag)) { variable |= (flag); refresh_tabs = true; }}
252 #define UNSET_FLAG(variable, flag) \
253 { if((variable) & (flag)) { variable &= ~(flag); refresh_tabs = true; }}
254
255 if(m_tab_scroll_left_button_rect.Contains(x, y))
256 SET_FLAG(m_tab_scroll_left_button_state, wxRIBBON_SCROLL_BTN_HOVERED)
257 else
258 UNSET_FLAG(m_tab_scroll_left_button_state, wxRIBBON_SCROLL_BTN_HOVERED)
259
260 if(m_tab_scroll_right_button_rect.Contains(x, y))
261 SET_FLAG(m_tab_scroll_right_button_state, wxRIBBON_SCROLL_BTN_HOVERED)
262 else
263 UNSET_FLAG(m_tab_scroll_right_button_state, wxRIBBON_SCROLL_BTN_HOVERED)
264 #undef SET_FLAG
265 #undef UNSET_FLAG
266 }
267 if(refresh_tabs)
268 {
269 RefreshTabBar();
270 }
271 if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
272 HitTestRibbonButton(m_toggle_button_rect, evt.GetPosition(), m_toggle_button_hovered);
273 if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
274 HitTestRibbonButton(m_help_button_rect, evt.GetPosition(), m_help_button_hovered);
275 }
276
OnMouseLeave(wxMouseEvent & WXUNUSED (evt))277 void wxRibbonBar::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
278 {
279 // The ribbon bar is (usually) at the top of a window, and at least on MSW, the mouse
280 // can leave the window quickly and leave a tab in the hovered state.
281 bool refresh_tabs = false;
282 if(m_current_hovered_page != -1)
283 {
284 m_pages.Item((int)m_current_hovered_page).hovered = false;
285 m_current_hovered_page = -1;
286 refresh_tabs = true;
287 }
288 if(m_tab_scroll_left_button_state & wxRIBBON_SCROLL_BTN_HOVERED)
289 {
290 m_tab_scroll_left_button_state &= ~wxRIBBON_SCROLL_BTN_HOVERED;
291 refresh_tabs = true;
292 }
293 if(m_tab_scroll_right_button_state & wxRIBBON_SCROLL_BTN_HOVERED)
294 {
295 m_tab_scroll_right_button_state &= ~wxRIBBON_SCROLL_BTN_HOVERED;
296 refresh_tabs = true;
297 }
298 if(refresh_tabs)
299 {
300 RefreshTabBar();
301 }
302 if(m_toggle_button_hovered)
303 {
304 m_bar_hovered = false;
305 m_toggle_button_hovered = false;
306 Refresh(false);
307 }
308 if ( m_help_button_hovered )
309 {
310 m_help_button_hovered = false;
311 m_bar_hovered = false;
312 Refresh(false);
313 }
314 }
315
GetPage(int n)316 wxRibbonPage* wxRibbonBar::GetPage(int n)
317 {
318 if(n < 0 || (size_t)n >= m_pages.GetCount())
319 return 0;
320 return m_pages.Item(n).page;
321 }
322
GetPageCount() const323 size_t wxRibbonBar::GetPageCount() const
324 {
325 return m_pages.GetCount();
326 }
327
IsPageShown(size_t page) const328 bool wxRibbonBar::IsPageShown(size_t page) const
329 {
330 if (page >= m_pages.GetCount())
331 return false;
332 return m_pages.Item(page).shown;
333 }
334
ShowPage(size_t page,bool show)335 void wxRibbonBar::ShowPage(size_t page, bool show)
336 {
337 if(page >= m_pages.GetCount())
338 return;
339 m_pages.Item(page).shown = show;
340 }
341
IsPageHighlighted(size_t page) const342 bool wxRibbonBar::IsPageHighlighted(size_t page) const
343 {
344 if (page >= m_pages.GetCount())
345 return false;
346 return m_pages.Item(page).highlight;
347 }
348
AddPageHighlight(size_t page,bool highlight)349 void wxRibbonBar::AddPageHighlight(size_t page, bool highlight)
350 {
351 if(page >= m_pages.GetCount())
352 return;
353 m_pages.Item(page).highlight = highlight;
354 }
355
DeletePage(size_t n)356 void wxRibbonBar::DeletePage(size_t n)
357 {
358 if(n < m_pages.GetCount())
359 {
360 wxRibbonPage *page = m_pages.Item(n).page;
361
362 // Schedule page object for destruction and not destroying directly
363 // as this function can be called in an event handler and page functions
364 // can be called afeter removing.
365 // Like in wxRibbonButtonBar::OnMouseUp
366 if(!wxTheApp->IsScheduledForDestruction(page))
367 {
368 wxTheApp->ScheduleForDestruction(page);
369 }
370
371 m_pages.RemoveAt(n);
372
373 if(m_current_page == static_cast<int>(n))
374 {
375 m_current_page = -1;
376
377 if(m_pages.GetCount() > 0)
378 {
379 if(n >= m_pages.GetCount())
380 {
381 SetActivePage(m_pages.GetCount() - 1);
382 }
383 else
384 {
385 SetActivePage(n - 1);
386 }
387 }
388 }
389 else if(m_current_page > static_cast<int>(n))
390 {
391 m_current_page--;
392 }
393 }
394 }
395
ClearPages()396 void wxRibbonBar::ClearPages()
397 {
398 size_t i;
399 for(i=0; i<m_pages.GetCount(); i++)
400 {
401 wxRibbonPage *page = m_pages.Item(i).page;
402 // Schedule page object for destruction and not destroying directly
403 // as this function can be called in an event handler and page functions
404 // can be called afeter removing.
405 // Like in wxRibbonButtonBar::OnMouseUp
406 if(!wxTheApp->IsScheduledForDestruction(page))
407 {
408 wxTheApp->ScheduleForDestruction(page);
409 }
410 }
411 m_pages.Empty();
412 Realize();
413 m_current_page = -1;
414 Refresh();
415 }
416
SetActivePage(size_t page)417 bool wxRibbonBar::SetActivePage(size_t page)
418 {
419 if(m_current_page == (int)page)
420 {
421 return true;
422 }
423
424 if(page >= m_pages.GetCount())
425 {
426 return false;
427 }
428
429 if(m_current_page != -1)
430 {
431 m_pages.Item((size_t)m_current_page).active = false;
432 m_pages.Item((size_t)m_current_page).page->Hide();
433 }
434 m_current_page = (int)page;
435 m_pages.Item(page).active = true;
436 m_pages.Item(page).shown = true;
437 {
438 wxRibbonPage* wnd = m_pages.Item(page).page;
439 RepositionPage(wnd);
440 wnd->Layout();
441 wnd->Show();
442 }
443 Refresh();
444
445 return true;
446 }
447
SetActivePage(wxRibbonPage * page)448 bool wxRibbonBar::SetActivePage(wxRibbonPage* page)
449 {
450 size_t numpages = m_pages.GetCount();
451 size_t i;
452 for(i = 0; i < numpages; ++i)
453 {
454 if(m_pages.Item(i).page == page)
455 {
456 return SetActivePage(i);
457 }
458 }
459 return false;
460 }
461
GetPageNumber(wxRibbonPage * page) const462 int wxRibbonBar::GetPageNumber(wxRibbonPage* page) const
463 {
464 size_t numpages = m_pages.GetCount();
465 for(size_t i = 0; i < numpages; ++i)
466 {
467 if(m_pages.Item(i).page == page)
468 {
469 return i;
470 }
471 }
472 return wxNOT_FOUND;
473 }
474
475
GetActivePage() const476 int wxRibbonBar::GetActivePage() const
477 {
478 return m_current_page;
479 }
480
SetTabCtrlMargins(int left,int right)481 void wxRibbonBar::SetTabCtrlMargins(int left, int right)
482 {
483 m_tab_margin_left = left;
484 m_tab_margin_right = right;
485
486 RecalculateTabSizes();
487 }
488
489 struct PageComparedBySmallWidthAsc
490 {
PageComparedBySmallWidthAscPageComparedBySmallWidthAsc491 explicit PageComparedBySmallWidthAsc(wxRibbonPageTabInfo* page)
492 : m_page(page)
493 {
494 }
495
operator <PageComparedBySmallWidthAsc496 bool operator<(const PageComparedBySmallWidthAsc& other) const
497 {
498 return m_page->small_must_have_separator_width
499 < other.m_page->small_must_have_separator_width;
500 }
501
502 wxRibbonPageTabInfo *m_page;
503 };
504
RecalculateTabSizes()505 void wxRibbonBar::RecalculateTabSizes()
506 {
507 size_t numtabs = m_pages.GetCount();
508
509 if(numtabs == 0)
510 return;
511
512 int width = GetSize().GetWidth() - m_tab_margin_left - m_tab_margin_right;
513 int tabsep = m_art->GetMetric(wxRIBBON_ART_TAB_SEPARATION_SIZE);
514 int x = m_tab_margin_left;
515 const int y = 0;
516
517 if(width >= m_tabs_total_width_ideal)
518 {
519 // Simple case: everything at ideal width
520 size_t i;
521 for(i = 0; i < numtabs; ++i)
522 {
523 wxRibbonPageTabInfo& info = m_pages.Item(i);
524 if (!info.shown)
525 continue;
526 info.rect.x = x;
527 info.rect.y = y;
528 info.rect.width = info.ideal_width;
529 info.rect.height = m_tab_height;
530 x += info.rect.width + tabsep;
531 }
532 m_tab_scroll_buttons_shown = false;
533 m_tab_scroll_left_button_rect.SetWidth(0);
534 m_tab_scroll_right_button_rect.SetWidth(0);
535 }
536 else if(width < m_tabs_total_width_minimum)
537 {
538 // Simple case: everything minimum with scrollbar
539 size_t i;
540 for(i = 0; i < numtabs; ++i)
541 {
542 wxRibbonPageTabInfo& info = m_pages.Item(i);
543 if (!info.shown)
544 continue;
545 info.rect.x = x;
546 info.rect.y = y;
547 info.rect.width = info.minimum_width;
548 info.rect.height = m_tab_height;
549 x += info.rect.width + tabsep;
550 }
551 if(!m_tab_scroll_buttons_shown)
552 {
553 m_tab_scroll_left_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
554 m_tab_scroll_right_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
555 m_tab_scroll_buttons_shown = true;
556 }
557 {
558 wxClientDC temp_dc(this);
559 int right_button_pos = GetClientSize().GetWidth() - m_tab_margin_right - m_tab_scroll_right_button_rect.GetWidth();
560 if ( right_button_pos < m_tab_margin_left )
561 right_button_pos = m_tab_margin_left;
562
563 m_tab_scroll_left_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_LEFT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
564 m_tab_scroll_left_button_rect.SetHeight(m_tab_height);
565 m_tab_scroll_left_button_rect.SetX(m_tab_margin_left);
566 m_tab_scroll_left_button_rect.SetY(0);
567 m_tab_scroll_right_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_RIGHT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
568 m_tab_scroll_right_button_rect.SetHeight(m_tab_height);
569 m_tab_scroll_right_button_rect.SetX(right_button_pos);
570 m_tab_scroll_right_button_rect.SetY(0);
571 }
572 if(m_tab_scroll_amount == 0)
573 {
574 m_tab_scroll_left_button_rect.SetWidth(0);
575 }
576 else if(m_tab_scroll_amount + width >= m_tabs_total_width_minimum)
577 {
578 m_tab_scroll_amount = m_tabs_total_width_minimum - width;
579 m_tab_scroll_right_button_rect.SetX(m_tab_scroll_right_button_rect.GetX() + m_tab_scroll_right_button_rect.GetWidth());
580 m_tab_scroll_right_button_rect.SetWidth(0);
581 }
582 for(i = 0; i < numtabs; ++i)
583 {
584 wxRibbonPageTabInfo& info = m_pages.Item(i);
585 if (!info.shown)
586 continue;
587 info.rect.x -= m_tab_scroll_amount;
588 }
589 }
590 else
591 {
592 m_tab_scroll_buttons_shown = false;
593 m_tab_scroll_left_button_rect.SetWidth(0);
594 m_tab_scroll_right_button_rect.SetWidth(0);
595 // Complex case: everything sized such that: minimum <= width < ideal
596 /*
597 Strategy:
598 1) Uniformly reduce all tab widths from ideal to small_must_have_separator_width
599 2) Reduce the largest tab by 1 pixel, repeating until all tabs are same width (or at minimum)
600 3) Uniformly reduce all tabs down to their minimum width
601 */
602 int smallest_tab_width = INT_MAX;
603 int total_small_width = tabsep * (numtabs - 1);
604 size_t i;
605 for(i = 0; i < numtabs; ++i)
606 {
607 wxRibbonPageTabInfo& info = m_pages.Item(i);
608 if (!info.shown)
609 continue;
610 if(info.small_must_have_separator_width < smallest_tab_width)
611 {
612 smallest_tab_width = info.small_must_have_separator_width;
613 }
614 total_small_width += info.small_must_have_separator_width;
615 }
616 if(width >= total_small_width)
617 {
618 // Do (1)
619 int total_delta = m_tabs_total_width_ideal - total_small_width;
620 total_small_width -= tabsep * (numtabs - 1);
621 width -= tabsep * (numtabs - 1);
622 for(i = 0; i < numtabs; ++i)
623 {
624 wxRibbonPageTabInfo& info = m_pages.Item(i);
625 if (!info.shown)
626 continue;
627 int delta = info.ideal_width - info.small_must_have_separator_width;
628 info.rect.x = x;
629 info.rect.y = y;
630 info.rect.width = info.small_must_have_separator_width + delta * (width - total_small_width) / total_delta;
631 info.rect.height = m_tab_height;
632
633 x += info.rect.width + tabsep;
634 total_delta -= delta;
635 total_small_width -= info.small_must_have_separator_width;
636 width -= info.rect.width;
637 }
638 }
639 else
640 {
641 total_small_width = tabsep * (numtabs - 1);
642 for(i = 0; i < numtabs; ++i)
643 {
644 wxRibbonPageTabInfo& info = m_pages.Item(i);
645 if (!info.shown)
646 continue;
647 if(info.minimum_width < smallest_tab_width)
648 {
649 total_small_width += smallest_tab_width;
650 }
651 else
652 {
653 total_small_width += info.minimum_width;
654 }
655 }
656 if(width >= total_small_width)
657 {
658 // Do (2)
659 wxVector<PageComparedBySmallWidthAsc> sorted_pages;
660 sorted_pages.reserve(numtabs);
661 for ( i = 0; i < numtabs; ++i )
662 sorted_pages.push_back(PageComparedBySmallWidthAsc(&m_pages.Item(i)));
663
664 wxVectorSort(sorted_pages);
665 width -= tabsep * (numtabs - 1);
666 for(i = 0; i < numtabs; ++i)
667 {
668 wxRibbonPageTabInfo* info = sorted_pages[i].m_page;
669 if (!info->shown)
670 continue;
671 if(info->small_must_have_separator_width * (int)(numtabs - i) <= width)
672 {
673 info->rect.width = info->small_must_have_separator_width;
674 }
675 else
676 {
677 info->rect.width = width / (numtabs - i);
678 }
679 width -= info->rect.width;
680 }
681 for(i = 0; i < numtabs; ++i)
682 {
683 wxRibbonPageTabInfo& info = m_pages.Item(i);
684 if (!info.shown)
685 continue;
686 info.rect.x = x;
687 info.rect.y = y;
688 info.rect.height = m_tab_height;
689 x += info.rect.width + tabsep;
690 }
691 }
692 else
693 {
694 // Do (3)
695 total_small_width = (smallest_tab_width + tabsep) * numtabs - tabsep;
696 int total_delta = total_small_width - m_tabs_total_width_minimum;
697 total_small_width = m_tabs_total_width_minimum - tabsep * (numtabs - 1);
698 width -= tabsep * (numtabs - 1);
699 for(i = 0; i < numtabs; ++i)
700 {
701 wxRibbonPageTabInfo& info = m_pages.Item(i);
702 if (!info.shown)
703 continue;
704 int delta = smallest_tab_width - info.minimum_width;
705 info.rect.x = x;
706 info.rect.y = y;
707 info.rect.width = info.minimum_width + delta * (width - total_small_width) / total_delta;
708 info.rect.height = m_tab_height;
709
710 x += info.rect.width + tabsep;
711 total_delta -= delta;
712 total_small_width -= info.minimum_width;
713 width -= info.rect.width;
714 }
715 }
716 }
717 }
718 }
719
wxRibbonBar()720 wxRibbonBar::wxRibbonBar()
721 {
722 m_flags = 0;
723 m_tabs_total_width_ideal = 0;
724 m_tabs_total_width_minimum = 0;
725 m_tab_margin_left = 0;
726 m_tab_margin_right = 0;
727 m_tab_height = 0;
728 m_tab_scroll_amount = 0;
729 m_current_page = -1;
730 m_current_hovered_page = -1;
731 m_tab_scroll_left_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
732 m_tab_scroll_right_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
733 m_tab_scroll_buttons_shown = false;
734 m_arePanelsShown = true;
735 m_help_button_hovered = false;
736
737 }
738
wxRibbonBar(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)739 wxRibbonBar::wxRibbonBar(wxWindow* parent,
740 wxWindowID id,
741 const wxPoint& pos,
742 const wxSize& size,
743 long style)
744 : wxRibbonControl(parent, id, pos, size, wxBORDER_NONE)
745 {
746 CommonInit(style);
747 }
748
~wxRibbonBar()749 wxRibbonBar::~wxRibbonBar()
750 {
751 SetArtProvider(NULL);
752
753 for ( size_t n = 0; n < m_image_lists.size(); ++n )
754 {
755 delete m_image_lists[n];
756 }
757 }
758
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)759 bool wxRibbonBar::Create(wxWindow* parent,
760 wxWindowID id,
761 const wxPoint& pos,
762 const wxSize& size,
763 long style)
764 {
765 if(!wxRibbonControl::Create(parent, id, pos, size, wxBORDER_NONE))
766 return false;
767
768 CommonInit(style);
769
770 return true;
771 }
772
CommonInit(long style)773 void wxRibbonBar::CommonInit(long style)
774 {
775 SetName(wxT("wxRibbonBar"));
776
777 m_flags = style;
778 m_tabs_total_width_ideal = 0;
779 m_tabs_total_width_minimum = 0;
780 m_tab_margin_left = 50;
781 m_tab_margin_right = 20;
782 if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
783 m_tab_margin_right += 20;
784 if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
785 m_tab_margin_right += 20;
786 m_tab_height = 20; // initial guess
787 m_tab_scroll_amount = 0;
788 m_current_page = -1;
789 m_current_hovered_page = -1;
790 m_tab_scroll_left_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
791 m_tab_scroll_right_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
792 m_tab_scroll_buttons_shown = false;
793 m_arePanelsShown = true;
794
795 if(m_art == NULL)
796 {
797 SetArtProvider(new wxRibbonDefaultArtProvider);
798 }
799 SetBackgroundStyle(wxBG_STYLE_PAINT);
800
801 m_toggle_button_hovered = false;
802 m_bar_hovered = false;
803
804 m_ribbon_state = wxRIBBON_BAR_PINNED;
805 }
806
GetButtonImageList(wxSize size)807 wxImageList* wxRibbonBar::GetButtonImageList(wxSize size)
808 {
809 for ( size_t n = 0; n < m_image_lists.size(); ++n )
810 {
811 if ( m_image_lists[n]->GetSize() == size )
812 return m_image_lists[n];
813 }
814
815 wxImageList* const
816 il = new wxImageList(size.GetWidth(), size.GetHeight(), /*mask*/false);
817 m_image_lists.push_back(il);
818
819 return il;
820 }
821
SetArtProvider(wxRibbonArtProvider * art)822 void wxRibbonBar::SetArtProvider(wxRibbonArtProvider* art)
823 {
824 wxRibbonArtProvider *old = m_art;
825 m_art = art;
826
827 if(art)
828 {
829 art->SetFlags(m_flags);
830 }
831 size_t numpages = m_pages.GetCount();
832 size_t i;
833 for(i = 0; i < numpages; ++i)
834 {
835 wxRibbonPage *page = m_pages.Item(i).page;
836 if(page->GetArtProvider() != art)
837 {
838 page->SetArtProvider(art);
839 }
840 }
841
842 delete old;
843 }
844
OnPaint(wxPaintEvent & WXUNUSED (evt))845 void wxRibbonBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
846 {
847 wxAutoBufferedPaintDC dc(this);
848
849 if(GetUpdateRegion().Contains(0, 0, GetClientSize().GetWidth(), m_tab_height) == wxOutRegion)
850 {
851 // Nothing to do in the tab area, and the page area is handled by the active page
852 return;
853 }
854
855 DoEraseBackground(dc);
856
857 if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
858 m_help_button_rect = m_art->GetRibbonHelpButtonArea(GetSize());
859 if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
860 m_toggle_button_rect = m_art->GetBarToggleButtonArea(GetSize());
861
862 size_t numtabs = m_pages.GetCount();
863 double sep_visibility = 0.0;
864 bool draw_sep = false;
865 wxRect tabs_rect(m_tab_margin_left, 0, GetClientSize().GetWidth() - m_tab_margin_left - m_tab_margin_right, m_tab_height);
866 if(m_tab_scroll_buttons_shown)
867 {
868 tabs_rect.x += m_tab_scroll_left_button_rect.GetWidth();
869 tabs_rect.width -= m_tab_scroll_left_button_rect.GetWidth() + m_tab_scroll_right_button_rect.GetWidth();
870 }
871 size_t i;
872 for(i = 0; i < numtabs; ++i)
873 {
874 wxRibbonPageTabInfo& info = m_pages.Item(i);
875 if (!info.shown)
876 continue;
877
878 dc.DestroyClippingRegion();
879 if(m_tab_scroll_buttons_shown)
880 {
881 if(!tabs_rect.Intersects(info.rect))
882 continue;
883 dc.SetClippingRegion(tabs_rect);
884 }
885 dc.SetClippingRegion(info.rect);
886 m_art->DrawTab(dc, this, info);
887
888 if(info.rect.width < info.small_begin_need_separator_width)
889 {
890 draw_sep = true;
891 if(info.rect.width < info.small_must_have_separator_width)
892 {
893 sep_visibility += 1.0;
894 }
895 else
896 {
897 sep_visibility += (double)(info.small_begin_need_separator_width - info.rect.width) / (double)(info.small_begin_need_separator_width - info.small_must_have_separator_width);
898 }
899 }
900 }
901 if(draw_sep)
902 {
903 wxRect rect = m_pages.Item(0).rect;
904 rect.width = m_art->GetMetric(wxRIBBON_ART_TAB_SEPARATION_SIZE);
905 sep_visibility /= (double)numtabs;
906 for(i = 0; i < numtabs - 1; ++i)
907 {
908 wxRibbonPageTabInfo& info = m_pages.Item(i);
909 if (!info.shown)
910 continue;
911 rect.x = info.rect.x + info.rect.width;
912
913 if(m_tab_scroll_buttons_shown && !tabs_rect.Intersects(rect))
914 {
915 continue;
916 }
917
918 dc.DestroyClippingRegion();
919 dc.SetClippingRegion(rect);
920 m_art->DrawTabSeparator(dc, this, rect, sep_visibility);
921 }
922 }
923 if(m_tab_scroll_buttons_shown)
924 {
925 if(m_tab_scroll_left_button_rect.GetWidth() != 0)
926 {
927 dc.DestroyClippingRegion();
928 dc.SetClippingRegion(m_tab_scroll_left_button_rect);
929 m_art->DrawScrollButton(dc, this, m_tab_scroll_left_button_rect, wxRIBBON_SCROLL_BTN_LEFT | m_tab_scroll_left_button_state | wxRIBBON_SCROLL_BTN_FOR_TABS);
930 }
931 if(m_tab_scroll_right_button_rect.GetWidth() != 0)
932 {
933 dc.DestroyClippingRegion();
934 dc.SetClippingRegion(m_tab_scroll_right_button_rect);
935 m_art->DrawScrollButton(dc, this, m_tab_scroll_right_button_rect, wxRIBBON_SCROLL_BTN_RIGHT | m_tab_scroll_right_button_state | wxRIBBON_SCROLL_BTN_FOR_TABS);
936 }
937 }
938
939 if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
940 m_art->DrawHelpButton(dc, this, m_help_button_rect);
941 if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
942 m_art->DrawToggleButton(dc, this, m_toggle_button_rect, m_ribbon_state);
943
944 }
945
OnEraseBackground(wxEraseEvent & WXUNUSED (evt))946 void wxRibbonBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
947 {
948 // Background painting done in main paint handler to reduce screen flicker
949 }
950
DoEraseBackground(wxDC & dc)951 void wxRibbonBar::DoEraseBackground(wxDC& dc)
952 {
953 wxRect tabs(GetSize());
954 tabs.height = m_tab_height;
955 m_art->DrawTabCtrlBackground(dc, this, tabs);
956 }
957
OnSize(wxSizeEvent & evt)958 void wxRibbonBar::OnSize(wxSizeEvent& evt)
959 {
960 RecalculateTabSizes();
961 if(m_current_page != -1)
962 {
963 RepositionPage(m_pages.Item(m_current_page).page);
964 }
965 RefreshTabBar();
966
967 evt.Skip();
968 }
969
RepositionPage(wxRibbonPage * page)970 void wxRibbonBar::RepositionPage(wxRibbonPage *page)
971 {
972 int w, h;
973 GetSize(&w, &h);
974 page->SetSizeWithScrollButtonAdjustment(0, m_tab_height, w, h - m_tab_height);
975 }
976
HitTestTabs(wxPoint position,int * index)977 wxRibbonPageTabInfo* wxRibbonBar::HitTestTabs(wxPoint position, int* index)
978 {
979 wxRect tabs_rect(m_tab_margin_left, 0, GetClientSize().GetWidth() - m_tab_margin_left - m_tab_margin_right, m_tab_height);
980 if(m_tab_scroll_buttons_shown)
981 {
982 tabs_rect.SetX(tabs_rect.GetX() + m_tab_scroll_left_button_rect.GetWidth());
983 tabs_rect.SetWidth(tabs_rect.GetWidth() - m_tab_scroll_left_button_rect.GetWidth() - m_tab_scroll_right_button_rect.GetWidth());
984 }
985 if(tabs_rect.Contains(position))
986 {
987 size_t numtabs = m_pages.GetCount();
988 size_t i;
989 for(i = 0; i < numtabs; ++i)
990 {
991 wxRibbonPageTabInfo& info = m_pages.Item(i);
992 if (!info.shown)
993 continue;
994 if(info.rect.Contains(position))
995 {
996 if(index != NULL)
997 {
998 *index = (int)i;
999 }
1000 return &info;
1001 }
1002 }
1003 }
1004 if(index != NULL)
1005 {
1006 *index = -1;
1007 }
1008 return NULL;
1009 }
1010
OnMouseLeftDown(wxMouseEvent & evt)1011 void wxRibbonBar::OnMouseLeftDown(wxMouseEvent& evt)
1012 {
1013 wxRibbonPageTabInfo *tab = HitTestTabs(evt.GetPosition());
1014 SetFocus();
1015 if ( tab )
1016 {
1017 if ( m_ribbon_state == wxRIBBON_BAR_MINIMIZED )
1018 {
1019 ShowPanels(wxRIBBON_BAR_EXPANDED);
1020 }
1021 else if ( (tab == &m_pages.Item(m_current_page)) && (m_ribbon_state == wxRIBBON_BAR_EXPANDED) )
1022 {
1023 HidePanels();
1024 }
1025 }
1026 else
1027 {
1028 if ( m_ribbon_state == wxRIBBON_BAR_EXPANDED )
1029 {
1030 HidePanels();
1031 }
1032 }
1033 if(tab && tab != &m_pages.Item(m_current_page))
1034 {
1035 wxRibbonBarEvent query(wxEVT_RIBBONBAR_PAGE_CHANGING, GetId(), tab->page);
1036 query.SetEventObject(this);
1037 ProcessWindowEvent(query);
1038 if(query.IsAllowed())
1039 {
1040 SetActivePage(query.GetPage());
1041
1042 wxRibbonBarEvent notification(wxEVT_RIBBONBAR_PAGE_CHANGED, GetId(), m_pages.Item(m_current_page).page);
1043 notification.SetEventObject(this);
1044 ProcessWindowEvent(notification);
1045 }
1046 }
1047 else if(tab == NULL)
1048 {
1049 if(m_tab_scroll_left_button_rect.Contains(evt.GetPosition()))
1050 {
1051 m_tab_scroll_left_button_state |= wxRIBBON_SCROLL_BTN_ACTIVE | wxRIBBON_SCROLL_BTN_HOVERED;
1052 RefreshTabBar();
1053 }
1054 else if(m_tab_scroll_right_button_rect.Contains(evt.GetPosition()))
1055 {
1056 m_tab_scroll_right_button_state |= wxRIBBON_SCROLL_BTN_ACTIVE | wxRIBBON_SCROLL_BTN_HOVERED;
1057 RefreshTabBar();
1058 }
1059 }
1060
1061 wxPoint position = evt.GetPosition();
1062
1063 if(position.x >= 0 && position.y >= 0)
1064 {
1065 wxSize size = GetSize();
1066 if(position.x < size.GetWidth() && position.y < size.GetHeight())
1067 {
1068 if(m_toggle_button_rect.Contains(position))
1069 {
1070 ShowPanels(ArePanelsShown() ? wxRIBBON_BAR_MINIMIZED : wxRIBBON_BAR_PINNED);
1071 wxRibbonBarEvent event(wxEVT_RIBBONBAR_TOGGLED, GetId());
1072 event.SetEventObject(this);
1073 ProcessWindowEvent(event);
1074 }
1075 if ( m_help_button_rect.Contains(position) )
1076 {
1077 wxRibbonBarEvent event(wxEVT_RIBBONBAR_HELP_CLICK, GetId());
1078 event.SetEventObject(this);
1079 ProcessWindowEvent(event);
1080 }
1081 }
1082 }
1083 }
1084
OnMouseLeftUp(wxMouseEvent & WXUNUSED (evt))1085 void wxRibbonBar::OnMouseLeftUp(wxMouseEvent& WXUNUSED(evt))
1086 {
1087 if(!m_tab_scroll_buttons_shown)
1088 {
1089 return;
1090 }
1091
1092 int amount = 0;
1093 if(m_tab_scroll_left_button_state & wxRIBBON_SCROLL_BTN_ACTIVE)
1094 {
1095 amount = -1;
1096 }
1097 else if(m_tab_scroll_right_button_state & wxRIBBON_SCROLL_BTN_ACTIVE)
1098 {
1099 amount = 1;
1100 }
1101 if(amount != 0)
1102 {
1103 m_tab_scroll_left_button_state &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
1104 m_tab_scroll_right_button_state &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
1105 ScrollTabBar(amount * 8);
1106 }
1107 }
1108
ScrollTabBar(int amount)1109 void wxRibbonBar::ScrollTabBar(int amount)
1110 {
1111 bool show_left = true;
1112 bool show_right = true;
1113 if(m_tab_scroll_amount + amount <= 0)
1114 {
1115 amount = -m_tab_scroll_amount;
1116 show_left = false;
1117 }
1118 else if(m_tab_scroll_amount + amount + (GetClientSize().GetWidth() - m_tab_margin_left - m_tab_margin_right) >= m_tabs_total_width_minimum)
1119 {
1120 amount = m_tabs_total_width_minimum - m_tab_scroll_amount - (GetClientSize().GetWidth() - m_tab_margin_left - m_tab_margin_right);
1121 show_right = false;
1122 }
1123 if(amount == 0)
1124 {
1125 return;
1126 }
1127 m_tab_scroll_amount += amount;
1128 size_t numtabs = m_pages.GetCount();
1129 size_t i;
1130 for(i = 0; i < numtabs; ++i)
1131 {
1132 wxRibbonPageTabInfo& info = m_pages.Item(i);
1133 if (!info.shown)
1134 continue;
1135 info.rect.SetX(info.rect.GetX() - amount);
1136 }
1137 if(show_right != (m_tab_scroll_right_button_rect.GetWidth() != 0) ||
1138 show_left != (m_tab_scroll_left_button_rect.GetWidth() != 0))
1139 {
1140 wxClientDC temp_dc(this);
1141 if(show_left)
1142 {
1143 m_tab_scroll_left_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_LEFT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
1144 }
1145 else
1146 {
1147 m_tab_scroll_left_button_rect.SetWidth(0);
1148 }
1149
1150 if(show_right)
1151 {
1152 if(m_tab_scroll_right_button_rect.GetWidth() == 0)
1153 {
1154 m_tab_scroll_right_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_RIGHT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
1155 m_tab_scroll_right_button_rect.SetX(m_tab_scroll_right_button_rect.GetX() - m_tab_scroll_right_button_rect.GetWidth());
1156 }
1157 }
1158 else
1159 {
1160 if(m_tab_scroll_right_button_rect.GetWidth() != 0)
1161 {
1162 m_tab_scroll_right_button_rect.SetX(m_tab_scroll_right_button_rect.GetX() + m_tab_scroll_right_button_rect.GetWidth());
1163 m_tab_scroll_right_button_rect.SetWidth(0);
1164 }
1165 }
1166 }
1167
1168 RefreshTabBar();
1169 }
1170
RefreshTabBar()1171 void wxRibbonBar::RefreshTabBar()
1172 {
1173 wxRect tab_rect(0, 0, GetClientSize().GetWidth(), m_tab_height);
1174 Refresh(false, &tab_rect);
1175 }
1176
OnMouseMiddleDown(wxMouseEvent & evt)1177 void wxRibbonBar::OnMouseMiddleDown(wxMouseEvent& evt)
1178 {
1179 DoMouseButtonCommon(evt, wxEVT_RIBBONBAR_TAB_MIDDLE_DOWN);
1180 }
1181
OnMouseMiddleUp(wxMouseEvent & evt)1182 void wxRibbonBar::OnMouseMiddleUp(wxMouseEvent& evt)
1183 {
1184 DoMouseButtonCommon(evt, wxEVT_RIBBONBAR_TAB_MIDDLE_UP);
1185 }
1186
OnMouseRightDown(wxMouseEvent & evt)1187 void wxRibbonBar::OnMouseRightDown(wxMouseEvent& evt)
1188 {
1189 DoMouseButtonCommon(evt, wxEVT_RIBBONBAR_TAB_RIGHT_DOWN);
1190 }
1191
OnMouseRightUp(wxMouseEvent & evt)1192 void wxRibbonBar::OnMouseRightUp(wxMouseEvent& evt)
1193 {
1194 DoMouseButtonCommon(evt, wxEVT_RIBBONBAR_TAB_RIGHT_UP);
1195 }
1196
OnMouseDoubleClick(wxMouseEvent & evt)1197 void wxRibbonBar::OnMouseDoubleClick(wxMouseEvent& evt)
1198 {
1199 wxRibbonPageTabInfo *tab = HitTestTabs(evt.GetPosition());
1200 SetFocus();
1201 if ( tab && tab == &m_pages.Item(m_current_page) )
1202 {
1203 if ( m_ribbon_state == wxRIBBON_BAR_PINNED )
1204 {
1205 HidePanels();
1206 }
1207 else
1208 {
1209 ShowPanels(wxRIBBON_BAR_PINNED);
1210 }
1211 }
1212 }
1213
DoMouseButtonCommon(wxMouseEvent & evt,wxEventType tab_event_type)1214 void wxRibbonBar::DoMouseButtonCommon(wxMouseEvent& evt, wxEventType tab_event_type)
1215 {
1216 wxRibbonPageTabInfo *tab = HitTestTabs(evt.GetPosition());
1217 if(tab)
1218 {
1219 wxRibbonBarEvent notification(tab_event_type, GetId(), tab->page);
1220 notification.SetEventObject(this);
1221 ProcessWindowEvent(notification);
1222 }
1223 }
1224
RecalculateMinSize()1225 void wxRibbonBar::RecalculateMinSize()
1226 {
1227 wxSize min_size(wxDefaultCoord, wxDefaultCoord);
1228 size_t numtabs = m_pages.GetCount();
1229 if(numtabs != 0)
1230 {
1231 min_size = m_pages.Item(0).page->GetMinSize();
1232
1233 size_t i;
1234 for(i = 1; i < numtabs; ++i)
1235 {
1236 wxRibbonPageTabInfo& info = m_pages.Item(i);
1237 if (!info.shown)
1238 continue;
1239 wxSize page_min = info.page->GetMinSize();
1240
1241 min_size.x = wxMax(min_size.x, page_min.x);
1242 min_size.y = wxMax(min_size.y, page_min.y);
1243 }
1244 }
1245 if(min_size.y != wxDefaultCoord)
1246 {
1247 // TODO: Decide on best course of action when min height is unspecified
1248 // - should we specify it to the tab minimum, or leave it unspecified?
1249 min_size.IncBy(0, m_tab_height);
1250 }
1251
1252 m_minWidth = min_size.GetWidth();
1253 m_minHeight = m_arePanelsShown ? min_size.GetHeight() : m_tab_height;
1254 }
1255
DoGetBestSize() const1256 wxSize wxRibbonBar::DoGetBestSize() const
1257 {
1258 wxSize best(0, 0);
1259 if(m_current_page != -1)
1260 {
1261 best = m_pages.Item(m_current_page).page->GetBestSize();
1262 }
1263 if(best.GetHeight() == wxDefaultCoord)
1264 {
1265 best.SetHeight(m_tab_height);
1266 }
1267 else
1268 {
1269 best.IncBy(0, m_tab_height);
1270 }
1271 if(!m_arePanelsShown)
1272 {
1273 best.SetHeight(m_tab_height);
1274 }
1275 return best;
1276 }
1277
HitTestRibbonButton(const wxRect & rect,const wxPoint & position,bool & hover_flag)1278 void wxRibbonBar::HitTestRibbonButton(const wxRect& rect, const wxPoint& position, bool &hover_flag)
1279 {
1280 bool hovered = false;
1281 if(position.x >= 0 && position.y >= 0)
1282 {
1283 wxSize size = GetSize();
1284 if(position.x < size.GetWidth() && position.y < size.GetHeight())
1285 {
1286 hovered = true;
1287 }
1288 }
1289 if(hovered)
1290 {
1291 bool toggle_button_hovered;
1292 toggle_button_hovered = rect.Contains(position);
1293
1294 if ( hovered != m_bar_hovered || toggle_button_hovered != hover_flag )
1295 {
1296 m_bar_hovered = hovered;
1297 hover_flag = toggle_button_hovered;
1298 Refresh(false);
1299 }
1300 }
1301 }
1302
HideIfExpanded()1303 void wxRibbonBar::HideIfExpanded()
1304 {
1305 if ( m_ribbon_state == wxRIBBON_BAR_EXPANDED)
1306 HidePanels();
1307 }
1308
OnKillFocus(wxFocusEvent & WXUNUSED (evt))1309 void wxRibbonBar::OnKillFocus(wxFocusEvent& WXUNUSED(evt))
1310 {
1311 HideIfExpanded();
1312 }
1313
1314 #endif // wxUSE_RIBBON
1315