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 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
284 if(m_buttons
.IsEmpty())
288 m_bitmap_size_large
= bitmap
.GetSize();
289 if(!bitmap_small
.IsOk())
291 m_bitmap_size_small
= m_bitmap_size_large
;
292 m_bitmap_size_small
*= 0.5;
295 if(bitmap_small
.IsOk())
297 m_bitmap_size_small
= bitmap_small
.GetSize();
300 m_bitmap_size_large
= m_bitmap_size_small
;
301 m_bitmap_size_large
*= 2.0;
306 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
307 base
->id
= button_id
;
309 base
->bitmap_large
= bitmap
;
310 if(!base
->bitmap_large
.IsOk())
312 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
313 m_bitmap_size_large
);
315 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
317 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
318 m_bitmap_size_large
);
320 base
->bitmap_small
= bitmap_small
;
321 if(!base
->bitmap_small
.IsOk())
323 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
324 m_bitmap_size_small
);
326 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
328 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
329 m_bitmap_size_small
);
331 base
->bitmap_large_disabled
= bitmap_disabled
;
332 if(!base
->bitmap_large_disabled
.IsOk())
334 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
336 base
->bitmap_small_disabled
= bitmap_small_disabled
;
337 if(!base
->bitmap_small_disabled
.IsOk())
339 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
342 base
->help_string
= help_string
;
343 base
->client_data
= client_data
;
346 wxClientDC
temp_dc(this);
347 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
348 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
349 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
353 m_layouts_valid
= false;
357 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
358 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
360 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
363 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
364 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
365 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
366 &info
.dropdown_region
);
369 info
.is_supported
= false;
372 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
374 wxImage
img(original
.ConvertToImage());
375 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
376 return wxBitmap(img
);
379 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
381 wxImage
img(original
.ConvertToImage());
382 return wxBitmap(img
.ConvertToGreyscale());
385 bool wxRibbonButtonBar::Realize()
390 m_layouts_valid
= true;
395 void wxRibbonButtonBar::ClearButtons()
397 m_layouts_valid
= false;
398 size_t count
= m_buttons
.GetCount();
400 for(i
= 0; i
< count
; ++i
)
402 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
409 bool wxRibbonButtonBar::DeleteButton(int button_id
)
411 size_t count
= m_buttons
.GetCount();
413 for(i
= 0; i
< count
; ++i
)
415 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
416 if(button
->id
== button_id
)
418 m_layouts_valid
= false;
419 m_buttons
.RemoveAt(i
);
428 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
430 size_t count
= m_buttons
.GetCount();
432 for(i
= 0; i
< count
; ++i
)
434 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
435 if(button
->id
== button_id
)
439 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
441 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
447 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
449 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
458 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
)
460 size_t count
= m_buttons
.GetCount();
462 for(i
= 0; i
< count
; ++i
)
464 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
465 if(button
->id
== button_id
)
469 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0)
471 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
477 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
)
479 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
488 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
495 wxRibbonControl::SetArtProvider(art
);
497 wxClientDC
temp_dc(this);
498 size_t btn_count
= m_buttons
.Count();
500 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
502 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
504 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
505 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
506 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
509 m_layouts_valid
= false;
513 bool wxRibbonButtonBar::IsSizingContinuous() const
518 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
521 size_t nlayouts
= m_layouts
.GetCount();
523 for(i
= 0; i
< nlayouts
; ++i
)
525 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
526 wxSize size
= layout
->overall_size
;
530 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
538 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
546 if(size
.x
< result
.x
&& size
.y
< result
.y
)
559 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
562 size_t nlayouts
= m_layouts
.GetCount();
567 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
568 wxSize size
= layout
->overall_size
;
572 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
580 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
588 if(size
.x
> result
.x
&& size
.y
> result
.y
)
601 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
603 // All painting done in main paint handler to minimise flicker
606 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
608 wxAutoBufferedPaintDC
dc(this);
609 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
611 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
613 size_t btn_count
= layout
->buttons
.Count();
615 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
617 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
618 wxRibbonButtonBarButtonBase
* base
= button
.base
;
620 wxBitmap
* bitmap
= &base
->bitmap_large
;
621 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
622 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
624 bitmap
= &base
->bitmap_large_disabled
;
625 bitmap_small
= &base
->bitmap_small_disabled
;
627 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
629 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
630 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
634 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
636 wxSize new_size
= evt
.GetSize();
637 size_t layout_count
= m_layouts
.GetCount();
639 m_current_layout
= layout_count
- 1;
640 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
642 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
643 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
645 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
646 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
647 m_current_layout
= layout_i
;
651 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
655 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
657 m_bitmap_size_large
= wxSize(32, 32);
658 m_bitmap_size_small
= wxSize(16, 16);
660 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
661 placeholder_layout
->overall_size
= wxSize(20, 20);
662 m_layouts
.Add(placeholder_layout
);
663 m_current_layout
= 0;
664 m_layout_offset
= wxPoint(0, 0);
665 m_hovered_button
= NULL
;
666 m_active_button
= NULL
;
667 m_lock_active_state
= false;
669 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
672 wxSize
wxRibbonButtonBar::GetMinSize() const
674 return m_layouts
.Last()->overall_size
;
677 wxSize
wxRibbonButtonBar::DoGetBestSize() const
679 return m_layouts
.Item(0)->overall_size
;
682 void wxRibbonButtonBar::MakeLayouts()
684 if(m_layouts_valid
|| m_art
== NULL
)
689 // Clear existing layouts
692 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
693 m_hovered_button
= NULL
;
697 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
698 m_active_button
= NULL
;
700 size_t count
= m_layouts
.GetCount();
702 for(i
= 0; i
< count
; ++i
)
704 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
709 size_t btn_count
= m_buttons
.Count();
712 // Best layout : all buttons large, stacking horizontally
713 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
714 wxPoint
cursor(0, 0);
715 layout
->overall_size
.SetHeight(0);
716 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
718 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
719 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
720 instance
.position
= cursor
;
721 instance
.size
= button
->GetLargestSize();
722 wxSize
& size
= button
->sizes
[instance
.size
].size
;
723 cursor
.x
+= size
.GetWidth();
724 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
726 layout
->buttons
.Add(instance
);
728 layout
->overall_size
.SetWidth(cursor
.x
);
729 m_layouts
.Add(layout
);
733 // Collapse the rightmost buttons and stack them vertically
734 size_t iLast
= btn_count
- 1;
735 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
742 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
743 size_t first_btn
, size_t* last_button
)
745 size_t btn_count
= m_buttons
.Count();
749 int available_width
= 0;
750 int available_height
= 0;
752 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
755 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
756 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
757 wxSize large_size
= button
->sizes
[large_size_class
].size
;
758 int t_available_height
= wxMax(available_height
,
759 large_size
.GetHeight());
760 int t_available_width
= available_width
+ large_size
.GetWidth();
761 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
762 if(!button
->GetSmallerSize(&small_size_class
))
766 wxSize small_size
= button
->sizes
[small_size_class
].size
;
767 int t_used_height
= used_height
+ small_size
.GetHeight();
768 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
770 if(t_used_height
> t_available_height
)
777 used_height
= t_used_height
;
778 used_width
= t_used_width
;
779 available_width
= t_available_width
;
780 available_height
= t_available_height
;
784 if(btn_i
>= first_btn
|| used_width
>= available_width
)
788 if(last_button
!= NULL
)
790 *last_button
= btn_i
;
793 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
794 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
795 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
796 bool preserve_height
= false;
799 // If height isn't preserved (i.e. it is reduced), then the minimum
800 // size for the button bar will decrease, preventing the original
801 // layout from being used (in some cases).
802 // It may be a good idea to always preverse the height, but for now
803 // it is only done when the first button is involved in a collapse.
804 preserve_height
= true;
807 for(; btn_i
<= first_btn
; ++btn_i
)
809 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
810 instance
.base
->GetSmallerSize(&instance
.size
);
811 instance
.position
= cursor
;
812 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
815 int x_adjust
= available_width
- used_width
;
817 for(; btn_i
< btn_count
; ++btn_i
)
819 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
820 instance
.position
.x
-= x_adjust
;
823 layout
->CalculateOverallSize();
826 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
827 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
830 wxFAIL_MSG("Layout collapse resulted in increased size");
836 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
839 m_layouts
.Add(layout
);
843 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
845 wxPoint
cursor(evt
.GetPosition());
846 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
847 long new_hovered_state
= 0;
849 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
850 size_t btn_count
= layout
->buttons
.Count();
852 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
854 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
855 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
857 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
858 btn_rect
.SetSize(size
.size
);
859 if(btn_rect
.Contains(cursor
))
861 new_hovered
= &instance
;
862 new_hovered_state
= instance
.base
->state
;
863 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
864 wxPoint
offset(cursor
);
865 offset
-= btn_rect
.GetTopLeft();
866 if(size
.normal_region
.Contains(offset
))
868 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
870 if(size
.dropdown_region
.Contains(offset
))
872 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
878 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
879 new_hovered_state
!= m_hovered_button
->base
->state
))
881 if(m_hovered_button
!= NULL
)
883 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
885 m_hovered_button
= new_hovered
;
886 if(m_hovered_button
!= NULL
)
888 m_hovered_button
->base
->state
= new_hovered_state
;
893 if(m_active_button
&& !m_lock_active_state
)
895 long new_active_state
= m_active_button
->base
->state
;
896 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
897 wxRibbonButtonBarButtonSizeInfo
& size
=
898 m_active_button
->base
->sizes
[m_active_button
->size
];
900 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
901 btn_rect
.SetSize(size
.size
);
902 if(btn_rect
.Contains(cursor
))
904 wxPoint
offset(cursor
);
905 offset
-= btn_rect
.GetTopLeft();
906 if(size
.normal_region
.Contains(offset
))
908 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
910 if(size
.dropdown_region
.Contains(offset
))
912 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
915 if(new_active_state
!= m_active_button
->base
->state
)
917 m_active_button
->base
->state
= new_active_state
;
923 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
925 wxPoint
cursor(evt
.GetPosition());
926 m_active_button
= NULL
;
928 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
929 size_t btn_count
= layout
->buttons
.Count();
931 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
933 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
934 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
936 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
937 btn_rect
.SetSize(size
.size
);
938 if(btn_rect
.Contains(cursor
))
940 m_active_button
= &instance
;
941 cursor
-= btn_rect
.GetTopLeft();
943 if(size
.normal_region
.Contains(cursor
))
944 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
945 else if(size
.dropdown_region
.Contains(cursor
))
946 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
947 instance
.base
->state
|= state
;
954 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
956 wxPoint
cursor(evt
.GetPosition());
960 wxRibbonButtonBarButtonSizeInfo
& size
=
961 m_active_button
->base
->sizes
[m_active_button
->size
];
963 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
964 btn_rect
.SetSize(size
.size
);
965 if(btn_rect
.Contains(cursor
))
967 int id
= m_active_button
->base
->id
;
968 cursor
-= btn_rect
.GetTopLeft();
969 wxEventType event_type
;
972 if(size
.normal_region
.Contains(cursor
))
973 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
974 else if(size
.dropdown_region
.Contains(cursor
))
975 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
978 wxRibbonButtonBarEvent
notification(event_type
, id
);
979 if(m_active_button
->base
->kind
== wxRIBBON_BUTTON_TOGGLE
)
981 m_active_button
->base
->state
^=
982 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
;
983 notification
.SetInt(m_active_button
->base
->state
&
984 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
);
986 notification
.SetEventObject(this);
987 notification
.SetBar(this);
988 m_lock_active_state
= true;
989 ProcessWindowEvent(notification
);
990 m_lock_active_state
= false;
992 if(m_active_button
) // may have been NULLed by event handler
994 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
995 m_active_button
= NULL
;
1002 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
1004 if(m_active_button
&& !evt
.LeftIsDown())
1006 m_active_button
= NULL
;
1010 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
1012 bool repaint
= false;
1013 if(m_hovered_button
!= NULL
)
1015 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
1016 m_hovered_button
= NULL
;
1019 if(m_active_button
!= NULL
&& !m_lock_active_state
)
1021 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
1028 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
1030 wxPoint pos
= wxDefaultPosition
;
1031 if(m_bar
->m_active_button
)
1033 wxRibbonButtonBarButtonSizeInfo
& size
=
1034 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
1036 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
1037 m_bar
->m_active_button
->position
);
1038 btn_rect
.SetSize(size
.size
);
1039 pos
= btn_rect
.GetBottomLeft();
1042 return m_bar
->PopupMenu(menu
, pos
);
1045 #endif // wxUSE_RIBBON