1 // Aseprite
2 // Copyright (C) 2016 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/tools/active_tool.h"
12
13 #include "app/pref/preferences.h"
14 #include "app/tools/active_tool_observer.h"
15 #include "app/tools/ink.h"
16 #include "app/tools/pointer.h"
17 #include "app/tools/tool_box.h"
18 #include "app/ui/color_bar.h"
19
20 namespace app {
21 namespace tools {
22
23 class ActiveToolChangeTrigger {
24 public:
ActiveToolChangeTrigger(ActiveToolManager * manager)25 ActiveToolChangeTrigger(ActiveToolManager* manager)
26 : m_manager(manager)
27 , m_oldTool(manager->activeTool()) {
28 }
29
~ActiveToolChangeTrigger()30 ~ActiveToolChangeTrigger() {
31 Tool* newTool = m_manager->activeTool();
32 if (m_oldTool != newTool) {
33 m_manager->notify_observers(
34 &ActiveToolObserver::onActiveToolChange, newTool);
35 }
36 }
37
38 private:
39 ActiveToolManager* m_manager;
40 Tool* m_oldTool;
41 };
42
ActiveToolManager(ToolBox * toolbox)43 ActiveToolManager::ActiveToolManager(ToolBox* toolbox)
44 : m_toolbox(toolbox)
45 , m_quickTool(nullptr)
46 , m_rightClick(false)
47 , m_rightClickTool(nullptr)
48 , m_rightClickInk(nullptr)
49 , m_proximityTool(nullptr)
50 , m_selectedTool(m_toolbox->getToolById(WellKnownTools::Pencil)) // "pencil" is the active tool by default
51 {
52 }
53
activeTool() const54 Tool* ActiveToolManager::activeTool() const
55 {
56 if (m_quickTool)
57 return m_quickTool;
58
59 if (m_rightClickTool)
60 return m_rightClickTool;
61
62 if (m_proximityTool)
63 return m_proximityTool;
64
65 // Active tool should never returns null
66 ASSERT(m_selectedTool);
67 return m_selectedTool;
68 }
69
activeInk() const70 Ink* ActiveToolManager::activeInk() const
71 {
72 if (!m_quickTool && m_rightClickInk)
73 return m_rightClickInk;
74
75 Tool* tool = activeTool();
76 Ink* ink = tool->getInk(m_rightClick ? 1: 0);
77 if (ink->isPaint() && !ink->isEffect()) {
78 tools::InkType inkType = Preferences::instance().tool(tool).ink();
79 const char* id = nullptr;
80
81 switch (inkType) {
82
83 case tools::InkType::SIMPLE: {
84 id = tools::WellKnownInks::Paint;
85
86 ColorBar* colorbar = ColorBar::instance();
87 app::Color color = (m_rightClick ? colorbar->getBgColor():
88 colorbar->getFgColor());
89 if (color.getAlpha() == 0)
90 id = tools::WellKnownInks::PaintCopy;
91 break;
92 }
93
94 case tools::InkType::ALPHA_COMPOSITING:
95 id = tools::WellKnownInks::Paint;
96 break;
97 case tools::InkType::COPY_COLOR:
98 id = tools::WellKnownInks::PaintCopy;
99 break;
100 case tools::InkType::LOCK_ALPHA:
101 id = tools::WellKnownInks::PaintLockAlpha;
102 break;
103 case tools::InkType::SHADING:
104 id = tools::WellKnownInks::Shading;
105 break;
106 }
107
108 if (id)
109 ink = m_toolbox->getInkById(id);
110 }
111
112 return ink;
113 }
114
quickTool() const115 Tool* ActiveToolManager::quickTool() const
116 {
117 return m_quickTool;
118 }
119
selectedTool() const120 Tool* ActiveToolManager::selectedTool() const
121 {
122 return m_selectedTool;
123 }
124
newToolSelectedInToolBar(Tool * tool)125 void ActiveToolManager::newToolSelectedInToolBar(Tool* tool)
126 {
127 ActiveToolChangeTrigger trigger(this);
128 m_selectedTool = tool;
129 }
130
newQuickToolSelectedFromEditor(Tool * tool)131 void ActiveToolManager::newQuickToolSelectedFromEditor(Tool* tool)
132 {
133 ActiveToolChangeTrigger trigger(this);
134 m_quickTool = tool;
135 }
136
regularTipProximity()137 void ActiveToolManager::regularTipProximity()
138 {
139 if (m_proximityTool != nullptr) {
140 ActiveToolChangeTrigger trigger(this);
141 m_proximityTool = nullptr;
142 }
143 }
144
eraserTipProximity()145 void ActiveToolManager::eraserTipProximity()
146 {
147 Tool* eraser = m_toolbox->getToolById(WellKnownTools::Eraser);
148 if (m_proximityTool != eraser) {
149 ActiveToolChangeTrigger trigger(this);
150 m_proximityTool = eraser;
151 }
152 }
153
pressButton(const Pointer & pointer)154 void ActiveToolManager::pressButton(const Pointer& pointer)
155 {
156 ActiveToolChangeTrigger trigger(this);
157 Tool* tool = nullptr;
158 Ink* ink = nullptr;
159
160 if (pointer.button() == Pointer::Right) {
161 m_rightClick = true;
162
163 if (isToolAffectedByRightClickMode(activeTool())) {
164 switch (Preferences::instance().editor.rightClickMode()) {
165 case app::gen::RightClickMode::PAINT_BGCOLOR:
166 // Do nothing, use the active tool
167 break;
168 case app::gen::RightClickMode::PICK_FGCOLOR:
169 tool = m_toolbox->getToolById(WellKnownTools::Eyedropper);
170 ink = m_toolbox->getInkById(tools::WellKnownInks::PickFg);
171 break;
172 case app::gen::RightClickMode::ERASE:
173 tool = m_toolbox->getToolById(WellKnownTools::Eraser);
174 ink = m_toolbox->getInkById(tools::WellKnownInks::Eraser);
175 break;
176 case app::gen::RightClickMode::SCROLL:
177 tool = m_toolbox->getToolById(WellKnownTools::Hand);
178 ink = m_toolbox->getInkById(tools::WellKnownInks::Scroll);
179 break;
180 case app::gen::RightClickMode::RECTANGULAR_MARQUEE:
181 tool = m_toolbox->getToolById(WellKnownTools::RectangularMarquee);
182 ink = m_toolbox->getInkById(tools::WellKnownInks::Selection);
183 break;
184 case app::gen::RightClickMode::LASSO:
185 tool = m_toolbox->getToolById(WellKnownTools::Lasso);
186 ink = m_toolbox->getInkById(tools::WellKnownInks::Selection);
187 break;
188 }
189 }
190 }
191 else {
192 m_rightClick = false;
193 }
194
195 m_rightClickTool = tool;
196 m_rightClickInk = ink;
197 }
198
releaseButtons()199 void ActiveToolManager::releaseButtons()
200 {
201 ActiveToolChangeTrigger trigger(this);
202
203 m_rightClick = false;
204 m_rightClickTool = nullptr;
205 m_rightClickInk = nullptr;
206 }
207
setSelectedTool(Tool * tool)208 void ActiveToolManager::setSelectedTool(Tool* tool)
209 {
210 ActiveToolChangeTrigger trigger(this);
211
212 m_selectedTool = tool;
213 notify_observers(&ActiveToolObserver::onSelectedToolChange, tool);
214 }
215
216 // static
isToolAffectedByRightClickMode(Tool * tool)217 bool ActiveToolManager::isToolAffectedByRightClickMode(Tool* tool)
218 {
219 bool shadingMode = (Preferences::instance().tool(tool).ink() == InkType::SHADING);
220 return
221 ((tool->getInk(0)->isPaint() && !shadingMode) ||
222 (tool->getInk(0)->isEffect())) &&
223 (!tool->getInk(0)->isEraser()) &&
224 (!tool->getInk(0)->isSelection());
225 }
226
227 } // namespace tools
228 } // namespace app
229