1 // Aseprite
2 // Copyright (C) 2001-2018  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "app/ui/toolbar.h"
12 
13 #include "app/app.h"
14 #include "app/commands/command.h"
15 #include "app/commands/commands.h"
16 #include "app/i18n/strings.h"
17 #include "app/modules/editors.h"
18 #include "app/modules/gfx.h"
19 #include "app/tools/active_tool.h"
20 #include "app/tools/tool_box.h"
21 #include "app/ui/keyboard_shortcuts.h"
22 #include "app/ui/main_window.h"
23 #include "app/ui/preview_editor.h"
24 #include "app/ui/skin/skin_theme.h"
25 #include "app/ui/status_bar.h"
26 #include "app/ui_context.h"
27 #include "base/bind.h"
28 #include "fmt/format.h"
29 #include "gfx/size.h"
30 #include "obs/signal.h"
31 #include "she/surface.h"
32 #include "ui/ui.h"
33 
34 #include <string>
35 
36 namespace app {
37 
38 using namespace app::skin;
39 using namespace gfx;
40 using namespace ui;
41 using namespace tools;
42 
43 // Class to show a group of tools (horizontally)
44 // This widget is inside the ToolBar::m_popupWindow
45 class ToolBar::ToolStrip : public Widget {
46 public:
47   ToolStrip(ToolGroup* group, ToolBar* toolbar);
48   ~ToolStrip();
49 
toolGroup()50   ToolGroup* toolGroup() { return m_group; }
51 
52   obs::signal<void(Tool*)> ToolSelected;
53 
54 protected:
55   bool onProcessMessage(Message* msg) override;
56   void onSizeHint(SizeHintEvent& ev) override;
57   void onPaint(PaintEvent& ev) override;
58 
59 private:
60   Rect getToolBounds(int index);
61 
62   ToolGroup* m_group;
63   Tool* m_hotTool;
64   ToolBar* m_toolbar;
65 };
66 
getToolIconSize(Widget * widget)67 static Size getToolIconSize(Widget* widget)
68 {
69   SkinTheme* theme = static_cast<SkinTheme*>(widget->theme());
70   she::Surface* icon = theme->getToolIcon("configuration");
71   if (icon)
72     return Size(icon->width(), icon->height());
73   else
74     return Size(16, 16) * guiscale();
75 }
76 
77 //////////////////////////////////////////////////////////////////////
78 // ToolBar
79 
80 ToolBar* ToolBar::m_instance = NULL;
81 
ToolBar()82 ToolBar::ToolBar()
83   : Widget(kGenericWidget)
84   , m_openedRecently(false)
85   , m_tipTimer(300, this)
86 {
87   m_instance = this;
88 
89   setBorder(gfx::Border(1*guiscale(), 0, 1*guiscale(), 0));
90 
91   m_hotTool = NULL;
92   m_hotIndex = NoneIndex;
93   m_openOnHot = false;
94   m_popupWindow = NULL;
95   m_currentStrip = NULL;
96   m_tipWindow = NULL;
97   m_tipOpened = false;
98 
99   ToolBox* toolbox = App::instance()->toolBox();
100   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
101     Tool* tool = *it;
102     if (m_selectedInGroup.find(tool->getGroup()) == m_selectedInGroup.end())
103       m_selectedInGroup[tool->getGroup()] = tool;
104   }
105 
106   App::instance()->activeToolManager()->add_observer(this);
107 }
108 
~ToolBar()109 ToolBar::~ToolBar()
110 {
111   App::instance()->activeToolManager()->remove_observer(this);
112 
113   delete m_popupWindow;
114   delete m_tipWindow;
115 }
116 
isToolVisible(Tool * tool)117 bool ToolBar::isToolVisible(Tool* tool)
118 {
119   return (m_selectedInGroup[tool->getGroup()] == tool);
120 }
121 
onProcessMessage(Message * msg)122 bool ToolBar::onProcessMessage(Message* msg)
123 {
124   switch (msg->type()) {
125 
126     case kMouseDownMessage: {
127       MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
128       ToolBox* toolbox = App::instance()->toolBox();
129       int groups = toolbox->getGroupsCount();
130       Rect toolrc;
131 
132       ToolGroupList::iterator it = toolbox->begin_group();
133       for (int c=0; c<groups; ++c, ++it) {
134         ToolGroup* tool_group = *it;
135         Tool* tool = m_selectedInGroup[tool_group];
136 
137         toolrc = getToolGroupBounds(c);
138         if (mouseMsg->position().y >= toolrc.y &&
139             mouseMsg->position().y < toolrc.y+toolrc.h) {
140           selectTool(tool);
141 
142           openPopupWindow(c, tool_group);
143 
144           // We capture the mouse so the user can continue navigating
145           // the ToolBar to open other groups while he is pressing the
146           // mouse button.
147           captureMouse();
148         }
149       }
150 
151       toolrc = getToolGroupBounds(PreviewVisibilityIndex);
152       if (mouseMsg->position().y >= toolrc.y &&
153           mouseMsg->position().y < toolrc.y+toolrc.h) {
154         // Toggle preview visibility
155         PreviewEditorWindow* preview =
156           App::instance()->mainWindow()->getPreviewEditor();
157         bool state = preview->isPreviewEnabled();
158         preview->setPreviewEnabled(!state);
159       }
160       break;
161     }
162 
163     case kMouseMoveMessage: {
164       MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
165       ToolBox* toolbox = App::instance()->toolBox();
166       int groups = toolbox->getGroupsCount();
167       Tool* new_hot_tool = NULL;
168       int new_hot_index = NoneIndex;
169       Rect toolrc;
170 
171       ToolGroupList::iterator it = toolbox->begin_group();
172 
173       for (int c=0; c<groups; ++c, ++it) {
174         ToolGroup* tool_group = *it;
175         Tool* tool = m_selectedInGroup[tool_group];
176 
177         toolrc = getToolGroupBounds(c);
178         if (mouseMsg->position().y >= toolrc.y &&
179             mouseMsg->position().y < toolrc.y+toolrc.h) {
180           new_hot_tool = tool;
181           new_hot_index = c;
182 
183           if ((m_openOnHot) && (m_hotTool != new_hot_tool) && hasCapture()) {
184             openPopupWindow(c, tool_group);
185           }
186           break;
187         }
188       }
189 
190       toolrc = getToolGroupBounds(PreviewVisibilityIndex);
191       if (mouseMsg->position().y >= toolrc.y &&
192           mouseMsg->position().y < toolrc.y+toolrc.h) {
193         new_hot_index = PreviewVisibilityIndex;
194       }
195 
196       // hot button changed
197       if (new_hot_tool != m_hotTool ||
198           new_hot_index != m_hotIndex) {
199 
200         m_hotTool = new_hot_tool;
201         m_hotIndex = new_hot_index;
202         invalidate();
203 
204         if (!m_currentStrip) {
205           if (m_hotIndex != NoneIndex && !hasCapture())
206             openTipWindow(m_hotIndex, m_hotTool);
207           else
208             closeTipWindow();
209         }
210 
211         if (m_hotTool) {
212           if (hasCapture())
213             selectTool(m_hotTool);
214           else
215             StatusBar::instance()->showTool(0, m_hotTool);
216         }
217       }
218 
219       // We can change the current tool if the user is dragging the
220       // mouse over the ToolBar.
221       if (hasCapture()) {
222         MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
223         Widget* pick = manager()->pick(mouseMsg->position());
224         if (ToolStrip* strip = dynamic_cast<ToolStrip*>(pick)) {
225           releaseMouse();
226 
227           MouseMessage* mouseMsg2 = new MouseMessage(
228             kMouseDownMessage,
229             mouseMsg->pointerType(),
230             mouseMsg->buttons(),
231             mouseMsg->modifiers(),
232             mouseMsg->position());
233           mouseMsg2->addRecipient(strip);
234           manager()->enqueueMessage(mouseMsg2);
235         }
236       }
237       break;
238     }
239 
240     case kMouseUpMessage:
241       if (!hasCapture())
242         break;
243 
244       if (!m_openedRecently) {
245         if (m_popupWindow && m_popupWindow->isVisible())
246           m_popupWindow->closeWindow(this);
247       }
248       m_openedRecently = false;
249 
250       releaseMouse();
251       // fallthrough
252 
253     case kMouseLeaveMessage:
254       if (hasCapture())
255         break;
256 
257       closeTipWindow();
258 
259       if (!m_popupWindow || !m_popupWindow->isVisible()) {
260         m_tipOpened = false;
261 
262         m_hotTool = NULL;
263         m_hotIndex = NoneIndex;
264         invalidate();
265       }
266 
267       StatusBar::instance()->clearText();
268       break;
269 
270     case kTimerMessage:
271       if (static_cast<TimerMessage*>(msg)->timer() == &m_tipTimer) {
272         if (m_tipWindow)
273           m_tipWindow->openWindow();
274 
275         m_tipTimer.stop();
276         m_tipOpened = true;
277       }
278       break;
279 
280   }
281 
282   return Widget::onProcessMessage(msg);
283 }
284 
onSizeHint(SizeHintEvent & ev)285 void ToolBar::onSizeHint(SizeHintEvent& ev)
286 {
287   Size iconsize = getToolIconSize(this);
288   iconsize.w += border().width();
289   iconsize.h += border().height();
290   ev.setSizeHint(iconsize);
291 }
292 
onPaint(ui::PaintEvent & ev)293 void ToolBar::onPaint(ui::PaintEvent& ev)
294 {
295   gfx::Rect bounds = clientBounds();
296   Graphics* g = ev.graphics();
297   SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
298   ToolBox* toolbox = App::instance()->toolBox();
299   Tool* activeTool = App::instance()->activeTool();
300   ToolGroupList::iterator it = toolbox->begin_group();
301   int groups = toolbox->getGroupsCount();
302   Rect toolrc;
303 
304   g->fillRect(theme->colors.tabActiveFace(), bounds);
305 
306   for (int c=0; c<groups; ++c, ++it) {
307     ToolGroup* tool_group = *it;
308     Tool* tool = m_selectedInGroup[tool_group];
309     SkinPartPtr nw;
310 
311     if (activeTool == tool || m_hotIndex == c) {
312       nw = theme->parts.toolbuttonHot();
313     }
314     else {
315       nw = c >= 0 && c < groups-1 ? theme->parts.toolbuttonNormal():
316                                     theme->parts.toolbuttonLast();
317     }
318 
319     toolrc = getToolGroupBounds(c);
320     toolrc.offset(-origin());
321     theme->drawRect(g, toolrc, nw.get());
322 
323     // Draw the tool icon
324     she::Surface* icon = theme->getToolIcon(tool->getId().c_str());
325     if (icon) {
326       g->drawRgbaSurface(icon,
327         toolrc.x+toolrc.w/2-icon->width()/2,
328         toolrc.y+toolrc.h/2-icon->height()/2);
329     }
330   }
331 
332   // Draw button to show/hide preview
333   toolrc = getToolGroupBounds(PreviewVisibilityIndex);
334   toolrc.offset(-origin());
335   bool isHot = (m_hotIndex == PreviewVisibilityIndex ||
336     App::instance()->mainWindow()->getPreviewEditor()->isPreviewEnabled());
337   theme->drawRect(
338     g,
339     toolrc,
340     (isHot ? theme->parts.toolbuttonHot().get():
341              theme->parts.toolbuttonLast().get()));
342 
343   she::Surface* icon = theme->getToolIcon("minieditor");
344   if (icon) {
345     g->drawRgbaSurface(icon,
346       toolrc.x+toolrc.w/2-icon->width()/2,
347       toolrc.y+toolrc.h/2-icon->height()/2);
348   }
349 }
350 
onVisible(bool visible)351 void ToolBar::onVisible(bool visible)
352 {
353   Widget::onVisible(visible);
354   if (!visible) {
355     if (m_popupWindow) {
356       closePopupWindow();
357       closeTipWindow();
358     }
359   }
360 }
361 
getToolGroupIndex(ToolGroup * group)362 int ToolBar::getToolGroupIndex(ToolGroup* group)
363 {
364   ToolBox* toolbox = App::instance()->toolBox();
365   ToolGroupList::iterator it = toolbox->begin_group();
366   int groups = toolbox->getGroupsCount();
367 
368   for (int c=0; c<groups; ++c, ++it) {
369     if (group == *it)
370       return c;
371   }
372 
373   return -1;
374 }
375 
openPopupWindow(int group_index,ToolGroup * tool_group)376 void ToolBar::openPopupWindow(int group_index, ToolGroup* tool_group)
377 {
378   if (m_popupWindow) {
379     // If we've already open the given group, do nothing.
380     if (m_currentStrip && m_currentStrip->toolGroup() == tool_group)
381       return;
382 
383     if (m_closeConn)
384       m_closeConn.disconnect();
385 
386     onClosePopup();
387     closePopupWindow();
388   }
389 
390   // Close tip window
391   closeTipWindow();
392 
393   // If this group contains only one tool, do not show the popup
394   ToolBox* toolbox = App::instance()->toolBox();
395   int count = 0;
396   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
397     Tool* tool = *it;
398     if (tool->getGroup() == tool_group)
399       ++count;
400   }
401   m_openOnHot = true;
402   if (count <= 1)
403     return;
404 
405   // In case this tool contains more than just one tool, show the popup window
406   m_popupWindow = new TransparentPopupWindow(PopupWindow::ClickBehavior::CloseOnClickOutsideHotRegion);
407   m_closeConn = m_popupWindow->Close.connect(base::Bind<void, ToolBar, ToolBar>(&ToolBar::onClosePopup, this));
408   m_openedRecently = true;
409 
410   ToolStrip* toolstrip = new ToolStrip(tool_group, this);
411   m_currentStrip = toolstrip;
412   m_popupWindow->addChild(toolstrip);
413 
414   Rect rc = getToolGroupBounds(group_index);
415   int w = 0;
416 
417   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
418     Tool* tool = *it;
419     if (tool->getGroup() == tool_group)
420       w += bounds().w-border().width()-1;
421   }
422 
423   rc.x -= w;
424   rc.w = w;
425 
426   // Set hotregion of popup window
427   Region rgn(gfx::Rect(rc).enlarge(16*guiscale()));
428   rgn.createUnion(rgn, Region(bounds()));
429   m_popupWindow->setHotRegion(rgn);
430   m_popupWindow->setAutoRemap(false);
431   m_popupWindow->setBounds(rc);
432   toolstrip->setBounds(rc);
433   m_popupWindow->openWindow();
434 
435   toolstrip->setBounds(rc);
436 }
437 
closePopupWindow()438 void ToolBar::closePopupWindow()
439 {
440   if (m_popupWindow) {
441     m_popupWindow->closeWindow(nullptr);
442     delete m_popupWindow;
443     m_popupWindow = nullptr;
444   }
445 }
446 
getToolGroupBounds(int group_index)447 Rect ToolBar::getToolGroupBounds(int group_index)
448 {
449   ToolBox* toolbox = App::instance()->toolBox();
450   int groups = toolbox->getGroupsCount();
451   Size iconsize = getToolIconSize(this);
452   Rect rc(bounds());
453   rc.shrink(border());
454 
455   switch (group_index) {
456 
457     case PreviewVisibilityIndex:
458       rc.y += rc.h - iconsize.h - 2*guiscale();
459       rc.h = iconsize.h+2*guiscale();
460       break;
461 
462     default:
463       rc.y += group_index*(iconsize.h-1*guiscale());
464       rc.h = group_index < groups-1 ? iconsize.h+1*guiscale():
465                                       iconsize.h+2*guiscale();
466       break;
467   }
468 
469   return rc;
470 }
471 
getToolPositionInGroup(int group_index,Tool * tool)472 Point ToolBar::getToolPositionInGroup(int group_index, Tool* tool)
473 {
474   ToolBox* toolbox = App::instance()->toolBox();
475   Size iconsize = getToolIconSize(this);
476   int nth = 0;
477 
478   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
479     if (tool == *it)
480       break;
481 
482     if ((*it)->getGroup() == tool->getGroup()) {
483       ++nth;
484     }
485   }
486 
487   return Point(iconsize.w/2+iconsize.w*nth, iconsize.h);
488 }
489 
openTipWindow(ToolGroup * tool_group,Tool * tool)490 void ToolBar::openTipWindow(ToolGroup* tool_group, Tool* tool)
491 {
492   openTipWindow(getToolGroupIndex(tool_group), tool);
493 }
494 
openTipWindow(int group_index,Tool * tool)495 void ToolBar::openTipWindow(int group_index, Tool* tool)
496 {
497   if (m_tipWindow)
498     closeTipWindow();
499 
500   std::string tooltip;
501   if (tool && group_index >= 0) {
502     tooltip = tool->getText();
503     if (tool->getTips().size() > 0) {
504       tooltip += ":\n";
505       tooltip += tool->getTips();
506     }
507 
508     // Tool shortcut
509     KeyPtr key = KeyboardShortcuts::instance()->tool(tool);
510     if (key && !key->accels().empty()) {
511       tooltip += "\n\n";
512       tooltip += fmt::format(Strings::tools_shortcut(),
513                              key->accels().front().toString());
514     }
515   }
516   else if (group_index == PreviewVisibilityIndex) {
517     if (App::instance()->mainWindow()->getPreviewEditor()->isPreviewEnabled())
518       tooltip = Strings::tools_preview_hide();
519     else
520       tooltip = Strings::tools_preview_show();
521   }
522   else
523     return;
524 
525   m_tipWindow = new TipWindow(tooltip);
526   m_tipWindow->remapWindow();
527 
528   Rect toolrc = getToolGroupBounds(group_index);
529   Point arrow = (tool ? getToolPositionInGroup(group_index, tool): Point(0, 0));
530   if (tool && m_popupWindow && m_popupWindow->isVisible())
531     toolrc.x += arrow.x - m_popupWindow->bounds().w;
532 
533   m_tipWindow->pointAt(TOP | RIGHT, toolrc);
534 
535   if (m_tipOpened)
536     m_tipWindow->openWindow();
537   else
538     m_tipTimer.start();
539 }
540 
closeTipWindow()541 void ToolBar::closeTipWindow()
542 {
543   m_tipTimer.stop();
544 
545   if (m_tipWindow) {
546     m_tipWindow->closeWindow(NULL);
547     delete m_tipWindow;
548     m_tipWindow = NULL;
549   }
550 }
551 
selectTool(Tool * tool)552 void ToolBar::selectTool(Tool* tool)
553 {
554   ASSERT(tool);
555 
556   m_selectedInGroup[tool->getGroup()] = tool;
557 
558   // Inform to the active tool manager about this tool change.
559   App::instance()->activeToolManager()->setSelectedTool(tool);
560 
561   if (m_currentStrip)
562     m_currentStrip->invalidate();
563 
564   invalidate();
565 }
566 
selectToolGroup(tools::ToolGroup * toolGroup)567 void ToolBar::selectToolGroup(tools::ToolGroup* toolGroup)
568 {
569   ASSERT(toolGroup);
570   ASSERT(m_selectedInGroup[toolGroup]);
571   if (m_selectedInGroup[toolGroup])
572     selectTool(m_selectedInGroup[toolGroup]);
573 }
574 
onClosePopup()575 void ToolBar::onClosePopup()
576 {
577   closeTipWindow();
578 
579   if (!hasMouse())
580     m_tipOpened = false;
581 
582   m_openOnHot = false;
583   m_hotTool = NULL;
584   m_hotIndex = NoneIndex;
585   m_currentStrip = NULL;
586 
587   invalidate();
588 }
589 
590 //////////////////////////////////////////////////////////////////////
591 // ToolStrip
592 //////////////////////////////////////////////////////////////////////
593 
ToolStrip(ToolGroup * group,ToolBar * toolbar)594 ToolBar::ToolStrip::ToolStrip(ToolGroup* group, ToolBar* toolbar)
595   : Widget(kGenericWidget)
596 {
597   m_group = group;
598   m_hotTool = NULL;
599   m_toolbar = toolbar;
600 
601   setDoubleBuffered(true);
602   setTransparent(true);
603 }
604 
~ToolStrip()605 ToolBar::ToolStrip::~ToolStrip()
606 {
607 }
608 
onProcessMessage(Message * msg)609 bool ToolBar::ToolStrip::onProcessMessage(Message* msg)
610 {
611   switch (msg->type()) {
612 
613     case kMouseDownMessage:
614       captureMouse();
615       // fallthrough
616 
617     case kMouseMoveMessage: {
618       MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
619       gfx::Point mousePos = mouseMsg->position();
620       ToolBox* toolbox = App::instance()->toolBox();
621       Tool* hot_tool = NULL;
622       Rect toolrc;
623       int index = 0;
624 
625       for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
626         Tool* tool = *it;
627         if (tool->getGroup() == m_group) {
628           toolrc = getToolBounds(index++);
629           if (toolrc.contains(Point(mousePos.x, mousePos.y))) {
630             hot_tool = tool;
631             break;
632           }
633         }
634       }
635 
636       // Hot button changed
637       if (m_hotTool != hot_tool) {
638         m_hotTool = hot_tool;
639         invalidate();
640 
641         // Show the tooltip for the hot tool
642         if (m_hotTool && !hasCapture())
643           m_toolbar->openTipWindow(m_group, m_hotTool);
644         else
645           m_toolbar->closeTipWindow();
646 
647         if (m_hotTool)
648           StatusBar::instance()->showTool(0, m_hotTool);
649       }
650 
651       if (hasCapture()) {
652         if (m_hotTool)
653           m_toolbar->selectTool(m_hotTool);
654 
655         Widget* pick = manager()->pick(mouseMsg->position());
656         if (ToolBar* bar = dynamic_cast<ToolBar*>(pick)) {
657           releaseMouse();
658 
659           MouseMessage* mouseMsg2 = new MouseMessage(
660             kMouseDownMessage,
661             mouseMsg->pointerType(),
662             mouseMsg->buttons(),
663             mouseMsg->modifiers(),
664             mouseMsg->position());
665           mouseMsg2->addRecipient(bar);
666           manager()->enqueueMessage(mouseMsg2);
667         }
668       }
669       break;
670     }
671 
672     case kMouseUpMessage:
673       if (hasCapture()) {
674         releaseMouse();
675         closeWindow();
676       }
677       break;
678 
679   }
680   return Widget::onProcessMessage(msg);
681 }
682 
onSizeHint(SizeHintEvent & ev)683 void ToolBar::ToolStrip::onSizeHint(SizeHintEvent& ev)
684 {
685   ToolBox* toolbox = App::instance()->toolBox();
686   int c = 0;
687 
688   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
689     Tool* tool = *it;
690     if (tool->getGroup() == m_group) {
691       ++c;
692     }
693   }
694 
695   Size iconsize = getToolIconSize(this);
696   ev.setSizeHint(Size(iconsize.w * c, iconsize.h));
697 }
698 
onPaint(PaintEvent & ev)699 void ToolBar::ToolStrip::onPaint(PaintEvent& ev)
700 {
701   Graphics* g = ev.graphics();
702   SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
703   ToolBox* toolbox = App::instance()->toolBox();
704   Tool* activeTool = App::instance()->activeTool();
705   Rect toolrc;
706   int index = 0;
707 
708   for (ToolIterator it = toolbox->begin(); it != toolbox->end(); ++it) {
709     Tool* tool = *it;
710     if (tool->getGroup() == m_group) {
711       SkinPartPtr nw;
712 
713       if (activeTool == tool || m_hotTool == tool) {
714         nw = theme->parts.toolbuttonHot();
715       }
716       else {
717         nw = theme->parts.toolbuttonLast();
718       }
719 
720       toolrc = getToolBounds(index++);
721       toolrc.offset(-bounds().x, -bounds().y);
722       theme->drawRect(g, toolrc, nw.get());
723 
724       // Draw the tool icon
725       she::Surface* icon = theme->getToolIcon(tool->getId().c_str());
726       if (icon) {
727         g->drawRgbaSurface(
728           icon,
729           toolrc.x+toolrc.w/2-icon->width()/2,
730           toolrc.y+toolrc.h/2-icon->height()/2);
731       }
732     }
733   }
734 }
735 
getToolBounds(int index)736 Rect ToolBar::ToolStrip::getToolBounds(int index)
737 {
738   const Rect& bounds(this->bounds());
739   Size iconsize = getToolIconSize(this);
740 
741   return Rect(bounds.x+index*(iconsize.w-1), bounds.y,
742               iconsize.w, bounds.h);
743 }
744 
onActiveToolChange(tools::Tool * tool)745 void ToolBar::onActiveToolChange(tools::Tool* tool)
746 {
747   invalidate();
748 }
749 
onSelectedToolChange(tools::Tool * tool)750 void ToolBar::onSelectedToolChange(tools::Tool* tool)
751 {
752   if (tool && m_selectedInGroup[tool->getGroup()] != tool)
753     m_selectedInGroup[tool->getGroup()] = tool;
754 
755   invalidate();
756 }
757 
758 } // namespace app
759