1 /*
2  * Xournal++
3  *
4  * Handles Tools
5  *
6  * @author Xournal++ Team
7  * https://github.com/xournalpp/xournalpp
8  *
9  * @license GNU GPLv2 or later
10  */
11 
12 #pragma once
13 
14 #include <array>
15 #include <functional>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
20 #include <util/Color.h>
21 
22 #include "settings/Settings.h"
23 #include "settings/SettingsEnums.h"
24 
25 #include "Tool.h"
26 #include "XournalType.h"
27 
28 // enum for ptrs that are dynamically pointing to different tools
29 /**
30  * @brief Enum for ptrs that are dynamically pointing to different tools
31  *  - active: describes the currently active tool used for drawing
32  *  - toolbar: describes the tool currently selected in the toolbar
33  *
34  * These tools are to be distinguished from ButtonTools which are mostly static
35  * apart from changes to the Config
36  *
37  */
38 enum SelectedTool { active, toolbar };
39 
40 class ToolListener {
41 public:
42     /**
43      * @brief Update the Cursor and the Toolbar based on the active color
44      *
45      */
46     virtual void toolColorChanged() = 0;
47     /**
48      * @brief Change the color of the current selection based on the active Tool
49      *
50      */
51     virtual void changeColorOfSelection() = 0;
52     virtual void setCustomColorSelected() = 0;
53     virtual void toolSizeChanged() = 0;
54     virtual void toolFillChanged() = 0;
55     virtual void toolLineStyleChanged() = 0;
56     virtual void toolChanged() = 0;
57 
58     virtual ~ToolListener();
59 };
60 
61 class ActionHandler;
62 
63 class ToolHandler {
64 public:
65     using ToolChangedCallback = std::function<void(ToolType)>;
66     ToolHandler(ToolListener* stateChangedListener, ActionHandler* actionHandler, Settings* settings);
67     virtual ~ToolHandler();
68 
69     /**
70      * @brief Reset the Button tool with a new tooltype
71      *
72      * @param type Tooltype to be set for the button
73      * @param button button which should be set
74      */
75     void resetButtonTool(ToolType type, Button button);
76 
77     /**
78      * Select the color for the active tool and under certain circumstances toolbar selected tool
79      *
80      * If the current tool does not have the color capability but the toolbar selected tool has
81      * the color can be set for the toolbar selected tool.
82      * This is indicated by a little pen shown on top of the color in the UI.
83      *
84      * @param color Color
85      * @param userSelection
86      * 			true if the user selected the color
87      * 			false if the color is selected by a tool change
88      * 			and therefore should not be applied to a selection
89      */
90     void setColor(Color color, bool userSelection);
91 
92     /**
93      * @brief Set the color for a Button
94      * This is a separate function from `setColor` to prevent mixup of different usecases.
95      *
96      * @param color color to be set
97      * @param button button to set color for
98      */
99     void setButtonColor(Color color, Button button);
100 
101     /**
102      * @brief Get the Color of the active tool
103      *
104      * @return Color of active tool
105      */
106     Color getColor();
107 
108     /**
109      * @brief Get the Fill of the active tool
110      *
111      * @return -1 if fill is disabled
112      * @return int > 0 otherwise
113      */
114     int getFill();
115 
116     /**
117      * @brief Get the Drawing Type one of selected tools
118      *
119      * @param selectedTool by the default the active one
120      * @return DrawingType
121      */
122     DrawingType getDrawingType(SelectedTool selectedTool = SelectedTool::active);
123 
124     /**
125      * @brief Set the Drawing Type of the toolbar selected tool
126      * @note It is safer to always set the toolbar tool as the active tool could be pointing to a button tool which
127      * could lead to hard to debug behaviour
128      *
129      * @param drawingType
130      */
131     void setDrawingType(DrawingType drawingType);
132 
133     /**
134      * @brief Set the Button Drawing Type  of the button tool
135      *
136      * @param drawingType
137      * @param button button tool to be selected
138      */
139     void setButtonDrawingType(DrawingType drawingType, Button button);
140 
141     /**
142      * @brief Get the Line Style of active tool
143      *
144      * @return const LineStyle&
145      */
146     const LineStyle& getLineStyle();
147 
148     /**
149      * @brief Get the Size of one of the selected tools
150      *
151      * @param selectedTool
152      * @return ToolSize
153      */
154     ToolSize getSize(SelectedTool selectedTool = SelectedTool::active);
155 
156     /**
157      * @brief Set the Size of toolbar selected tool
158      * @note It is safer to always set the toolbar tool as the active tool could be pointing to a button tool which
159      * could lead to hard to debug behaviour
160      *
161      * @param size is clamped to be within the defined range [0,5)
162      */
163     void setSize(ToolSize size);
164 
165     /**
166      * @brief Set the Button Size
167      *
168      * @param size is clamped to be within the defined range [0,5)
169      * @param button size will be applied to
170      */
171     void setButtonSize(ToolSize size, Button button);
172 
173     /**
174      * @brief Get the Thickness of the active tool
175      *
176      * @return double
177      */
178     double getThickness();
179 
180     void setLineStyle(const LineStyle& style);
181 
182     ToolSize getPenSize();
183     ToolSize getEraserSize();
184     ToolSize getHighlighterSize();
185     void setPenSize(ToolSize size);
186     void setEraserSize(ToolSize size);
187     void setHighlighterSize(ToolSize size);
188 
189     void setPenFillEnabled(bool fill, bool fireEvent = true);
190     bool getPenFillEnabled();
191     void setPenFill(int alpha);
192     int getPenFill();
193 
194     void setHighlighterFillEnabled(bool fill, bool fireEvent = true);
195     bool getHighlighterFillEnabled();
196     void setHighlighterFill(int alpha);
197     int getHighlighterFill();
198 
199     /**
200      * @brief Set the toolbar selected tool to the type
201      * This will also point the active tool to the same tool as the toolbar selected tool.
202      * This ensure that the toolbar and the cursor are correctly updated right after selecting the tool in the toolbar.
203      *
204      * @param type
205      */
206     void selectTool(ToolType type);
207 
208     /**
209      * @brief Get the Tool Type of active tool
210      *
211      * @return ToolType
212      */
213     ToolType getToolType();
214 
215     /**
216      * @brief Update the Toolbar and the cursor based on the active Tool
217      *
218      */
219     void fireToolChanged();
220 
221     /**
222      * @brief Listen for tool changes.
223      *
224      * Different from the listener given to the constructor -- [listener]
225      * here only listens for when the current tool is changed to another.
226      *
227      * @param listener A callback, called when the user/client
228      *  changes tools.
229      */
230     void addToolChangedListener(ToolChangedCallback listener);
231 
232     /**
233      * @brief Get the Tool of a certain type
234      *
235      * @param type
236      * @return Tool&
237      */
238     Tool& getTool(ToolType type);
239 
240     /**
241      * @brief Set the Eraser Type of the Eraser in the toolbar
242      * @note Here the Eraser Tool in the toolbar is changed regardless of the the tool currently selected.
243      * This is necessary to allow users to change the Eraser type for their Button Tools while having another tool
244      * active. This is relevant in case of Eraser Type being set to "Don't Change" for the button.
245      *
246      * @param eraserType
247      */
248     void setEraserType(EraserType eraserType);
249 
250     /**
251      * @brief Set the Button Eraser Type
252      *
253      * @param eraserType
254      * @param button
255      */
256     void setButtonEraserType(EraserType eraserType, Button button);
257 
258     /**
259      * @brief Get the Eraser Type
260      * If the currently active Tool is an eraser it's type is returned (relevant for Buttontools).
261      * If the currently active Tool is not a eraser the erasertype of the eraser in the toolbar is obtained.
262      *
263      * @param selectedTool
264      * @return EraserType
265      */
266     EraserType getEraserType();
267 
268     /**
269      * @brief Update the toolbar based on the Eraser type of the active tool
270      *
271      */
272     void eraserTypeChanged();
273 
274     /**
275      * @brief Check whether the selectedTool has a certain capability
276      *
277      * @param cap
278      * @param selectedTool
279      * @return true if tool has the capability
280      * @return false if tool does not have the capability
281      */
282     bool hasCapability(ToolCapabilities cap, SelectedTool selectedTool = SelectedTool::active);
283 
284     /**
285      * @brief Check whether the active tool is a Drawing tool.
286      * Drawing tools are considered all tools that directly change the canvas.
287      * Right now these are:
288      *  - Highlighter
289      *  - Pen
290      *  - Eraser
291      *
292      * @return true if active tool is a drawing tool
293      * @return false if active tool is no drawing tool
294      */
295     bool isDrawingTool();
296 
297     void saveSettings();
298     void loadSettings();
299 
300     /**
301      * @brief Point the active tool to the corresponding button tool if it is not already pointing to it
302      *
303      * @param button Button tool which should be pointed to
304      * @return true if the active toolpointer was changed
305      * @return false if the active toolpointer was not changed (it was already pointing to the right button)
306      */
307     bool pointActiveToolToButtonTool(Button button);
308     /**
309      * @brief Point the active tool to tool selected in the toolbar
310      *
311      * @return true if the active toolpointer was changed
312      * @return false if the active toolpointer was not changed (it was already pointing to the toolbar-tool)
313      */
314     bool pointActiveToolToToolbarTool();
315 
316     [[maybe_unused]] std::array<std::unique_ptr<Tool>, TOOL_COUNT> const& getTools() const;
317 
318     /**
319      * Change the selection tools capabilities, depending on the selected elements
320      */
321     void setSelectionEditTools(bool setColor, bool setSize, bool setFill);
322 
323     const double* getToolThickness(ToolType type);
324 
325     /**
326      * Returns whether the current tool will create an element that may only reside on a single page even when the
327      * pointer moves to another
328      * @return
329      */
330     bool isSinglePageTool();
331 
332 protected:
333     void initTools();
334 
335 private:
336     std::array<std::unique_ptr<Tool>, TOOL_COUNT> tools;
337 
338     /**
339      * @brief Get the Button Tool pointer based on enum
340      *
341      * @param button
342      * @return Tool*
343      */
344     Tool* getButtonTool(Button button);
345 
346     /**
347      * @brief Get the Selected Tool pointer based on enum
348      *
349      * @param selectedTool
350      * @return Tool*
351      */
352     Tool* getSelectedTool(SelectedTool selectedTool);
353 
354     // active Tool which is used for drawing
355     Tool* activeTool = nullptr;
356 
357     // tool which is selected in the toolbar
358     Tool* toolbarSelectedTool = nullptr;
359 
360     // tools set for the different Buttons
361     std::unique_ptr<Tool> stylusButton1Tool;
362     std::unique_ptr<Tool> stylusButton2Tool;
363     std::unique_ptr<Tool> eraserButtonTool;
364     std::unique_ptr<Tool> mouseMiddleButtonTool;
365     std::unique_ptr<Tool> mouseRightButtonTool;
366     std::unique_ptr<Tool> touchDrawingButtonTool;
367 
368     std::vector<ToolChangedCallback> toolChangeListeners;
369 
370     ToolListener* stateChangeListener = nullptr;
371     ActionHandler* actionHandler = nullptr;
372     Settings* settings = nullptr;
373 };
374