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;
804 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
807 wxSize
wxRibbonButtonBar::GetMinSize() const
809 return m_layouts
.Last()->overall_size
;
812 wxSize
wxRibbonButtonBar::DoGetBestSize() const
814 return m_layouts
.Item(0)->overall_size
;
817 void wxRibbonButtonBar::MakeLayouts()
819 if(m_layouts_valid
|| m_art
== NULL
)
824 // Clear existing layouts
827 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
828 m_hovered_button
= NULL
;
832 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
833 m_active_button
= NULL
;
835 size_t count
= m_layouts
.GetCount();
837 for(i
= 0; i
< count
; ++i
)
839 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
844 size_t btn_count
= m_buttons
.Count();
847 // Best layout : all buttons large, stacking horizontally
848 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
849 wxPoint
cursor(0, 0);
850 layout
->overall_size
.SetHeight(0);
851 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
853 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
854 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
855 instance
.position
= cursor
;
856 instance
.size
= button
->GetLargestSize();
857 wxSize
& size
= button
->sizes
[instance
.size
].size
;
858 cursor
.x
+= size
.GetWidth();
859 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
861 layout
->buttons
.Add(instance
);
863 layout
->overall_size
.SetWidth(cursor
.x
);
864 m_layouts
.Add(layout
);
868 // Collapse the rightmost buttons and stack them vertically
869 size_t iLast
= btn_count
- 1;
870 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
877 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
878 size_t first_btn
, size_t* last_button
)
880 size_t btn_count
= m_buttons
.Count();
884 int available_width
= 0;
885 int available_height
= 0;
887 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
890 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
891 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
892 wxSize large_size
= button
->sizes
[large_size_class
].size
;
893 int t_available_height
= wxMax(available_height
,
894 large_size
.GetHeight());
895 int t_available_width
= available_width
+ large_size
.GetWidth();
896 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
897 if(!button
->GetSmallerSize(&small_size_class
))
901 wxSize small_size
= button
->sizes
[small_size_class
].size
;
902 int t_used_height
= used_height
+ small_size
.GetHeight();
903 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
905 if(t_used_height
> t_available_height
)
912 used_height
= t_used_height
;
913 used_width
= t_used_width
;
914 available_width
= t_available_width
;
915 available_height
= t_available_height
;
919 if(btn_i
>= first_btn
|| used_width
>= available_width
)
923 if(last_button
!= NULL
)
925 *last_button
= btn_i
;
928 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
929 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
930 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
931 bool preserve_height
= false;
934 // If height isn't preserved (i.e. it is reduced), then the minimum
935 // size for the button bar will decrease, preventing the original
936 // layout from being used (in some cases).
937 // It may be a good idea to always preverse the height, but for now
938 // it is only done when the first button is involved in a collapse.
939 preserve_height
= true;
942 for(; btn_i
<= first_btn
; ++btn_i
)
944 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
945 instance
.base
->GetSmallerSize(&instance
.size
);
946 instance
.position
= cursor
;
947 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
950 int x_adjust
= available_width
- used_width
;
952 for(; btn_i
< btn_count
; ++btn_i
)
954 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
955 instance
.position
.x
-= x_adjust
;
958 layout
->CalculateOverallSize();
961 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
962 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
965 wxFAIL_MSG("Layout collapse resulted in increased size");
971 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
974 m_layouts
.Add(layout
);
978 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
980 wxPoint
cursor(evt
.GetPosition());
981 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
982 long new_hovered_state
= 0;
984 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
985 size_t btn_count
= layout
->buttons
.Count();
987 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
989 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
990 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
992 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
993 btn_rect
.SetSize(size
.size
);
994 if(btn_rect
.Contains(cursor
))
996 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
998 new_hovered
= &instance
;
999 new_hovered_state
= instance
.base
->state
;
1000 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1001 wxPoint
offset(cursor
);
1002 offset
-= btn_rect
.GetTopLeft();
1003 if(size
.normal_region
.Contains(offset
))
1005 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
1007 if(size
.dropdown_region
.Contains(offset
))
1009 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
1017 if(new_hovered
== NULL
&& GetToolTip())
1023 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
1024 new_hovered_state
!= m_hovered_button
->base
->state
))
1026 if(m_hovered_button
!= NULL
)
1028 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1030 m_hovered_button
= new_hovered
;
1031 if(m_hovered_button
!= NULL
)
1033 m_hovered_button
->base
->state
= new_hovered_state
;
1035 SetToolTip(m_hovered_button
->base
->help_string
);
1041 if(m_active_button
&& !m_lock_active_state
)
1043 long new_active_state
= m_active_button
->base
->state
;
1044 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1045 wxRibbonButtonBarButtonSizeInfo
& size
=
1046 m_active_button
->base
->sizes
[m_active_button
->size
];
1048 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1049 btn_rect
.SetSize(size
.size
);
1050 if(btn_rect
.Contains(cursor
))
1052 wxPoint
offset(cursor
);
1053 offset
-= btn_rect
.GetTopLeft();
1054 if(size
.normal_region
.Contains(offset
))
1056 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1058 if(size
.dropdown_region
.Contains(offset
))
1060 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1063 if(new_active_state
!= m_active_button
->base
->state
)
1065 m_active_button
->base
->state
= new_active_state
;
1071 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
1073 wxPoint
cursor(evt
.GetPosition());
1074 m_active_button
= NULL
;
1076 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
1077 size_t btn_count
= layout
->buttons
.Count();
1079 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1081 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1082 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1084 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1085 btn_rect
.SetSize(size
.size
);
1086 if(btn_rect
.Contains(cursor
))
1088 if((instance
.base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
1090 m_active_button
= &instance
;
1091 cursor
-= btn_rect
.GetTopLeft();
1093 if(size
.normal_region
.Contains(cursor
))
1094 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1095 else if(size
.dropdown_region
.Contains(cursor
))
1096 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1097 instance
.base
->state
|= state
;
1105 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
1107 wxPoint
cursor(evt
.GetPosition());
1111 wxRibbonButtonBarButtonSizeInfo
& size
=
1112 m_active_button
->base
->sizes
[m_active_button
->size
];
1114 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1115 btn_rect
.SetSize(size
.size
);
1116 if(btn_rect
.Contains(cursor
))
1118 int id
= m_active_button
->base
->id
;
1119 cursor
-= btn_rect
.GetTopLeft();
1120 wxEventType event_type
;
1123 if(size
.normal_region
.Contains(cursor
))
1124 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
1125 else if(size
.dropdown_region
.Contains(cursor
))
1126 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
1129 wxRibbonButtonBarEvent
notification(event_type
, id
);
1130 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
1132 m_active_button
->base
->state
^=
1133 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
1134 notification
.SetInt(m_active_button
->base
->state
&
1135 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
1137 notification
.SetEventObject(this);
1138 notification
.SetBar(this);
1139 notification
.SetButton(m_active_button
->base
);
1140 m_lock_active_state
= true;
1141 ProcessWindowEvent(notification
);
1142 m_lock_active_state
= false;
1144 wxStaticCast(m_parent
, wxRibbonPanel
)->HideIfExpanded();
1146 if(m_active_button
) // may have been NULLed by event handler
1148 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1149 m_active_button
= NULL
;
1156 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1158 if(m_active_button
&& !evt
.LeftIsDown())
1160 m_active_button
= NULL
;
1164 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1166 bool repaint
= false;
1167 if(m_hovered_button
!= NULL
)
1169 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1170 m_hovered_button
= NULL
;
1173 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1175 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1182 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetActiveItem() const
1184 return m_active_button
== NULL
? NULL
: m_active_button
->base
;
1188 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetHoveredItem() const
1190 return m_hovered_button
== NULL
? NULL
: m_hovered_button
->base
;
1194 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItem(size_t n
) const
1196 wxCHECK_MSG(n
< m_buttons
.GetCount(), NULL
, "wxRibbonButtonBar item's index is out of bound");
1197 return m_buttons
.Item(n
);
1200 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItemById(int button_id
) const
1202 size_t count
= m_buttons
.GetCount();
1203 for ( size_t i
= 0; i
< count
; ++i
)
1205 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
1206 if ( button
->id
== button_id
)
1214 int wxRibbonButtonBar::GetItemId(wxRibbonButtonBarButtonBase
*item
) const
1216 wxCHECK_MSG(item
!= NULL
, wxNOT_FOUND
, "wxRibbonButtonBar item should not be NULL");
1221 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1223 wxPoint pos
= wxDefaultPosition
;
1224 if(m_bar
->m_active_button
)
1226 wxRibbonButtonBarButtonSizeInfo
& size
=
1227 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1229 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1230 m_bar
->m_active_button
->position
);
1231 btn_rect
.SetSize(size
.size
);
1232 pos
= btn_rect
.GetBottomLeft();
1235 return m_bar
->PopupMenu(menu
, pos
);
1238 #endif // wxUSE_RIBBON