Added ability to switch off more components of the size page UI
[wxWidgets.git] / src / ribbon / toolbar.cpp
CommitLineData
3c3ead1d
PC
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/ribbon/toolbar.cpp
3// Purpose: Ribbon-style tool bar
4// Author: Peter Cawley
5// Modified by:
6// Created: 2009-07-06
7// RCS-ID: $Id$
8// Copyright: (C) Peter Cawley
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15 #pragma hdrstop
16#endif
17
3c3ead1d
PC
18#if wxUSE_RIBBON
19
4cf018e1 20#include "wx/ribbon/toolbar.h"
3c3ead1d
PC
21#include "wx/ribbon/art.h"
22#include "wx/ribbon/bar.h"
23#include "wx/dcbuffer.h"
24
25#ifndef WX_PRECOMP
26#endif
27
28#ifdef __WXMSW__
29#include "wx/msw/private.h"
30#endif
31
32class wxRibbonToolBarToolBase
33{
34public:
35 wxString help_string;
36 wxBitmap bitmap;
37 wxBitmap bitmap_disabled;
38 wxRect dropdown;
39 wxPoint position;
40 wxSize size;
41 wxObject* client_data;
42 int id;
43 wxRibbonButtonKind kind;
44 long state;
45};
46
c155b9b5 47WX_DEFINE_ARRAY_PTR(wxRibbonToolBarToolBase*, wxArrayRibbonToolBarToolBase);
3c3ead1d
PC
48
49class wxRibbonToolBarToolGroup
50{
51public:
52 // To identify the group as a wxRibbonToolBarToolBase*
53 wxRibbonToolBarToolBase dummy_tool;
54
55 wxArrayRibbonToolBarToolBase tools;
56 wxPoint position;
57 wxSize size;
58};
59
60wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_CLICKED, wxRibbonToolBarEvent);
61wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED, wxRibbonToolBarEvent);
62
63IMPLEMENT_DYNAMIC_CLASS(wxRibbonToolBarEvent, wxCommandEvent)
64IMPLEMENT_CLASS(wxRibbonToolBar, wxRibbonControl)
65
66BEGIN_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)
75END_EVENT_TABLE()
76
77wxRibbonToolBar::wxRibbonToolBar()
78{
79}
80
81wxRibbonToolBar::wxRibbonToolBar(wxWindow* parent,
82 wxWindowID id,
83 const wxPoint& pos,
84 const wxSize& size,
85 long style)
86 : wxRibbonControl(parent, id, pos, size, wxBORDER_NONE)
87{
88 CommonInit(style);
89}
90
91bool wxRibbonToolBar::Create(wxWindow* parent,
92 wxWindowID id,
93 const wxPoint& pos,
94 const wxSize& size,
95 long style)
96{
97 if(!wxRibbonControl::Create(parent, id, pos, size, wxBORDER_NONE))
98 {
99 return false;
100 }
101
102 CommonInit(style);
103 return true;
104}
105
106void wxRibbonToolBar::CommonInit(long WXUNUSED(style))
107{
108 AppendGroup();
109 m_hover_tool = NULL;
110 m_active_tool = NULL;
111 m_nrows_min = 1;
112 m_nrows_max = 1;
113 m_sizes = new wxSize[1];
114 m_sizes[0] = wxSize(0, 0);
115 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
116}
117
118wxRibbonToolBar::~wxRibbonToolBar()
119{
120 size_t count = m_groups.GetCount();
121 size_t i, t;
122 for(i = 0; i < count; ++i)
123 {
124 wxRibbonToolBarToolGroup* group = m_groups.Item(i);
125 size_t tool_count = group->tools.GetCount();
126 for(t = 0; t < tool_count; ++t)
127 {
128 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
129 delete tool;
130 }
131 delete group;
132 }
133 m_groups.Clear();
134 delete[] m_sizes;
135}
136
137wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool(
138 int tool_id,
139 const wxBitmap& bitmap,
140 const wxString& help_string,
141 wxRibbonButtonKind kind)
142{
143 return AddTool(tool_id, bitmap, wxNullBitmap, help_string, kind, NULL);
144}
145
146wxRibbonToolBarToolBase* wxRibbonToolBar::AddDropdownTool(
147 int tool_id,
148 const wxBitmap& bitmap,
149 const wxString& help_string)
150{
151 return AddTool(tool_id, bitmap, wxNullBitmap, help_string,
152 wxRIBBON_BUTTON_DROPDOWN, NULL);
153}
154
155wxRibbonToolBarToolBase* wxRibbonToolBar::AddHybridTool(
156 int tool_id,
157 const wxBitmap& bitmap,
158 const wxString& help_string)
159{
160 return AddTool(tool_id, bitmap, wxNullBitmap, help_string,
161 wxRIBBON_BUTTON_HYBRID, NULL);
162}
163
d1bf0be0
VZ
164wxRibbonToolBarToolBase* wxRibbonToolBar::AddToggleTool(
165 int tool_id,
166 const wxBitmap& bitmap,
167 const wxString& help_string)
168{
169 return AddTool(tool_id, bitmap, wxNullBitmap, help_string,
170 wxRIBBON_BUTTON_TOGGLE, NULL);
171}
172
3c3ead1d
PC
173wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool(
174 int tool_id,
175 const wxBitmap& bitmap,
176 const wxBitmap& bitmap_disabled,
177 const wxString& help_string,
178 wxRibbonButtonKind kind,
179 wxObject* client_data)
d1bf0be0
VZ
180{
181 return InsertTool(GetToolCount(), tool_id, bitmap, bitmap_disabled,
182 help_string, kind, client_data);
183}
184
185wxRibbonToolBarToolBase* wxRibbonToolBar::AddSeparator()
186{
187 if(m_groups.Last()->tools.IsEmpty())
188 return NULL;
189
190 AppendGroup();
191 return &m_groups.Last()->dummy_tool;
192}
193
194
195wxRibbonToolBarToolBase* wxRibbonToolBar::InsertTool(
196 size_t pos,
197 int tool_id,
198 const wxBitmap& bitmap,
199 const wxString& help_string,
200 wxRibbonButtonKind kind)
201{
202 return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string, kind,
203 NULL);
204}
205
206wxRibbonToolBarToolBase* wxRibbonToolBar::InsertDropdownTool(
207 size_t pos,
208 int tool_id,
209 const wxBitmap& bitmap,
210 const wxString& help_string)
211{
212 return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string,
213 wxRIBBON_BUTTON_DROPDOWN, NULL);
214}
215
216wxRibbonToolBarToolBase* wxRibbonToolBar::InsertHybridTool(
217 size_t pos,
218 int tool_id,
219 const wxBitmap& bitmap,
220 const wxString& help_string)
221{
222 return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string,
223 wxRIBBON_BUTTON_HYBRID, NULL);
224}
225
226wxRibbonToolBarToolBase* wxRibbonToolBar::InsertToggleTool(
227 size_t pos,
228 int tool_id,
229 const wxBitmap& bitmap,
230 const wxString& help_string)
231{
232 return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string,
233 wxRIBBON_BUTTON_TOGGLE, NULL);
234}
235
236wxRibbonToolBarToolBase* wxRibbonToolBar::InsertTool(
237 size_t pos,
238 int tool_id,
239 const wxBitmap& bitmap,
240 const wxBitmap& bitmap_disabled,
241 const wxString& help_string,
242 wxRibbonButtonKind kind,
243 wxObject* client_data)
3c3ead1d
PC
244{
245 wxASSERT(bitmap.IsOk());
246
d1bf0be0 247 // Create the wxRibbonToolBarToolBase with parameters
3c3ead1d
PC
248 wxRibbonToolBarToolBase* tool = new wxRibbonToolBarToolBase;
249 tool->id = tool_id;
250 tool->bitmap = bitmap;
251 if(bitmap_disabled.IsOk())
252 {
253 wxASSERT(bitmap.GetSize() == bitmap_disabled.GetSize());
254 tool->bitmap_disabled = bitmap_disabled;
255 }
256 else
257 tool->bitmap_disabled = MakeDisabledBitmap(bitmap);
258 tool->help_string = help_string;
259 tool->kind = kind;
260 tool->client_data = client_data;
261 tool->position = wxPoint(0, 0);
262 tool->size = wxSize(0, 0);
263 tool->state = 0;
264
d1bf0be0
VZ
265 // Find the position where insert tool
266 size_t group_count = m_groups.GetCount();
267 size_t g;
268 for(g = 0; g < group_count; ++g)
269 {
270 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
271 size_t tool_count = group->tools.GetCount();
272 if(pos <= tool_count)
273 {
274 group->tools.Insert(tool, pos);
275 return tool;
276 }
277 pos -= tool_count + 1;
278 }
279 wxFAIL_MSG("Tool position out of toolbar bounds.");
280 return NULL;
3c3ead1d
PC
281}
282
d1bf0be0 283wxRibbonToolBarToolBase* wxRibbonToolBar::InsertSeparator(size_t pos)
3c3ead1d 284{
d1bf0be0
VZ
285 size_t group_count = m_groups.GetCount();
286 size_t g;
287 for(g = 0; g < group_count; ++g)
288 {
289 if(pos==0) // Prepend group
290 return &InsertGroup(g)->dummy_tool;
291 if(pos==group_count) // Append group
292 return &InsertGroup(g+1)->dummy_tool;
293
294 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
295 size_t tool_count = group->tools.GetCount();
296 if(pos < tool_count)
297 {
298 wxRibbonToolBarToolGroup* new_group = InsertGroup(g+1);
299
300 for(size_t t = pos; t < tool_count; t++)
301 new_group->tools.Add(group->tools[t]);
302 group->tools.RemoveAt(pos, tool_count-pos);
303
304 return &group->dummy_tool;
305 }
306 pos -= tool_count + 1;
307 }
308 // Add an empty group at the end of the bar.
3c3ead1d
PC
309 if(m_groups.Last()->tools.IsEmpty())
310 return NULL;
3c3ead1d
PC
311 AppendGroup();
312 return &m_groups.Last()->dummy_tool;
313}
314
d1bf0be0
VZ
315wxRibbonToolBarToolGroup* wxRibbonToolBar::InsertGroup(size_t pos)
316{
317 wxRibbonToolBarToolGroup* group = new wxRibbonToolBarToolGroup;
318 group->position = wxPoint(0, 0);
319 group->size = wxSize(0, 0);
320 m_groups.Insert(group, pos);
321 return group;
322}
323
324void wxRibbonToolBar::ClearTools()
325{
326 size_t count = m_groups.GetCount();
327 size_t i, t;
328 for(i = 0; i < count; ++i)
329 {
330 wxRibbonToolBarToolGroup* group = m_groups.Item(i);
331 size_t tool_count = group->tools.GetCount();
332 for(t = 0; t < tool_count; ++t)
333 {
334 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
335 delete tool;
336 }
337 delete group;
338 }
339 m_groups.Clear();
340}
341
342bool wxRibbonToolBar::DeleteTool(int tool_id)
343{
344 size_t group_count = m_groups.GetCount();
345 size_t g, t;
346 for(g = 0; g < group_count; ++g)
347 {
348 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
349 size_t tool_count = group->tools.GetCount();
350 for(t = 0; t < tool_count; ++t)
351 {
352 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
353 if(tool->id == tool_id)
354 {
355 group->tools.RemoveAt(t);
356 delete tool;
357 return true;
358 }
359 }
360 }
361 return false;
362}
363
364bool wxRibbonToolBar::DeleteToolByPos(size_t pos)
365{
366 size_t group_count = m_groups.GetCount();
367 size_t g, t;
368 for(g = 0; g < group_count; ++g)
369 {
370 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
371 size_t tool_count = group->tools.GetCount();
372 if(pos<tool_count)
373 {
374 // Remove tool
375 wxRibbonToolBarToolBase* tool = group->tools.Item(pos);
376 group->tools.RemoveAt(pos);
377 delete tool;
378 return true;
379 }
380 else if(pos==tool_count)
381 {
382 // Remove separator
383 if(g < group_count - 1)
384 {
385 wxRibbonToolBarToolGroup* next_group = m_groups.Item(g+1);
386 for(t = 0; t < next_group->tools.GetCount(); ++t)
387 group->tools.Add(next_group->tools[t]);
388 m_groups.RemoveAt(g+1);
389 delete next_group;
390 }
391 return true;
392 }
393 }
394 return false;
395}
396
397wxRibbonToolBarToolBase* wxRibbonToolBar::FindById(int tool_id)const
398{
399 size_t group_count = m_groups.GetCount();
400 size_t g, t;
401 for(g = 0; g < group_count; ++g)
402 {
403 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
404 size_t tool_count = group->tools.GetCount();
405 for(t = 0; t < tool_count; ++t)
406 {
407 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
408 if(tool->id == tool_id)
409 {
410 return tool;
411 }
412 }
413 }
414 return NULL;
415}
416
417wxRibbonToolBarToolBase* wxRibbonToolBar::GetToolByPos(size_t pos)const
418{
419 size_t group_count = m_groups.GetCount();
420 size_t g;
421 for(g = 0; g < group_count; ++g)
422 {
423 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
424 size_t tool_count = group->tools.GetCount();
425 if(pos<tool_count)
426 {
427 return group->tools[pos];
428 }
429 else if(pos==tool_count)
430 {
431 return NULL;
432 }
433 }
434 return NULL;
435}
436
437size_t wxRibbonToolBar::GetToolCount() const
438{
439 size_t count = 0;
440 for(size_t g = 0; g < m_groups.GetCount(); ++g)
441 {
442 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
443 count += group->tools.GetCount();
444 }
445 // There is a splitter in front of every group except for the first
446 // If only one group, no separator.
447 if(m_groups.GetCount()>1)
448 count += m_groups.GetCount() - 1;
449 return count;
450}
451
452int wxRibbonToolBar::GetToolId(const wxRibbonToolBarToolBase* tool)const
453{
454 wxCHECK_MSG(tool != NULL , wxNOT_FOUND, "The tool pointer must not be NULL");
455 return tool->id;
456}
457
458wxObject* wxRibbonToolBar::GetToolClientData(int tool_id)const
459{
460 wxRibbonToolBarToolBase* tool = FindById(tool_id);
461 wxCHECK_MSG(tool != NULL , NULL, "Invalid tool id");
462 return tool->client_data;
463}
464
465bool wxRibbonToolBar::GetToolEnabled(int tool_id)const
466{
467 wxRibbonToolBarToolBase* tool = FindById(tool_id);
468 wxCHECK_MSG(tool != NULL , false, "Invalid tool id");
469 return (tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED) == 0;
470}
471
472wxString wxRibbonToolBar::GetToolHelpString(int tool_id)const
473{
474 wxRibbonToolBarToolBase* tool = FindById(tool_id);
475 wxCHECK_MSG(tool != NULL , wxEmptyString, "Invalid tool id");
476 return tool->help_string;
477}
478
479wxRibbonButtonKind wxRibbonToolBar::GetToolKind(int tool_id)const
480{
481 wxRibbonToolBarToolBase* tool = FindById(tool_id);
482 wxCHECK_MSG(tool != NULL , wxRIBBON_BUTTON_NORMAL, "Invalid tool id");
483 return tool->kind;
484}
485
486int wxRibbonToolBar::GetToolPos(int tool_id)const
487{
488 size_t group_count = m_groups.GetCount();
489 size_t g, t;
490 int pos = 0;
491 for(g = 0; g < group_count; ++g)
492 {
493 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
494 size_t tool_count = group->tools.GetCount();
495 for(t = 0; t < tool_count; ++t)
496 {
497 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
498 if(tool->id == tool_id)
499 {
500 return pos;
501 }
502 ++pos;
503 }
504 ++pos; // Increment pos for group separator.
505 }
506 return wxNOT_FOUND;
507}
508
509bool wxRibbonToolBar::GetToolState(int tool_id)const
510{
511 wxRibbonToolBarToolBase* tool = FindById(tool_id);
512 wxCHECK_MSG(tool != NULL , false, "Invalid tool id");
513 return (tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED) != 0;
514}
515
3c3ead1d
PC
516wxBitmap wxRibbonToolBar::MakeDisabledBitmap(const wxBitmap& original)
517{
518 wxImage img(original.ConvertToImage());
519 return wxBitmap(img.ConvertToGreyscale());
520}
521
522void wxRibbonToolBar::AppendGroup()
523{
524 wxRibbonToolBarToolGroup* group = new wxRibbonToolBarToolGroup;
525 group->position = wxPoint(0, 0);
526 group->size = wxSize(0, 0);
527 m_groups.Add(group);
528}
529
530bool wxRibbonToolBar::IsSizingContinuous() const
531{
532 return false;
533}
534
d1bf0be0
VZ
535void wxRibbonToolBar::SetToolClientData(int tool_id, wxObject* clientData)
536{
537 wxRibbonToolBarToolBase* tool = FindById(tool_id);
538 wxCHECK_RET(tool != NULL , "Invalid tool id");
539 tool->client_data = clientData;
540}
541
542void wxRibbonToolBar::SetToolDisabledBitmap(int tool_id, const wxBitmap &bitmap)
543{
544 wxRibbonToolBarToolBase* tool = FindById(tool_id);
545 wxCHECK_RET(tool != NULL , "Invalid tool id");
546 tool->bitmap_disabled = bitmap;
547}
548
549void wxRibbonToolBar::SetToolHelpString(int tool_id, const wxString& helpString)
550{
551 wxRibbonToolBarToolBase* tool = FindById(tool_id);
552 wxCHECK_RET(tool != NULL , "Invalid tool id");
553 tool->help_string = helpString;
554}
555
556void wxRibbonToolBar::SetToolNormalBitmap(int tool_id, const wxBitmap &bitmap)
557{
558 wxRibbonToolBarToolBase* tool = FindById(tool_id);
559 wxCHECK_RET(tool != NULL , "Invalid tool id");
560 tool->bitmap = bitmap;
561}
562
563void wxRibbonToolBar::EnableTool(int tool_id, bool enable)
564{
565 wxRibbonToolBarToolBase* tool = FindById(tool_id);
566 wxCHECK_RET(tool != NULL , "Invalid tool id");
567 if(enable)
568 {
569 if(tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED)
570 {
571 tool->state &= ~wxRIBBON_TOOLBAR_TOOL_DISABLED;
572 Refresh();
573 }
574 }
575 else
576 {
577 if((tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED)==0)
578 {
579 tool->state |= wxRIBBON_TOOLBAR_TOOL_DISABLED;
580 Refresh();
581 }
582 }
583}
584
585void wxRibbonToolBar::ToggleTool(int tool_id, bool checked)
586{
587 wxRibbonToolBarToolBase* tool = FindById(tool_id);
588 wxCHECK_RET(tool != NULL , "Invalid tool id");
589 if(checked)
590 {
591 if((tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED) == 0)
592 {
593 tool->state |= wxRIBBON_TOOLBAR_TOOL_TOGGLED;
594 Refresh();
595 }
596 }
597 else
598 {
599 if(tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED)
600 {
601 tool->state &= ~wxRIBBON_TOOLBAR_TOOL_TOGGLED;
602 Refresh();
603 }
604 }
605}
606
3c3ead1d
PC
607static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
608{
609 switch(orientation)
610 {
611 case wxHORIZONTAL: return size.GetWidth();
612 case wxVERTICAL: return size.GetHeight();
613 case wxBOTH: return size.GetWidth() * size.GetHeight();
614 default: return 0;
615 }
616}
617
618wxSize wxRibbonToolBar::DoGetNextSmallerSize(wxOrientation direction,
619 wxSize relative_to) const
620{
621 wxSize result(relative_to);
622 int area = 0;
623 int nrows;
624 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
625 {
626 wxSize size(m_sizes[nrows - m_nrows_min]);
627 wxSize original(size);
628 switch(direction)
629 {
630 case wxHORIZONTAL:
631 if(size.GetWidth() < relative_to.GetWidth()
632 && size.GetHeight() <= relative_to.GetHeight())
633 {
634 size.SetHeight(relative_to.GetHeight());
635 break;
636 }
637 continue;
638 case wxVERTICAL:
639 if(size.GetWidth() <= relative_to.GetWidth()
640 && size.GetHeight() < relative_to.GetHeight())
641 {
642 size.SetWidth(relative_to.GetWidth());
643 break;
644 }
645 continue;
646 case wxBOTH:
647 if(size.GetWidth() < relative_to.GetWidth()
648 && size.GetHeight() < relative_to.GetHeight())
649 {
650 break;
651 }
652 continue;
653 }
654 if(GetSizeInOrientation(original, direction) > area)
655 {
656 result = size;
657 area = GetSizeInOrientation(original, direction);
658 }
659 }
660 return result;
661}
662
663wxSize wxRibbonToolBar::DoGetNextLargerSize(wxOrientation direction,
664 wxSize relative_to) const
665{
666 // Pick the smallest of our sizes which are larger than the given size
667 wxSize result(relative_to);
668 int area = INT_MAX;
669 int nrows;
670 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
671 {
672 wxSize size(m_sizes[nrows - m_nrows_min]);
673 wxSize original(size);
674 switch(direction)
675 {
676 case wxHORIZONTAL:
677 if(size.GetWidth() > relative_to.GetWidth()
678 && size.GetHeight() <= relative_to.GetHeight())
679 {
680 size.SetHeight(relative_to.GetHeight());
681 break;
682 }
683 continue;
684 case wxVERTICAL:
685 if(size.GetWidth() <= relative_to.GetWidth()
686 && size.GetHeight() > relative_to.GetHeight())
687 {
688 size.SetWidth(relative_to.GetWidth());
689 break;
690 }
691 continue;
692 case wxBOTH:
693 if(size.GetWidth() > relative_to.GetWidth()
694 && size.GetHeight() > relative_to.GetHeight())
695 {
696 break;
697 }
698 continue;
699 }
700 if(GetSizeInOrientation(original, direction) < area)
701 {
702 result = size;
703 area = GetSizeInOrientation(original, direction);
704 }
705 }
706
707 return result;
708}
709
710void wxRibbonToolBar::SetRows(int nMin, int nMax)
711{
712 if(nMax == -1)
713 nMax = nMin;
714
715 wxASSERT(1 <= nMin);
716 wxASSERT(nMin <= nMax);
717
718 m_nrows_min = nMin;
719 m_nrows_max = nMax;
720
721 delete[] m_sizes;
722 m_sizes = new wxSize[m_nrows_max - m_nrows_min + 1];
723 for(int i = m_nrows_min; i <= m_nrows_max; ++i)
724 m_sizes[i - m_nrows_min] = wxSize(0, 0);
725
726 Realize();
727}
728
729bool wxRibbonToolBar::Realize()
730{
731 if(m_art == NULL)
732 return false;
733
734 // Calculate the size of each group and the position/size of each tool
735 wxMemoryDC temp_dc;
736 size_t group_count = m_groups.GetCount();
737 size_t g, t;
738 for(g = 0; g < group_count; ++g)
739 {
740 wxRibbonToolBarToolBase* prev = NULL;
741 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
742 size_t tool_count = group->tools.GetCount();
743 int tallest = 0;
744 for(t = 0; t < tool_count; ++t)
745 {
746 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
747 tool->size = m_art->GetToolSize(temp_dc, this,
748 tool->bitmap.GetSize(), tool->kind, t == 0,
749 t == (tool_count - 1), &tool->dropdown);
3c3ead1d
PC
750 if(t == 0)
751 tool->state |= wxRIBBON_TOOLBAR_TOOL_FIRST;
752 if(t == tool_count - 1)
753 tool->state |= wxRIBBON_TOOLBAR_TOOL_LAST;
754 if(tool->size.GetHeight() > tallest)
755 tallest = tool->size.GetHeight();
756 if(prev)
757 {
758 tool->position = prev->position;
759 tool->position.x += prev->size.x;
760 }
761 else
762 {
763 tool->position = wxPoint(0, 0);
764 }
765 prev = tool;
766 }
767 if(tool_count == 0)
768 group->size = wxSize(0, 0);
769 else
770 {
771 group->size = wxSize(prev->position.x + prev->size.x, tallest);
772 for(t = 0; t < tool_count; ++t)
773 group->tools.Item(t)->size.SetHeight(tallest);
774 }
775 }
776
777 // Calculate the minimum size for each possible number of rows
778 int nrows, r;
779 int sep = m_art->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE);
780 int smallest_area = INT_MAX;
781 wxSize* row_sizes = new wxSize[m_nrows_max];
782 wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ?
783 wxVERTICAL : wxHORIZONTAL;
98742322 784
3c3ead1d 785 SetMinSize(wxSize(0, 0));
98742322
JS
786 wxSize minSize(INT_MAX, INT_MAX);
787
788 // See if we're sizing flexibly (i.e. wrapping), and set min size differently
789 bool sizingFlexibly = false;
790 wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel);
791 if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE))
792 sizingFlexibly = true;
793
794 // Without this, there will be redundant horizontal space because SetMinSize will
795 // use the smallest possible height (and therefore largest width).
796 if (sizingFlexibly)
797 major_axis = wxHORIZONTAL;
798
3c3ead1d
PC
799 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
800 {
801 for(r = 0; r < nrows; ++r)
802 row_sizes[r] = wxSize(0, 0);
803 for(g = 0; g < group_count; ++g)
804 {
805 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
806 int shortest_row = 0;
807 for(r = 1; r < nrows; ++r)
808 {
809 if(row_sizes[r].GetWidth() < row_sizes[shortest_row].GetWidth())
810 shortest_row = r;
811 }
812 row_sizes[shortest_row].x += group->size.x + sep;
813 if(group->size.y > row_sizes[shortest_row].y)
814 row_sizes[shortest_row].y = group->size.y;
815 }
816 wxSize size(0, 0);
817 for(r = 0; r < nrows; ++r)
818 {
819 if(row_sizes[r].GetWidth() != 0)
820 row_sizes[r].DecBy(sep, 0);
821 if(row_sizes[r].GetWidth() > size.GetWidth())
822 size.SetWidth(row_sizes[r].GetWidth());
823 size.IncBy(0, row_sizes[r].y);
824 }
825 m_sizes[nrows - m_nrows_min] = size;
98742322 826
3c3ead1d
PC
827 if(GetSizeInOrientation(size, major_axis) < smallest_area)
828 {
3c3ead1d 829 smallest_area = GetSizeInOrientation(size, major_axis);
98742322
JS
830 SetMinSize(size);
831 }
832
833 if (sizingFlexibly)
834 {
835 if (size.x < minSize.x)
836 minSize.x = size.x;
837 if (size.y < minSize.y)
838 minSize.y = size.y;
3c3ead1d
PC
839 }
840 }
98742322
JS
841
842 if (sizingFlexibly)
843 {
844 // Give it the min size in either direction regardless of row,
845 // so that we're able to vary the size of the panel according to
846 // the space the toolbar takes up.
847 SetMinSize(minSize);
848 }
960615f4 849 delete[] row_sizes;
3c3ead1d
PC
850
851 // Position the groups
852 wxSizeEvent dummy_event(GetSize());
853 OnSize(dummy_event);
854
855 return true;
856}
857
858void wxRibbonToolBar::OnSize(wxSizeEvent& evt)
859{
860 if(m_art == NULL)
861 return;
862
863 // Choose row count with largest possible area
864 wxSize size = evt.GetSize();
865 int row_count = m_nrows_max;
866 wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ?
867 wxVERTICAL : wxHORIZONTAL;
98742322
JS
868
869 // See if we're sizing flexibly, and set min size differently
870 bool sizingFlexibly = false;
871 wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel);
872 if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE))
873 sizingFlexibly = true;
874
875 // Without this, there will be redundant horizontal space because SetMinSize will
876 // use the smallest possible height (and therefore largest width).
877 if (sizingFlexibly)
878 major_axis = wxHORIZONTAL;
879
880 wxSize bestSize = m_sizes[0];
881
3c3ead1d
PC
882 if(m_nrows_max != m_nrows_min)
883 {
884 int area = 0;
885 for(int i = 0; i <= m_nrows_max - m_nrows_min; ++i)
886 {
887 if(m_sizes[i].x <= size.x && m_sizes[i].y <= size.y &&
888 GetSizeInOrientation(m_sizes[i], major_axis) > area)
889 {
890 area = GetSizeInOrientation(m_sizes[i], major_axis);
891 row_count = m_nrows_min + i;
98742322 892 bestSize = m_sizes[i];
3c3ead1d
PC
893 }
894 }
895 }
896
897 // Assign groups to rows and calculate row widths
898 wxSize* row_sizes = new wxSize[row_count];
899 int sep = m_art->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE);
900
901 int r;
902 for(r = 0; r < row_count; ++r)
903 row_sizes[r] = wxSize(0, 0);
904 size_t g;
905 size_t group_count = m_groups.GetCount();
906 for(g = 0; g < group_count; ++g)
907 {
908 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
909 int shortest_row = 0;
910 for(r = 1; r < row_count; ++r)
911 {
912 if(row_sizes[r].GetWidth() < row_sizes[shortest_row].GetWidth())
913 shortest_row = r;
914 }
915 group->position = wxPoint(row_sizes[shortest_row].x, shortest_row);
916 row_sizes[shortest_row].x += group->size.x + sep;
917 if(group->size.y > row_sizes[shortest_row].y)
918 row_sizes[shortest_row].y = group->size.y;
919 }
920
921 // Calculate row positions
922 int total_height = 0;
923 for(r = 0; r < row_count; ++r)
924 total_height += row_sizes[r].GetHeight();
925 int rowsep = (size.GetHeight() - total_height) / (row_count + 1);
926 int* rowypos = new int[row_count];
927 rowypos[0] = rowsep;
928 for(r = 1; r < row_count; ++r)
929 {
930 rowypos[r] = rowypos[r - 1] + row_sizes[r - 1].GetHeight() + rowsep;
931 }
932
933 // Set group y positions
934 for(g = 0; g < group_count; ++g)
935 {
936 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
937 group->position.y = rowypos[group->position.y];
938 }
939
940 delete[] rowypos;
941 delete[] row_sizes;
942}
943
98742322
JS
944// Finds the best width and height given the parents' width and height
945wxSize wxRibbonToolBar::GetBestSizeForParentSize(const wxSize& parentSize) const
946{
947 if (!m_sizes)
948 return GetMinSize();
949
950 // Choose row count with largest possible area
951 wxSize size = parentSize;
98742322
JS
952
953 // A toolbar should maximize its width whether vertical or horizontal, so
954 // force the major axis to be horizontal. Without this, there will be
955 // redundant horizontal space.
e14c5105 956 wxOrientation major_axis = wxHORIZONTAL;
98742322
JS
957 wxSize bestSize = m_sizes[0];
958
959 if(m_nrows_max != m_nrows_min)
960 {
961 int area = 0;
962 for(int i = 0; i <= m_nrows_max - m_nrows_min; ++i)
963 {
964 if(m_sizes[i].x <= size.x && m_sizes[i].y <= size.y &&
965 GetSizeInOrientation(m_sizes[i], major_axis) > area)
966 {
967 area = GetSizeInOrientation(m_sizes[i], major_axis);
98742322
JS
968 bestSize = m_sizes[i];
969 }
970 }
971 }
972 return bestSize;
973}
974
3c3ead1d
PC
975wxSize wxRibbonToolBar::DoGetBestSize() const
976{
977 return GetMinSize();
978}
979
980void wxRibbonToolBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
981{
982 // All painting done in main paint handler to minimise flicker
983}
984
985void wxRibbonToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
986{
987 wxAutoBufferedPaintDC dc(this);
988 if(m_art == NULL)
989 return;
990
991 m_art->DrawToolBarBackground(dc, this, GetSize());
992
993 size_t group_count = m_groups.GetCount();
994 size_t g, t;
995 for(g = 0; g < group_count; ++g)
996 {
997 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
998 size_t tool_count = group->tools.GetCount();
999 if(tool_count != 0)
1000 {
1001 m_art->DrawToolGroupBackground(dc, this,
1002 wxRect(group->position, group->size));
1003 for(t = 0; t < tool_count; ++t)
1004 {
1005 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
1006 wxRect rect(group->position + tool->position, tool->size);
d1bf0be0
VZ
1007 if(tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED)
1008 m_art->DrawTool(dc, this, rect, tool->bitmap_disabled,
1009 tool->kind, tool->state);
1010 else
1011 m_art->DrawTool(dc, this, rect, tool->bitmap, tool->kind,
1012 tool->state);
3c3ead1d
PC
1013 }
1014 }
1015 }
1016}
1017
1018void wxRibbonToolBar::OnMouseMove(wxMouseEvent& evt)
1019{
1020 wxPoint pos(evt.GetPosition());
1021 wxRibbonToolBarToolBase *new_hover = NULL;
1022
1023 size_t group_count = m_groups.GetCount();
1024 size_t g, t;
1025 for(g = 0; g < group_count; ++g)
1026 {
1027 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
1028 if(group->position.x <= pos.x && pos.x < group->position.x + group->size.x
1029 && group->position.y <= pos.y && pos.y < group->position.y + group->size.y)
1030 {
1031 size_t tool_count = group->tools.GetCount();
1032 pos -= group->position;
1033 for(t = 0; t < tool_count; ++t)
1034 {
1035 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
1036 if(tool->position.x <= pos.x && pos.x < tool->position.x + tool->size.x
1037 && tool->position.y <= pos.y && pos.y < tool->position.y + tool->size.y)
1038 {
1039 pos -= tool->position;
1040 new_hover = tool;
1041 break;
1042 }
1043 }
1044 break;
1045 }
1046 }
1047
f8193bbb 1048#if wxUSE_TOOLTIPS
349f41fd
VZ
1049 if(new_hover)
1050 {
1051 SetToolTip(new_hover->help_string);
1052 }
1053 else if(GetToolTip())
1054 {
1055 UnsetToolTip();
1056 }
f8193bbb 1057#endif
349f41fd 1058
d1bf0be0
VZ
1059 if(new_hover && new_hover->state & wxRIBBON_TOOLBAR_TOOL_DISABLED)
1060 {
1061 new_hover = NULL; // A disabled tool can not be hilighted
1062 }
1063
3c3ead1d
PC
1064 if(new_hover != m_hover_tool)
1065 {
1066 if(m_hover_tool)
1067 {
1068 m_hover_tool->state &= ~(wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
1069 | wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK);
1070 }
1071 m_hover_tool = new_hover;
1072 if(new_hover)
1073 {
1074 long what = wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED;
1075 if(new_hover->dropdown.Contains(pos))
1076 what = wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED;
1077
1078 new_hover->state |= what;
ce00f59b 1079
3c3ead1d
PC
1080 if(new_hover == m_active_tool)
1081 {
1082 new_hover->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
1083 new_hover->state |= (what << 2);
1084 }
1085 }
1086 Refresh(false);
1087 }
1088 else if(m_hover_tool && m_hover_tool->kind == wxRIBBON_BUTTON_HYBRID)
1089 {
1090 long newstate = m_hover_tool->state &~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK;
1091 long what = wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED;
1092 if(m_hover_tool->dropdown.Contains(pos))
1093 what = wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED;
1094 newstate |= what;
1095 if(newstate != m_hover_tool->state)
1096 {
1097 m_hover_tool->state = newstate;
1098 if(m_hover_tool == m_active_tool)
1099 {
1100 m_hover_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
1101 m_hover_tool->state |= (what << 2);
1102 }
1103 Refresh(false);
1104 }
1105 }
1106}
1107
1108void wxRibbonToolBar::OnMouseDown(wxMouseEvent& evt)
1109{
1110 OnMouseMove(evt);
1111 if(m_hover_tool)
1112 {
1113 m_active_tool = m_hover_tool;
1114 m_active_tool->state |=
1115 (m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_HOVER_MASK) << 2;
1116 Refresh(false);
1117 }
1118}
1119
1120void wxRibbonToolBar::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
1121{
1122 if(m_hover_tool)
1123 {
1124 m_hover_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK;
1125 m_hover_tool = NULL;
1126 Refresh(false);
1127 }
1128}
1129
1130void wxRibbonToolBar::OnMouseUp(wxMouseEvent& WXUNUSED(evt))
1131{
1132 if(m_active_tool)
1133 {
1134 if(m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK)
1135 {
1136 wxEventType evt_type = wxEVT_COMMAND_RIBBONTOOL_CLICKED;
1137 if(m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_DROPDOWN_ACTIVE)
1138 evt_type = wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED;
1139 wxRibbonToolBarEvent notification(evt_type, m_active_tool->id);
d1bf0be0
VZ
1140 if(m_active_tool->kind == wxRIBBON_BUTTON_TOGGLE)
1141 {
1142 m_active_tool->state ^=
1143 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED;
1144 notification.SetInt(m_active_tool->state &
1145 wxRIBBON_BUTTONBAR_BUTTON_TOGGLED);
1146 }
3c3ead1d
PC
1147 notification.SetEventObject(this);
1148 notification.SetBar(this);
1149 ProcessEvent(notification);
42d73941
VZ
1150
1151 wxStaticCast(m_parent, wxRibbonPanel)->HideIfExpanded();
3c3ead1d 1152 }
6f269254
VZ
1153
1154 // Notice that m_active_tool could have been reset by the event handler
1155 // above so we need to test it again.
1156 if (m_active_tool)
1157 {
1158 m_active_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
1159 m_active_tool = NULL;
1160 Refresh(false);
1161 }
3c3ead1d
PC
1162 }
1163}
1164
1165void wxRibbonToolBar::OnMouseEnter(wxMouseEvent& evt)
1166{
1167 if(m_active_tool && !evt.LeftIsDown())
1168 {
1169 m_active_tool = NULL;
1170 }
1171}
1172
d1bf0be0
VZ
1173void wxRibbonToolBar::UpdateWindowUI(long flags)
1174{
1175 wxWindowBase::UpdateWindowUI(flags);
1176
1177 // don't waste time updating state of tools in a hidden toolbar
1178 if ( !IsShown() )
1179 return;
1180
1181 size_t group_count = m_groups.GetCount();
1182 size_t g, t;
1183 for(g = 0; g < group_count; ++g)
1184 {
1185 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
1186 size_t tool_count = group->tools.GetCount();
1187 for(t = 0; t < tool_count; ++t)
1188 {
1189 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
1190 int id = tool->id;
1191
1192 wxUpdateUIEvent event(id);
1193 event.SetEventObject(this);
1194
1195 if ( ProcessWindowEvent(event) )
1196 {
1197 if ( event.GetSetEnabled() )
1198 EnableTool(id, event.GetEnabled());
1199 if ( event.GetSetChecked() )
1200 ToggleTool(id, event.GetChecked());
1201 }
1202 }
1203 }
1204}
1205
3c3ead1d
PC
1206bool wxRibbonToolBarEvent::PopupMenu(wxMenu* menu)
1207{
1208 wxPoint pos = wxDefaultPosition;
1209 if(m_bar->m_active_tool)
1210 {
1211 // Find the group which contains the tool
1212 size_t group_count = m_bar->m_groups.GetCount();
1213 size_t g, t;
1214 for(g = 0; g < group_count; ++g)
1215 {
1216 wxRibbonToolBarToolGroup* group = m_bar->m_groups.Item(g);
1217 size_t tool_count = group->tools.GetCount();
1218 for(t = 0; t < tool_count; ++t)
1219 {
1220 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
1221 if(tool == m_bar->m_active_tool)
1222 {
1223 pos = group->position;
1224 pos += tool->position;
1225 pos.y += tool->size.GetHeight();
1226 g = group_count;
1227 break;
1228 }
1229 }
1230 }
1231 }
1232 return m_bar->PopupMenu(menu, pos);
1233}
1234
1235#endif // wxUSE_RIBBON