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 wxObject
* 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
,
282 wxObject
* client_data
)
284 return InsertButton(GetButtonCount(), button_id
, label
, bitmap
,
285 bitmap_small
, bitmap_disabled
,bitmap_small_disabled
, kind
, help_string
,
289 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
292 const wxString
& label
,
293 const wxBitmap
& bitmap
,
294 const wxBitmap
& bitmap_small
,
295 const wxBitmap
& bitmap_disabled
,
296 const wxBitmap
& bitmap_small_disabled
,
297 wxRibbonButtonKind kind
,
298 const wxString
& help_string
,
299 wxObject
* client_data
)
301 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
302 if(m_buttons
.IsEmpty())
306 m_bitmap_size_large
= bitmap
.GetSize();
307 if(!bitmap_small
.IsOk())
309 m_bitmap_size_small
= m_bitmap_size_large
;
310 m_bitmap_size_small
*= 0.5;
313 if(bitmap_small
.IsOk())
315 m_bitmap_size_small
= bitmap_small
.GetSize();
318 m_bitmap_size_large
= m_bitmap_size_small
;
319 m_bitmap_size_large
*= 2.0;
324 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
325 base
->id
= button_id
;
327 base
->bitmap_large
= bitmap
;
328 if(!base
->bitmap_large
.IsOk())
330 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
331 m_bitmap_size_large
);
333 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
335 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
336 m_bitmap_size_large
);
338 base
->bitmap_small
= bitmap_small
;
339 if(!base
->bitmap_small
.IsOk())
341 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
342 m_bitmap_size_small
);
344 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
346 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
347 m_bitmap_size_small
);
349 base
->bitmap_large_disabled
= bitmap_disabled
;
350 if(!base
->bitmap_large_disabled
.IsOk())
352 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
354 base
->bitmap_small_disabled
= bitmap_small_disabled
;
355 if(!base
->bitmap_small_disabled
.IsOk())
357 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
360 base
->help_string
= help_string
;
361 base
->client_data
= client_data
;
364 wxClientDC
temp_dc(this);
365 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
366 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
367 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
369 m_buttons
.Insert(base
, pos
);
370 m_layouts_valid
= false;
374 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
377 const wxString
& label
,
378 const wxBitmap
& bitmap
,
379 const wxString
& help_string
,
380 wxRibbonButtonKind kind
)
382 return InsertButton(pos
, button_id
, label
, bitmap
, wxNullBitmap
,
383 wxNullBitmap
, wxNullBitmap
, kind
, help_string
);
386 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertDropdownButton(
389 const wxString
& label
,
390 const wxBitmap
& bitmap
,
391 const wxString
& help_string
)
393 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
394 wxRIBBON_BUTTON_DROPDOWN
);
397 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertToggleButton(
400 const wxString
& label
,
401 const wxBitmap
& bitmap
,
402 const wxString
& help_string
)
404 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
405 wxRIBBON_BUTTON_TOGGLE
);
408 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertHybridButton(
411 const wxString
& label
,
412 const wxBitmap
& bitmap
,
413 const wxString
& help_string
)
415 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
416 wxRIBBON_BUTTON_HYBRID
);
419 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
420 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
422 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
425 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
426 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
427 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
428 &info
.dropdown_region
);
431 info
.is_supported
= false;
434 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
436 wxImage
img(original
.ConvertToImage());
437 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
438 return wxBitmap(img
);
441 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
443 wxImage
img(original
.ConvertToImage());
444 return wxBitmap(img
.ConvertToGreyscale());
447 size_t wxRibbonButtonBar::GetButtonCount() const
449 return m_buttons
.GetCount();
452 bool wxRibbonButtonBar::Realize()
457 m_layouts_valid
= true;
462 void wxRibbonButtonBar::ClearButtons()
464 m_layouts_valid
= false;
465 size_t count
= m_buttons
.GetCount();
467 for(i
= 0; i
< count
; ++i
)
469 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
476 bool wxRibbonButtonBar::DeleteButton(int button_id
)
478 size_t count
= m_buttons
.GetCount();
480 for(i
= 0; i
< count
; ++i
)
482 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
483 if(button
->id
== button_id
)
485 m_layouts_valid
= false;
486 m_buttons
.RemoveAt(i
);
495 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
497 size_t count
= m_buttons
.GetCount();
499 for(i
= 0; i
< count
; ++i
)
501 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
502 if(button
->id
== button_id
)
506 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
508 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
514 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
516 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
525 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
)
527 size_t count
= m_buttons
.GetCount();
529 for(i
= 0; i
< count
; ++i
)
531 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
532 if(button
->id
== button_id
)
536 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0)
538 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
544 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
)
546 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
555 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
562 wxRibbonControl::SetArtProvider(art
);
564 wxClientDC
temp_dc(this);
565 size_t btn_count
= m_buttons
.Count();
567 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
569 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
571 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
572 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
573 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
576 m_layouts_valid
= false;
580 bool wxRibbonButtonBar::IsSizingContinuous() const
585 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
588 size_t nlayouts
= m_layouts
.GetCount();
590 for(i
= 0; i
< nlayouts
; ++i
)
592 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
593 wxSize size
= layout
->overall_size
;
597 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
605 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
613 if(size
.x
< result
.x
&& size
.y
< result
.y
)
626 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
629 size_t nlayouts
= m_layouts
.GetCount();
634 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
635 wxSize size
= layout
->overall_size
;
639 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
647 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
655 if(size
.x
> result
.x
&& size
.y
> result
.y
)
668 void wxRibbonButtonBar::UpdateWindowUI(long flags
)
670 wxWindowBase::UpdateWindowUI(flags
);
672 // don't waste time updating state of tools in a hidden toolbar
676 size_t btn_count
= m_buttons
.size();
677 bool rerealize
= false;
678 for ( size_t btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
680 wxRibbonButtonBarButtonBase
& btn
= *m_buttons
.Item(btn_i
);
683 wxUpdateUIEvent
event(id
);
684 event
.SetEventObject(this);
686 if ( ProcessWindowEvent(event
) )
688 if ( event
.GetSetEnabled() )
689 EnableButton(id
, event
.GetEnabled());
690 if ( event
.GetSetChecked() )
691 ToggleButton(id
, event
.GetChecked());
692 if ( event
.GetSetText() )
694 btn
.label
= event
.GetText();
704 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
706 // All painting done in main paint handler to minimise flicker
709 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
711 wxAutoBufferedPaintDC
dc(this);
712 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
714 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
716 size_t btn_count
= layout
->buttons
.Count();
718 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
720 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
721 wxRibbonButtonBarButtonBase
* base
= button
.base
;
723 wxBitmap
* bitmap
= &base
->bitmap_large
;
724 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
725 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
727 bitmap
= &base
->bitmap_large_disabled
;
728 bitmap_small
= &base
->bitmap_small_disabled
;
730 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
732 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
733 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
737 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
739 wxSize new_size
= evt
.GetSize();
740 size_t layout_count
= m_layouts
.GetCount();
742 m_current_layout
= layout_count
- 1;
743 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
745 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
746 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
748 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
749 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
750 m_current_layout
= layout_i
;
754 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
758 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
760 m_bitmap_size_large
= wxSize(32, 32);
761 m_bitmap_size_small
= wxSize(16, 16);
763 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
764 placeholder_layout
->overall_size
= wxSize(20, 20);
765 m_layouts
.Add(placeholder_layout
);
766 m_current_layout
= 0;
767 m_layout_offset
= wxPoint(0, 0);
768 m_hovered_button
= NULL
;
769 m_active_button
= NULL
;
770 m_lock_active_state
= false;
772 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
775 wxSize
wxRibbonButtonBar::GetMinSize() const
777 return m_layouts
.Last()->overall_size
;
780 wxSize
wxRibbonButtonBar::DoGetBestSize() const
782 return m_layouts
.Item(0)->overall_size
;
785 void wxRibbonButtonBar::MakeLayouts()
787 if(m_layouts_valid
|| m_art
== NULL
)
792 // Clear existing layouts
795 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
796 m_hovered_button
= NULL
;
800 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
801 m_active_button
= NULL
;
803 size_t count
= m_layouts
.GetCount();
805 for(i
= 0; i
< count
; ++i
)
807 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
812 size_t btn_count
= m_buttons
.Count();
815 // Best layout : all buttons large, stacking horizontally
816 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
817 wxPoint
cursor(0, 0);
818 layout
->overall_size
.SetHeight(0);
819 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
821 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
822 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
823 instance
.position
= cursor
;
824 instance
.size
= button
->GetLargestSize();
825 wxSize
& size
= button
->sizes
[instance
.size
].size
;
826 cursor
.x
+= size
.GetWidth();
827 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
829 layout
->buttons
.Add(instance
);
831 layout
->overall_size
.SetWidth(cursor
.x
);
832 m_layouts
.Add(layout
);
836 // Collapse the rightmost buttons and stack them vertically
837 size_t iLast
= btn_count
- 1;
838 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
845 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
846 size_t first_btn
, size_t* last_button
)
848 size_t btn_count
= m_buttons
.Count();
852 int available_width
= 0;
853 int available_height
= 0;
855 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
858 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
859 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
860 wxSize large_size
= button
->sizes
[large_size_class
].size
;
861 int t_available_height
= wxMax(available_height
,
862 large_size
.GetHeight());
863 int t_available_width
= available_width
+ large_size
.GetWidth();
864 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
865 if(!button
->GetSmallerSize(&small_size_class
))
869 wxSize small_size
= button
->sizes
[small_size_class
].size
;
870 int t_used_height
= used_height
+ small_size
.GetHeight();
871 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
873 if(t_used_height
> t_available_height
)
880 used_height
= t_used_height
;
881 used_width
= t_used_width
;
882 available_width
= t_available_width
;
883 available_height
= t_available_height
;
887 if(btn_i
>= first_btn
|| used_width
>= available_width
)
891 if(last_button
!= NULL
)
893 *last_button
= btn_i
;
896 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
897 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
898 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
899 bool preserve_height
= false;
902 // If height isn't preserved (i.e. it is reduced), then the minimum
903 // size for the button bar will decrease, preventing the original
904 // layout from being used (in some cases).
905 // It may be a good idea to always preverse the height, but for now
906 // it is only done when the first button is involved in a collapse.
907 preserve_height
= true;
910 for(; btn_i
<= first_btn
; ++btn_i
)
912 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
913 instance
.base
->GetSmallerSize(&instance
.size
);
914 instance
.position
= cursor
;
915 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
918 int x_adjust
= available_width
- used_width
;
920 for(; btn_i
< btn_count
; ++btn_i
)
922 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
923 instance
.position
.x
-= x_adjust
;
926 layout
->CalculateOverallSize();
929 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
930 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
933 wxFAIL_MSG("Layout collapse resulted in increased size");
939 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
942 m_layouts
.Add(layout
);
946 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
948 wxPoint
cursor(evt
.GetPosition());
949 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
950 long new_hovered_state
= 0;
952 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
953 size_t btn_count
= layout
->buttons
.Count();
955 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
957 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
958 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
960 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
961 btn_rect
.SetSize(size
.size
);
962 if(btn_rect
.Contains(cursor
))
964 new_hovered
= &instance
;
965 new_hovered_state
= instance
.base
->state
;
966 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
967 wxPoint
offset(cursor
);
968 offset
-= btn_rect
.GetTopLeft();
969 if(size
.normal_region
.Contains(offset
))
971 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
973 if(size
.dropdown_region
.Contains(offset
))
975 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
982 if(new_hovered
== NULL
&& GetToolTip())
988 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
989 new_hovered_state
!= m_hovered_button
->base
->state
))
991 if(m_hovered_button
!= NULL
)
993 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
995 m_hovered_button
= new_hovered
;
996 if(m_hovered_button
!= NULL
)
998 m_hovered_button
->base
->state
= new_hovered_state
;
1000 SetToolTip(m_hovered_button
->base
->help_string
);
1006 if(m_active_button
&& !m_lock_active_state
)
1008 long new_active_state
= m_active_button
->base
->state
;
1009 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1010 wxRibbonButtonBarButtonSizeInfo
& size
=
1011 m_active_button
->base
->sizes
[m_active_button
->size
];
1013 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1014 btn_rect
.SetSize(size
.size
);
1015 if(btn_rect
.Contains(cursor
))
1017 wxPoint
offset(cursor
);
1018 offset
-= btn_rect
.GetTopLeft();
1019 if(size
.normal_region
.Contains(offset
))
1021 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1023 if(size
.dropdown_region
.Contains(offset
))
1025 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1028 if(new_active_state
!= m_active_button
->base
->state
)
1030 m_active_button
->base
->state
= new_active_state
;
1036 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
1038 wxPoint
cursor(evt
.GetPosition());
1039 m_active_button
= NULL
;
1041 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
1042 size_t btn_count
= layout
->buttons
.Count();
1044 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1046 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1047 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1049 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1050 btn_rect
.SetSize(size
.size
);
1051 if(btn_rect
.Contains(cursor
))
1053 m_active_button
= &instance
;
1054 cursor
-= btn_rect
.GetTopLeft();
1056 if(size
.normal_region
.Contains(cursor
))
1057 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1058 else if(size
.dropdown_region
.Contains(cursor
))
1059 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1060 instance
.base
->state
|= state
;
1067 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
1069 wxPoint
cursor(evt
.GetPosition());
1073 wxRibbonButtonBarButtonSizeInfo
& size
=
1074 m_active_button
->base
->sizes
[m_active_button
->size
];
1076 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1077 btn_rect
.SetSize(size
.size
);
1078 if(btn_rect
.Contains(cursor
))
1080 int id
= m_active_button
->base
->id
;
1081 cursor
-= btn_rect
.GetTopLeft();
1082 wxEventType event_type
;
1085 if(size
.normal_region
.Contains(cursor
))
1086 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
1087 else if(size
.dropdown_region
.Contains(cursor
))
1088 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
1091 wxRibbonButtonBarEvent
notification(event_type
, id
);
1092 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
1094 m_active_button
->base
->state
^=
1095 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
1096 notification
.SetInt(m_active_button
->base
->state
&
1097 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
1099 notification
.SetEventObject(this);
1100 notification
.SetBar(this);
1101 m_lock_active_state
= true;
1102 ProcessWindowEvent(notification
);
1103 m_lock_active_state
= false;
1105 wxStaticCast(m_parent
, wxRibbonPanel
)->HideIfExpanded();
1107 if(m_active_button
) // may have been NULLed by event handler
1109 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1110 m_active_button
= NULL
;
1117 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1119 if(m_active_button
&& !evt
.LeftIsDown())
1121 m_active_button
= NULL
;
1125 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1127 bool repaint
= false;
1128 if(m_hovered_button
!= NULL
)
1130 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1131 m_hovered_button
= NULL
;
1134 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1136 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1142 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItem(size_t n
) const
1144 wxCHECK_MSG(n
>= 0 && n
< m_buttons
.GetCount(), NULL
, "wxRibbonButtonBar item's index is out of bound");
1145 return m_buttons
.Item(n
);
1148 wxRibbonButtonBarButtonBase
*wxRibbonButtonBar::GetItemById(int button_id
) const
1150 size_t count
= m_buttons
.GetCount();
1151 for ( size_t i
= 0; i
< count
; ++i
)
1153 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
1154 if ( button
->id
== button_id
)
1162 int wxRibbonButtonBar::GetItemId(wxRibbonButtonBarButtonBase
*item
) const
1164 wxCHECK_MSG(item
!= NULL
, wxNOT_FOUND
, "wxRibbonButtonBar item should not be NULL");
1169 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1171 wxPoint pos
= wxDefaultPosition
;
1172 if(m_bar
->m_active_button
)
1174 wxRibbonButtonBarButtonSizeInfo
& size
=
1175 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1177 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1178 m_bar
->m_active_button
->position
);
1179 btn_rect
.SetSize(size
.size
);
1180 pos
= btn_rect
.GetBottomLeft();
1183 return m_bar
->PopupMenu(menu
, pos
);
1186 #endif // wxUSE_RIBBON