1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/ribbon/toolbar.cpp 
   3 // Purpose:     Ribbon-style 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/toolbar.h" 
  21 #include "wx/ribbon/art.h" 
  22 #include "wx/ribbon/bar.h" 
  23 #include "wx/dcbuffer.h" 
  29 #include "wx/msw/private.h" 
  32 class wxRibbonToolBarToolBase
 
  37     wxBitmap bitmap_disabled
; 
  41     wxObject
* client_data
; 
  43     wxRibbonButtonKind kind
; 
  47 WX_DEFINE_ARRAY(wxRibbonToolBarToolBase
*, wxArrayRibbonToolBarToolBase
); 
  49 class wxRibbonToolBarToolGroup
 
  52     // To identify the group as a wxRibbonToolBarToolBase* 
  53     wxRibbonToolBarToolBase dummy_tool
; 
  55     wxArrayRibbonToolBarToolBase tools
; 
  60 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_CLICKED
, wxRibbonToolBarEvent
); 
  61 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED
, wxRibbonToolBarEvent
); 
  63 IMPLEMENT_DYNAMIC_CLASS(wxRibbonToolBarEvent
, wxCommandEvent
) 
  64 IMPLEMENT_CLASS(wxRibbonToolBar
, wxRibbonControl
) 
  66 BEGIN_EVENT_TABLE(wxRibbonToolBar
, wxRibbonControl
) 
  67     EVT_ENTER_WINDOW(wxRibbonToolBar::OnMouseEnter
) 
  68     EVT_ERASE_BACKGROUND(wxRibbonToolBar::OnEraseBackground
) 
  69     EVT_LEAVE_WINDOW(wxRibbonToolBar::OnMouseLeave
) 
  70     EVT_LEFT_DOWN(wxRibbonToolBar::OnMouseDown
) 
  71     EVT_LEFT_UP(wxRibbonToolBar::OnMouseUp
) 
  72     EVT_MOTION(wxRibbonToolBar::OnMouseMove
) 
  73     EVT_PAINT(wxRibbonToolBar::OnPaint
) 
  74     EVT_SIZE(wxRibbonToolBar::OnSize
) 
  77 wxRibbonToolBar::wxRibbonToolBar() 
  81 wxRibbonToolBar::wxRibbonToolBar(wxWindow
* parent
, 
  86     : wxRibbonControl(parent
, id
, pos
, size
, wxBORDER_NONE
) 
  91 bool wxRibbonToolBar::Create(wxWindow
* parent
, 
  97     if(!wxRibbonControl::Create(parent
, id
, pos
, size
, wxBORDER_NONE
)) 
 106 void wxRibbonToolBar::CommonInit(long WXUNUSED(style
)) 
 110     m_active_tool 
= NULL
; 
 113     m_sizes 
= new wxSize
[1]; 
 114     m_sizes
[0] = wxSize(0, 0); 
 115     SetBackgroundStyle(wxBG_STYLE_CUSTOM
); 
 118 wxRibbonToolBar::~wxRibbonToolBar() 
 120     size_t count 
= m_groups
.GetCount(); 
 122     for(i 
= 0; i 
< count
; ++i
) 
 124         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(i
); 
 125         size_t tool_count 
= group
->tools
.GetCount(); 
 126         for(t 
= 0; t 
< tool_count
; ++t
) 
 128             wxRibbonToolBarToolBase
* tool 
= group
->tools
.Item(t
); 
 137 wxRibbonToolBarToolBase
* wxRibbonToolBar::AddTool( 
 139                 const wxBitmap
& bitmap
, 
 140                 const wxString
& help_string
, 
 141                 wxRibbonButtonKind kind
) 
 143     return AddTool(tool_id
, bitmap
, wxNullBitmap
, help_string
, kind
, NULL
); 
 146 wxRibbonToolBarToolBase
* wxRibbonToolBar::AddDropdownTool( 
 148             const wxBitmap
& bitmap
, 
 149             const wxString
& help_string
) 
 151     return AddTool(tool_id
, bitmap
, wxNullBitmap
, help_string
, 
 152         wxRIBBON_BUTTON_DROPDOWN
, NULL
); 
 155 wxRibbonToolBarToolBase
* wxRibbonToolBar::AddHybridTool( 
 157             const wxBitmap
& bitmap
, 
 158             const wxString
& help_string
) 
 160     return AddTool(tool_id
, bitmap
, wxNullBitmap
, help_string
, 
 161         wxRIBBON_BUTTON_HYBRID
, NULL
); 
 164 wxRibbonToolBarToolBase
* wxRibbonToolBar::AddTool( 
 166             const wxBitmap
& bitmap
, 
 167             const wxBitmap
& bitmap_disabled
, 
 168             const wxString
& help_string
, 
 169             wxRibbonButtonKind kind
, 
 170             wxObject
* client_data
) 
 172     wxASSERT(bitmap
.IsOk()); 
 174     wxRibbonToolBarToolBase
* tool 
= new wxRibbonToolBarToolBase
; 
 176     tool
->bitmap 
= bitmap
; 
 177     if(bitmap_disabled
.IsOk()) 
 179         wxASSERT(bitmap
.GetSize() == bitmap_disabled
.GetSize()); 
 180         tool
->bitmap_disabled 
= bitmap_disabled
; 
 183         tool
->bitmap_disabled 
= MakeDisabledBitmap(bitmap
); 
 184     tool
->help_string 
= help_string
; 
 186     tool
->client_data 
= client_data
; 
 187     tool
->position 
= wxPoint(0, 0); 
 188     tool
->size 
= wxSize(0, 0); 
 191     m_groups
.Last()->tools
.Add(tool
); 
 195 wxRibbonToolBarToolBase
* wxRibbonToolBar::AddSeparator() 
 197     if(m_groups
.Last()->tools
.IsEmpty()) 
 201     return &m_groups
.Last()->dummy_tool
; 
 204 wxBitmap 
wxRibbonToolBar::MakeDisabledBitmap(const wxBitmap
& original
) 
 206     wxImage 
img(original
.ConvertToImage()); 
 207     return wxBitmap(img
.ConvertToGreyscale()); 
 210 void wxRibbonToolBar::AppendGroup() 
 212     wxRibbonToolBarToolGroup
* group 
= new wxRibbonToolBarToolGroup
; 
 213     group
->position 
= wxPoint(0, 0); 
 214     group
->size 
= wxSize(0, 0); 
 218 bool wxRibbonToolBar::IsSizingContinuous() const 
 223 static int GetSizeInOrientation(wxSize size
, wxOrientation orientation
) 
 227     case wxHORIZONTAL
: return size
.GetWidth(); 
 228     case wxVERTICAL
: return size
.GetHeight(); 
 229     case wxBOTH
: return size
.GetWidth() * size
.GetHeight(); 
 234 wxSize 
wxRibbonToolBar::DoGetNextSmallerSize(wxOrientation direction
, 
 235                                       wxSize relative_to
) const 
 237     wxSize 
result(relative_to
); 
 240     for(nrows 
= m_nrows_min
; nrows 
<= m_nrows_max
; ++nrows
) 
 242         wxSize 
size(m_sizes
[nrows 
- m_nrows_min
]); 
 243         wxSize 
original(size
); 
 247             if(size
.GetWidth() < relative_to
.GetWidth() 
 248                 && size
.GetHeight() <= relative_to
.GetHeight()) 
 250                 size
.SetHeight(relative_to
.GetHeight()); 
 255             if(size
.GetWidth() <= relative_to
.GetWidth() 
 256                 && size
.GetHeight() < relative_to
.GetHeight()) 
 258                 size
.SetWidth(relative_to
.GetWidth()); 
 263             if(size
.GetWidth() < relative_to
.GetWidth() 
 264                 && size
.GetHeight() < relative_to
.GetHeight()) 
 270         if(GetSizeInOrientation(original
, direction
) > area
) 
 273             area 
= GetSizeInOrientation(original
, direction
); 
 279 wxSize 
wxRibbonToolBar::DoGetNextLargerSize(wxOrientation direction
, 
 280                                  wxSize relative_to
) const 
 282     // Pick the smallest of our sizes which are larger than the given size 
 283     wxSize 
result(relative_to
); 
 286     for(nrows 
= m_nrows_min
; nrows 
<= m_nrows_max
; ++nrows
) 
 288         wxSize 
size(m_sizes
[nrows 
- m_nrows_min
]); 
 289         wxSize 
original(size
); 
 293             if(size
.GetWidth() > relative_to
.GetWidth() 
 294                 && size
.GetHeight() <= relative_to
.GetHeight()) 
 296                 size
.SetHeight(relative_to
.GetHeight()); 
 301             if(size
.GetWidth() <= relative_to
.GetWidth() 
 302                 && size
.GetHeight() > relative_to
.GetHeight()) 
 304                 size
.SetWidth(relative_to
.GetWidth()); 
 309             if(size
.GetWidth() > relative_to
.GetWidth() 
 310                 && size
.GetHeight() > relative_to
.GetHeight()) 
 316         if(GetSizeInOrientation(original
, direction
) < area
) 
 319             area 
= GetSizeInOrientation(original
, direction
); 
 326 void wxRibbonToolBar::SetRows(int nMin
, int nMax
) 
 332     wxASSERT(nMin 
<= nMax
); 
 338     m_sizes 
= new wxSize
[m_nrows_max 
- m_nrows_min 
+ 1]; 
 339     for(int i 
= m_nrows_min
; i 
<= m_nrows_max
; ++i
) 
 340         m_sizes
[i 
- m_nrows_min
] = wxSize(0, 0); 
 345 bool wxRibbonToolBar::Realize() 
 350     // Calculate the size of each group and the position/size of each tool 
 352     size_t group_count 
= m_groups
.GetCount(); 
 354     for(g 
= 0; g 
< group_count
; ++g
) 
 356         wxRibbonToolBarToolBase
* prev 
= NULL
; 
 357         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 358         size_t tool_count 
= group
->tools
.GetCount(); 
 360         for(t 
= 0; t 
< tool_count
; ++t
) 
 362             wxRibbonToolBarToolBase
* tool 
= group
->tools
.Item(t
); 
 363             tool
->size 
= m_art
->GetToolSize(temp_dc
, this, 
 364                 tool
->bitmap
.GetSize(), tool
->kind
, t 
== 0, 
 365                 t 
== (tool_count 
- 1), &tool
->dropdown
); 
 366             tool
->state 
= tool
->state 
& ~wxRIBBON_TOOLBAR_TOOL_DISABLED
; 
 368                 tool
->state 
|= wxRIBBON_TOOLBAR_TOOL_FIRST
; 
 369             if(t 
== tool_count 
- 1) 
 370                 tool
->state 
|= wxRIBBON_TOOLBAR_TOOL_LAST
; 
 371             if(tool
->size
.GetHeight() > tallest
) 
 372                 tallest 
= tool
->size
.GetHeight(); 
 375                 tool
->position 
= prev
->position
; 
 376                 tool
->position
.x 
+= prev
->size
.x
; 
 380                 tool
->position 
= wxPoint(0, 0); 
 385             group
->size 
= wxSize(0, 0); 
 388             group
->size 
= wxSize(prev
->position
.x 
+ prev
->size
.x
, tallest
); 
 389             for(t 
= 0; t 
< tool_count
; ++t
) 
 390                 group
->tools
.Item(t
)->size
.SetHeight(tallest
); 
 394     // Calculate the minimum size for each possible number of rows 
 396     int sep 
= m_art
->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE
); 
 397     int smallest_area 
= INT_MAX
; 
 398     wxSize
* row_sizes 
= new wxSize
[m_nrows_max
]; 
 399     wxOrientation major_axis 
= m_art
->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL 
? 
 400         wxVERTICAL 
: wxHORIZONTAL
; 
 401     SetMinSize(wxSize(0, 0)); 
 402     for(nrows 
= m_nrows_min
; nrows 
<= m_nrows_max
; ++nrows
) 
 404         for(r 
= 0; r 
< nrows
; ++r
) 
 405             row_sizes
[r
] = wxSize(0, 0); 
 406         for(g 
= 0; g 
< group_count
; ++g
) 
 408             wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 409             int shortest_row 
= 0; 
 410             for(r 
= 1; r 
< nrows
; ++r
) 
 412                 if(row_sizes
[r
].GetWidth() < row_sizes
[shortest_row
].GetWidth()) 
 415             row_sizes
[shortest_row
].x 
+= group
->size
.x 
+ sep
; 
 416             if(group
->size
.y 
> row_sizes
[shortest_row
].y
) 
 417                 row_sizes
[shortest_row
].y 
= group
->size
.y
; 
 420         for(r 
= 0; r 
< nrows
; ++r
) 
 422             if(row_sizes
[r
].GetWidth() != 0) 
 423                 row_sizes
[r
].DecBy(sep
, 0); 
 424             if(row_sizes
[r
].GetWidth() > size
.GetWidth()) 
 425                 size
.SetWidth(row_sizes
[r
].GetWidth()); 
 426             size
.IncBy(0, row_sizes
[r
].y
); 
 428         m_sizes
[nrows 
- m_nrows_min
] = size
; 
 429         if(GetSizeInOrientation(size
, major_axis
) < smallest_area
) 
 432             smallest_area 
= GetSizeInOrientation(size
, major_axis
); 
 437     // Position the groups 
 438     wxSizeEvent 
dummy_event(GetSize()); 
 444 void wxRibbonToolBar::OnSize(wxSizeEvent
& evt
) 
 449     // Choose row count with largest possible area 
 450     wxSize size 
= evt
.GetSize(); 
 451     int row_count 
= m_nrows_max
; 
 452     wxOrientation major_axis 
= m_art
->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL 
? 
 453         wxVERTICAL 
: wxHORIZONTAL
; 
 454     if(m_nrows_max 
!= m_nrows_min
) 
 457         for(int i 
= 0; i 
<= m_nrows_max 
- m_nrows_min
; ++i
) 
 459             if(m_sizes
[i
].x 
<= size
.x 
&& m_sizes
[i
].y 
<= size
.y 
&& 
 460                 GetSizeInOrientation(m_sizes
[i
], major_axis
) > area
) 
 462                 area 
= GetSizeInOrientation(m_sizes
[i
], major_axis
); 
 463                 row_count 
= m_nrows_min 
+ i
; 
 468     // Assign groups to rows and calculate row widths 
 469     wxSize
* row_sizes 
= new wxSize
[row_count
]; 
 470     int sep 
= m_art
->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE
); 
 473     for(r 
= 0; r 
< row_count
; ++r
) 
 474         row_sizes
[r
] = wxSize(0, 0); 
 476     size_t group_count 
= m_groups
.GetCount(); 
 477     for(g 
= 0; g 
< group_count
; ++g
) 
 479         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 480         int shortest_row 
= 0; 
 481         for(r 
= 1; r 
< row_count
; ++r
) 
 483             if(row_sizes
[r
].GetWidth() < row_sizes
[shortest_row
].GetWidth()) 
 486         group
->position 
= wxPoint(row_sizes
[shortest_row
].x
, shortest_row
); 
 487         row_sizes
[shortest_row
].x 
+= group
->size
.x 
+ sep
; 
 488         if(group
->size
.y 
> row_sizes
[shortest_row
].y
) 
 489             row_sizes
[shortest_row
].y 
= group
->size
.y
; 
 492     // Calculate row positions 
 493     int total_height 
= 0; 
 494     for(r 
= 0; r 
< row_count
; ++r
) 
 495         total_height 
+= row_sizes
[r
].GetHeight(); 
 496     int rowsep 
= (size
.GetHeight() - total_height
) / (row_count 
+ 1); 
 497     int* rowypos 
= new int[row_count
]; 
 499     for(r 
= 1; r 
< row_count
; ++r
) 
 501         rowypos
[r
] = rowypos
[r 
- 1] + row_sizes
[r 
- 1].GetHeight() + rowsep
; 
 504     // Set group y positions 
 505     for(g 
= 0; g 
< group_count
; ++g
) 
 507         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 508         group
->position
.y 
= rowypos
[group
->position
.y
]; 
 515 wxSize 
wxRibbonToolBar::DoGetBestSize() const 
 520 void wxRibbonToolBar::OnEraseBackground(wxEraseEvent
& WXUNUSED(evt
)) 
 522     // All painting done in main paint handler to minimise flicker 
 525 void wxRibbonToolBar::OnPaint(wxPaintEvent
& WXUNUSED(evt
)) 
 527     wxAutoBufferedPaintDC 
dc(this); 
 531     m_art
->DrawToolBarBackground(dc
, this, GetSize()); 
 533     size_t group_count 
= m_groups
.GetCount(); 
 535     for(g 
= 0; g 
< group_count
; ++g
) 
 537         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 538         size_t tool_count 
= group
->tools
.GetCount(); 
 541             m_art
->DrawToolGroupBackground(dc
, this, 
 542                 wxRect(group
->position
, group
->size
)); 
 543             for(t 
= 0; t 
< tool_count
; ++t
) 
 545                 wxRibbonToolBarToolBase
* tool 
= group
->tools
.Item(t
); 
 546                 wxRect 
rect(group
->position 
+ tool
->position
, tool
->size
); 
 547                 m_art
->DrawTool(dc
, this, rect
, tool
->bitmap
, tool
->kind
, 
 554 void wxRibbonToolBar::OnMouseMove(wxMouseEvent
& evt
) 
 556     wxPoint 
pos(evt
.GetPosition()); 
 557     wxRibbonToolBarToolBase 
*new_hover 
= NULL
; 
 559     size_t group_count 
= m_groups
.GetCount(); 
 561     for(g 
= 0; g 
< group_count
; ++g
) 
 563         wxRibbonToolBarToolGroup
* group 
= m_groups
.Item(g
); 
 564         if(group
->position
.x 
<= pos
.x 
&& pos
.x 
< group
->position
.x 
+ group
->size
.x
 
 565             && group
->position
.y 
<= pos
.y 
&& pos
.y 
< group
->position
.y 
+ group
->size
.y
) 
 567             size_t tool_count 
= group
->tools
.GetCount(); 
 568             pos 
-= group
->position
; 
 569             for(t 
= 0; t 
< tool_count
; ++t
) 
 571                 wxRibbonToolBarToolBase
* tool 
= group
->tools
.Item(t
); 
 572                 if(tool
->position
.x 
<= pos
.x 
&& pos
.x 
< tool
->position
.x 
+ tool
->size
.x
 
 573                     && tool
->position
.y 
<= pos
.y 
&& pos
.y 
< tool
->position
.y 
+ tool
->size
.y
) 
 575                     pos 
-= tool
->position
; 
 584     if(new_hover 
!= m_hover_tool
) 
 588             m_hover_tool
->state 
&= ~(wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
 
 589                 | wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK
); 
 591         m_hover_tool 
= new_hover
; 
 594             long what 
= wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED
; 
 595             if(new_hover
->dropdown
.Contains(pos
)) 
 596                 what 
= wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED
; 
 598             new_hover
->state 
|= what
; 
 600             if(new_hover 
== m_active_tool
) 
 602                 new_hover
->state 
&= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK
; 
 603                 new_hover
->state 
|= (what 
<< 2); 
 608     else if(m_hover_tool 
&& m_hover_tool
->kind 
== wxRIBBON_BUTTON_HYBRID
) 
 610         long newstate 
= m_hover_tool
->state 
&~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
; 
 611         long what 
= wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED
; 
 612         if(m_hover_tool
->dropdown
.Contains(pos
)) 
 613             what 
= wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED
; 
 615         if(newstate 
!= m_hover_tool
->state
) 
 617             m_hover_tool
->state 
= newstate
; 
 618             if(m_hover_tool 
== m_active_tool
) 
 620                 m_hover_tool
->state 
&= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK
; 
 621                 m_hover_tool
->state 
|= (what 
<< 2); 
 628 void wxRibbonToolBar::OnMouseDown(wxMouseEvent
& evt
) 
 633         m_active_tool 
= m_hover_tool
; 
 634         m_active_tool
->state 
|= 
 635             (m_active_tool
->state 
& wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
) << 2; 
 640 void wxRibbonToolBar::OnMouseLeave(wxMouseEvent
& WXUNUSED(evt
)) 
 644         m_hover_tool
->state 
&= ~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
; 
 650 void wxRibbonToolBar::OnMouseUp(wxMouseEvent
& WXUNUSED(evt
)) 
 654         if(m_active_tool
->state 
& wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK
) 
 656             wxEventType evt_type 
= wxEVT_COMMAND_RIBBONTOOL_CLICKED
; 
 657             if(m_active_tool
->state 
& wxRIBBON_TOOLBAR_TOOL_DROPDOWN_ACTIVE
) 
 658                 evt_type 
= wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED
; 
 659             wxRibbonToolBarEvent 
notification(evt_type
, m_active_tool
->id
); 
 660             notification
.SetEventObject(this); 
 661             notification
.SetBar(this); 
 662             ProcessEvent(notification
); 
 664         m_active_tool
->state 
&= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK
; 
 665         m_active_tool 
= NULL
; 
 670 void wxRibbonToolBar::OnMouseEnter(wxMouseEvent
& evt
) 
 672     if(m_active_tool 
&& !evt
.LeftIsDown()) 
 674         m_active_tool 
= NULL
; 
 678 bool wxRibbonToolBarEvent::PopupMenu(wxMenu
* menu
) 
 680     wxPoint pos 
= wxDefaultPosition
; 
 681     if(m_bar
->m_active_tool
) 
 683         // Find the group which contains the tool 
 684         size_t group_count 
= m_bar
->m_groups
.GetCount(); 
 686         for(g 
= 0; g 
< group_count
; ++g
) 
 688             wxRibbonToolBarToolGroup
* group 
= m_bar
->m_groups
.Item(g
); 
 689             size_t tool_count 
= group
->tools
.GetCount(); 
 690             for(t 
= 0; t 
< tool_count
; ++t
) 
 692                 wxRibbonToolBarToolBase
* tool 
= group
->tools
.Item(t
); 
 693                 if(tool 
== m_bar
->m_active_tool
) 
 695                     pos 
= group
->position
; 
 696                     pos 
+= tool
->position
; 
 697                     pos
.y 
+= tool
->size
.GetHeight(); 
 704     return m_bar
->PopupMenu(menu
, pos
); 
 707 #endif // wxUSE_RIBBON