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