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