The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
mouse_action.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2008 - 2025
3 by Tomasz Sniatowski <kailoran@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-editor"
17
22
23#include "gettext.hpp"
25
26namespace editor {
27
29{
30 return false;
31}
32
34{
35 if (hex == previous_move_hex_) {
36 return;
37 }
38
39 update_brush_highlights(disp, hex);
41}
42
47
48std::set<map_location> mouse_action::affected_hexes(
49 editor_display& /*disp*/, const map_location& hex)
50{
51 std::set<map_location> res;
52 res.insert(hex);
53 return res;
54}
55
56std::unique_ptr<editor_action> mouse_action::drag_left(editor_display& /*disp*/,
57 int /*x*/, int /*y*/, bool& /*partial*/, editor_action* /*last_undo*/)
58{
59 return nullptr;
60}
61
62std::unique_ptr<editor_action> mouse_action::drag_right(editor_display& /*disp*/,
63 int /*x*/, int /*y*/, bool& /*partial*/, editor_action* /*last_undo*/)
64{
65 return nullptr;
66}
67
68std::unique_ptr<editor_action> mouse_action::drag_end_left(
69 editor_display& /*disp*/, int /*x*/, int /*y*/)
70{
71 return nullptr;
72}
73
74std::unique_ptr<editor_action> mouse_action::drag_end_right(
75 editor_display& /*disp*/, int /*x*/, int /*y*/)
76{
77 return nullptr;
78}
79
80std::unique_ptr<editor_action> mouse_action::up_right(
81 editor_display& /*disp*/, int /*x*/, int /*y*/)
82{
83 return nullptr;
84}
85
86std::unique_ptr<editor_action> mouse_action::up_left(
87 editor_display& /*disp*/, int /*x*/, int /*y*/)
88{
89 return nullptr;
90}
91
92std::unique_ptr<editor_action> mouse_action::key_event(
93 editor_display& disp, const SDL_Event& event)
94{
95 if (!has_alt_modifier() && (event.key.key >= '1' && event.key.key <= '9')) {
96 int side = event.key.key - '0';
97 if (side >= 1 && side <= gamemap::MAX_PLAYERS) {
98 map_location pos = disp.get_map().starting_position(side);
99 if (pos.valid()) {
100 disp.scroll_to_tile(pos, display::WARP);
101 }
102 }
103 return nullptr;
104 }
105 if (!disp.get_map().on_board(previous_move_hex_) || event.type != SDL_EVENT_KEY_UP) {
106 return nullptr;
107 }
108 std::unique_ptr<editor_action> a;
109 if ((has_alt_modifier() && (event.key.key >= '1' && event.key.key <= '9'))
110 || event.key.key == SDLK_DELETE) {
111 int res = event.key.key - '0';
112 if (res > gamemap::MAX_PLAYERS || event.key.key == SDLK_DELETE) res = 0;
113 const std::string* old_id = disp.get_map().is_special_location(previous_move_hex_);
114 if (res == 0 && old_id != nullptr) {
115 a = std::make_unique<editor_action_starting_position>(map_location(), *old_id);
116 } else if (res > 0 && (old_id == nullptr || *old_id == std::to_string(res))) {
117 a = std::make_unique<editor_action_starting_position>(previous_move_hex_, std::to_string(res));
118 }
119 }
120 return a;
121}
122
127
129{
130 return key_[SDLK_RALT] || key_[SDLK_LALT];
131}
132
134{
135 return key_[SDLK_RSHIFT] || key_[SDLK_LSHIFT];
136}
137
139{
140#ifdef __APPLE__
141 return key_[SDLK_RGUI] || key_[SDLK_LGUI];
142#else
143 return key_[SDLK_RCTRL] || key_[SDLK_LCTRL];
144#endif
145}
146
148 editor_display& disp,
151{
152 const std::string fg_path = disp.get_map().get_terrain_info(fg).editor_image();
153 const std::string bg_path = disp.get_map().get_terrain_info(bg).editor_image();
154 const std::string blank_hex = "misc/blank-hex.png";
155
156 if (!image::exists(fg_path) || !image::exists(bg_path)) {
157 ERR_ED << "Missing terrain icon";
159 return;
160 }
161
162 // For efficiency the size of the tile is cached.
163 // We assume all tiles are of the same size.
164 // The zoom factor can change, so it's not cached.
165 // NOTE: when zooming and not moving the mouse, there are glitches.
166 // Since the optimal alpha factor is unknown, it has to be calculated
167 // on the fly, and caching the surfaces makes no sense yet.
168 static const int size = image::get_size(blank_hex).x;
169 static const int half_size = size / 2;
170 static const int quarter_size = size / 4;
171 static const int offset = 2;
172 static const int new_size = half_size - 2;
173
174 // Inserting scaled FG and BG hexes via IPF.
175 std::stringstream path;
176 // "hex~BLIT(fg~SCALE(ns,ns),2,qs)~BLIT(bg~SCALE(ns,ns),hs,qs)"
177 path << blank_hex
178 << "~BLIT(" << fg_path << "~SCALE(" << new_size << "," << new_size
179 << ")," << offset << "," << quarter_size << ")"
180 << "~BLIT(" << bg_path << "~SCALE(" << new_size << "," << new_size
181 << ")," << half_size << "," << quarter_size << ")";
182
183 // Set as mouseover overlay.
185}
186
188 editor_display& /*disp*/, const map_location& hex)
189{
190 return get_brush().project(hex);
191}
192
193std::unique_ptr<editor_action> brush_drag_mouse_action::click_left(editor_display& disp, int x, int y)
194{
195 map_location hex = disp.hex_clicked_on(x, y);
196 previous_drag_hex_ = hex;
197 return click_perform_left(disp, affected_hexes(disp, hex));
198}
199
200std::unique_ptr<editor_action> brush_drag_mouse_action::click_right(editor_display& disp, int x, int y)
201{
202 map_location hex = disp.hex_clicked_on(x, y);
203 previous_drag_hex_ = hex;
204 return click_perform_right(disp, affected_hexes(disp, hex));
205}
206
207std::unique_ptr<editor_action> brush_drag_mouse_action::drag_left(editor_display& disp,
208 int x, int y, bool& partial, editor_action* last_undo)
209{
210 return drag_generic<&brush_drag_mouse_action::click_perform_left>(disp, x, y, partial, last_undo);
211}
212
213std::unique_ptr<editor_action> brush_drag_mouse_action::drag_right(editor_display& disp,
214 int x, int y, bool& partial, editor_action* last_undo)
215{
216 return drag_generic<&brush_drag_mouse_action::click_perform_right>(disp, x, y, partial, last_undo);
217}
218
219std::unique_ptr<editor_action> brush_drag_mouse_action::drag_end(
220 editor_display& /*disp*/, int /*x*/, int /*y*/)
221{
222 return nullptr;
223}
224
225template <std::unique_ptr<editor_action> (brush_drag_mouse_action::*perform_func)(editor_display&, const std::set<map_location>&)>
226std::unique_ptr<editor_action> brush_drag_mouse_action::drag_generic(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo)
227{
228 map_location hex = disp.hex_clicked_on(x, y);
229 move(disp, hex);
230 if (hex != previous_drag_hex_) {
231 editor_action_extendable* last_undo_x = dynamic_cast<editor_action_extendable*>(last_undo);
232 LOG_ED << "Last undo is " << last_undo << " and as x " << last_undo_x;
233 partial = true;
234 auto a = (this->*perform_func)(disp, affected_hexes(disp, hex));
235 previous_drag_hex_ = hex;
236 return a;
237 } else {
238 return nullptr;
239 }
240}
241
243{
244 assert(brush_);
245 assert(*brush_);
246 return **brush_;
247}
248
249
250std::unique_ptr<editor_action> mouse_action_paint::click_left(editor_display& disp, int x, int y)
251{
252 if (has_ctrl_modifier()) {
253 map_location hex = disp.hex_clicked_on(x, y);
255 return nullptr;
256 } else {
257 return brush_drag_mouse_action::click_left(disp, x, y);
258 }
259}
260
261std::unique_ptr<editor_action> mouse_action_paint::click_right(editor_display& disp, int x, int y)
262{
263 if (has_ctrl_modifier()) {
264 map_location hex = disp.hex_clicked_on(x, y);
266 return nullptr;
267 } else {
268 return brush_drag_mouse_action::click_right(disp, x, y);
269 }
270}
271
272std::unique_ptr<editor_action> mouse_action_paint::click_perform_left(
273 editor_display& /*disp*/, const std::set<map_location>& hexes)
274{
275 if (has_ctrl_modifier()) return nullptr;
276 // \todo why is this a chain and not an individual action? I guess that mouse drags were meant
277 // to be optimised with one undo for multiple hexes, but it seems that was never added.
278 auto chain = std::make_unique<editor_action_chain>();
279 chain->append_action(std::make_unique<editor_action_paint_area>(
281 return chain;
282}
283
284std::unique_ptr<editor_action> mouse_action_paint::click_perform_right(
285 editor_display& /*disp*/, const std::set<map_location>& hexes)
286{
287 if (has_ctrl_modifier()) return nullptr;
288 // \todo why is this a chain and not an individual action?
289 auto chain = std::make_unique<editor_action_chain>();
290 chain->append_action(std::make_unique<editor_action_paint_area>(
292 return chain;
293}
294
300
301
302
303
304
306{
307 return true;
308}
309
311 editor_display& /*disp*/, const map_location& hex)
312{
313 return paste_.get_offset_area(hex);
314}
315
316std::unique_ptr<editor_action> mouse_action_paste::click_left(editor_display& disp, int x, int y)
317{
318 map_location hex = disp.hex_clicked_on(x, y);
319 return std::make_unique<editor_action_paste>(paste_, hex);
320}
321
322std::unique_ptr<editor_action> mouse_action_paste::click_right(editor_display& /*disp*/, int /*x*/, int /*y*/)
323{
324 return nullptr;
325}
326
328{
331 // center 60px icon on blank hex template
333 "misc/blank-hex.png",
334 "~BLIT(icons/action/editor-paste_60.png,6,6)"
335 )
336 )
337 );
338}
339
341 editor_display& disp, const map_location& hex)
342{
343 return disp.get_map().get_contiguous_terrain_tiles(hex);
344}
345
346std::unique_ptr<editor_action> mouse_action_fill::click_left(editor_display& disp, int x, int y)
347{
348 map_location hex = disp.hex_clicked_on(x, y);
349 if (has_ctrl_modifier()) {
351 return nullptr;
352 } else {
353 /** @todo only take the base terrain into account when searching for contiguous terrain when painting base only */
354 //or use a different key modifier for that
355 return std::make_unique<editor_action_fill>(hex, terrain_palette_.selected_fg_item(),
357 }
358}
359
360std::unique_ptr<editor_action> mouse_action_fill::click_right(editor_display& disp, int x, int y)
361{
362 map_location hex = disp.hex_clicked_on(x, y);
363 if (has_ctrl_modifier()) {
365 return nullptr;
366 } else {
367 /** @todo only take the base terrain into account when searching for contiguous terrain when painting base only */
368 //or use a different key modifier for that
369 return std::make_unique<editor_action_fill>(hex, terrain_palette_.selected_bg_item(),
371 }
372}
373
379
380std::unique_ptr<editor_action> mouse_action_starting_position::up_left(editor_display& disp, int x, int y)
381{
382 if (!click_) return nullptr;
383 click_ = false;
384 map_location hex = disp.hex_clicked_on(x, y);
385 if (!disp.get_map().on_board(hex)) {
386 return nullptr;
387 }
388 auto player_starting_at_hex = disp.get_map().is_special_location(hex);
389
390 if (has_ctrl_modifier()) {
391 if (player_starting_at_hex) {
392 location_palette_.add_item(*player_starting_at_hex);
393 }
394 return nullptr;
395 }
396
397 std::string new_player_at_hex = location_palette_.selected_item();
398 std::unique_ptr<editor_action> a;
399
400 if(!player_starting_at_hex || new_player_at_hex != *player_starting_at_hex) {
401 // Set a starting position
402 a = std::make_unique<editor_action_starting_position>(hex, new_player_at_hex);
403 }
404 else {
405 // Erase current starting position
406 a = std::make_unique<editor_action_starting_position>(map_location(), *player_starting_at_hex);
407 }
408
409 update_brush_highlights(disp, hex);
410
411 return a;
412}
413
414std::unique_ptr<editor_action> mouse_action_starting_position::click_left(editor_display& /*disp*/, int /*x*/, int /*y*/)
415{
416 click_ = true;
417 return nullptr;
418}
419
420std::unique_ptr<editor_action> mouse_action_starting_position::up_right(editor_display& disp, int x, int y)
421{
422 map_location hex = disp.hex_clicked_on(x, y);
423 auto player_starting_at_hex = disp.get_map().is_special_location(hex);
424 if (player_starting_at_hex != nullptr) {
425 return std::make_unique<editor_action_starting_position>(map_location(), *player_starting_at_hex);
426 } else {
427 return nullptr;
428 }
429}
430
431std::unique_ptr<editor_action> mouse_action_starting_position::click_right(editor_display& /*disp*/, int /*x*/, int /*y*/)
432{
433 return nullptr;
434}
435
437{
440 // center 60px icon on blank hex template
442 "misc/blank-hex.png",
443 "~BLIT(icons/action/editor-tool-starting-position_60.png,6,6)"
444 )
445 )
446 );
447}
448
449
450} //end namespace editor
void scroll_to_tile(const map_location &loc, SCROLL_TYPE scroll_type=ONSCREEN, bool check_fogged=true, bool force=true)
Scroll such that location loc is on-screen.
Definition display.cpp:1815
map_location hex_clicked_on(int x, int y) const
given x,y co-ordinates of an onscreen pixel, will return the location of the hex that this pixel corr...
Definition display.cpp:533
A brush-drag mouse action base class which adds brush and drag processing to a basic mouse action.
std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y)
Calls click_perform_left()
std::unique_ptr< editor_action > drag_right(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Calls click_perform for every new hex the mouse is dragged into.
const brush *const *const brush_
Current brush handle.
const brush & get_brush()
Brush accessor.
std::unique_ptr< editor_action > drag_left(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Calls click_perform() for every new hex the mouse is dragged into.
virtual std::unique_ptr< editor_action > click_perform_right(editor_display &disp, const std::set< map_location > &hexes)=0
The actual action function which is called by click() and drag().
virtual std::unique_ptr< editor_action > click_perform_left(editor_display &disp, const std::set< map_location > &hexes)=0
The actual action function which is called by click() and drag().
std::unique_ptr< editor_action > drag_end(editor_display &disp, int x, int y)
End of dragging.
map_location previous_drag_hex_
The previous hex dragged into.
std::set< map_location > affected_hexes(editor_display &disp, const map_location &hex)
The affected hexes of a brush action are the result of projecting the current brush on the mouseover ...
std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y)
Calls click_perform_right()
The brush class represents a single brush – a set of relative locations around a "hotspot",...
Definition brush.hpp:27
std::set< map_location > project(const map_location &hotspot) const
Get a set of locations affected (i.e.
Definition brush.cpp:61
Base class for actions that: 1) operate on an area 2) can be used as undo for a click-drag operation ...
Definition action.hpp:61
Base class for all editor actions.
void set_mouseover_hex_overlay(const texture &image)
Sets texture to be drawn in hex under the mouse's location.
const editor_map & get_map() const
void set_brush_locs(const std::set< map_location > &hexes)
std::set< map_location > get_contiguous_terrain_tiles(const map_location &start) const
Get a contiguous set of tiles having the same terrain as the starting location.
void add_item(const std::string &id)
const std::string & selected_item() const
Return the currently selected item.
std::set< map_location > get_offset_area(const map_location &offset) const
Get the area covered by this map fragment, shifted by an offset.
terrain_palette & terrain_palette_
std::set< map_location > affected_hexes(editor_display &disp, const map_location &hex) override
Tiles that will be painted to, possibly use modifier keys here.
std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y) override
Left / right click fills with the respective terrain.
std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y) override
Left / right click fills with the respective terrain.
virtual void set_mouse_overlay(editor_display &disp) override
Set the mouse overlay for this action.
std::unique_ptr< editor_action > click_perform_right(editor_display &disp, const std::set< map_location > &hexes) override
Create an appropriate editor_action and return it.
std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y) override
Handle terrain sampling before calling generic handler.
terrain_palette & terrain_palette_
void set_mouse_overlay(editor_display &disp) override
Set the mouse overlay for this action.
std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y) override
Handle terrain sampling before calling generic handler.
std::unique_ptr< editor_action > click_perform_left(editor_display &disp, const std::set< map_location > &hexes) override
Create an appropriate editor_action and return it.
virtual bool has_context_menu() const override
std::set< map_location > affected_hexes(editor_display &disp, const map_location &hex) override
Show an outline of where the paste will go.
std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y) override
Return a paste with offset action.
virtual void set_mouse_overlay(editor_display &disp) override
Set the mouse overlay for this action.
std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y) override
Right click does nothing for now.
const map_fragment & paste_
Reference to the buffer used for pasting (e.g.
std::unique_ptr< editor_action > up_right(editor_display &disp, int x, int y) override
Right click only erases the starting position if there is one.
std::unique_ptr< editor_action > up_left(editor_display &disp, int x, int y) override
Left click displays a player-number-selector dialog and then creates an action or returns nullptr if ...
std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y) override
A click, possibly the beginning of a drag.
std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y) override
A click, possibly the beginning of a drag.
virtual void set_mouse_overlay(editor_display &disp) override
Set the mouse overlay for this action.
bool has_shift_modifier() const
void update_brush_highlights(editor_display &disp, const map_location &hex)
Unconditionally update the brush highlights for the current tool when hex is the center location.
virtual std::unique_ptr< editor_action > drag_end_right(editor_display &disp, int x, int y)
virtual bool has_context_menu() const
void set_terrain_mouse_overlay(editor_display &disp, const t_translation::terrain_code &fg, const t_translation::terrain_code &bg)
Helper function for derived classes that need a active-terrain mouse overlay.
virtual std::set< map_location > affected_hexes(editor_display &disp, const map_location &hex)
Locations that would be affected by a click, used by move to update highlights.
virtual std::unique_ptr< editor_action > up_left(editor_display &disp, int x, int y)
bool has_ctrl_modifier() const
const CKey & key_
Key presses, used for modifiers (alt, shift) in some operations.
map_location previous_move_hex_
The hex previously used in move operations.
virtual void move(editor_display &disp, const map_location &hex)
Mouse move (not a drag).
virtual std::unique_ptr< editor_action > up_right(editor_display &disp, int x, int y)
virtual std::unique_ptr< editor_action > key_event(editor_display &disp, const SDL_Event &e)
Function called by the controller on a key event for the current mouse action.
virtual std::unique_ptr< editor_action > drag_left(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Drag operation.
virtual std::unique_ptr< editor_action > drag_right(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Drag operation.
virtual void set_mouse_overlay(editor_display &disp)
Set the mouse overlay for this action.
bool has_alt_modifier() const
virtual std::unique_ptr< editor_action > drag_end_left(editor_display &disp, int x, int y)
The end of dragging.
void select_fg_item(const t_translation::terrain_code &terrain)
const t_translation::terrain_code & selected_bg_item() const
const t_translation::terrain_code & selected_fg_item() const
void select_bg_item(const t_translation::terrain_code &terrain)
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition map.cpp:265
static const int MAX_PLAYERS
Maximum number of players supported.
Definition map.hpp:45
map_location starting_position(int side) const
Definition map.cpp:286
const std::string * is_special_location(const map_location &loc) const
returns the name of the special location at position loc, null if no such location exists.
Definition map.cpp:319
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition map.cpp:347
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition map.cpp:78
Generic locator abstracting the location of an image.
Definition picture.hpp:59
const std::string & editor_image() const
Definition terrain.hpp:47
Editor action classes.
#define LOG_ED
#define ERR_ED
Manage the empty-palette in the editor.
Definition action.cpp:31
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
Definition picture.cpp:855
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition picture.cpp:955
point get_size(const locator &i_locator, bool skip_cache)
Returns the width and height of an image.
Definition picture.cpp:815
STL namespace.
@ partial
There are still moves and/or attacks possible, but the unit doesn't fit in the "unmoved" status.
Encapsulates the map of the game.
Definition location.hpp:46
bool valid() const
Definition location.hpp:111
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...