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::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         wxFAIL_MSG("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