1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/ribbon/buttonbar.cpp
3 // Purpose: Ribbon control similar to a tool bar
4 // Author: Peter Cawley
8 // Copyright: (C) Peter Cawley
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
20 #include "wx/ribbon/panel.h"
21 #include "wx/ribbon/buttonbar.h"
22 #include "wx/ribbon/art.h"
23 #include "wx/dcbuffer.h"
29 #include "wx/msw/private.h"
32 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_CLICKED
, wxRibbonButtonBarEvent
);
33 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
, wxRibbonButtonBarEvent
);
35 IMPLEMENT_DYNAMIC_CLASS(wxRibbonButtonBarEvent
, wxCommandEvent
)
36 IMPLEMENT_CLASS(wxRibbonButtonBar
, wxRibbonControl
)
38 BEGIN_EVENT_TABLE(wxRibbonButtonBar
, wxRibbonControl
)
39 EVT_ERASE_BACKGROUND(wxRibbonButtonBar::OnEraseBackground
)
40 EVT_ENTER_WINDOW(wxRibbonButtonBar::OnMouseEnter
)
41 EVT_LEAVE_WINDOW(wxRibbonButtonBar::OnMouseLeave
)
42 EVT_MOTION(wxRibbonButtonBar::OnMouseMove
)
43 EVT_PAINT(wxRibbonButtonBar::OnPaint
)
44 EVT_SIZE(wxRibbonButtonBar::OnSize
)
45 EVT_LEFT_DOWN(wxRibbonButtonBar::OnMouseDown
)
46 EVT_LEFT_UP(wxRibbonButtonBar::OnMouseUp
)
49 class wxRibbonButtonBarButtonSizeInfo
55 wxRect dropdown_region
;
58 class wxRibbonButtonBarButtonInstance
62 wxRibbonButtonBarButtonBase
* base
;
63 wxRibbonButtonBarButtonState size
;
66 class wxRibbonButtonBarButtonBase
69 wxRibbonButtonBarButtonInstance
NewInstance()
71 wxRibbonButtonBarButtonInstance i
;
76 wxRibbonButtonBarButtonState
GetLargestSize()
78 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_LARGE
].is_supported
)
79 return wxRIBBON_BUTTONBAR_BUTTON_LARGE
;
80 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
)
81 return wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
;
82 wxASSERT(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
);
83 return wxRIBBON_BUTTONBAR_BUTTON_SMALL
;
87 wxRibbonButtonBarButtonState
* size
, int n
= 1)
93 case wxRIBBON_BUTTONBAR_BUTTON_LARGE
:
94 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
)
96 *size
= wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
;
99 case wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
:
100 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
)
102 *size
= wxRIBBON_BUTTONBAR_BUTTON_SMALL
;
105 case wxRIBBON_BUTTONBAR_BUTTON_SMALL
:
114 wxString help_string
;
115 wxBitmap bitmap_large
;
116 wxBitmap bitmap_large_disabled
;
117 wxBitmap bitmap_small
;
118 wxBitmap bitmap_small_disabled
;
119 wxRibbonButtonBarButtonSizeInfo sizes
[3];
120 wxClientDataContainer client_data
;
122 wxRibbonButtonKind kind
;
126 WX_DECLARE_OBJARRAY(wxRibbonButtonBarButtonInstance
, wxArrayRibbonButtonBarButtonInstance
);
127 #include "wx/arrimpl.cpp"
128 WX_DEFINE_OBJARRAY(wxArrayRibbonButtonBarButtonInstance
)
130 class wxRibbonButtonBarLayout
134 wxArrayRibbonButtonBarButtonInstance buttons
;
136 void CalculateOverallSize()
138 overall_size
= wxSize(0, 0);
139 size_t btn_count
= buttons
.Count();
141 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
143 wxRibbonButtonBarButtonInstance
& instance
= buttons
.Item(btn_i
);
144 wxSize size
= instance
.base
->sizes
[instance
.size
].size
;
145 int right
= instance
.position
.x
+ size
.GetWidth();
146 int bottom
= instance
.position
.y
+ size
.GetHeight();
147 if(right
> overall_size
.GetWidth())
149 overall_size
.SetWidth(right
);
151 if(bottom
> overall_size
.GetHeight())
153 overall_size
.SetHeight(bottom
);
158 wxRibbonButtonBarButtonInstance
* FindSimilarInstance(
159 wxRibbonButtonBarButtonInstance
* inst
)
165 size_t btn_count
= buttons
.Count();
167 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
169 wxRibbonButtonBarButtonInstance
& instance
= buttons
.Item(btn_i
);
170 if(instance
.base
== inst
->base
)
179 wxRibbonButtonBar::wxRibbonButtonBar()
181 m_layouts_valid
= false;
185 wxRibbonButtonBar::wxRibbonButtonBar(wxWindow
* parent
,
190 : wxRibbonControl(parent
, id
, pos
, size
, wxBORDER_NONE
)
192 m_layouts_valid
= false;
197 wxRibbonButtonBar::~wxRibbonButtonBar()
199 size_t count
= m_buttons
.GetCount();
201 for(i
= 0; i
< count
; ++i
)
203 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
208 count
= m_layouts
.GetCount();
209 for(i
= 0; i
< count
; ++i
)
211 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
217 bool wxRibbonButtonBar::Create(wxWindow
* parent
,
223 if(!wxRibbonControl::Create(parent
, id
, pos
, size
, wxBORDER_NONE
))
232 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton(
234 const wxString
& label
,
235 const wxBitmap
& bitmap
,
236 const wxString
& help_string
,
237 wxRibbonButtonKind kind
)
239 return AddButton(button_id
, label
, bitmap
, wxNullBitmap
, wxNullBitmap
,
240 wxNullBitmap
, kind
, help_string
);
243 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddDropdownButton(
245 const wxString
& label
,
246 const wxBitmap
& bitmap
,
247 const wxString
& help_string
)
249 return AddButton(button_id
, label
, bitmap
, help_string
,
250 wxRIBBON_BUTTON_DROPDOWN
);
253 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddToggleButton(
255 const wxString
& label
,
256 const wxBitmap
& bitmap
,
257 const wxString
& help_string
)
259 return AddButton(button_id
, label
, bitmap
, help_string
,
260 wxRIBBON_BUTTON_TOGGLE
);
263 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddHybridButton(
265 const wxString
& label
,
266 const wxBitmap
& bitmap
,
267 const wxString
& help_string
)
269 return AddButton(button_id
, label
, bitmap
, help_string
,
270 wxRIBBON_BUTTON_HYBRID
);
273 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton(
275 const wxString
& label
,
276 const wxBitmap
& bitmap
,
277 const wxBitmap
& bitmap_small
,
278 const wxBitmap
& bitmap_disabled
,
279 const wxBitmap
& bitmap_small_disabled
,
280 wxRibbonButtonKind kind
,
281 const wxString
& help_string
)
283 return InsertButton(GetButtonCount(), button_id
, label
, bitmap
,
284 bitmap_small
, bitmap_disabled
,bitmap_small_disabled
, kind
, help_string
);
287 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
290 const wxString
& label
,
291 const wxBitmap
& bitmap
,
292 const wxBitmap
& bitmap_small
,
293 const wxBitmap
& bitmap_disabled
,
294 const wxBitmap
& bitmap_small_disabled
,
295 wxRibbonButtonKind kind
,
296 const wxString
& help_string
)
298 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
299 if(m_buttons
.IsEmpty())
303 m_bitmap_size_large
= bitmap
.GetSize();
304 if(!bitmap_small
.IsOk())
306 m_bitmap_size_small
= m_bitmap_size_large
;
307 m_bitmap_size_small
*= 0.5;
310 if(bitmap_small
.IsOk())
312 m_bitmap_size_small
= bitmap_small
.GetSize();
315 m_bitmap_size_large
= m_bitmap_size_small
;
316 m_bitmap_size_large
*= 2.0;
321 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
322 base
->id
= button_id
;
324 base
->bitmap_large
= bitmap
;
325 if(!base
->bitmap_large
.IsOk())
327 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
328 m_bitmap_size_large
);
330 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
332 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
333 m_bitmap_size_large
);
335 base
->bitmap_small
= bitmap_small
;
336 if(!base
->bitmap_small
.IsOk())
338 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
339 m_bitmap_size_small
);
341 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
343 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
344 m_bitmap_size_small
);
346 base
->bitmap_large_disabled
= bitmap_disabled
;
347 if(!base
->bitmap_large_disabled
.IsOk())
349 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
351 base
->bitmap_small_disabled
= bitmap_small_disabled
;
352 if(!base
->bitmap_small_disabled
.IsOk())
354 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
357 base
->help_string
= help_string
;
360 wxClientDC
temp_dc(this);
361 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
362 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
363 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
365 m_buttons
.Insert(base
, pos
);
366 m_layouts_valid
= false;
372 wxRibbonButtonBar::SetItemClientObject(wxRibbonButtonBarButtonBase
* item
,
375 wxCHECK_RET( item
, "Can't associate client object with an invalid item" );
377 item
->client_data
.SetClientObject(data
);
381 wxRibbonButtonBar::GetItemClientObject(const wxRibbonButtonBarButtonBase
* item
) const
383 wxCHECK_MSG( item
, NULL
, "Can't get client object for an invalid item" );
385 return item
->client_data
.GetClientObject();
389 wxRibbonButtonBar::SetItemClientData(wxRibbonButtonBarButtonBase
* item
,
392 wxCHECK_RET( item
, "Can't associate client data with an invalid item" );
394 item
->client_data
.SetClientData(data
);
398 wxRibbonButtonBar::GetItemClientData(const wxRibbonButtonBarButtonBase
* item
) const
400 wxCHECK_MSG( item
, NULL
, "Can't get client data for an invalid item" );
402 return item
->client_data
.GetClientData();
406 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
409 const wxString
& label
,
410 const wxBitmap
& bitmap
,
411 const wxString
& help_string
,
412 wxRibbonButtonKind kind
)
414 return InsertButton(pos
, button_id
, label
, bitmap
, wxNullBitmap
,
415 wxNullBitmap
, wxNullBitmap
, kind
, help_string
);
418 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertDropdownButton(
421 const wxString
& label
,
422 const wxBitmap
& bitmap
,
423 const wxString
& help_string
)
425 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
426 wxRIBBON_BUTTON_DROPDOWN
);
429 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertToggleButton(
432 const wxString
& label
,
433 const wxBitmap
& bitmap
,
434 const wxString
& help_string
)
436 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
437 wxRIBBON_BUTTON_TOGGLE
);
440 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertHybridButton(
443 const wxString
& label
,
444 const wxBitmap
& bitmap
,
445 const wxString
& help_string
)
447 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
448 wxRIBBON_BUTTON_HYBRID
);
451 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
452 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
454 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
457 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
458 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
459 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
460 &info
.dropdown_region
);
463 info
.is_supported
= false;
466 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
468 wxImage
img(original
.ConvertToImage());
469 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
470 return wxBitmap(img
);
473 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
475 wxImage
img(original
.ConvertToImage());
476 return wxBitmap(img
.ConvertToGreyscale());
479 size_t wxRibbonButtonBar::GetButtonCount() const
481 return m_buttons
.GetCount();
484 bool wxRibbonButtonBar::Realize()
489 m_layouts_valid
= true;
494 void wxRibbonButtonBar::ClearButtons()
496 m_layouts_valid
= false;
497 size_t count
= m_buttons
.GetCount();
499 for(i
= 0; i
< count
; ++i
)
501 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
508 bool wxRibbonButtonBar::DeleteButton(int button_id
)
510 size_t count
= m_buttons
.GetCount();
512 for(i
= 0; i
< count
; ++i
)
514 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
515 if(button
->id
== button_id
)
517 m_layouts_valid
= false;
518 m_buttons
.RemoveAt(i
);
527 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
529 size_t count
= m_buttons
.GetCount();
531 for(i
= 0; i
< count
; ++i
)
533 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
534 if(button
->id
== button_id
)
538 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
540 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
546 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
548 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
557 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
)
559 size_t count
= m_buttons
.GetCount();
561 for(i
= 0; i
< count
; ++i
)
563 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
564 if(button
->id
== button_id
)
568 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0)
570 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
576 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
)
578 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
587 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
594 wxRibbonControl::SetArtProvider(art
);
596 wxClientDC
temp_dc(this);
597 size_t btn_count
= m_buttons
.Count();
599 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
601 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
603 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
604 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
605 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
608 m_layouts_valid
= false;
612 bool wxRibbonButtonBar::IsSizingContinuous() const
617 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
620 size_t nlayouts
= m_layouts
.GetCount();
622 for(i
= 0; i
< nlayouts
; ++i
)
624 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
625 wxSize size
= layout
->overall_size
;
629 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
637 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
645 if(size
.x
< result
.x
&& size
.y
< result
.y
)
658 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
661 size_t nlayouts
= m_layouts
.GetCount();
666 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
667 wxSize size
= layout
->overall_size
;
671 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
679 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
687 if(size
.x
> result
.x
&& size
.y
> result
.y
)
700 void wxRibbonButtonBar::UpdateWindowUI(long flags
)
702 wxWindowBase::UpdateWindowUI(flags
);
704 // don't waste time updating state of tools in a hidden toolbar
708 size_t btn_count
= m_buttons
.size();
709 bool rerealize
= false;
710 for ( size_t btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
712 wxRibbonButtonBarButtonBase
& btn
= *m_buttons
.Item(btn_i
);
715 wxUpdateUIEvent
event(id
);
716 event
.SetEventObject(this);
718 if ( ProcessWindowEvent(event
) )
720 if ( event
.GetSetEnabled() )
721 EnableButton(id
, event
.GetEnabled());
722 if ( event
.GetSetChecked() )
723 ToggleButton(id
, event
.GetChecked());
724 if ( event
.GetSetText() )
726 btn
.label
= event
.GetText();
736 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
738 // All painting done in main paint handler to minimise flicker
741 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
743 wxAutoBufferedPaintDC
dc(this);
744 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
746 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
748 size_t btn_count
= layout
->buttons
.Count();
750 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
752 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
753 wxRibbonButtonBarButtonBase
* base
= button
.base
;
755 wxBitmap
* bitmap
= &base
->bitmap_large
;
756 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
757 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
759 bitmap
= &base
->bitmap_large_disabled
;
760 bitmap_small
= &base
->bitmap_small_disabled
;
762 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
764 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
765 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
769 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
771 wxSize new_size
= evt
.GetSize();
772 size_t layout_count
= m_layouts
.GetCount();
774 m_current_layout
= layout_count
- 1;
775 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
777 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
778 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
780 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
781 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
782 m_current_layout
= layout_i
;
786 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
790 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
792 m_bitmap_size_large
= wxSize(32, 32);
793 m_bitmap_size_small
= wxSize(16, 16);
795 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
796 placeholder_layout
->overall_size
= wxSize(20, 20);
797 m_layouts
.Add(placeholder_layout
);
798 m_current_layout
= 0;
799 m_layout_offset
= wxPoint(0, 0);
800 m_hovered_button
= NULL
;
801 m_active_button
= NULL
;
802 m_lock_active_state
= false;
803 m_show_tooltips_for_disabled
= false;
805 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
808 void wxRibbonButtonBar::SetShowToolTipsForDisabled(bool show
)
810 m_show_tooltips_for_disabled
= show
;
813 bool wxRibbonButtonBar::GetShowToolTipsForDisabled() const
815 return m_show_tooltips_for_disabled
;
818 wxSize
wxRibbonButtonBar::GetMinSize() const
820 return m_layouts
.Last()->overall_size
;
823 wxSize
wxRibbonButtonBar::DoGetBestSize() const
825 return m_layouts
.Item(0)->overall_size
;
828 void wxRibbonButtonBar::MakeLayouts()
830 if(m_layouts_valid
|| m_art
== NULL
)
835 // Clear existing layouts
838 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
839 m_hovered_button
= NULL
;
843 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
844 m_active_button
= NULL
;
846 size_t count
= m_layouts
.GetCount();
848 for(i
= 0; i
< count
; ++i
)
850 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
855 size_t btn_count
= m_buttons
.Count();
858 // Best layout : all buttons large, stacking horizontally
859 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
860 wxPoint
cursor(0, 0);
861 layout
->overall_size
.SetHeight(0);
862 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
864 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
865 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
866 instance
.position
= cursor
;
867 instance
.size
= button
->GetLargestSize();
868 wxSize
& size
= button
->sizes
[instance
.size
].size
;
869 cursor
.x
+= size
.GetWidth();
870 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
872 layout
->buttons
.Add(instance
);
874 layout
->overall_size
.SetWidth(cursor
.x
);
875 m_layouts
.Add(layout
);
879 // Collapse the rightmost buttons and stack them vertically
880 size_t iLast
= btn_count
- 1;
881 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
888 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
889 size_t first_btn
, size_t* last_button
)
891 size_t btn_count
= m_buttons
.Count();
895 int available_width
= 0;
896 int available_height
= 0;
898 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
901 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
902 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
903 wxSize large_size
= button
->sizes
[large_size_class
].size
;
904 int t_available_height
= wxMax(available_height
,
905 large_size
.GetHeight());
906 int t_available_width
= available_width
+ large_size
.GetWidth();
907 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
908 if(!button
->GetSmallerSize(&small_size_class
))
912 wxSize small_size
= button
->sizes
[small_size_class
].size
;
913 int t_used_height
= used_height
+ small_size
.GetHeight();
914 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
916 if(t_used_height
> t_available_height
)
923 used_height
= t_used_height
;
924 used_width
= t_used_width
;
925 available_width
= t_available_width
;
926 available_height
= t_available_height
;
930 if(btn_i
>= first_btn
|| used_width
>= available_width
)
934 if(last_button
!= NULL
)
936 *last_button
= btn_i
;
939 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
940 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
941 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
942 bool preserve_height
= false;
945 // If height isn't preserved (i.e. it is reduced), then the minimum
946 // size for the button bar will decrease, preventing the original
947 // layout from being used (in some cases).
948 // It may be a good idea to always preverse the height, but for now
949 // it is only done when the first button is involved in a collapse.
950 preserve_height
= true;
953 for(; btn_i
<= first_btn
; ++btn_i
)
955 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
956 instance
.base
->GetSmallerSize(&instance
.size
);
957 instance
.position
= cursor
;
958 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
961 int x_adjust
= available_width
- used_width
;
963 for(; btn_i
< btn_count
; ++btn_i
)
965 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
966 instance
.position
.x
-= x_adjust
;
969 layout
->CalculateOverallSize();
972 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
973 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
976 wxFAIL_MSG("Layout collapse resulted in increased size");
982 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
985 m_layouts
.Add(layout
);
989 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
991 wxPoint
cursor(evt
.GetPosition());
992 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
993 wxRibbonButtonBarButtonInstance
* tooltipButton
= NULL
;
994 long new_hovered_state
= 0;
996 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
997 size_t btn_count
= layout
->buttons
.Count();
999 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1001 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1002 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1004 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1005 btn_rect
.SetSize(size
.size
);
1006 if(btn_rect
.Contains(cursor
))
1008 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
1010 tooltipButton
= &instance
;
1011 new_hovered
= &instance
;
1012 new_hovered_state
= instance
.base
->state
;
1013 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1014 wxPoint
offset(cursor
);
1015 offset
-= btn_rect
.GetTopLeft();
1016 if(size
.normal_region
.Contains(offset
))
1018 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
1020 if(size
.dropdown_region
.Contains(offset
))
1022 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
1026 else if (m_show_tooltips_for_disabled
)
1028 tooltipButton
= &instance
;
1034 if(tooltipButton
== NULL
&& GetToolTip())
1040 SetToolTip(tooltipButton
->base
->help_string
);
1044 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
1045 new_hovered_state
!= m_hovered_button
->base
->state
))
1047 if(m_hovered_button
!= NULL
)
1049 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1051 m_hovered_button
= new_hovered
;
1052 if(m_hovered_button
!= NULL
)
1054 m_hovered_button
->base
->state
= new_hovered_state
;
1059 if(m_active_button
&& !m_lock_active_state
)
1061 long new_active_state
= m_active_button
->base
->state
;
1062 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1063 wxRibbonButtonBarButtonSizeInfo
& size
=
1064 m_active_button
->base
->sizes
[m_active_button
->size
];
1066 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1067 btn_rect
.SetSize(size
.size
);
1068 if(btn_rect
.Contains(cursor
))
1070 wxPoint
offset(cursor
);
1071 offset
-= btn_rect
.GetTopLeft();
1072 if(size
.normal_region
.Contains(offset
))
1074 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1076 if(size
.dropdown_region
.Contains(offset
))
1078 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1081 if(new_active_state
!= m_active_button
->base
->state
)
1083 m_active_button
->base
->state
= new_active_state
;
1089 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
1091 wxPoint
cursor(evt
.GetPosition());
1092 m_active_button
= NULL
;
1094 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
1095 size_t btn_count
= layout
->buttons
.Count();
1097 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1099 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1100 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1102 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1103 btn_rect
.SetSize(size
.size
);
1104 if(btn_rect
.Contains(cursor
))
1106 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
1108 m_active_button
= &instance
;
1109 cursor
-= btn_rect
.GetTopLeft();
1111 if(size
.normal_region
.Contains(cursor
))
1112 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1113 else if(size
.dropdown_region
.Contains(cursor
))
1114 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1115 instance
.base
->state
|= state
;
1123 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
1125 wxPoint
cursor(evt
.GetPosition());
1129 wxRibbonButtonBarButtonSizeInfo
& size
=
1130 m_active_button
->base
->sizes
[m_active_button
->size
];
1132 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1133 btn_rect
.SetSize(size
.size
);
1134 if(btn_rect
.Contains(cursor
))
1136 int id
= m_active_button
->base
->id
;
1137 cursor
-= btn_rect
.GetTopLeft();
1138 wxEventType event_type
;
1141 if(size
.normal_region
.Contains(cursor
))
1142 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
1143 else if(size
.dropdown_region
.Contains(cursor
))
1144 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
1147 wxRibbonButtonBarEvent
notification(event_type
, id
);
1148 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
1150 m_active_button
->base
->state
^=
1151 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
1152 notification
.SetInt(m_active_button
->base
->state
&
1153 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
1155 notification
.SetEventObject(this);
1156 notification
.SetBar(this);
1157 notification
.SetButton(m_active_button
->base
);
1158 m_lock_active_state
= true;
1159 ProcessWindowEvent(notification
);
1160 m_lock_active_state
= false;
1162 wxStaticCast(m_parent
, wxRibbonPanel
)->HideIfExpanded();
1164 if(m_active_button
) // may have been NULLed by event handler
1166 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1167 m_active_button
= NULL
;
1174 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1176 if(m_active_button
&& !evt
.LeftIsDown())
1178 m_active_button
= NULL
;
1182 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1184 bool repaint
= false;
1185 if(m_hovered_button
!= NULL
)
1187 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1188 m_hovered_button
= NULL
;
1191 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1193 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1200 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetActiveItem() const
1202 return m_active_button
== NULL
? NULL
: m_active_button
->base
;
1206 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetHoveredItem() const
1208 return m_hovered_button
== NULL
? NULL
: m_hovered_button
->base
;
1212 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItem(size_t n
) const
1214 wxCHECK_MSG(n
< m_buttons
.GetCount(), NULL
, "wxRibbonButtonBar item's index is out of bound");
1215 return m_buttons
.Item(n
);
1218 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItemById(int button_id
) const
1220 size_t count
= m_buttons
.GetCount();
1221 for ( size_t i
= 0; i
< count
; ++i
)
1223 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
1224 if ( button
->id
== button_id
)
1232 int wxRibbonButtonBar::GetItemId(wxRibbonButtonBarButtonBase
*item
) const
1234 wxCHECK_MSG(item
!= NULL
, wxNOT_FOUND
, "wxRibbonButtonBar item should not be NULL");
1239 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1241 wxPoint pos
= wxDefaultPosition
;
1242 if(m_bar
->m_active_button
)
1244 wxRibbonButtonBarButtonSizeInfo
& size
=
1245 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1247 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1248 m_bar
->m_active_button
->position
);
1249 btn_rect
.SetSize(size
.size
);
1250 pos
= btn_rect
.GetBottomLeft();
1253 return m_bar
->PopupMenu(menu
, pos
);
1256 #endif // wxUSE_RIBBON