1 /*
2    Copyright (C) 2008 - 2018 by Tomasz Sniatowski <kailoran@gmail.com>
3    Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY.
11 
12    See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include "editor/action/action_base.hpp"
18 #include "editor/map/editor_map.hpp"
19 #include "theme.hpp"
20 #include "editor/palette/editor_palettes.hpp"
21 #include "editor/palette/terrain_palettes.hpp"
22 #include "editor/palette/location_palette.hpp"
23 #include "editor/palette/empty_palette.hpp"
24 
25 class CKey;
26 
27 namespace editor {
28 
29 /**
30  * A mouse action receives events from the controller, and responds to them by creating
31  * an appropriate editor_action object. Mouse actions may store some temporary data
32  * such as the last clicked hex for better handling of click-drag. They should *not* modify
33  * the map or trigger refreshes, but may set brush locations and similar overlays that
34  * should be visible around the mouse cursor, hence the display references are not const.
35  */
36 class mouse_action
37 {
38 public:
mouse_action(common_palette & palette,const CKey & key)39 	mouse_action(common_palette& palette, const CKey& key)
40 		: previous_move_hex_()
41 		, key_(key)
42 		, toolbar_button_(nullptr)
43 		, palette_(palette)
44 	{
45 	}
46 
~mouse_action()47 	virtual ~mouse_action() {}
48 
49 	virtual bool has_context_menu() const;
50 
51 	/**
52 	 * Mouse move (not a drag). Never changes anything (other than temporary highlights and similar)
53 	 */
54 	virtual void move(editor_display& disp, const map_location& hex);
55 
56 	/**
57 	 * Unconditionally update the brush highlights for the current tool when hex is the center location
58 	 */
59 	void update_brush_highlights(editor_display& disp, const map_location& hex);
60 
61 	/**
62 	 * Locations that would be affected by a click, used by move to update highlights. Defaults to highlight the mouseover hex.
63 	 * Maybe also used for actually performing the action in click() or drag().
64 	 */
65 	virtual std::set<map_location> affected_hexes(editor_display& disp, const map_location& hex);
66 
67 	/**
68 	 * A click, possibly the beginning of a drag. Must be overridden.
69 	 */
70 	virtual editor_action* click_left(editor_display& disp, int x, int y) = 0;
71 
72 	/**
73 	 * A click, possibly the beginning of a drag. Must be overridden.
74 	 */
75 	virtual editor_action* click_right(editor_display& disp, int x, int y) = 0;
76 
77 	/**
78 	 * Drag operation. A click should have occurred earlier. Defaults to no action.
79 	 */
80 	virtual editor_action* drag_left(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
81 
82 	/**
83 	 * Drag operation. A click should have occurred earlier. Defaults to no action.
84 	 */
85 	virtual editor_action* drag_right(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
86 
87 	/**
88 	 * The end of dragging. Defaults to no action.
89 	 */
90 	virtual editor_action* drag_end_left(editor_display& disp, int x, int y);
91 
92 	virtual editor_action* drag_end_right(editor_display& disp, int x, int y);
93 
94 	virtual editor_action* up_left(editor_display& disp, int x, int y);
95 
96 	virtual editor_action* up_right(editor_display& disp, int x, int y);
97 
98 	/**
99 	 * Function called by the controller on a key event for the current mouse action.
100 	 * Defaults to starting position processing.
101 	 */
102 	virtual editor_action* key_event(editor_display& disp, const SDL_Event& e);
103 
104 	/**
105 	 * Helper variable setter - pointer to a toolbar menu/button used for highlighting
106 	 * the current action. Should always be nullptr or point to a valid menu.
107 	 */
set_toolbar_button(const theme::menu * value)108 	void set_toolbar_button(const theme::menu* value) { toolbar_button_ = value; }
109 
110 	/**
111 	 * Getter for the (possibly nullptr) associated menu/button.
112 	 */
toolbar_button() const113 	const theme::menu* toolbar_button() const { return toolbar_button_; }
114 
115 	/**
116 	 * Getter for the associated palette.
117 	 */
get_palette()118 	common_palette& get_palette() { return palette_; }
119 
120 	/** Whether we need the brush bar, is used to grey it out.*/
supports_brushes() const121 	virtual bool supports_brushes() const { return false; }
122 
123 	/**
124 	 * Set the mouse overlay for this action. Defaults to an empty overlay.
125 	 */
126 	virtual void set_mouse_overlay(editor_display& disp);
127 
128 
129 protected:
130 	bool has_alt_modifier() const;
131 	bool has_shift_modifier() const;
132 	bool has_ctrl_modifier() const;
133 
134 	/**
135 	 * Helper function for derived classes that need a active-terrain mouse overlay
136 	 */
137 	void set_terrain_mouse_overlay(editor_display& disp, const t_translation::terrain_code & fg,
138 		const t_translation::terrain_code & bg);
139 
140 	/**
141 	 * The hex previously used in move operations
142 	 */
143 	map_location previous_move_hex_;
144 
145 	/**
146 	 * Key presses, used for modifiers (alt, shift) in some operations
147 	 */
148 	const CKey& key_;
149 
150 private:
151 	/**
152 	 * Pointer to an associated menu/button, if such exists
153 	 */
154 	const theme::menu* toolbar_button_;
155 
156 	/**
157 	 * Pointer to an associated palette, if such exists
158 	 */
159 	common_palette& palette_;
160 };
161 
162 /**
163  * A brush-drag mouse action base class which adds brush and drag processing to a basic mouse action
164  */
165 class brush_drag_mouse_action : public mouse_action
166 {
167 public:
brush_drag_mouse_action(common_palette & palette,const brush * const * const brush,const CKey & key)168 	brush_drag_mouse_action(common_palette& palette, const brush* const * const brush, const CKey& key)
169 		: mouse_action(palette, key)
170 		, previous_drag_hex_()
171 		, brush_(brush)
172 	{
173 	}
174 
175 	/**
176 	 * The affected hexes of a brush action are the result of projecting the current brush on the mouseover hex
177 	 */
178 	std::set<map_location> affected_hexes(editor_display& disp, const map_location& hex);
179 
180 	/**
181 	 * The actual action function which is called by click() and drag(). Derived classes override this instead of click() and drag().
182 	 */
183 	virtual editor_action* click_perform_left(editor_display& disp, const std::set<map_location>& hexes) = 0;
184 
185 	/**
186 	 * The actual action function which is called by click() and drag(). Derived classes override this instead of click() and drag().
187 	 */
188 	virtual editor_action* click_perform_right(editor_display& disp, const std::set<map_location>& hexes) = 0;
189 
190 	/**
191 	 * Calls click_perform_left()
192 	 */
193 	editor_action* click_left(editor_display& disp, int x, int y);
194 
195 	/**
196 	 * Calls click_perform_right()
197 	 */
198 	editor_action* click_right(editor_display& disp, int x, int y);
199 
200 	/**
201 	 * Calls click_perform() for every new hex the mouse is dragged into.
202 	 * @todo partial actions support and merging of many drag actions into one
203 	 */
204 	editor_action* drag_left(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
205 
206 	/**
207 	 * Calls click_perform for every new hex the mouse is dragged into.
208 	 * @todo partial actions support and merging of many drag actions into one
209 	 */
210 	editor_action* drag_right(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
211 
212 	/**
213 	 * End of dragging.
214 	 * @todo partial actions (the entire drag should end up as one action)
215 	 */
216 	editor_action* drag_end(editor_display& disp, int x, int y);
217 
218 protected:
219 	/** Brush accessor */
220 	const brush& get_brush();
221 
222 	/**
223 	 * The previous hex dragged into.
224 	 * @todo keep a set of all "visited" locations to reduce action count in long drags that hit the same hexes multiple times?
225 	 */
226 	map_location previous_drag_hex_;
227 
228 private:
229 	/**
230 	 * Template helper gathering actions common for both drag_right and drag_left.
231 	 * The drags differ only in the worker function called, which should be
232 	 * passed as the template parameter. This exists only to avoid copy-pasting code.
233 	 */
234 	template <editor_action* (brush_drag_mouse_action::*perform_func)(editor_display&, const std::set<map_location>&)>
235 	editor_action* drag_generic(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
236 
237 	/**
238 	 * Current brush handle. Currently a pointer-to-pointer with full constness.
239 	 * The mouse action does not modify the brush, does not modify the pointer
240 	 * to the current brush, and we allow setting this pointr only once, hence
241 	 * the three "consts".
242 	 */
243 	const brush* const * const brush_;
244 };
245 
246 /**
247  * Brush paint mouse action. Uses keyboard modifiers for one-layer painting.
248  */
249 class mouse_action_paint : public brush_drag_mouse_action
250 {
251 public:
mouse_action_paint(const brush * const * const brush,const CKey & key,terrain_palette & palette)252 	mouse_action_paint(
253 		const brush* const * const brush, const CKey& key, terrain_palette& palette)
254 	: brush_drag_mouse_action(palette, brush, key)
255 	, terrain_palette_(palette)
256 	{
257 	}
258 
259 	/**
260 	 * Handle terrain sampling before calling generic handler
261 	 */
262 	editor_action* click_left(editor_display& disp, int x, int y) override;
263 
264 	/**
265 	 * Handle terrain sampling before calling generic handler
266 	 */
267 	editor_action* click_right(editor_display& disp, int x, int y) override;
268 
269 	/**
270 	 * Create an appropriate editor_action and return it
271 	 */
272 	editor_action* click_perform_left(editor_display& disp, const std::set<map_location>& hexes) override;
273 
274 	/**
275 	 * Create an appropriate editor_action and return it
276 	 */
277 	editor_action* click_perform_right(editor_display& disp, const std::set<map_location>& hexes) override;
278 
279 	void set_mouse_overlay(editor_display& disp) override;
280 
supports_brushes() const281 	virtual bool supports_brushes() const override { return true; }
282 
283 protected:
284 
285 	terrain_palette& terrain_palette_;
286 
287 };
288 
289 
290 
291 /**
292  * Paste action. No dragging capabilities.
293  */
294 class mouse_action_paste : public mouse_action
295 {
296 public:
mouse_action_paste(const map_fragment & paste,const CKey & key,common_palette & palette)297 	mouse_action_paste(const map_fragment& paste, const CKey& key, common_palette& palette)
298 	: mouse_action(palette, key), paste_(paste)
299 	{
300 	}
301 
302 	virtual bool has_context_menu() const override;
303 
304 	/**
305 	 * Show an outline of where the paste will go
306 	 */
307 	std::set<map_location> affected_hexes(editor_display& disp, const map_location& hex) override;
308 
309 	/**
310 	 * Return a paste with offset action
311 	 */
312 	editor_action* click_left(editor_display& disp, int x, int y) override;
313 
314 	/**
315 	 * Right click does nothing for now
316 	 */
317 	editor_action* click_right(editor_display& disp, int x, int y) override;
318 
319 	virtual void set_mouse_overlay(editor_display& disp) override;
320 
321 protected:
322 	/**
323 	 * Reference to the buffer used for pasting (e.g. the clipboard)
324 	 */
325 	const map_fragment& paste_;
326 };
327 
328 /**
329  * Fill action. No dragging capabilities. Uses keyboard modifiers for one-layer painting.
330  */
331 class mouse_action_fill : public mouse_action
332 {
333 public:
mouse_action_fill(const CKey & key,terrain_palette & terrain_palette)334 	mouse_action_fill(const CKey& key,
335 			terrain_palette& terrain_palette)
336 	: mouse_action(terrain_palette, key)
337 	, terrain_palette_(terrain_palette)
338 	{
339 	}
340 
341 	/**
342 	 * Tiles that will be painted to, possibly use modifier keys here
343 	 */
344 	std::set<map_location> affected_hexes(editor_display& disp, const map_location& hex);
345 
346 	/**
347 	 * Left / right click fills with the respective terrain
348 	 */
349 	editor_action* click_left(editor_display& disp, int x, int y);
350 
351 	/**
352 	 * Left / right click fills with the respective terrain
353 	 */
354 	editor_action* click_right(editor_display& disp, int x, int y);
355 
356 	virtual void set_mouse_overlay(editor_display& disp);
357 
358 protected:
359 	terrain_palette& terrain_palette_;
360 };
361 
362 /**
363  * Set starting position action.
364  */
365 class mouse_action_starting_position : public mouse_action
366 {
367 public:
mouse_action_starting_position(const CKey & key,location_palette & palette)368 	mouse_action_starting_position(const CKey& key, location_palette& palette)
369 	: mouse_action(palette, key), click_(false), location_palette_(palette)
370 	{
371 	}
372 
373 	/**
374 	 * Left click displays a player-number-selector dialog and then creates an action
375 	 * or returns nullptr if cancel was pressed or there would be no change.
376 	 * Do this on mouse up to avoid drag issue.
377 	 */
378 	editor_action* up_left(editor_display& disp, int x, int y);
379 
380 	editor_action* click_left(editor_display& disp, int x, int y);
381 	/**
382 	 * Right click only erases the starting position if there is one.
383 	 * Do this on mouse up to avoid drag issue,
384 	 */
385 	editor_action* up_right(editor_display& disp, int x, int y);
386 
387 	editor_action* click_right(editor_display& disp, int x, int y);
388 
389 	virtual void set_mouse_overlay(editor_display& disp);
390 
391 private:
392 	bool click_;
393 	location_palette& location_palette_;
394 };
395 
396 
397 
398 } //end namespace editor
399