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"
18 #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;
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::AddHybridButton(
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_HYBRID
);
262 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton(
264 const wxString
& label
,
265 const wxBitmap
& bitmap
,
266 const wxBitmap
& bitmap_small
,
267 const wxBitmap
& bitmap_disabled
,
268 const wxBitmap
& bitmap_small_disabled
,
269 wxRibbonButtonKind kind
,
270 const wxString
& help_string
,
271 wxObject
* client_data
)
273 wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk());
274 if(m_buttons
.IsEmpty())
278 m_bitmap_size_large
= bitmap
.GetSize();
279 if(!bitmap_small
.IsOk())
281 m_bitmap_size_small
= m_bitmap_size_large
;
282 m_bitmap_size_small
*= 0.5;
285 if(bitmap_small
.IsOk())
287 m_bitmap_size_small
= bitmap_small
.GetSize();
290 m_bitmap_size_large
= m_bitmap_size_small
;
291 m_bitmap_size_large
*= 2.0;
296 wxRibbonButtonBarButtonBase
* base
= new wxRibbonButtonBarButtonBase
;
297 base
->id
= button_id
;
299 base
->bitmap_large
= bitmap
;
300 if(!base
->bitmap_large
.IsOk())
302 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_small
,
303 m_bitmap_size_large
);
305 else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
)
307 base
->bitmap_large
= MakeResizedBitmap(base
->bitmap_large
,
308 m_bitmap_size_large
);
310 base
->bitmap_small
= bitmap_small
;
311 if(!base
->bitmap_small
.IsOk())
313 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_large
,
314 m_bitmap_size_small
);
316 else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
)
318 base
->bitmap_small
= MakeResizedBitmap(base
->bitmap_small
,
319 m_bitmap_size_small
);
321 base
->bitmap_large_disabled
= bitmap_disabled
;
322 if(!base
->bitmap_large_disabled
.IsOk())
324 base
->bitmap_large_disabled
= MakeDisabledBitmap(base
->bitmap_large
);
326 base
->bitmap_small_disabled
= bitmap_small_disabled
;
327 if(!base
->bitmap_small_disabled
.IsOk())
329 base
->bitmap_small_disabled
= MakeDisabledBitmap(base
->bitmap_small
);
332 base
->help_string
= help_string
;
333 base
->client_data
= client_data
;
336 wxClientDC
temp_dc(this);
337 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
338 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
339 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
343 m_layouts_valid
= false;
347 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
,
348 wxRibbonButtonBarButtonState size
, wxDC
& dc
)
350 wxRibbonButtonBarButtonSizeInfo
& info
= button
->sizes
[size
];
353 info
.is_supported
= m_art
->GetButtonBarButtonSize(dc
, this,
354 button
->kind
, size
, button
->label
, m_bitmap_size_large
,
355 m_bitmap_size_small
, &info
.size
, &info
.normal_region
,
356 &info
.dropdown_region
);
359 info
.is_supported
= false;
362 wxBitmap
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
)
364 wxImage
img(original
.ConvertToImage());
365 img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
);
366 return wxBitmap(img
);
369 wxBitmap
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
)
371 wxImage
img(original
.ConvertToImage());
372 return wxBitmap(img
.ConvertToGreyscale());
375 bool wxRibbonButtonBar::Realize()
380 m_layouts_valid
= true;
385 void wxRibbonButtonBar::ClearButtons()
387 m_layouts_valid
= false;
388 size_t count
= m_buttons
.GetCount();
390 for(i
= 0; i
< count
; ++i
)
392 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
399 bool wxRibbonButtonBar::DeleteButton(int button_id
)
401 size_t count
= m_buttons
.GetCount();
403 for(i
= 0; i
< count
; ++i
)
405 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
406 if(button
->id
== button_id
)
408 m_layouts_valid
= false;
409 m_buttons
.RemoveAt(i
);
418 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
)
420 size_t count
= m_buttons
.GetCount();
422 for(i
= 0; i
< count
; ++i
)
424 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(i
);
425 if(button
->id
== button_id
)
429 if(button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
431 button
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
437 if((button
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0)
439 button
->state
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
;
448 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
)
455 wxRibbonControl::SetArtProvider(art
);
457 wxClientDC
temp_dc(this);
458 size_t btn_count
= m_buttons
.Count();
460 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
462 wxRibbonButtonBarButtonBase
* base
= m_buttons
.Item(btn_i
);
464 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
);
465 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
);
466 FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
);
469 m_layouts_valid
= false;
473 bool wxRibbonButtonBar::IsSizingContinuous() const
478 wxSize
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
,
481 size_t nlayouts
= m_layouts
.GetCount();
483 for(i
= 0; i
< nlayouts
; ++i
)
485 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
486 wxSize size
= layout
->overall_size
;
490 if(size
.x
< result
.x
&& size
.y
<= result
.y
)
498 if(size
.x
<= result
.x
&& size
.y
< result
.y
)
506 if(size
.x
< result
.x
&& size
.y
< result
.y
)
519 wxSize
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
,
522 size_t nlayouts
= m_layouts
.GetCount();
527 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
528 wxSize size
= layout
->overall_size
;
532 if(size
.x
> result
.x
&& size
.y
<= result
.y
)
540 if(size
.x
<= result
.x
&& size
.y
> result
.y
)
548 if(size
.x
> result
.x
&& size
.y
> result
.y
)
561 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
))
563 // All painting done in main paint handler to minimise flicker
566 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
568 wxAutoBufferedPaintDC
dc(this);
569 m_art
->DrawButtonBarBackground(dc
, this, GetSize());
571 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
573 size_t btn_count
= layout
->buttons
.Count();
575 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
577 wxRibbonButtonBarButtonInstance
& button
= layout
->buttons
.Item(btn_i
);
578 wxRibbonButtonBarButtonBase
* base
= button
.base
;
580 wxBitmap
* bitmap
= &base
->bitmap_large
;
581 wxBitmap
* bitmap_small
= &base
->bitmap_small
;
582 if(base
->state
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
)
584 bitmap
= &base
->bitmap_large_disabled
;
585 bitmap_small
= &base
->bitmap_small_disabled
;
587 wxRect
rect(button
.position
+ m_layout_offset
, base
->sizes
[button
.size
].size
);
589 m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
,
590 base
->state
| button
.size
, base
->label
, *bitmap
, *bitmap_small
);
594 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
)
596 wxSize new_size
= evt
.GetSize();
597 size_t layout_count
= m_layouts
.GetCount();
599 m_current_layout
= layout_count
- 1;
600 for(layout_i
= 0; layout_i
< layout_count
; ++layout_i
)
602 wxSize layout_size
= m_layouts
.Item(layout_i
)->overall_size
;
603 if(layout_size
.x
<= new_size
.x
&& layout_size
.y
<= new_size
.y
)
605 m_layout_offset
.x
= (new_size
.x
- layout_size
.x
) / 2;
606 m_layout_offset
.y
= (new_size
.y
- layout_size
.y
) / 2;
607 m_current_layout
= layout_i
;
611 m_hovered_button
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
);
615 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
))
617 m_bitmap_size_large
= wxSize(32, 32);
618 m_bitmap_size_small
= wxSize(16, 16);
620 wxRibbonButtonBarLayout
* placeholder_layout
= new wxRibbonButtonBarLayout
;
621 placeholder_layout
->overall_size
= wxSize(20, 20);
622 m_layouts
.Add(placeholder_layout
);
623 m_current_layout
= 0;
624 m_layout_offset
= wxPoint(0, 0);
625 m_hovered_button
= NULL
;
626 m_active_button
= NULL
;
627 m_lock_active_state
= false;
629 SetBackgroundStyle(wxBG_STYLE_CUSTOM
);
632 wxSize
wxRibbonButtonBar::GetMinSize() const
634 return m_layouts
.Last()->overall_size
;
637 wxSize
wxRibbonButtonBar::DoGetBestSize() const
639 return m_layouts
.Item(0)->overall_size
;
642 void wxRibbonButtonBar::MakeLayouts()
644 if(m_layouts_valid
|| m_art
== NULL
)
649 // Clear existing layouts
652 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
653 m_hovered_button
= NULL
;
657 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
658 m_active_button
= NULL
;
660 size_t count
= m_layouts
.GetCount();
662 for(i
= 0; i
< count
; ++i
)
664 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(i
);
669 size_t btn_count
= m_buttons
.Count();
672 // Best layout : all buttons large, stacking horizontally
673 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
674 wxPoint
cursor(0, 0);
675 layout
->overall_size
.SetHeight(0);
676 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
678 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
679 wxRibbonButtonBarButtonInstance instance
= button
->NewInstance();
680 instance
.position
= cursor
;
681 instance
.size
= button
->GetLargestSize();
682 wxSize
& size
= button
->sizes
[instance
.size
].size
;
683 cursor
.x
+= size
.GetWidth();
684 layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(),
686 layout
->buttons
.Add(instance
);
688 layout
->overall_size
.SetWidth(cursor
.x
);
689 m_layouts
.Add(layout
);
693 // Collapse the rightmost buttons and stack them vertically
694 size_t iLast
= btn_count
- 1;
695 while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast
> 0)
702 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
,
703 size_t first_btn
, size_t* last_button
)
705 size_t btn_count
= m_buttons
.Count();
709 int available_width
= 0;
710 int available_height
= 0;
712 for(btn_i
= first_btn
+ 1; btn_i
> 0; /* decrement is inside loop */)
715 wxRibbonButtonBarButtonBase
* button
= m_buttons
.Item(btn_i
);
716 wxRibbonButtonBarButtonState large_size_class
= button
->GetLargestSize();
717 wxSize large_size
= button
->sizes
[large_size_class
].size
;
718 int t_available_height
= wxMax(available_height
,
719 large_size
.GetHeight());
720 int t_available_width
= available_width
+ large_size
.GetWidth();
721 wxRibbonButtonBarButtonState small_size_class
= large_size_class
;
722 if(!button
->GetSmallerSize(&small_size_class
))
726 wxSize small_size
= button
->sizes
[small_size_class
].size
;
727 int t_used_height
= used_height
+ small_size
.GetHeight();
728 int t_used_width
= wxMax(used_width
, small_size
.GetWidth());
730 if(t_used_height
> t_available_height
)
737 used_height
= t_used_height
;
738 used_width
= t_used_width
;
739 available_width
= t_available_width
;
740 available_height
= t_available_height
;
744 if(btn_i
>= first_btn
|| used_width
>= available_width
)
748 if(last_button
!= NULL
)
750 *last_button
= btn_i
;
753 wxRibbonButtonBarLayout
* layout
= new wxRibbonButtonBarLayout
;
754 WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
);
755 wxPoint
cursor(layout
->buttons
.Item(btn_i
).position
);
756 bool preserve_height
= false;
759 // If height isn't preserved (i.e. it is reduced), then the minimum
760 // size for the button bar will decrease, preventing the original
761 // layout from being used (in some cases).
762 // It may be a good idea to always preverse the height, but for now
763 // it is only done when the first button is involved in a collapse.
764 preserve_height
= true;
767 for(; btn_i
<= first_btn
; ++btn_i
)
769 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
770 instance
.base
->GetSmallerSize(&instance
.size
);
771 instance
.position
= cursor
;
772 cursor
.y
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight();
775 int x_adjust
= available_width
- used_width
;
777 for(; btn_i
< btn_count
; ++btn_i
)
779 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
780 instance
.position
.x
-= x_adjust
;
783 layout
->CalculateOverallSize();
786 if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() ||
787 layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight())
790 wxASSERT_MSG(false, wxT("Layout collapse resulted in increased size"));
796 layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight());
799 m_layouts
.Add(layout
);
803 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
)
805 wxPoint
cursor(evt
.GetPosition());
806 wxRibbonButtonBarButtonInstance
* new_hovered
= NULL
;
807 long new_hovered_state
= 0;
809 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
810 size_t btn_count
= layout
->buttons
.Count();
812 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
814 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
815 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
817 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
818 btn_rect
.SetSize(size
.size
);
819 if(btn_rect
.Contains(cursor
))
821 new_hovered
= &instance
;
822 new_hovered_state
= instance
.base
->state
;
823 new_hovered_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
824 wxPoint
offset(cursor
);
825 offset
-= btn_rect
.GetTopLeft();
826 if(size
.normal_region
.Contains(offset
))
828 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
;
830 if(size
.dropdown_region
.Contains(offset
))
832 new_hovered_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
;
838 if(new_hovered
!= m_hovered_button
|| (m_hovered_button
!= NULL
&&
839 new_hovered_state
!= m_hovered_button
->base
->state
))
841 if(m_hovered_button
!= NULL
)
843 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
845 m_hovered_button
= new_hovered
;
846 if(m_hovered_button
!= NULL
)
848 m_hovered_button
->base
->state
= new_hovered_state
;
853 if(m_active_button
&& !m_lock_active_state
)
855 long new_active_state
= m_active_button
->base
->state
;
856 new_active_state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
857 wxRibbonButtonBarButtonSizeInfo
& size
=
858 m_active_button
->base
->sizes
[m_active_button
->size
];
860 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
861 btn_rect
.SetSize(size
.size
);
862 if(btn_rect
.Contains(cursor
))
864 wxPoint
offset(cursor
);
865 offset
-= btn_rect
.GetTopLeft();
866 if(size
.normal_region
.Contains(offset
))
868 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
870 if(size
.dropdown_region
.Contains(offset
))
872 new_active_state
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
875 if(new_active_state
!= m_active_button
->base
->state
)
877 m_active_button
->base
->state
= new_active_state
;
883 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
)
885 wxPoint
cursor(evt
.GetPosition());
886 m_active_button
= NULL
;
888 wxRibbonButtonBarLayout
* layout
= m_layouts
.Item(m_current_layout
);
889 size_t btn_count
= layout
->buttons
.Count();
891 for(btn_i
= 0; btn_i
< btn_count
; ++btn_i
)
893 wxRibbonButtonBarButtonInstance
& instance
= layout
->buttons
.Item(btn_i
);
894 wxRibbonButtonBarButtonSizeInfo
& size
= instance
.base
->sizes
[instance
.size
];
896 btn_rect
.SetTopLeft(m_layout_offset
+ instance
.position
);
897 btn_rect
.SetSize(size
.size
);
898 if(btn_rect
.Contains(cursor
))
900 m_active_button
= &instance
;
901 cursor
-= btn_rect
.GetTopLeft();
903 if(size
.normal_region
.Contains(cursor
))
904 state
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
;
905 else if(size
.dropdown_region
.Contains(cursor
))
906 state
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
;
907 instance
.base
->state
|= state
;
914 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
)
916 wxPoint
cursor(evt
.GetPosition());
920 wxRibbonButtonBarButtonSizeInfo
& size
=
921 m_active_button
->base
->sizes
[m_active_button
->size
];
923 btn_rect
.SetTopLeft(m_layout_offset
+ m_active_button
->position
);
924 btn_rect
.SetSize(size
.size
);
925 if(btn_rect
.Contains(cursor
))
927 int id
= m_active_button
->base
->id
;
928 cursor
-= btn_rect
.GetTopLeft();
929 wxEventType event_type
;
932 if(size
.normal_region
.Contains(cursor
))
933 event_type
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
;
934 else if(size
.dropdown_region
.Contains(cursor
))
935 event_type
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
;
938 wxRibbonButtonBarEvent
notification(event_type
, id
);
939 notification
.SetEventObject(this);
940 notification
.SetBar(this);
941 m_lock_active_state
= true;
942 ProcessWindowEvent(notification
);
943 m_lock_active_state
= false;
945 if(m_active_button
) // may have been NULLed by event handler
947 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
948 m_active_button
= NULL
;
955 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
)
957 if(m_active_button
&& !evt
.LeftIsDown())
959 m_active_button
= NULL
;
963 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
))
965 bool repaint
= false;
966 if(m_hovered_button
!= NULL
)
968 m_hovered_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
;
969 m_hovered_button
= NULL
;
972 if(m_active_button
!= NULL
&& !m_lock_active_state
)
974 m_active_button
->base
->state
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
;
981 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
)
983 wxPoint pos
= wxDefaultPosition
;
984 if(m_bar
->m_active_button
)
986 wxRibbonButtonBarButtonSizeInfo
& size
=
987 m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
];
989 btn_rect
.SetTopLeft(m_bar
->m_layout_offset
+
990 m_bar
->m_active_button
->position
);
991 btn_rect
.SetSize(size
.size
);
992 pos
= btn_rect
.GetBottomLeft();
995 return m_bar
->PopupMenu(menu
, pos
);
998 #endif // wxUSE_RIBBON