1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/ribbon/buttonbar.cpp
3 // Purpose: Ribbon control similar to a tool bar
4 // Author: Peter Cawley
7 // Copyright: (C) Peter Cawley
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
19 #include "wx/ribbon/panel.h"
20 #include "wx/ribbon/buttonbar.h"
21 #include "wx/ribbon/art.h"
22 #include "wx/dcbuffer.h"
28 #include "wx/msw/private.h"
31 wxDEFINE_EVENT(wxEVT_RIBBONBUTTONBAR_CLICKED
, wxRibbonButtonBarEvent
);
32 wxDEFINE_EVENT(wxEVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED
, wxRibbonButtonBarEvent
);
34 IMPLEMENT_DYNAMIC_CLASS(wxRibbonButtonBarEvent
, wxCommandEvent
)
35 IMPLEMENT_CLASS(wxRibbonButtonBar
, wxRibbonControl
)
37 BEGIN_EVENT_TABLE(wxRibbonButtonBar
, wxRibbonControl
)
38 EVT_ERASE_BACKGROUND(wxRibbonButtonBar::OnEraseBackground
)
39 EVT_ENTER_WINDOW(wxRibbonButtonBar::OnMouseEnter
)
40 EVT_LEAVE_WINDOW(wxRibbonButtonBar::OnMouseLeave
)
41 EVT_MOTION(wxRibbonButtonBar::OnMouseMove
)
42 EVT_PAINT(wxRibbonButtonBar::OnPaint
)
43 EVT_SIZE(wxRibbonButtonBar::OnSize
)
44 EVT_LEFT_DOWN(wxRibbonButtonBar::OnMouseDown
)
45 EVT_LEFT_UP(wxRibbonButtonBar::OnMouseUp
)
48 class wxRibbonButtonBarButtonSizeInfo
54 wxRect dropdown_region
;
57 class wxRibbonButtonBarButtonInstance
61 wxRibbonButtonBarButtonBase
* base
;
62 wxRibbonButtonBarButtonState size
;
65 class wxRibbonButtonBarButtonBase
68 wxRibbonButtonBarButtonInstance
NewInstance()
70 wxRibbonButtonBarButtonInstance i
;
75 wxRibbonButtonBarButtonState
GetLargestSize()
77 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_LARGE
].is_supported
)
78 return wxRIBBON_BUTTONBAR_BUTTON_LARGE
;
79 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
)
80 return wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
;
81 wxASSERT(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
);
82 return wxRIBBON_BUTTONBAR_BUTTON_SMALL
;
86 wxRibbonButtonBarButtonState
* size
, int n
= 1)
92 case wxRIBBON_BUTTONBAR_BUTTON_LARGE
:
93 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
)
95 *size
= wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
;
98 case wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
:
99 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
)
101 *size
= wxRIBBON_BUTTONBAR_BUTTON_SMALL
;
104 case wxRIBBON_BUTTONBAR_BUTTON_SMALL
:
113 wxString help_string
;
114 wxBitmap bitmap_large
;
115 wxBitmap bitmap_large_disabled
;
116 wxBitmap bitmap_small
;
117 wxBitmap bitmap_small_disabled
;
118 wxRibbonButtonBarButtonSizeInfo sizes
[3];
119 wxClientDataContainer client_data
;
121 wxRibbonButtonKind kind
;
125 WX_DECLARE_OBJARRAY(wxRibbonButtonBarButtonInstance
, wxArrayRibbonButtonBarButtonInstance
);
126 #include "wx/arrimpl.cpp"
127 WX_DEFINE_OBJARRAY(wxArrayRibbonButtonBarButtonInstance
)
129 class wxRibbonButtonBarLayout
133 wxArrayRibbonButtonBarButtonInstance buttons
;
135 void CalculateOverallSize()
137 overall_size
= wxSize(0, 0);
138 size_t btn_count
= buttons
.Count();
140 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
142 wxRibbonButtonBarButtonInstance
& instance
= buttons
.Item(btn_i
);
143 wxSize size
= instance
.base
->sizes
[instance
.size
].size
;
144 int right
= instance
.position
.x
+ size
.GetWidth();
145 int bottom
= instance
.position
.y
+ size
.GetHeight();
146 if(right
> overall_size
.GetWidth())
148 overall_size
.SetWidth(right
);
150 if(bottom
> overall_size
.GetHeight())
152 overall_size
.SetHeight(bottom
);
157 wxRibbonButtonBarButtonInstance
* FindSimilarInstance(
158 wxRibbonButtonBarButtonInstance
* inst
)
164 size_t btn_count
= buttons
.Count();
166 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
168 wxRibbonButtonBarButtonInstance
& instance
= buttons
.Item(btn_i
);
169 if(instance
.base
== inst
->base
)
178 wxRibbonButtonBar::wxRibbonButtonBar()
180 m_layouts_valid
= false;
184 wxRibbonButtonBar::wxRibbonButtonBar(wxWindow
* parent
,
189 : wxRibbonControl(parent
, id
, pos
, size
, wxBORDER_NONE
)
191 m_layouts_valid
= false;
196 wxRibbonButtonBar::~wxRibbonButtonBar()
198 size_t count
= m_buttons
.GetCount();
200 for(i
= 0; i
< count
; ++i
)
202 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
207 count
= m_layouts
.GetCount();
208 for(i
= 0; i
< count
; ++i
)
210 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
216 bool wxRibbonButtonBar::Create(wxWindow
* parent
,
222 if(!wxRibbonControl::Create(parent
, id
, pos
, size
, wxBORDER_NONE
))
231 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton(
233 const wxString
& label
,
234 const wxBitmap
& bitmap
,
235 const wxString
& help_string
,
236 wxRibbonButtonKind kind
)
238 return AddButton(button_id
, label
, bitmap
, wxNullBitmap
, wxNullBitmap
,
239 wxNullBitmap
, kind
, help_string
);
242 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddDropdownButton(
244 const wxString
& label
,
245 const wxBitmap
& bitmap
,
246 const wxString
& help_string
)
248 return AddButton(button_id
, label
, bitmap
, help_string
,
249 wxRIBBON_BUTTON_DROPDOWN
);
252 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddToggleButton(
254 const wxString
& label
,
255 const wxBitmap
& bitmap
,
256 const wxString
& help_string
)
258 return AddButton(button_id
, label
, bitmap
, help_string
,
259 wxRIBBON_BUTTON_TOGGLE
);
262 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddHybridButton(
264 const wxString
& label
,
265 const wxBitmap
& bitmap
,
266 const wxString
& help_string
)
268 return AddButton(button_id
, label
, bitmap
, help_string
,
269 wxRIBBON_BUTTON_HYBRID
);
272 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton(
274 const wxString
& label
,
275 const wxBitmap
& bitmap
,
276 const wxBitmap
& bitmap_small
,
277 const wxBitmap
& bitmap_disabled
,
278 const wxBitmap
& bitmap_small_disabled
,
279 wxRibbonButtonKind kind
,
280 const wxString
& help_string
)
282 return InsertButton(GetButtonCount(), button_id
, label
, bitmap
,
283 bitmap_small
, bitmap_disabled
,bitmap_small_disabled
, kind
, help_string
);
286 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
289 const wxString
& label
,
290 const wxBitmap
& bitmap
,
291 const wxBitmap
& bitmap_small
,
292 const wxBitmap
& bitmap_disabled
,
293 const wxBitmap
& bitmap_small_disabled
,
294 wxRibbonButtonKind kind
,
295 const wxString
& help_string
)
297 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
298 if(m_buttons
.IsEmpty())
302 m_bitmap_size_large
= bitmap
.GetSize();
303 if(!bitmap_small
.IsOk())
305 m_bitmap_size_small
= m_bitmap_size_large
;
306 m_bitmap_size_small
*= 0.5;
309 if(bitmap_small
.IsOk())
311 m_bitmap_size_small
= bitmap_small
.GetSize();
314 m_bitmap_size_large
= m_bitmap_size_small
;
315 m_bitmap_size_large
*= 2.0;
320 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
321 base
->id
= button_id
;
323 base
->bitmap_large
= bitmap
;
324 if(!base
->bitmap_large
.IsOk())
326 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
327 m_bitmap_size_large
);
329 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
331 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
332 m_bitmap_size_large
);
334 base
->bitmap_small
= bitmap_small
;
335 if(!base
->bitmap_small
.IsOk())
337 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
338 m_bitmap_size_small
);
340 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
342 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
343 m_bitmap_size_small
);
345 base
->bitmap_large_disabled
= bitmap_disabled
;
346 if(!base
->bitmap_large_disabled
.IsOk())
348 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
350 base
->bitmap_small_disabled
= bitmap_small_disabled
;
351 if(!base
->bitmap_small_disabled
.IsOk())
353 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
356 base
->help_string
= help_string
;
359 wxClientDC
temp_dc(this);
360 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
361 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
362 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
364 m_buttons
.Insert(base
, pos
);
365 m_layouts_valid
= false;
371 wxRibbonButtonBar::SetItemClientObject(wxRibbonButtonBarButtonBase
* item
,
374 wxCHECK_RET( item
, "Can't associate client object with an invalid item" );
376 item
->client_data
.SetClientObject(data
);
380 wxRibbonButtonBar::GetItemClientObject(const wxRibbonButtonBarButtonBase
* item
) const
382 wxCHECK_MSG( item
, NULL
, "Can't get client object for an invalid item" );
384 return item
->client_data
.GetClientObject();
388 wxRibbonButtonBar::SetItemClientData(wxRibbonButtonBarButtonBase
* item
,
391 wxCHECK_RET( item
, "Can't associate client data with an invalid item" );
393 item
->client_data
.SetClientData(data
);
397 wxRibbonButtonBar::GetItemClientData(const wxRibbonButtonBarButtonBase
* item
) const
399 wxCHECK_MSG( item
, NULL
, "Can't get client data for an invalid item" );
401 return item
->client_data
.GetClientData();
405 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
408 const wxString
& label
,
409 const wxBitmap
& bitmap
,
410 const wxString
& help_string
,
411 wxRibbonButtonKind kind
)
413 return InsertButton(pos
, button_id
, label
, bitmap
, wxNullBitmap
,
414 wxNullBitmap
, wxNullBitmap
, kind
, help_string
);
417 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertDropdownButton(
420 const wxString
& label
,
421 const wxBitmap
& bitmap
,
422 const wxString
& help_string
)
424 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
425 wxRIBBON_BUTTON_DROPDOWN
);
428 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertToggleButton(
431 const wxString
& label
,
432 const wxBitmap
& bitmap
,
433 const wxString
& help_string
)
435 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
436 wxRIBBON_BUTTON_TOGGLE
);
439 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertHybridButton(
442 const wxString
& label
,
443 const wxBitmap
& bitmap
,
444 const wxString
& help_string
)
446 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
447 wxRIBBON_BUTTON_HYBRID
);
450 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
451 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
453 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
456 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
457 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
458 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
459 &info
.dropdown_region
);
462 info
.is_supported
= false;
465 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
467 wxImage
img(original
.ConvertToImage());
468 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
469 return wxBitmap(img
);
472 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
474 wxImage
img(original
.ConvertToImage());
475 return wxBitmap(img
.ConvertToGreyscale());
478 size_t wxRibbonButtonBar::GetButtonCount() const
480 return m_buttons
.GetCount();
483 bool wxRibbonButtonBar::Realize()
488 m_layouts_valid
= true;
493 void wxRibbonButtonBar::ClearButtons()
495 m_layouts_valid
= false;
496 size_t count
= m_buttons
.GetCount();
498 for(i
= 0; i
< count
; ++i
)
500 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
507 bool wxRibbonButtonBar::DeleteButton(int button_id
)
509 size_t count
= m_buttons
.GetCount();
511 for(i
= 0; i
< count
; ++i
)
513 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
514 if(button
->id
== button_id
)
516 m_layouts_valid
= false;
517 m_buttons
.RemoveAt(i
);
526 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
528 size_t count
= m_buttons
.GetCount();
530 for(i
= 0; i
< count
; ++i
)
532 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
533 if(button
->id
== button_id
)
537 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
539 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
545 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
547 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
556 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
)
558 size_t count
= m_buttons
.GetCount();
560 for(i
= 0; i
< count
; ++i
)
562 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
563 if(button
->id
== button_id
)
567 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0)
569 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
575 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
)
577 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
586 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
593 wxRibbonControl::SetArtProvider(art
);
595 wxClientDC
temp_dc(this);
596 size_t btn_count
= m_buttons
.Count();
598 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
600 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
602 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
603 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
604 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
607 m_layouts_valid
= false;
611 bool wxRibbonButtonBar::IsSizingContinuous() const
616 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
619 size_t nlayouts
= m_layouts
.GetCount();
621 for(i
= 0; i
< nlayouts
; ++i
)
623 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
624 wxSize size
= layout
->overall_size
;
628 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
636 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
644 if(size
.x
< result
.x
&& size
.y
< result
.y
)
657 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
660 size_t nlayouts
= m_layouts
.GetCount();
665 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
666 wxSize size
= layout
->overall_size
;
670 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
678 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
686 if(size
.x
> result
.x
&& size
.y
> result
.y
)
699 void wxRibbonButtonBar::UpdateWindowUI(long flags
)
701 wxWindowBase::UpdateWindowUI(flags
);
703 // don't waste time updating state of tools in a hidden toolbar
707 size_t btn_count
= m_buttons
.size();
708 bool rerealize
= false;
709 for ( size_t btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
711 wxRibbonButtonBarButtonBase
& btn
= *m_buttons
.Item(btn_i
);
714 wxUpdateUIEvent
event(id
);
715 event
.SetEventObject(this);
717 if ( ProcessWindowEvent(event
) )
719 if ( event
.GetSetEnabled() )
720 EnableButton(id
, event
.GetEnabled());
721 if ( event
.GetSetChecked() )
722 ToggleButton(id
, event
.GetChecked());
723 if ( event
.GetSetText() )
725 btn
.label
= event
.GetText();
735 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
737 // All painting done in main paint handler to minimise flicker
740 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
742 wxAutoBufferedPaintDC
dc(this);
743 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
745 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
747 size_t btn_count
= layout
->buttons
.Count();
749 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
751 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
752 wxRibbonButtonBarButtonBase
* base
= button
.base
;
754 wxBitmap
* bitmap
= &base
->bitmap_large
;
755 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
756 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
758 bitmap
= &base
->bitmap_large_disabled
;
759 bitmap_small
= &base
->bitmap_small_disabled
;
761 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
763 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
764 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
768 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
770 wxSize new_size
= evt
.GetSize();
771 size_t layout_count
= m_layouts
.GetCount();
773 m_current_layout
= layout_count
- 1;
774 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
776 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
777 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
779 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
780 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
781 m_current_layout
= layout_i
;
785 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
789 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
791 m_bitmap_size_large
= wxSize(32, 32);
792 m_bitmap_size_small
= wxSize(16, 16);
794 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
795 placeholder_layout
->overall_size
= wxSize(20, 20);
796 m_layouts
.Add(placeholder_layout
);
797 m_current_layout
= 0;
798 m_layout_offset
= wxPoint(0, 0);
799 m_hovered_button
= NULL
;
800 m_active_button
= NULL
;
801 m_lock_active_state
= false;
802 m_show_tooltips_for_disabled
= false;
804 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
807 void wxRibbonButtonBar::SetShowToolTipsForDisabled(bool show
)
809 m_show_tooltips_for_disabled
= show
;
812 bool wxRibbonButtonBar::GetShowToolTipsForDisabled() const
814 return m_show_tooltips_for_disabled
;
817 wxSize
wxRibbonButtonBar::GetMinSize() const
819 return m_layouts
.Last()->overall_size
;
822 wxSize
wxRibbonButtonBar::DoGetBestSize() const
824 return m_layouts
.Item(0)->overall_size
;
827 void wxRibbonButtonBar::MakeLayouts()
829 if(m_layouts_valid
|| m_art
== NULL
)
834 // Clear existing layouts
837 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
838 m_hovered_button
= NULL
;
842 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
843 m_active_button
= NULL
;
845 size_t count
= m_layouts
.GetCount();
847 for(i
= 0; i
< count
; ++i
)
849 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
854 size_t btn_count
= m_buttons
.Count();
857 // Best layout : all buttons large, stacking horizontally
858 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
859 wxPoint
cursor(0, 0);
860 layout
->overall_size
.SetHeight(0);
861 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
863 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
864 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
865 instance
.position
= cursor
;
866 instance
.size
= button
->GetLargestSize();
867 wxSize
& size
= button
->sizes
[instance
.size
].size
;
868 cursor
.x
+= size
.GetWidth();
869 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
871 layout
->buttons
.Add(instance
);
873 layout
->overall_size
.SetWidth(cursor
.x
);
874 m_layouts
.Add(layout
);
878 // Collapse the rightmost buttons and stack them vertically
879 size_t iLast
= btn_count
- 1;
880 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
887 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
888 size_t first_btn
, size_t* last_button
)
890 size_t btn_count
= m_buttons
.Count();
894 int available_width
= 0;
895 int available_height
= 0;
897 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
900 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
901 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
902 wxSize large_size
= button
->sizes
[large_size_class
].size
;
903 int t_available_height
= wxMax(available_height
,
904 large_size
.GetHeight());
905 int t_available_width
= available_width
+ large_size
.GetWidth();
906 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
907 if(!button
->GetSmallerSize(&small_size_class
))
911 wxSize small_size
= button
->sizes
[small_size_class
].size
;
912 int t_used_height
= used_height
+ small_size
.GetHeight();
913 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
915 if(t_used_height
> t_available_height
)
922 used_height
= t_used_height
;
923 used_width
= t_used_width
;
924 available_width
= t_available_width
;
925 available_height
= t_available_height
;
929 if(btn_i
>= first_btn
|| used_width
>= available_width
)
933 if(last_button
!= NULL
)
935 *last_button
= btn_i
;
938 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
939 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
940 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
941 bool preserve_height
= false;
944 // If height isn't preserved (i.e. it is reduced), then the minimum
945 // size for the button bar will decrease, preventing the original
946 // layout from being used (in some cases).
947 // It may be a good idea to always preserve the height, but for now
948 // it is only done when the first button is involved in a collapse.
949 preserve_height
= true;
952 for(; btn_i
<= first_btn
; ++btn_i
)
954 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
955 instance
.base
->GetSmallerSize(&instance
.size
);
956 instance
.position
= cursor
;
957 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
960 int x_adjust
= available_width
- used_width
;
962 for(; btn_i
< btn_count
; ++btn_i
)
964 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
965 instance
.position
.x
-= x_adjust
;
968 layout
->CalculateOverallSize();
971 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
972 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
975 wxFAIL_MSG("Layout collapse resulted in increased size");
981 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
984 m_layouts
.Add(layout
);
988 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
990 wxPoint
cursor(evt
.GetPosition());
991 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
992 wxRibbonButtonBarButtonInstance
* tooltipButton
= NULL
;
993 long new_hovered_state
= 0;
995 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
996 size_t btn_count
= layout
->buttons
.Count();
998 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1000 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1001 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1003 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1004 btn_rect
.SetSize(size
.size
);
1005 if(btn_rect
.Contains(cursor
))
1007 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
1009 tooltipButton
= &instance
;
1010 new_hovered
= &instance
;
1011 new_hovered_state
= instance
.base
->state
;
1012 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1013 wxPoint
offset(cursor
);
1014 offset
-= btn_rect
.GetTopLeft();
1015 if(size
.normal_region
.Contains(offset
))
1017 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
1019 if(size
.dropdown_region
.Contains(offset
))
1021 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
1025 else if (m_show_tooltips_for_disabled
)
1027 tooltipButton
= &instance
;
1033 if(tooltipButton
== NULL
&& GetToolTip())
1039 SetToolTip(tooltipButton
->base
->help_string
);
1043 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
1044 new_hovered_state
!= m_hovered_button
->base
->state
))
1046 if(m_hovered_button
!= NULL
)
1048 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1050 m_hovered_button
= new_hovered
;
1051 if(m_hovered_button
!= NULL
)
1053 m_hovered_button
->base
->state
= new_hovered_state
;
1058 if(m_active_button
&& !m_lock_active_state
)
1060 long new_active_state
= m_active_button
->base
->state
;
1061 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1062 wxRibbonButtonBarButtonSizeInfo
& size
=
1063 m_active_button
->base
->sizes
[m_active_button
->size
];
1065 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1066 btn_rect
.SetSize(size
.size
);
1067 if(btn_rect
.Contains(cursor
))
1069 wxPoint
offset(cursor
);
1070 offset
-= btn_rect
.GetTopLeft();
1071 if(size
.normal_region
.Contains(offset
))
1073 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1075 if(size
.dropdown_region
.Contains(offset
))
1077 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1080 if(new_active_state
!= m_active_button
->base
->state
)
1082 m_active_button
->base
->state
= new_active_state
;
1088 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
1090 wxPoint
cursor(evt
.GetPosition());
1091 m_active_button
= NULL
;
1093 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
1094 size_t btn_count
= layout
->buttons
.Count();
1096 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1098 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1099 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1101 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1102 btn_rect
.SetSize(size
.size
);
1103 if(btn_rect
.Contains(cursor
))
1105 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
1107 m_active_button
= &instance
;
1108 cursor
-= btn_rect
.GetTopLeft();
1110 if(size
.normal_region
.Contains(cursor
))
1111 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1112 else if(size
.dropdown_region
.Contains(cursor
))
1113 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1114 instance
.base
->state
|= state
;
1122 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
1124 wxPoint
cursor(evt
.GetPosition());
1128 wxRibbonButtonBarButtonSizeInfo
& size
=
1129 m_active_button
->base
->sizes
[m_active_button
->size
];
1131 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1132 btn_rect
.SetSize(size
.size
);
1133 if(btn_rect
.Contains(cursor
))
1135 int id
= m_active_button
->base
->id
;
1136 cursor
-= btn_rect
.GetTopLeft();
1137 wxEventType event_type
;
1140 if(size
.normal_region
.Contains(cursor
))
1141 event_type
= wxEVT_RIBBONBUTTONBAR_CLICKED
;
1142 else if(size
.dropdown_region
.Contains(cursor
))
1143 event_type
= wxEVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED
;
1146 wxRibbonButtonBarEvent
notification(event_type
, id
);
1147 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
1149 m_active_button
->base
->state
^=
1150 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
1151 notification
.SetInt(m_active_button
->base
->state
&
1152 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
1154 notification
.SetEventObject(this);
1155 notification
.SetBar(this);
1156 notification
.SetButton(m_active_button
->base
);
1157 m_lock_active_state
= true;
1158 ProcessWindowEvent(notification
);
1159 m_lock_active_state
= false;
1161 wxStaticCast(m_parent
, wxRibbonPanel
)->HideIfExpanded();
1163 if(m_active_button
) // may have been NULLed by event handler
1165 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1166 m_active_button
= NULL
;
1173 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1175 if(m_active_button
&& !evt
.LeftIsDown())
1177 m_active_button
= NULL
;
1181 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1183 bool repaint
= false;
1184 if(m_hovered_button
!= NULL
)
1186 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1187 m_hovered_button
= NULL
;
1190 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1192 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1199 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetActiveItem() const
1201 return m_active_button
== NULL
? NULL
: m_active_button
->base
;
1205 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetHoveredItem() const
1207 return m_hovered_button
== NULL
? NULL
: m_hovered_button
->base
;
1211 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItem(size_t n
) const
1213 wxCHECK_MSG(n
< m_buttons
.GetCount(), NULL
, "wxRibbonButtonBar item's index is out of bound");
1214 return m_buttons
.Item(n
);
1217 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItemById(int button_id
) const
1219 size_t count
= m_buttons
.GetCount();
1220 for ( size_t i
= 0; i
< count
; ++i
)
1222 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
1223 if ( button
->id
== button_id
)
1231 int wxRibbonButtonBar::GetItemId(wxRibbonButtonBarButtonBase
*item
) const
1233 wxCHECK_MSG(item
!= NULL
, wxNOT_FOUND
, "wxRibbonButtonBar item should not be NULL");
1238 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1240 wxPoint pos
= wxDefaultPosition
;
1241 if(m_bar
->m_active_button
)
1243 wxRibbonButtonBarButtonSizeInfo
& size
=
1244 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1246 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1247 m_bar
->m_active_button
->position
);
1248 btn_rect
.SetSize(size
.size
);
1249 pos
= btn_rect
.GetBottomLeft();
1252 return m_bar
->PopupMenu(menu
, pos
);
1255 #endif // wxUSE_RIBBON