1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/ribbon/buttonbar.cpp 
   3 // Purpose:     Ribbon control similar to a tool bar 
   4 // Author:      Peter Cawley 
   8 // Copyright:   (C) Peter Cawley 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  20 #include "wx/ribbon/panel.h" 
  21 #include "wx/ribbon/buttonbar.h" 
  22 #include "wx/ribbon/art.h" 
  23 #include "wx/dcbuffer.h" 
  29 #include "wx/msw/private.h" 
  32 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_CLICKED
, wxRibbonButtonBarEvent
); 
  33 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
, wxRibbonButtonBarEvent
); 
  35 IMPLEMENT_DYNAMIC_CLASS(wxRibbonButtonBarEvent
, wxCommandEvent
) 
  36 IMPLEMENT_CLASS(wxRibbonButtonBar
, wxRibbonControl
) 
  38 BEGIN_EVENT_TABLE(wxRibbonButtonBar
, wxRibbonControl
) 
  39     EVT_ERASE_BACKGROUND(wxRibbonButtonBar::OnEraseBackground
) 
  40     EVT_ENTER_WINDOW(wxRibbonButtonBar::OnMouseEnter
) 
  41     EVT_LEAVE_WINDOW(wxRibbonButtonBar::OnMouseLeave
) 
  42     EVT_MOTION(wxRibbonButtonBar::OnMouseMove
) 
  43     EVT_PAINT(wxRibbonButtonBar::OnPaint
) 
  44     EVT_SIZE(wxRibbonButtonBar::OnSize
) 
  45     EVT_LEFT_DOWN(wxRibbonButtonBar::OnMouseDown
) 
  46     EVT_LEFT_UP(wxRibbonButtonBar::OnMouseUp
) 
  49 class wxRibbonButtonBarButtonSizeInfo
 
  55     wxRect dropdown_region
; 
  58 class wxRibbonButtonBarButtonInstance
 
  62     wxRibbonButtonBarButtonBase
* base
; 
  63     wxRibbonButtonBarButtonState size
; 
  66 class wxRibbonButtonBarButtonBase
 
  69     wxRibbonButtonBarButtonInstance 
NewInstance() 
  71         wxRibbonButtonBarButtonInstance i
; 
  76     wxRibbonButtonBarButtonState 
GetLargestSize() 
  78         if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_LARGE
].is_supported
) 
  79             return wxRIBBON_BUTTONBAR_BUTTON_LARGE
; 
  80         if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
) 
  81             return wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
; 
  82         wxASSERT(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
); 
  83         return wxRIBBON_BUTTONBAR_BUTTON_SMALL
; 
  87         wxRibbonButtonBarButtonState
* size
, int n 
= 1) 
  93             case wxRIBBON_BUTTONBAR_BUTTON_LARGE
: 
  94                 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
].is_supported
) 
  96                     *size 
= wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
; 
  99             case wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
: 
 100                 if(sizes
[wxRIBBON_BUTTONBAR_BUTTON_SMALL
].is_supported
) 
 102                     *size 
= wxRIBBON_BUTTONBAR_BUTTON_SMALL
; 
 105             case wxRIBBON_BUTTONBAR_BUTTON_SMALL
: 
 114     wxString help_string
; 
 115     wxBitmap bitmap_large
; 
 116     wxBitmap bitmap_large_disabled
; 
 117     wxBitmap bitmap_small
; 
 118     wxBitmap bitmap_small_disabled
; 
 119     wxRibbonButtonBarButtonSizeInfo sizes
[3]; 
 120     wxObject
* client_data
; 
 122     wxRibbonButtonKind kind
; 
 126 WX_DECLARE_OBJARRAY(wxRibbonButtonBarButtonInstance
, wxArrayRibbonButtonBarButtonInstance
); 
 127 #include "wx/arrimpl.cpp" 
 128 WX_DEFINE_OBJARRAY(wxArrayRibbonButtonBarButtonInstance
) 
 130 class wxRibbonButtonBarLayout
 
 134     wxArrayRibbonButtonBarButtonInstance buttons
; 
 136     void CalculateOverallSize() 
 138         overall_size 
= wxSize(0, 0); 
 139         size_t btn_count 
= buttons
.Count(); 
 141         for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 143             wxRibbonButtonBarButtonInstance
& instance 
= buttons
.Item(btn_i
); 
 144             wxSize size 
= instance
.base
->sizes
[instance
.size
].size
; 
 145             int right 
= instance
.position
.x 
+ size
.GetWidth(); 
 146             int bottom 
= instance
.position
.y 
+ size
.GetHeight(); 
 147             if(right 
> overall_size
.GetWidth()) 
 149                 overall_size
.SetWidth(right
); 
 151             if(bottom 
> overall_size
.GetHeight()) 
 153                 overall_size
.SetHeight(bottom
); 
 158     wxRibbonButtonBarButtonInstance
* FindSimilarInstance( 
 159         wxRibbonButtonBarButtonInstance
* inst
) 
 165         size_t btn_count 
= buttons
.Count(); 
 167         for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 169             wxRibbonButtonBarButtonInstance
& instance 
= buttons
.Item(btn_i
); 
 170             if(instance
.base 
== inst
->base
) 
 179 wxRibbonButtonBar::wxRibbonButtonBar() 
 181     m_layouts_valid 
= false; 
 185 wxRibbonButtonBar::wxRibbonButtonBar(wxWindow
* parent
, 
 190     : wxRibbonControl(parent
, id
, pos
, size
, wxBORDER_NONE
) 
 192     m_layouts_valid 
= false; 
 197 wxRibbonButtonBar::~wxRibbonButtonBar() 
 199     size_t count 
= m_buttons
.GetCount(); 
 201     for(i 
= 0; i 
< count
; ++i
) 
 203         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(i
); 
 208     count 
= m_layouts
.GetCount(); 
 209     for(i 
= 0; i 
< count
; ++i
) 
 211         wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(i
); 
 217 bool wxRibbonButtonBar::Create(wxWindow
* parent
, 
 223     if(!wxRibbonControl::Create(parent
, id
, pos
, size
, wxBORDER_NONE
)) 
 232 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton( 
 234                 const wxString
& label
, 
 235                 const wxBitmap
& bitmap
, 
 236                 const wxString
& help_string
, 
 237                 wxRibbonButtonKind kind
) 
 239     return AddButton(button_id
, label
, bitmap
, wxNullBitmap
, wxNullBitmap
, 
 240         wxNullBitmap
, kind
, help_string
); 
 243 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddDropdownButton( 
 245                 const wxString
& label
, 
 246                 const wxBitmap
& bitmap
, 
 247                 const wxString
& help_string
) 
 249     return AddButton(button_id
, label
, bitmap
, help_string
, 
 250         wxRIBBON_BUTTON_DROPDOWN
); 
 253 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddToggleButton( 
 255                 const wxString
& label
, 
 256                 const wxBitmap
& bitmap
, 
 257                 const wxString
& help_string
) 
 259     return AddButton(button_id
, label
, bitmap
, help_string
, 
 260         wxRIBBON_BUTTON_TOGGLE
); 
 263 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddHybridButton( 
 265                 const wxString
& label
, 
 266                 const wxBitmap
& bitmap
, 
 267                 const wxString
& help_string
) 
 269     return AddButton(button_id
, label
, bitmap
, help_string
, 
 270         wxRIBBON_BUTTON_HYBRID
); 
 273 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::AddButton( 
 275                 const wxString
& label
, 
 276                 const wxBitmap
& bitmap
, 
 277                 const wxBitmap
& bitmap_small
, 
 278                 const wxBitmap
& bitmap_disabled
, 
 279                 const wxBitmap
& bitmap_small_disabled
, 
 280                 wxRibbonButtonKind kind
, 
 281                 const wxString
& help_string
, 
 282                 wxObject
* client_data
) 
 284     return InsertButton(GetButtonCount(), button_id
, label
, bitmap
, 
 285         bitmap_small
, bitmap_disabled
,bitmap_small_disabled
, kind
, help_string
, 
 289 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton( 
 292                 const wxString
& label
, 
 293                 const wxBitmap
& bitmap
, 
 294                 const wxBitmap
& bitmap_small
, 
 295                 const wxBitmap
& bitmap_disabled
, 
 296                 const wxBitmap
& bitmap_small_disabled
, 
 297                 wxRibbonButtonKind kind
, 
 298                 const wxString
& help_string
, 
 299                 wxObject
* client_data
) 
 301     wxASSERT(bitmap
.IsOk() || bitmap_small
.IsOk()); 
 302     if(m_buttons
.IsEmpty()) 
 306             m_bitmap_size_large 
= bitmap
.GetSize(); 
 307             if(!bitmap_small
.IsOk()) 
 309                 m_bitmap_size_small 
= m_bitmap_size_large
; 
 310                 m_bitmap_size_small 
*= 0.5; 
 313         if(bitmap_small
.IsOk()) 
 315             m_bitmap_size_small 
= bitmap_small
.GetSize(); 
 318                 m_bitmap_size_large 
= m_bitmap_size_small
; 
 319                 m_bitmap_size_large 
*= 2.0; 
 324     wxRibbonButtonBarButtonBase
* base 
= new wxRibbonButtonBarButtonBase
; 
 325     base
->id 
= button_id
; 
 327     base
->bitmap_large 
= bitmap
; 
 328     if(!base
->bitmap_large
.IsOk()) 
 330         base
->bitmap_large 
= MakeResizedBitmap(base
->bitmap_small
, 
 331             m_bitmap_size_large
); 
 333     else if(base
->bitmap_large
.GetSize() != m_bitmap_size_large
) 
 335         base
->bitmap_large 
= MakeResizedBitmap(base
->bitmap_large
, 
 336             m_bitmap_size_large
); 
 338     base
->bitmap_small 
= bitmap_small
; 
 339     if(!base
->bitmap_small
.IsOk()) 
 341         base
->bitmap_small 
= MakeResizedBitmap(base
->bitmap_large
, 
 342             m_bitmap_size_small
); 
 344     else if(base
->bitmap_small
.GetSize() != m_bitmap_size_small
) 
 346         base
->bitmap_small 
= MakeResizedBitmap(base
->bitmap_small
, 
 347             m_bitmap_size_small
); 
 349     base
->bitmap_large_disabled 
= bitmap_disabled
; 
 350     if(!base
->bitmap_large_disabled
.IsOk()) 
 352         base
->bitmap_large_disabled 
= MakeDisabledBitmap(base
->bitmap_large
); 
 354     base
->bitmap_small_disabled 
= bitmap_small_disabled
; 
 355     if(!base
->bitmap_small_disabled
.IsOk()) 
 357         base
->bitmap_small_disabled 
= MakeDisabledBitmap(base
->bitmap_small
); 
 360     base
->help_string 
= help_string
; 
 361     base
->client_data 
= client_data
; 
 364     wxClientDC 
temp_dc(this); 
 365     FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
); 
 366     FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
); 
 367     FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
); 
 369     m_buttons
.Insert(base
, pos
); 
 370     m_layouts_valid 
= false; 
 374 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertButton( 
 377                 const wxString
& label
, 
 378                 const wxBitmap
& bitmap
, 
 379                 const wxString
& help_string
, 
 380                 wxRibbonButtonKind kind
) 
 382     return InsertButton(pos
, button_id
, label
, bitmap
, wxNullBitmap
, 
 383         wxNullBitmap
, wxNullBitmap
, kind
, help_string
); 
 386 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertDropdownButton( 
 389                 const wxString
& label
, 
 390                 const wxBitmap
& bitmap
, 
 391                 const wxString
& help_string
) 
 393     return InsertButton(pos
, button_id
, label
, bitmap
, help_string
, 
 394         wxRIBBON_BUTTON_DROPDOWN
); 
 397 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertToggleButton( 
 400                 const wxString
& label
, 
 401                 const wxBitmap
& bitmap
, 
 402                 const wxString
& help_string
) 
 404     return InsertButton(pos
, button_id
, label
, bitmap
, help_string
, 
 405         wxRIBBON_BUTTON_TOGGLE
); 
 408 wxRibbonButtonBarButtonBase
* wxRibbonButtonBar::InsertHybridButton( 
 411                 const wxString
& label
, 
 412                 const wxBitmap
& bitmap
, 
 413                 const wxString
& help_string
) 
 415     return InsertButton(pos
, button_id
, label
, bitmap
, help_string
, 
 416         wxRIBBON_BUTTON_HYBRID
); 
 419 void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase
* button
, 
 420         wxRibbonButtonBarButtonState size
, wxDC
& dc
) 
 422     wxRibbonButtonBarButtonSizeInfo
& info 
= button
->sizes
[size
]; 
 425         info
.is_supported 
= m_art
->GetButtonBarButtonSize(dc
, this, 
 426             button
->kind
, size
, button
->label
, m_bitmap_size_large
, 
 427             m_bitmap_size_small
, &info
.size
, &info
.normal_region
, 
 428             &info
.dropdown_region
); 
 431         info
.is_supported 
= false; 
 434 wxBitmap 
wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap
& original
, wxSize size
) 
 436     wxImage 
img(original
.ConvertToImage()); 
 437     img
.Rescale(size
.GetWidth(), size
.GetHeight(), wxIMAGE_QUALITY_HIGH
); 
 438     return wxBitmap(img
); 
 441 wxBitmap 
wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap
& original
) 
 443     wxImage 
img(original
.ConvertToImage()); 
 444     return wxBitmap(img
.ConvertToGreyscale()); 
 447 size_t wxRibbonButtonBar::GetButtonCount() const 
 449     return m_buttons
.GetCount(); 
 452 bool wxRibbonButtonBar::Realize() 
 457         m_layouts_valid 
= true; 
 462 void wxRibbonButtonBar::ClearButtons() 
 464     m_layouts_valid 
= false; 
 465     size_t count 
= m_buttons
.GetCount(); 
 467     for(i 
= 0; i 
< count
; ++i
) 
 469         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(i
); 
 476 bool wxRibbonButtonBar::DeleteButton(int button_id
) 
 478     size_t count 
= m_buttons
.GetCount(); 
 480     for(i 
= 0; i 
< count
; ++i
) 
 482         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(i
); 
 483         if(button
->id 
== button_id
) 
 485             m_layouts_valid 
= false; 
 486             m_buttons
.RemoveAt(i
); 
 495 void wxRibbonButtonBar::EnableButton(int button_id
, bool enable
) 
 497     size_t count 
= m_buttons
.GetCount(); 
 499     for(i 
= 0; i 
< count
; ++i
) 
 501         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(i
); 
 502         if(button
->id 
== button_id
) 
 506                 if(button
->state 
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) 
 508                     button
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED
; 
 514                 if((button
->state 
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) == 0) 
 516                     button
->state 
|= wxRIBBON_BUTTONBAR_BUTTON_DISABLED
; 
 525 void wxRibbonButtonBar::ToggleButton(int button_id
, bool checked
) 
 527     size_t count 
= m_buttons
.GetCount(); 
 529     for(i 
= 0; i 
< count
; ++i
) 
 531         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(i
); 
 532         if(button
->id 
== button_id
) 
 536                 if((button
->state 
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) == 0) 
 538                     button
->state 
|= wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
; 
 544                 if(button
->state 
& wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
) 
 546                     button
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
; 
 555 void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider
* art
) 
 562     wxRibbonControl::SetArtProvider(art
); 
 564     wxClientDC 
temp_dc(this); 
 565     size_t btn_count 
= m_buttons
.Count(); 
 567     for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 569         wxRibbonButtonBarButtonBase
* base 
= m_buttons
.Item(btn_i
); 
 571         FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_SMALL
, temp_dc
); 
 572         FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM
, temp_dc
); 
 573         FetchButtonSizeInfo(base
, wxRIBBON_BUTTONBAR_BUTTON_LARGE
, temp_dc
); 
 576     m_layouts_valid 
= false; 
 580 bool wxRibbonButtonBar::IsSizingContinuous() const 
 585 wxSize 
wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction
, 
 588     size_t nlayouts 
= m_layouts
.GetCount(); 
 590     for(i 
= 0; i 
< nlayouts
; ++i
) 
 592         wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(i
); 
 593         wxSize size 
= layout
->overall_size
; 
 597             if(size
.x 
< result
.x 
&& size
.y 
<= result
.y
) 
 605             if(size
.x 
<= result
.x 
&& size
.y 
< result
.y
) 
 613             if(size
.x 
< result
.x 
&& size
.y 
< result
.y
) 
 626 wxSize 
wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction
, 
 629     size_t nlayouts 
= m_layouts
.GetCount(); 
 634         wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(i
); 
 635         wxSize size 
= layout
->overall_size
; 
 639             if(size
.x 
> result
.x 
&& size
.y 
<= result
.y
) 
 647             if(size
.x 
<= result
.x 
&& size
.y 
> result
.y
) 
 655             if(size
.x 
> result
.x 
&& size
.y 
> result
.y
) 
 668 void wxRibbonButtonBar::UpdateWindowUI(long flags
) 
 670     wxWindowBase::UpdateWindowUI(flags
); 
 672     // don't waste time updating state of tools in a hidden toolbar 
 676     size_t btn_count 
= m_buttons
.size(); 
 677     bool rerealize 
= false; 
 678     for ( size_t btn_i 
= 0; btn_i 
< btn_count
; ++btn_i 
) 
 680         wxRibbonButtonBarButtonBase
& btn 
= *m_buttons
.Item(btn_i
); 
 683         wxUpdateUIEvent 
event(id
); 
 684         event
.SetEventObject(this); 
 686         if ( ProcessWindowEvent(event
) ) 
 688             if ( event
.GetSetEnabled() ) 
 689                 EnableButton(id
, event
.GetEnabled()); 
 690             if ( event
.GetSetChecked() ) 
 691                 ToggleButton(id
, event
.GetChecked()); 
 692             if ( event
.GetSetText() ) 
 694                 btn
.label 
= event
.GetText(); 
 704 void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
)) 
 706     // All painting done in main paint handler to minimise flicker 
 709 void wxRibbonButtonBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
)) 
 711     wxAutoBufferedPaintDC 
dc(this); 
 712     m_art
->DrawButtonBarBackground(dc
, this, GetSize()); 
 714     wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(m_current_layout
); 
 716     size_t btn_count 
= layout
->buttons
.Count(); 
 718     for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 720         wxRibbonButtonBarButtonInstance
& button 
= layout
->buttons
.Item(btn_i
); 
 721         wxRibbonButtonBarButtonBase
* base 
= button
.base
; 
 723         wxBitmap
* bitmap 
= &base
->bitmap_large
; 
 724         wxBitmap
* bitmap_small 
= &base
->bitmap_small
; 
 725         if(base
->state 
& wxRIBBON_BUTTONBAR_BUTTON_DISABLED
) 
 727             bitmap 
= &base
->bitmap_large_disabled
; 
 728             bitmap_small 
= &base
->bitmap_small_disabled
; 
 730         wxRect 
rect(button
.position 
+ m_layout_offset
, base
->sizes
[button
.size
].size
); 
 732         m_art
->DrawButtonBarButton(dc
, this, rect
, base
->kind
, 
 733             base
->state 
| button
.size
, base
->label
, *bitmap
, *bitmap_small
); 
 737 void wxRibbonButtonBar::OnSize(wxSizeEvent
& evt
) 
 739     wxSize new_size 
= evt
.GetSize(); 
 740     size_t layout_count 
= m_layouts
.GetCount(); 
 742     m_current_layout 
= layout_count 
- 1; 
 743     for(layout_i 
= 0; layout_i 
< layout_count
; ++layout_i
) 
 745         wxSize layout_size 
= m_layouts
.Item(layout_i
)->overall_size
; 
 746         if(layout_size
.x 
<= new_size
.x 
&& layout_size
.y 
<= new_size
.y
) 
 748             m_layout_offset
.x 
= (new_size
.x 
- layout_size
.x
) / 2; 
 749             m_layout_offset
.y 
= (new_size
.y 
- layout_size
.y
) / 2; 
 750             m_current_layout 
= layout_i
; 
 754     m_hovered_button 
= m_layouts
.Item(m_current_layout
)->FindSimilarInstance(m_hovered_button
); 
 758 void wxRibbonButtonBar::CommonInit(long WXUNUSED(style
)) 
 760     m_bitmap_size_large 
= wxSize(32, 32); 
 761     m_bitmap_size_small 
= wxSize(16, 16); 
 763     wxRibbonButtonBarLayout
* placeholder_layout 
= new wxRibbonButtonBarLayout
; 
 764     placeholder_layout
->overall_size 
= wxSize(20, 20); 
 765     m_layouts
.Add(placeholder_layout
); 
 766     m_current_layout 
= 0; 
 767     m_layout_offset 
= wxPoint(0, 0); 
 768     m_hovered_button 
= NULL
; 
 769     m_active_button 
= NULL
; 
 770     m_lock_active_state 
= false; 
 772     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 775 wxSize 
wxRibbonButtonBar::GetMinSize() const 
 777     return m_layouts
.Last()->overall_size
; 
 780 wxSize 
wxRibbonButtonBar::DoGetBestSize() const 
 782     return m_layouts
.Item(0)->overall_size
; 
 785 void wxRibbonButtonBar::MakeLayouts() 
 787     if(m_layouts_valid 
|| m_art 
== NULL
) 
 792         // Clear existing layouts 
 795             m_hovered_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
; 
 796             m_hovered_button 
= NULL
; 
 800             m_active_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
; 
 801             m_active_button 
= NULL
; 
 803         size_t count 
= m_layouts
.GetCount(); 
 805         for(i 
= 0; i 
< count
; ++i
) 
 807             wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(i
); 
 812     size_t btn_count 
= m_buttons
.Count(); 
 815         // Best layout : all buttons large, stacking horizontally 
 816         wxRibbonButtonBarLayout
* layout 
= new wxRibbonButtonBarLayout
; 
 817         wxPoint 
cursor(0, 0); 
 818         layout
->overall_size
.SetHeight(0); 
 819         for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 821             wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(btn_i
); 
 822             wxRibbonButtonBarButtonInstance instance 
= button
->NewInstance(); 
 823             instance
.position 
= cursor
; 
 824             instance
.size 
= button
->GetLargestSize(); 
 825             wxSize
& size 
= button
->sizes
[instance
.size
].size
; 
 826             cursor
.x 
+= size
.GetWidth(); 
 827             layout
->overall_size
.SetHeight(wxMax(layout
->overall_size
.GetHeight(), 
 829             layout
->buttons
.Add(instance
); 
 831         layout
->overall_size
.SetWidth(cursor
.x
); 
 832         m_layouts
.Add(layout
); 
 836         // Collapse the rightmost buttons and stack them vertically 
 837         size_t iLast 
= btn_count 
- 1; 
 838         while(TryCollapseLayout(m_layouts
.Last(), iLast
, &iLast
) && iLast 
> 0) 
 845 bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout
* original
, 
 846                                           size_t first_btn
, size_t* last_button
) 
 848     size_t btn_count 
= m_buttons
.Count(); 
 852     int available_width 
= 0; 
 853     int available_height 
= 0; 
 855     for(btn_i 
= first_btn 
+ 1; btn_i 
> 0; /* decrement is inside loop */) 
 858         wxRibbonButtonBarButtonBase
* button 
= m_buttons
.Item(btn_i
); 
 859         wxRibbonButtonBarButtonState large_size_class 
= button
->GetLargestSize(); 
 860         wxSize large_size 
= button
->sizes
[large_size_class
].size
; 
 861         int t_available_height 
= wxMax(available_height
, 
 862             large_size
.GetHeight()); 
 863         int t_available_width 
= available_width 
+ large_size
.GetWidth(); 
 864         wxRibbonButtonBarButtonState small_size_class 
= large_size_class
; 
 865         if(!button
->GetSmallerSize(&small_size_class
)) 
 869         wxSize small_size 
= button
->sizes
[small_size_class
].size
; 
 870         int t_used_height 
= used_height 
+ small_size
.GetHeight(); 
 871         int t_used_width 
= wxMax(used_width
, small_size
.GetWidth()); 
 873         if(t_used_height 
> t_available_height
) 
 880             used_height 
= t_used_height
; 
 881             used_width 
= t_used_width
; 
 882             available_width 
= t_available_width
; 
 883             available_height 
= t_available_height
; 
 887     if(btn_i 
>= first_btn 
|| used_width 
>= available_width
) 
 891     if(last_button 
!= NULL
) 
 893         *last_button 
= btn_i
; 
 896     wxRibbonButtonBarLayout
* layout 
= new wxRibbonButtonBarLayout
; 
 897     WX_APPEND_ARRAY(layout
->buttons
, original
->buttons
); 
 898     wxPoint 
cursor(layout
->buttons
.Item(btn_i
).position
); 
 899     bool preserve_height 
= false; 
 902         // If height isn't preserved (i.e. it is reduced), then the minimum 
 903         // size for the button bar will decrease, preventing the original 
 904         // layout from being used (in some cases). 
 905         // It may be a good idea to always preverse the height, but for now 
 906         // it is only done when the first button is involved in a collapse. 
 907         preserve_height 
= true; 
 910     for(; btn_i 
<= first_btn
; ++btn_i
) 
 912         wxRibbonButtonBarButtonInstance
& instance 
= layout
->buttons
.Item(btn_i
); 
 913         instance
.base
->GetSmallerSize(&instance
.size
); 
 914         instance
.position 
= cursor
; 
 915         cursor
.y 
+= instance
.base
->sizes
[instance
.size
].size
.GetHeight(); 
 918     int x_adjust 
= available_width 
- used_width
; 
 920     for(; btn_i 
< btn_count
; ++btn_i
) 
 922         wxRibbonButtonBarButtonInstance
& instance 
= layout
->buttons
.Item(btn_i
); 
 923         instance
.position
.x 
-= x_adjust
; 
 926     layout
->CalculateOverallSize(); 
 929     if(layout
->overall_size
.GetWidth() >= original
->overall_size
.GetWidth() || 
 930         layout
->overall_size
.GetHeight() > original
->overall_size
.GetHeight()) 
 933         wxFAIL_MSG("Layout collapse resulted in increased size"); 
 939         layout
->overall_size
.SetHeight(original
->overall_size
.GetHeight()); 
 942     m_layouts
.Add(layout
); 
 946 void wxRibbonButtonBar::OnMouseMove(wxMouseEvent
& evt
) 
 948     wxPoint 
cursor(evt
.GetPosition()); 
 949     wxRibbonButtonBarButtonInstance
* new_hovered 
= NULL
; 
 950     long new_hovered_state 
= 0; 
 952     wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(m_current_layout
); 
 953     size_t btn_count 
= layout
->buttons
.Count(); 
 955     for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
 957         wxRibbonButtonBarButtonInstance
& instance 
= layout
->buttons
.Item(btn_i
); 
 958         wxRibbonButtonBarButtonSizeInfo
& size 
= instance
.base
->sizes
[instance
.size
]; 
 960         btn_rect
.SetTopLeft(m_layout_offset 
+ instance
.position
); 
 961         btn_rect
.SetSize(size
.size
); 
 962         if(btn_rect
.Contains(cursor
)) 
 964             new_hovered 
= &instance
; 
 965             new_hovered_state 
= instance
.base
->state
; 
 966             new_hovered_state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
; 
 967             wxPoint 
offset(cursor
); 
 968             offset 
-= btn_rect
.GetTopLeft(); 
 969             if(size
.normal_region
.Contains(offset
)) 
 971                 new_hovered_state 
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED
; 
 973             if(size
.dropdown_region
.Contains(offset
)) 
 975                 new_hovered_state 
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED
; 
 982     if(new_hovered 
== NULL 
&& GetToolTip()) 
 988     if(new_hovered 
!= m_hovered_button 
|| (m_hovered_button 
!= NULL 
&& 
 989         new_hovered_state 
!= m_hovered_button
->base
->state
)) 
 991         if(m_hovered_button 
!= NULL
) 
 993             m_hovered_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
; 
 995         m_hovered_button 
= new_hovered
; 
 996         if(m_hovered_button 
!= NULL
) 
 998             m_hovered_button
->base
->state 
= new_hovered_state
; 
1000             SetToolTip(m_hovered_button
->base
->help_string
); 
1006     if(m_active_button 
&& !m_lock_active_state
) 
1008         long new_active_state 
= m_active_button
->base
->state
; 
1009         new_active_state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
; 
1010         wxRibbonButtonBarButtonSizeInfo
& size 
= 
1011             m_active_button
->base
->sizes
[m_active_button
->size
]; 
1013         btn_rect
.SetTopLeft(m_layout_offset 
+ m_active_button
->position
); 
1014         btn_rect
.SetSize(size
.size
); 
1015         if(btn_rect
.Contains(cursor
)) 
1017             wxPoint 
offset(cursor
); 
1018             offset 
-= btn_rect
.GetTopLeft(); 
1019             if(size
.normal_region
.Contains(offset
)) 
1021                 new_active_state 
|= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
; 
1023             if(size
.dropdown_region
.Contains(offset
)) 
1025                 new_active_state 
|= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
; 
1028         if(new_active_state 
!= m_active_button
->base
->state
) 
1030             m_active_button
->base
->state 
= new_active_state
; 
1036 void wxRibbonButtonBar::OnMouseDown(wxMouseEvent
& evt
) 
1038     wxPoint 
cursor(evt
.GetPosition()); 
1039     m_active_button 
= NULL
; 
1041     wxRibbonButtonBarLayout
* layout 
= m_layouts
.Item(m_current_layout
); 
1042     size_t btn_count 
= layout
->buttons
.Count(); 
1044     for(btn_i 
= 0; btn_i 
< btn_count
; ++btn_i
) 
1046         wxRibbonButtonBarButtonInstance
& instance 
= layout
->buttons
.Item(btn_i
); 
1047         wxRibbonButtonBarButtonSizeInfo
& size 
= instance
.base
->sizes
[instance
.size
]; 
1049         btn_rect
.SetTopLeft(m_layout_offset 
+ instance
.position
); 
1050         btn_rect
.SetSize(size
.size
); 
1051         if(btn_rect
.Contains(cursor
)) 
1053             m_active_button 
= &instance
; 
1054             cursor 
-= btn_rect
.GetTopLeft(); 
1056             if(size
.normal_region
.Contains(cursor
)) 
1057                 state 
= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE
; 
1058             else if(size
.dropdown_region
.Contains(cursor
)) 
1059                 state 
= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE
; 
1060             instance
.base
->state 
|= state
; 
1067 void wxRibbonButtonBar::OnMouseUp(wxMouseEvent
& evt
) 
1069     wxPoint 
cursor(evt
.GetPosition()); 
1073         wxRibbonButtonBarButtonSizeInfo
& size 
= 
1074             m_active_button
->base
->sizes
[m_active_button
->size
]; 
1076         btn_rect
.SetTopLeft(m_layout_offset 
+ m_active_button
->position
); 
1077         btn_rect
.SetSize(size
.size
); 
1078         if(btn_rect
.Contains(cursor
)) 
1080             int id 
= m_active_button
->base
->id
; 
1081             cursor 
-= btn_rect
.GetTopLeft(); 
1082             wxEventType event_type
; 
1085                 if(size
.normal_region
.Contains(cursor
)) 
1086                     event_type 
= wxEVT_COMMAND_RIBBONBUTTON_CLICKED
; 
1087                 else if(size
.dropdown_region
.Contains(cursor
)) 
1088                     event_type 
= wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED
; 
1091                 wxRibbonButtonBarEvent 
notification(event_type
, id
); 
1092                 if(m_active_button
->base
->kind 
== wxRIBBON_BUTTON_TOGGLE
) 
1094                     m_active_button
->base
->state 
^= 
1095                         wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
; 
1096                     notification
.SetInt(m_active_button
->base
->state 
& 
1097                         wxRIBBON_BUTTONBAR_BUTTON_TOGGLED
); 
1099                 notification
.SetEventObject(this); 
1100                 notification
.SetBar(this); 
1101                 m_lock_active_state 
= true; 
1102                 ProcessWindowEvent(notification
); 
1103                 m_lock_active_state 
= false; 
1105                 wxStaticCast(m_parent
, wxRibbonPanel
)->HideIfExpanded(); 
1107             if(m_active_button
) // may have been NULLed by event handler 
1109                 m_active_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
; 
1110                 m_active_button 
= NULL
; 
1117 void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent
& evt
) 
1119     if(m_active_button 
&& !evt
.LeftIsDown()) 
1121         m_active_button 
= NULL
; 
1125 void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
)) 
1127     bool repaint 
= false; 
1128     if(m_hovered_button 
!= NULL
) 
1130         m_hovered_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK
; 
1131         m_hovered_button 
= NULL
; 
1134     if(m_active_button 
!= NULL 
&& !m_lock_active_state
) 
1136         m_active_button
->base
->state 
&= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK
; 
1143 bool wxRibbonButtonBarEvent::PopupMenu(wxMenu
* menu
) 
1145     wxPoint pos 
= wxDefaultPosition
; 
1146     if(m_bar
->m_active_button
) 
1148         wxRibbonButtonBarButtonSizeInfo
& size 
= 
1149             m_bar
->m_active_button
->base
->sizes
[m_bar
->m_active_button
->size
]; 
1151         btn_rect
.SetTopLeft(m_bar
->m_layout_offset 
+ 
1152             m_bar
->m_active_button
->position
); 
1153         btn_rect
.SetSize(size
.size
); 
1154         pos 
= btn_rect
.GetBottomLeft(); 
1157     return m_bar
->PopupMenu(menu
, pos
); 
1160 #endif // wxUSE_RIBBON