Rewrote wxRibbonPage realisation and layout code to avoid setting the position and...
[wxWidgets.git] / src / ribbon / toolbar.cpp
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
18 #include "wx/ribbon/toolbar.h"
19
20 #if wxUSE_RIBBON
21
22 #include "wx/ribbon/art.h"
23 #include "wx/ribbon/bar.h"
24 #include "wx/dcbuffer.h"
25
26 #ifndef WX_PRECOMP
27 #endif
28
29 #ifdef __WXMSW__
30 #include "wx/msw/private.h"
31 #endif
32
33 class wxRibbonToolBarToolBase
34 {
35 public:
36 wxString help_string;
37 wxBitmap bitmap;
38 wxBitmap bitmap_disabled;
39 wxRect dropdown;
40 wxPoint position;
41 wxSize size;
42 wxObject* client_data;
43 int id;
44 wxRibbonButtonKind kind;
45 long state;
46 };
47
48 WX_DEFINE_ARRAY(wxRibbonToolBarToolBase*, wxArrayRibbonToolBarToolBase);
49
50 class wxRibbonToolBarToolGroup
51 {
52 public:
53 // To identify the group as a wxRibbonToolBarToolBase*
54 wxRibbonToolBarToolBase dummy_tool;
55
56 wxArrayRibbonToolBarToolBase tools;
57 wxPoint position;
58 wxSize size;
59 };
60
61 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_CLICKED, wxRibbonToolBarEvent);
62 wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED, wxRibbonToolBarEvent);
63
64 IMPLEMENT_DYNAMIC_CLASS(wxRibbonToolBarEvent, wxCommandEvent)
65 IMPLEMENT_CLASS(wxRibbonToolBar, wxRibbonControl)
66
67 BEGIN_EVENT_TABLE(wxRibbonToolBar, wxRibbonControl)
68 EVT_ENTER_WINDOW(wxRibbonToolBar::OnMouseEnter)
69 EVT_ERASE_BACKGROUND(wxRibbonToolBar::OnEraseBackground)
70 EVT_LEAVE_WINDOW(wxRibbonToolBar::OnMouseLeave)
71 EVT_LEFT_DOWN(wxRibbonToolBar::OnMouseDown)
72 EVT_LEFT_UP(wxRibbonToolBar::OnMouseUp)
73 EVT_MOTION(wxRibbonToolBar::OnMouseMove)
74 EVT_PAINT(wxRibbonToolBar::OnPaint)
75 EVT_SIZE(wxRibbonToolBar::OnSize)
76 END_EVENT_TABLE()
77
78 wxRibbonToolBar::wxRibbonToolBar()
79 {
80 }
81
82 wxRibbonToolBar::wxRibbonToolBar(wxWindow* parent,
83 wxWindowID id,
84 const wxPoint& pos,
85 const wxSize& size,
86 long style)
87 : wxRibbonControl(parent, id, pos, size, wxBORDER_NONE)
88 {
89 CommonInit(style);
90 }
91
92 bool wxRibbonToolBar::Create(wxWindow* parent,
93 wxWindowID id,
94 const wxPoint& pos,
95 const wxSize& size,
96 long style)
97 {
98 if(!wxRibbonControl::Create(parent, id, pos, size, wxBORDER_NONE))
99 {
100 return false;
101 }
102
103 CommonInit(style);
104 return true;
105 }
106
107 void wxRibbonToolBar::CommonInit(long WXUNUSED(style))
108 {
109 AppendGroup();
110 m_hover_tool = NULL;
111 m_active_tool = NULL;
112 m_nrows_min = 1;
113 m_nrows_max = 1;
114 m_sizes = new wxSize[1];
115 m_sizes[0] = wxSize(0, 0);
116 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
117 }
118
119 wxRibbonToolBar::~wxRibbonToolBar()
120 {
121 size_t count = m_groups.GetCount();
122 size_t i, t;
123 for(i = 0; i < count; ++i)
124 {
125 wxRibbonToolBarToolGroup* group = m_groups.Item(i);
126 size_t tool_count = group->tools.GetCount();
127 for(t = 0; t < tool_count; ++t)
128 {
129 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
130 delete tool;
131 }
132 delete group;
133 }
134 m_groups.Clear();
135 delete[] m_sizes;
136 }
137
138 wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool(
139 int tool_id,
140 const wxBitmap& bitmap,
141 const wxString& help_string,
142 wxRibbonButtonKind kind)
143 {
144 return AddTool(tool_id, bitmap, wxNullBitmap, help_string, kind, NULL);
145 }
146
147 wxRibbonToolBarToolBase* wxRibbonToolBar::AddDropdownTool(
148 int tool_id,
149 const wxBitmap& bitmap,
150 const wxString& help_string)
151 {
152 return AddTool(tool_id, bitmap, wxNullBitmap, help_string,
153 wxRIBBON_BUTTON_DROPDOWN, NULL);
154 }
155
156 wxRibbonToolBarToolBase* wxRibbonToolBar::AddHybridTool(
157 int tool_id,
158 const wxBitmap& bitmap,
159 const wxString& help_string)
160 {
161 return AddTool(tool_id, bitmap, wxNullBitmap, help_string,
162 wxRIBBON_BUTTON_HYBRID, NULL);
163 }
164
165 wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool(
166 int tool_id,
167 const wxBitmap& bitmap,
168 const wxBitmap& bitmap_disabled,
169 const wxString& help_string,
170 wxRibbonButtonKind kind,
171 wxObject* client_data)
172 {
173 wxASSERT(bitmap.IsOk());
174
175 wxRibbonToolBarToolBase* tool = new wxRibbonToolBarToolBase;
176 tool->id = tool_id;
177 tool->bitmap = bitmap;
178 if(bitmap_disabled.IsOk())
179 {
180 wxASSERT(bitmap.GetSize() == bitmap_disabled.GetSize());
181 tool->bitmap_disabled = bitmap_disabled;
182 }
183 else
184 tool->bitmap_disabled = MakeDisabledBitmap(bitmap);
185 tool->help_string = help_string;
186 tool->kind = kind;
187 tool->client_data = client_data;
188 tool->position = wxPoint(0, 0);
189 tool->size = wxSize(0, 0);
190 tool->state = 0;
191
192 m_groups.Last()->tools.Add(tool);
193 return tool;
194 }
195
196 wxRibbonToolBarToolBase* wxRibbonToolBar::AddSeparator()
197 {
198 if(m_groups.Last()->tools.IsEmpty())
199 return NULL;
200
201 AppendGroup();
202 return &m_groups.Last()->dummy_tool;
203 }
204
205 wxBitmap wxRibbonToolBar::MakeDisabledBitmap(const wxBitmap& original)
206 {
207 wxImage img(original.ConvertToImage());
208 return wxBitmap(img.ConvertToGreyscale());
209 }
210
211 void wxRibbonToolBar::AppendGroup()
212 {
213 wxRibbonToolBarToolGroup* group = new wxRibbonToolBarToolGroup;
214 group->position = wxPoint(0, 0);
215 group->size = wxSize(0, 0);
216 m_groups.Add(group);
217 }
218
219 bool wxRibbonToolBar::IsSizingContinuous() const
220 {
221 return false;
222 }
223
224 static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
225 {
226 switch(orientation)
227 {
228 case wxHORIZONTAL: return size.GetWidth();
229 case wxVERTICAL: return size.GetHeight();
230 case wxBOTH: return size.GetWidth() * size.GetHeight();
231 default: return 0;
232 }
233 }
234
235 wxSize wxRibbonToolBar::DoGetNextSmallerSize(wxOrientation direction,
236 wxSize relative_to) const
237 {
238 wxSize result(relative_to);
239 int area = 0;
240 int nrows;
241 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
242 {
243 wxSize size(m_sizes[nrows - m_nrows_min]);
244 wxSize original(size);
245 switch(direction)
246 {
247 case wxHORIZONTAL:
248 if(size.GetWidth() < relative_to.GetWidth()
249 && size.GetHeight() <= relative_to.GetHeight())
250 {
251 size.SetHeight(relative_to.GetHeight());
252 break;
253 }
254 continue;
255 case wxVERTICAL:
256 if(size.GetWidth() <= relative_to.GetWidth()
257 && size.GetHeight() < relative_to.GetHeight())
258 {
259 size.SetWidth(relative_to.GetWidth());
260 break;
261 }
262 continue;
263 case wxBOTH:
264 if(size.GetWidth() < relative_to.GetWidth()
265 && size.GetHeight() < relative_to.GetHeight())
266 {
267 break;
268 }
269 continue;
270 }
271 if(GetSizeInOrientation(original, direction) > area)
272 {
273 result = size;
274 area = GetSizeInOrientation(original, direction);
275 }
276 }
277 return result;
278 }
279
280 wxSize wxRibbonToolBar::DoGetNextLargerSize(wxOrientation direction,
281 wxSize relative_to) const
282 {
283 // Pick the smallest of our sizes which are larger than the given size
284 wxSize result(relative_to);
285 int area = INT_MAX;
286 int nrows;
287 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
288 {
289 wxSize size(m_sizes[nrows - m_nrows_min]);
290 wxSize original(size);
291 switch(direction)
292 {
293 case wxHORIZONTAL:
294 if(size.GetWidth() > relative_to.GetWidth()
295 && size.GetHeight() <= relative_to.GetHeight())
296 {
297 size.SetHeight(relative_to.GetHeight());
298 break;
299 }
300 continue;
301 case wxVERTICAL:
302 if(size.GetWidth() <= relative_to.GetWidth()
303 && size.GetHeight() > relative_to.GetHeight())
304 {
305 size.SetWidth(relative_to.GetWidth());
306 break;
307 }
308 continue;
309 case wxBOTH:
310 if(size.GetWidth() > relative_to.GetWidth()
311 && size.GetHeight() > relative_to.GetHeight())
312 {
313 break;
314 }
315 continue;
316 }
317 if(GetSizeInOrientation(original, direction) < area)
318 {
319 result = size;
320 area = GetSizeInOrientation(original, direction);
321 }
322 }
323
324 return result;
325 }
326
327 void wxRibbonToolBar::SetRows(int nMin, int nMax)
328 {
329 if(nMax == -1)
330 nMax = nMin;
331
332 wxASSERT(1 <= nMin);
333 wxASSERT(nMin <= nMax);
334
335 m_nrows_min = nMin;
336 m_nrows_max = nMax;
337
338 delete[] m_sizes;
339 m_sizes = new wxSize[m_nrows_max - m_nrows_min + 1];
340 for(int i = m_nrows_min; i <= m_nrows_max; ++i)
341 m_sizes[i - m_nrows_min] = wxSize(0, 0);
342
343 Realize();
344 }
345
346 bool wxRibbonToolBar::Realize()
347 {
348 if(m_art == NULL)
349 return false;
350
351 // Calculate the size of each group and the position/size of each tool
352 wxMemoryDC temp_dc;
353 size_t group_count = m_groups.GetCount();
354 size_t g, t;
355 for(g = 0; g < group_count; ++g)
356 {
357 wxRibbonToolBarToolBase* prev = NULL;
358 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
359 size_t tool_count = group->tools.GetCount();
360 int tallest = 0;
361 for(t = 0; t < tool_count; ++t)
362 {
363 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
364 tool->size = m_art->GetToolSize(temp_dc, this,
365 tool->bitmap.GetSize(), tool->kind, t == 0,
366 t == (tool_count - 1), &tool->dropdown);
367 tool->state = tool->state & ~wxRIBBON_TOOLBAR_TOOL_DISABLED;
368 if(t == 0)
369 tool->state |= wxRIBBON_TOOLBAR_TOOL_FIRST;
370 if(t == tool_count - 1)
371 tool->state |= wxRIBBON_TOOLBAR_TOOL_LAST;
372 if(tool->size.GetHeight() > tallest)
373 tallest = tool->size.GetHeight();
374 if(prev)
375 {
376 tool->position = prev->position;
377 tool->position.x += prev->size.x;
378 }
379 else
380 {
381 tool->position = wxPoint(0, 0);
382 }
383 prev = tool;
384 }
385 if(tool_count == 0)
386 group->size = wxSize(0, 0);
387 else
388 {
389 group->size = wxSize(prev->position.x + prev->size.x, tallest);
390 for(t = 0; t < tool_count; ++t)
391 group->tools.Item(t)->size.SetHeight(tallest);
392 }
393 }
394
395 // Calculate the minimum size for each possible number of rows
396 int nrows, r;
397 int sep = m_art->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE);
398 int smallest_area = INT_MAX;
399 wxSize* row_sizes = new wxSize[m_nrows_max];
400 wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ?
401 wxVERTICAL : wxHORIZONTAL;
402 SetMinSize(wxSize(0, 0));
403 for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows)
404 {
405 for(r = 0; r < nrows; ++r)
406 row_sizes[r] = wxSize(0, 0);
407 for(g = 0; g < group_count; ++g)
408 {
409 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
410 int shortest_row = 0;
411 for(r = 1; r < nrows; ++r)
412 {
413 if(row_sizes[r].GetWidth() < row_sizes[shortest_row].GetWidth())
414 shortest_row = r;
415 }
416 row_sizes[shortest_row].x += group->size.x + sep;
417 if(group->size.y > row_sizes[shortest_row].y)
418 row_sizes[shortest_row].y = group->size.y;
419 }
420 wxSize size(0, 0);
421 for(r = 0; r < nrows; ++r)
422 {
423 if(row_sizes[r].GetWidth() != 0)
424 row_sizes[r].DecBy(sep, 0);
425 if(row_sizes[r].GetWidth() > size.GetWidth())
426 size.SetWidth(row_sizes[r].GetWidth());
427 size.IncBy(0, row_sizes[r].y);
428 }
429 m_sizes[nrows - m_nrows_min] = size;
430 if(GetSizeInOrientation(size, major_axis) < smallest_area)
431 {
432 SetMinSize(size);
433 smallest_area = GetSizeInOrientation(size, major_axis);
434 }
435 }
436 delete[] row_sizes;
437
438 // Position the groups
439 wxSizeEvent dummy_event(GetSize());
440 OnSize(dummy_event);
441
442 return true;
443 }
444
445 void wxRibbonToolBar::OnSize(wxSizeEvent& evt)
446 {
447 if(m_art == NULL)
448 return;
449
450 // Choose row count with largest possible area
451 wxSize size = evt.GetSize();
452 int row_count = m_nrows_max;
453 wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ?
454 wxVERTICAL : wxHORIZONTAL;
455 if(m_nrows_max != m_nrows_min)
456 {
457 int area = 0;
458 for(int i = 0; i <= m_nrows_max - m_nrows_min; ++i)
459 {
460 if(m_sizes[i].x <= size.x && m_sizes[i].y <= size.y &&
461 GetSizeInOrientation(m_sizes[i], major_axis) > area)
462 {
463 area = GetSizeInOrientation(m_sizes[i], major_axis);
464 row_count = m_nrows_min + i;
465 }
466 }
467 }
468
469 // Assign groups to rows and calculate row widths
470 wxSize* row_sizes = new wxSize[row_count];
471 int sep = m_art->GetMetric(wxRIBBON_ART_TOOL_GROUP_SEPARATION_SIZE);
472
473 int r;
474 for(r = 0; r < row_count; ++r)
475 row_sizes[r] = wxSize(0, 0);
476 size_t g;
477 size_t group_count = m_groups.GetCount();
478 for(g = 0; g < group_count; ++g)
479 {
480 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
481 int shortest_row = 0;
482 for(r = 1; r < row_count; ++r)
483 {
484 if(row_sizes[r].GetWidth() < row_sizes[shortest_row].GetWidth())
485 shortest_row = r;
486 }
487 group->position = wxPoint(row_sizes[shortest_row].x, shortest_row);
488 row_sizes[shortest_row].x += group->size.x + sep;
489 if(group->size.y > row_sizes[shortest_row].y)
490 row_sizes[shortest_row].y = group->size.y;
491 }
492
493 // Calculate row positions
494 int total_height = 0;
495 for(r = 0; r < row_count; ++r)
496 total_height += row_sizes[r].GetHeight();
497 int rowsep = (size.GetHeight() - total_height) / (row_count + 1);
498 int* rowypos = new int[row_count];
499 rowypos[0] = rowsep;
500 for(r = 1; r < row_count; ++r)
501 {
502 rowypos[r] = rowypos[r - 1] + row_sizes[r - 1].GetHeight() + rowsep;
503 }
504
505 // Set group y positions
506 for(g = 0; g < group_count; ++g)
507 {
508 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
509 group->position.y = rowypos[group->position.y];
510 }
511
512 delete[] rowypos;
513 delete[] row_sizes;
514 }
515
516 wxSize wxRibbonToolBar::DoGetBestSize() const
517 {
518 return GetMinSize();
519 }
520
521 void wxRibbonToolBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
522 {
523 // All painting done in main paint handler to minimise flicker
524 }
525
526 void wxRibbonToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
527 {
528 wxAutoBufferedPaintDC dc(this);
529 if(m_art == NULL)
530 return;
531
532 m_art->DrawToolBarBackground(dc, this, GetSize());
533
534 size_t group_count = m_groups.GetCount();
535 size_t g, t;
536 for(g = 0; g < group_count; ++g)
537 {
538 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
539 size_t tool_count = group->tools.GetCount();
540 if(tool_count != 0)
541 {
542 m_art->DrawToolGroupBackground(dc, this,
543 wxRect(group->position, group->size));
544 for(t = 0; t < tool_count; ++t)
545 {
546 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
547 wxRect rect(group->position + tool->position, tool->size);
548 m_art->DrawTool(dc, this, rect, tool->bitmap, tool->kind,
549 tool->state);
550 }
551 }
552 }
553 }
554
555 void wxRibbonToolBar::OnMouseMove(wxMouseEvent& evt)
556 {
557 wxPoint pos(evt.GetPosition());
558 wxRibbonToolBarToolBase *new_hover = NULL;
559
560 size_t group_count = m_groups.GetCount();
561 size_t g, t;
562 for(g = 0; g < group_count; ++g)
563 {
564 wxRibbonToolBarToolGroup* group = m_groups.Item(g);
565 if(group->position.x <= pos.x && pos.x < group->position.x + group->size.x
566 && group->position.y <= pos.y && pos.y < group->position.y + group->size.y)
567 {
568 size_t tool_count = group->tools.GetCount();
569 pos -= group->position;
570 for(t = 0; t < tool_count; ++t)
571 {
572 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
573 if(tool->position.x <= pos.x && pos.x < tool->position.x + tool->size.x
574 && tool->position.y <= pos.y && pos.y < tool->position.y + tool->size.y)
575 {
576 pos -= tool->position;
577 new_hover = tool;
578 break;
579 }
580 }
581 break;
582 }
583 }
584
585 if(new_hover != m_hover_tool)
586 {
587 if(m_hover_tool)
588 {
589 m_hover_tool->state &= ~(wxRIBBON_TOOLBAR_TOOL_HOVER_MASK
590 | wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK);
591 }
592 m_hover_tool = new_hover;
593 if(new_hover)
594 {
595 long what = wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED;
596 if(new_hover->dropdown.Contains(pos))
597 what = wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED;
598
599 new_hover->state |= what;
600
601 if(new_hover == m_active_tool)
602 {
603 new_hover->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
604 new_hover->state |= (what << 2);
605 }
606 }
607 Refresh(false);
608 }
609 else if(m_hover_tool && m_hover_tool->kind == wxRIBBON_BUTTON_HYBRID)
610 {
611 long newstate = m_hover_tool->state &~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK;
612 long what = wxRIBBON_TOOLBAR_TOOL_NORMAL_HOVERED;
613 if(m_hover_tool->dropdown.Contains(pos))
614 what = wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED;
615 newstate |= what;
616 if(newstate != m_hover_tool->state)
617 {
618 m_hover_tool->state = newstate;
619 if(m_hover_tool == m_active_tool)
620 {
621 m_hover_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
622 m_hover_tool->state |= (what << 2);
623 }
624 Refresh(false);
625 }
626 }
627 }
628
629 void wxRibbonToolBar::OnMouseDown(wxMouseEvent& evt)
630 {
631 OnMouseMove(evt);
632 if(m_hover_tool)
633 {
634 m_active_tool = m_hover_tool;
635 m_active_tool->state |=
636 (m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_HOVER_MASK) << 2;
637 Refresh(false);
638 }
639 }
640
641 void wxRibbonToolBar::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
642 {
643 if(m_hover_tool)
644 {
645 m_hover_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_HOVER_MASK;
646 m_hover_tool = NULL;
647 Refresh(false);
648 }
649 }
650
651 void wxRibbonToolBar::OnMouseUp(wxMouseEvent& WXUNUSED(evt))
652 {
653 if(m_active_tool)
654 {
655 if(m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK)
656 {
657 wxEventType evt_type = wxEVT_COMMAND_RIBBONTOOL_CLICKED;
658 if(m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_DROPDOWN_ACTIVE)
659 evt_type = wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED;
660 wxRibbonToolBarEvent notification(evt_type, m_active_tool->id);
661 notification.SetEventObject(this);
662 notification.SetBar(this);
663 ProcessEvent(notification);
664 }
665 m_active_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK;
666 m_active_tool = NULL;
667 Refresh(false);
668 }
669 }
670
671 void wxRibbonToolBar::OnMouseEnter(wxMouseEvent& evt)
672 {
673 if(m_active_tool && !evt.LeftIsDown())
674 {
675 m_active_tool = NULL;
676 }
677 }
678
679 bool wxRibbonToolBarEvent::PopupMenu(wxMenu* menu)
680 {
681 wxPoint pos = wxDefaultPosition;
682 if(m_bar->m_active_tool)
683 {
684 // Find the group which contains the tool
685 size_t group_count = m_bar->m_groups.GetCount();
686 size_t g, t;
687 for(g = 0; g < group_count; ++g)
688 {
689 wxRibbonToolBarToolGroup* group = m_bar->m_groups.Item(g);
690 size_t tool_count = group->tools.GetCount();
691 for(t = 0; t < tool_count; ++t)
692 {
693 wxRibbonToolBarToolBase* tool = group->tools.Item(t);
694 if(tool == m_bar->m_active_tool)
695 {
696 pos = group->position;
697 pos += tool->position;
698 pos.y += tool->size.GetHeight();
699 g = group_count;
700 break;
701 }
702 }
703 }
704 }
705 return m_bar->PopupMenu(menu, pos);
706 }
707
708 #endif // wxUSE_RIBBON