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/buttonbar.h"
21 #include "wx/ribbon/art.h"
22 #include "wx/dcbuffer.h"
28 #include "wx/msw/private.h"
31 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_CLICKED
, wxRibbonButtonBarEvent
);
32 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_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 wxObject
* 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
,
281 wxObject
* client_data
)
283 return InsertButton(GetButtonCount(), button_id
, label
, bitmap
,
284 bitmap_small
, bitmap_disabled
,bitmap_small_disabled
, kind
, help_string
,
288 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
291 const wxString
& label
,
292 const wxBitmap
& bitmap
,
293 const wxBitmap
& bitmap_small
,
294 const wxBitmap
& bitmap_disabled
,
295 const wxBitmap
& bitmap_small_disabled
,
296 wxRibbonButtonKind kind
,
297 const wxString
& help_string
,
298 wxObject
* client_data
)
300 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
301 if(m_buttons
.IsEmpty())
305 m_bitmap_size_large
= bitmap
.GetSize();
306 if(!bitmap_small
.IsOk())
308 m_bitmap_size_small
= m_bitmap_size_large
;
309 m_bitmap_size_small
*= 0.5;
312 if(bitmap_small
.IsOk())
314 m_bitmap_size_small
= bitmap_small
.GetSize();
317 m_bitmap_size_large
= m_bitmap_size_small
;
318 m_bitmap_size_large
*= 2.0;
323 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
324 base
->id
= button_id
;
326 base
->bitmap_large
= bitmap
;
327 if(!base
->bitmap_large
.IsOk())
329 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
330 m_bitmap_size_large
);
332 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
334 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
335 m_bitmap_size_large
);
337 base
->bitmap_small
= bitmap_small
;
338 if(!base
->bitmap_small
.IsOk())
340 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
341 m_bitmap_size_small
);
343 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
345 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
346 m_bitmap_size_small
);
348 base
->bitmap_large_disabled
= bitmap_disabled
;
349 if(!base
->bitmap_large_disabled
.IsOk())
351 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
353 base
->bitmap_small_disabled
= bitmap_small_disabled
;
354 if(!base
->bitmap_small_disabled
.IsOk())
356 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
359 base
->help_string
= help_string
;
360 base
->client_data
= client_data
;
363 wxClientDC
temp_dc(this);
364 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
365 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
366 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
368 m_buttons
.Insert(base
, pos
);
369 m_layouts_valid
= false;
373 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton(
376 const wxString
& label
,
377 const wxBitmap
& bitmap
,
378 const wxString
& help_string
,
379 wxRibbonButtonKind kind
)
381 return InsertButton(pos
, button_id
, label
, bitmap
, wxNullBitmap
,
382 wxNullBitmap
, wxNullBitmap
, kind
, help_string
);
385 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertDropdownButton(
388 const wxString
& label
,
389 const wxBitmap
& bitmap
,
390 const wxString
& help_string
)
392 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
393 wxRIBBON_BUTTON_DROPDOWN
);
396 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertToggleButton(
399 const wxString
& label
,
400 const wxBitmap
& bitmap
,
401 const wxString
& help_string
)
403 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
404 wxRIBBON_BUTTON_TOGGLE
);
407 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertHybridButton(
410 const wxString
& label
,
411 const wxBitmap
& bitmap
,
412 const wxString
& help_string
)
414 return InsertButton(pos
, button_id
, label
, bitmap
, help_string
,
415 wxRIBBON_BUTTON_HYBRID
);
418 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
419 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
421 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
424 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
425 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
426 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
427 &info
.dropdown_region
);
430 info
.is_supported
= false;
433 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
435 wxImage
img(original
.ConvertToImage());
436 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
437 return wxBitmap(img
);
440 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
442 wxImage
img(original
.ConvertToImage());
443 return wxBitmap(img
.ConvertToGreyscale());
446 size_t wxRibbonButtonBar::GetButtonCount() const
448 return m_buttons
.GetCount();
451 bool wxRibbonButtonBar::Realize()
456 m_layouts_valid
= true;
461 void wxRibbonButtonBar::ClearButtons()
463 m_layouts_valid
= false;
464 size_t count
= m_buttons
.GetCount();
466 for(i
= 0; i
< count
; ++i
)
468 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
475 bool wxRibbonButtonBar::DeleteButton(int button_id
)
477 size_t count
= m_buttons
.GetCount();
479 for(i
= 0; i
< count
; ++i
)
481 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
482 if(button
->id
== button_id
)
484 m_layouts_valid
= false;
485 m_buttons
.RemoveAt(i
);
494 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
496 size_t count
= m_buttons
.GetCount();
498 for(i
= 0; i
< count
; ++i
)
500 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
501 if(button
->id
== button_id
)
505 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
507 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
513 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
515 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
524 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
)
526 size_t count
= m_buttons
.GetCount();
528 for(i
= 0; i
< count
; ++i
)
530 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
531 if(button
->id
== button_id
)
535 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0)
537 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
543 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
)
545 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
554 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
561 wxRibbonControl::SetArtProvider(art
);
563 wxClientDC
temp_dc(this);
564 size_t btn_count
= m_buttons
.Count();
566 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
568 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
570 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
571 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
572 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
575 m_layouts_valid
= false;
579 bool wxRibbonButtonBar::IsSizingContinuous() const
584 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
587 size_t nlayouts
= m_layouts
.GetCount();
589 for(i
= 0; i
< nlayouts
; ++i
)
591 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
592 wxSize size
= layout
->overall_size
;
596 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
604 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
612 if(size
.x
< result
.x
&& size
.y
< result
.y
)
625 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
628 size_t nlayouts
= m_layouts
.GetCount();
633 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
634 wxSize size
= layout
->overall_size
;
638 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
646 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
654 if(size
.x
> result
.x
&& size
.y
> result
.y
)
667 void wxRibbonButtonBar::UpdateWindowUI(long flags
)
669 wxWindowBase::UpdateWindowUI(flags
);
671 // don't waste time updating state of tools in a hidden toolbar
675 size_t btn_count
= m_buttons
.size();
676 bool rerealize
= false;
677 for ( size_t btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
679 wxRibbonButtonBarButtonBase
& btn
= *m_buttons
.Item(btn_i
);
682 wxUpdateUIEvent
event(id
);
683 event
.SetEventObject(this);
685 if ( ProcessWindowEvent(event
) )
687 if ( event
.GetSetEnabled() )
688 EnableButton(id
, event
.GetEnabled());
689 if ( event
.GetSetChecked() )
690 ToggleButton(id
, event
.GetChecked());
691 if ( event
.GetSetText() )
693 btn
.label
= event
.GetText();
703 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
705 // All painting done in main paint handler to minimise flicker
708 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
710 wxAutoBufferedPaintDC
dc(this);
711 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
713 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
715 size_t btn_count
= layout
->buttons
.Count();
717 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
719 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
720 wxRibbonButtonBarButtonBase
* base
= button
.base
;
722 wxBitmap
* bitmap
= &base
->bitmap_large
;
723 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
724 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
726 bitmap
= &base
->bitmap_large_disabled
;
727 bitmap_small
= &base
->bitmap_small_disabled
;
729 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
731 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
732 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
736 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
738 wxSize new_size
= evt
.GetSize();
739 size_t layout_count
= m_layouts
.GetCount();
741 m_current_layout
= layout_count
- 1;
742 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
744 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
745 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
747 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
748 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
749 m_current_layout
= layout_i
;
753 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
757 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
759 m_bitmap_size_large
= wxSize(32, 32);
760 m_bitmap_size_small
= wxSize(16, 16);
762 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
763 placeholder_layout
->overall_size
= wxSize(20, 20);
764 m_layouts
.Add(placeholder_layout
);
765 m_current_layout
= 0;
766 m_layout_offset
= wxPoint(0, 0);
767 m_hovered_button
= NULL
;
768 m_active_button
= NULL
;
769 m_lock_active_state
= false;
771 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
774 wxSize
wxRibbonButtonBar::GetMinSize() const
776 return m_layouts
.Last()->overall_size
;
779 wxSize
wxRibbonButtonBar::DoGetBestSize() const
781 return m_layouts
.Item(0)->overall_size
;
784 void wxRibbonButtonBar::MakeLayouts()
786 if(m_layouts_valid
|| m_art
== NULL
)
791 // Clear existing layouts
794 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
795 m_hovered_button
= NULL
;
799 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
800 m_active_button
= NULL
;
802 size_t count
= m_layouts
.GetCount();
804 for(i
= 0; i
< count
; ++i
)
806 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
811 size_t btn_count
= m_buttons
.Count();
814 // Best layout : all buttons large, stacking horizontally
815 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
816 wxPoint
cursor(0, 0);
817 layout
->overall_size
.SetHeight(0);
818 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
820 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
821 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
822 instance
.position
= cursor
;
823 instance
.size
= button
->GetLargestSize();
824 wxSize
& size
= button
->sizes
[instance
.size
].size
;
825 cursor
.x
+= size
.GetWidth();
826 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
828 layout
->buttons
.Add(instance
);
830 layout
->overall_size
.SetWidth(cursor
.x
);
831 m_layouts
.Add(layout
);
835 // Collapse the rightmost buttons and stack them vertically
836 size_t iLast
= btn_count
- 1;
837 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
844 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
845 size_t first_btn
, size_t* last_button
)
847 size_t btn_count
= m_buttons
.Count();
851 int available_width
= 0;
852 int available_height
= 0;
854 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
857 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
858 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
859 wxSize large_size
= button
->sizes
[large_size_class
].size
;
860 int t_available_height
= wxMax(available_height
,
861 large_size
.GetHeight());
862 int t_available_width
= available_width
+ large_size
.GetWidth();
863 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
864 if(!button
->GetSmallerSize(&small_size_class
))
868 wxSize small_size
= button
->sizes
[small_size_class
].size
;
869 int t_used_height
= used_height
+ small_size
.GetHeight();
870 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
872 if(t_used_height
> t_available_height
)
879 used_height
= t_used_height
;
880 used_width
= t_used_width
;
881 available_width
= t_available_width
;
882 available_height
= t_available_height
;
886 if(btn_i
>= first_btn
|| used_width
>= available_width
)
890 if(last_button
!= NULL
)
892 *last_button
= btn_i
;
895 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
896 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
897 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
898 bool preserve_height
= false;
901 // If height isn't preserved (i.e. it is reduced), then the minimum
902 // size for the button bar will decrease, preventing the original
903 // layout from being used (in some cases).
904 // It may be a good idea to always preverse the height, but for now
905 // it is only done when the first button is involved in a collapse.
906 preserve_height
= true;
909 for(; btn_i
<= first_btn
; ++btn_i
)
911 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
912 instance
.base
->GetSmallerSize(&instance
.size
);
913 instance
.position
= cursor
;
914 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
917 int x_adjust
= available_width
- used_width
;
919 for(; btn_i
< btn_count
; ++btn_i
)
921 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
922 instance
.position
.x
-= x_adjust
;
925 layout
->CalculateOverallSize();
928 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
929 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
932 wxFAIL_MSG("Layout collapse resulted in increased size");
938 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
941 m_layouts
.Add(layout
);
945 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
947 wxPoint
cursor(evt
.GetPosition());
948 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
949 long new_hovered_state
= 0;
951 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
952 size_t btn_count
= layout
->buttons
.Count();
954 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
956 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
957 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
959 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
960 btn_rect
.SetSize(size
.size
);
961 if(btn_rect
.Contains(cursor
))
963 new_hovered
= &instance
;
964 new_hovered_state
= instance
.base
->state
;
965 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
966 wxPoint
offset(cursor
);
967 offset
-= btn_rect
.GetTopLeft();
968 if(size
.normal_region
.Contains(offset
))
970 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
972 if(size
.dropdown_region
.Contains(offset
))
974 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
981 if(new_hovered
== NULL
&& GetToolTip())
987 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
988 new_hovered_state
!= m_hovered_button
->base
->state
))
990 if(m_hovered_button
!= NULL
)
992 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
994 m_hovered_button
= new_hovered
;
995 if(m_hovered_button
!= NULL
)
997 m_hovered_button
->base
->state
= new_hovered_state
;
999 SetToolTip(m_hovered_button
->base
->help_string
);
1005 if(m_active_button
&& !m_lock_active_state
)
1007 long new_active_state
= m_active_button
->base
->state
;
1008 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1009 wxRibbonButtonBarButtonSizeInfo
& size
=
1010 m_active_button
->base
->sizes
[m_active_button
->size
];
1012 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1013 btn_rect
.SetSize(size
.size
);
1014 if(btn_rect
.Contains(cursor
))
1016 wxPoint
offset(cursor
);
1017 offset
-= btn_rect
.GetTopLeft();
1018 if(size
.normal_region
.Contains(offset
))
1020 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1022 if(size
.dropdown_region
.Contains(offset
))
1024 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1027 if(new_active_state
!= m_active_button
->base
->state
)
1029 m_active_button
->base
->state
= new_active_state
;
1035 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
1037 wxPoint
cursor(evt
.GetPosition());
1038 m_active_button
= NULL
;
1040 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
1041 size_t btn_count
= layout
->buttons
.Count();
1043 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
1045 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
1046 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
1048 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
1049 btn_rect
.SetSize(size
.size
);
1050 if(btn_rect
.Contains(cursor
))
1052 m_active_button
= &instance
;
1053 cursor
-= btn_rect
.GetTopLeft();
1055 if(size
.normal_region
.Contains(cursor
))
1056 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
1057 else if(size
.dropdown_region
.Contains(cursor
))
1058 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
1059 instance
.base
->state
|= state
;
1066 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
1068 wxPoint
cursor(evt
.GetPosition());
1072 wxRibbonButtonBarButtonSizeInfo
& size
=
1073 m_active_button
->base
->sizes
[m_active_button
->size
];
1075 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
1076 btn_rect
.SetSize(size
.size
);
1077 if(btn_rect
.Contains(cursor
))
1079 int id
= m_active_button
->base
->id
;
1080 cursor
-= btn_rect
.GetTopLeft();
1081 wxEventType event_type
;
1084 if(size
.normal_region
.Contains(cursor
))
1085 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
1086 else if(size
.dropdown_region
.Contains(cursor
))
1087 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
1090 wxRibbonButtonBarEvent
notification(event_type
, id
);
1091 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
1093 m_active_button
->base
->state
^=
1094 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
1095 notification
.SetInt(m_active_button
->base
->state
&
1096 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
1098 notification
.SetEventObject(this);
1099 notification
.SetBar(this);
1100 m_lock_active_state
= true;
1101 ProcessWindowEvent(notification
);
1102 m_lock_active_state
= false;
1104 if(m_active_button
) // may have been NULLed by event handler
1106 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1107 m_active_button
= NULL
;
1114 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1116 if(m_active_button
&& !evt
.LeftIsDown())
1118 m_active_button
= NULL
;
1122 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1124 bool repaint
= false;
1125 if(m_hovered_button
!= NULL
)
1127 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1128 m_hovered_button
= NULL
;
1131 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1133 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1140 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1142 wxPoint pos
= wxDefaultPosition
;
1143 if(m_bar
->m_active_button
)
1145 wxRibbonButtonBarButtonSizeInfo
& size
=
1146 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1148 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1149 m_bar
->m_active_button
->position
);
1150 btn_rect
.SetSize(size
.size
);
1151 pos
= btn_rect
.GetBottomLeft();
1154 return m_bar
->PopupMenu(menu
, pos
);
1157 #endif // wxUSE_RIBBON