The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mouse_handler_base.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2016 by Joerg Hinrichs <[email protected]>
3  wesnoth playturn Copyright (C) 2003 by David White <[email protected]>
4  Part of the Battle for Wesnoth Project http://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 #include "mouse_handler_base.hpp"
17 
18 #include "cursor.hpp"
19 #include "display.hpp"
20 #include "log.hpp"
21 #include "preferences.hpp"
22 #include "tooltips.hpp"
23 #include "sdl/rect.hpp"
24 
25 static lg::log_domain log_display("display");
26 #define WRN_DP LOG_STREAM(warn, log_display)
27 
28 namespace events {
29 
31 {
33 }
34 
36 {
38 }
39 
41 
42 static bool command_active()
43 {
44 #ifdef __APPLE__
45  return (SDL_GetModState()&KMOD_CTRL) != 0;
46 #else
47  return false;
48 #endif
49 }
50 
52  simple_warp_(false),
53  minimap_scrolling_(false),
54  dragging_left_(false),
55  dragging_started_(false),
56  dragging_right_(false),
57  drag_from_x_(0),
58  drag_from_y_(0),
59  drag_from_hex_(),
60  last_hex_(),
61  show_menu_(false),
62  scroll_start_x_(0),
63  scroll_start_y_(0),
64  scroll_started_(false)
65 {
66 }
67 
69 {
71 }
72 
73 void mouse_handler_base::mouse_motion_event(const SDL_MouseMotionEvent& event, const bool browse)
74 {
75  mouse_motion(event.x,event.y, browse);
76 }
77 
78 void mouse_handler_base::mouse_update(const bool browse, map_location loc)
79 {
80  int x, y;
81  SDL_GetMouseState(&x,&y);
82  mouse_motion(x, y, browse, true, loc);
83 }
84 
85 bool mouse_handler_base::mouse_motion_default(int x, int y, bool /*update*/)
86 {
87  tooltips::process(x, y);
88 
89  if(simple_warp_) {
90  return true;
91  }
92 
93  if(minimap_scrolling_) {
94  //if the game is run in a window, we could miss a LMB/MMB up event
95  // if it occurs outside our window.
96  // thus, we need to check if the LMB/MMB is still down
97  minimap_scrolling_ = ((SDL_GetMouseState(nullptr,nullptr) & (SDL_BUTTON(1) | SDL_BUTTON(2))) != 0);
98  if(minimap_scrolling_) {
99  const map_location& loc = gui().minimap_location_on(x,y);
100  if(loc.valid()) {
101  if(loc != last_hex_) {
102  last_hex_ = loc;
103  gui().scroll_to_tile(loc,display::WARP,false);
104  }
105  } else {
106  // clicking outside of the minimap will end minimap scrolling
107  minimap_scrolling_ = false;
108  }
109  }
110  if(minimap_scrolling_) return true;
111  }
112 
113  // Fire the drag & drop only after minimal drag distance
114  // While we check the mouse buttons state, we also grab fresh position data.
115  int mx = drag_from_x_; // some default value to prevent unlikely SDL bug
116  int my = drag_from_y_;
117  if (is_dragging() && !dragging_started_) {
118  if ((dragging_left_ && (SDL_GetMouseState(&mx,&my) & SDL_BUTTON_LEFT) != 0)
119  || (dragging_right_ && (SDL_GetMouseState(&mx,&my) & SDL_BUTTON_RIGHT) != 0)) {
120  const double drag_distance = std::pow(static_cast<double>(drag_from_x_- mx), 2)
121  + std::pow(static_cast<double>(drag_from_y_- my), 2);
122  if (drag_distance > drag_threshold()*drag_threshold()) {
123  dragging_started_ = true;
124  cursor::set_dragging(true);
125  }
126  }
127  }
128  return false;
129 }
130 
131 void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bool browse)
132 {
134  simple_warp_ = true;
135  }
136  show_menu_ = false;
137  map_location loc = gui().hex_clicked_on(event.x,event.y);
138  mouse_update(browse, loc);
139 
140  if (is_left_click(event)) {
141  if (event.state == SDL_PRESSED) {
142  cancel_dragging();
144  left_click(event.x, event.y, browse);
145  } else if (event.state == SDL_RELEASED) {
146  minimap_scrolling_ = false;
147  clear_dragging(event, browse);
148  left_mouse_up(event.x, event.y, browse);
149  }
150  } else if (is_right_click(event)) {
151  if (event.state == SDL_PRESSED) {
152  cancel_dragging();
154  right_click(event.x, event.y, browse);
155  } else if (event.state == SDL_RELEASED) {
156  minimap_scrolling_ = false;
157  clear_dragging(event, browse);
158  right_mouse_up(event.x, event.y, browse);
159  }
160  } else if (is_middle_click(event)) {
161  if (event.state == SDL_PRESSED) {
162  set_scroll_start(event.x, event.y);
163  scroll_started_ = true;
164 
165  map_location loc = gui().minimap_location_on(event.x,event.y);
166  minimap_scrolling_ = false;
167  if(loc.valid()) {
168  simple_warp_ = false;
169  minimap_scrolling_ = true;
170  last_hex_ = loc;
171  gui().scroll_to_tile(loc,display::WARP,false);
172  } else if(simple_warp_) {
173  // middle click not on minimap, check gamemap instead
174  loc = gui().hex_clicked_on(event.x,event.y);
175  if(loc.valid()) {
176  last_hex_ = loc;
177  gui().scroll_to_tile(loc,display::WARP,false);
178  }
179  }
180  } else if (event.state == SDL_RELEASED) {
181  minimap_scrolling_ = false;
182  simple_warp_ = false;
183  scroll_started_ = false;
184  }
185  }
187  dragging_started_ = false;
188  cursor::set_dragging(false);
189  }
190  mouse_update(browse, loc);
191 }
192 
194  const SDL_MouseButtonEvent& event) const
195 {
196  return event.button == SDL_BUTTON_LEFT && !command_active();
197 }
198 
200  const SDL_MouseButtonEvent& event) const
201 {
202  return event.button == SDL_BUTTON_MIDDLE;
203 }
204 
206  const SDL_MouseButtonEvent& event) const
207 {
208  return event.button == SDL_BUTTON_RIGHT
209  || (event.button == SDL_BUTTON_LEFT && command_active());
210 }
211 
213 {
214  return true;
215 }
216 
217 bool mouse_handler_base::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
218 {
219  return true;
220 }
221 
222 bool mouse_handler_base::left_click(int x, int y, const bool /*browse*/)
223 {
224  if(tooltips::click(x,y))
225  return true;
226 
227  // clicked on a hex on the minimap? then initiate minimap scrolling
228  const map_location& loc = gui().minimap_location_on(x, y);
229  minimap_scrolling_ = false;
230  if(loc.valid()) {
231  minimap_scrolling_ = true;
232  last_hex_ = loc;
233  gui().scroll_to_tile(loc,display::WARP, false);
234  return true;
235  }
236  return false;
237 }
238 
239 void mouse_handler_base::move_action(const bool /*browse*/)
240 {
241  // Overridden with unit move code elsewhere
242 }
243 
244 void mouse_handler_base::left_drag_end(int /*x*/, int /*y*/, const bool browse)
245 {
246  move_action(browse);
247 }
248 
249 void mouse_handler_base::left_mouse_up(int /*x*/, int /*y*/, const bool /*browse*/)
250 {
251 }
252 
253 void mouse_handler_base::mouse_wheel(int scrollx, int scrolly, bool browse)
254 {
255  int x, y;
256  SDL_GetMouseState(&x, &y);
257 
258  int movex = scrollx * preferences::scroll_speed();
259  int movey = scrolly * preferences::scroll_speed();
260 
261  // Don't scroll map and map zoom slider at same time
262  std::shared_ptr<gui::slider> s = gui().find_slider("map-zoom-slider");
263  if (s && sdl::point_in_rect(x, y, s->location())) {
264  movex = 0; movey = 0;
265  }
266 
267  if (movex != 0 || movey != 0) {
268  CKey pressed;
269  // Alt + mousewheel do an 90° rotation on the scroll direction
270  if (pressed[SDLK_LALT] || pressed[SDLK_RALT]) {
271  gui().scroll(-movey,-movex);
272  } else {
273  gui().scroll(-movex,-movey);
274  }
275  }
276 
277  if (scrollx < 0) {
278  mouse_wheel_left(x, y, browse);
279  } else if (scrollx > 0) {
280  mouse_wheel_right(x, y, browse);
281  }
282 
283  if (scrolly < 0) {
284  mouse_wheel_down(x, y, browse);
285  } else if (scrolly > 0) {
286  mouse_wheel_up(x, y, browse);
287  }
288 }
289 
290 void mouse_handler_base::mouse_wheel_up(int /*x*/, int /*y*/, const bool /*browse*/)
291 {
292 }
293 
294 void mouse_handler_base::mouse_wheel_down(int /*x*/, int /*y*/, const bool /*browse*/)
295 {
296 }
297 
298 void mouse_handler_base::mouse_wheel_left(int /*x*/, int /*y*/, const bool /*browse*/)
299 {
300 }
301 
302 void mouse_handler_base::mouse_wheel_right(int /*x*/, int /*y*/, const bool /*browse*/)
303 {
304 }
305 
306 bool mouse_handler_base::right_click(int x, int y, const bool browse)
307 {
308  if (right_click_show_menu(x, y, browse)) {
309  gui().draw(); // redraw highlight (and maybe some more)
310  const theme::menu* const m = gui().get_theme().context_menu();
311  if (m != nullptr) {
312  show_menu_ = true;
313  } else {
314  WRN_DP << "no context menu found..." << std::endl;
315  }
316  return true;
317  }
318  return false;
319 }
320 
321 void mouse_handler_base::right_drag_end(int /*x*/, int /*y*/, const bool /*browse*/)
322 {
323  //FIXME: This is called when we select an option in context-menu,
324  // which is bad because that was not a real dragging
325 }
326 
327 void mouse_handler_base::right_mouse_up(int /*x*/, int /*y*/, const bool /*browse*/)
328 {
329 }
330 
331 void mouse_handler_base::init_dragging(bool& dragging_flag)
332 {
333  dragging_flag = true;
334  SDL_GetMouseState(&drag_from_x_, &drag_from_y_);
336 }
337 
339 {
340  dragging_started_ = false;
341  dragging_left_ = false;
342  dragging_right_ = false;
343  cursor::set_dragging(false);
344 }
345 
346 void mouse_handler_base::clear_dragging(const SDL_MouseButtonEvent& event, bool browse)
347 {
348  // we reset dragging info before calling functions
349  // because they may take time to return, and we
350  // could have started other drag&drop before that
351  cursor::set_dragging(false);
352  if (dragging_started_) {
353  dragging_started_ = false;
354  if (dragging_left_) {
355  dragging_left_ = false;
356  left_drag_end(event.x, event.y, browse);
357  }
358  if (dragging_right_) {
359  dragging_right_ = false;
360  right_drag_end(event.x, event.y, browse);
361  }
362  } else {
363  dragging_left_ = false;
364  dragging_right_ = false;
365  }
366 }
367 
368 
369 } //end namespace events
bool mouse_motion_default(int x, int y, bool update)
This handles minimap scrolling and click-drag.
int drag_from_x_
Drag start position x.
void clear_dragging(const SDL_MouseButtonEvent &event, bool browse)
#define WRN_DP
virtual void left_mouse_up(int x, int y, const bool browse)
Called when the left mouse button is up.
bool is_left_click(const SDL_MouseButtonEvent &event) const
bool dragging_right_
RMB drag init flag.
std::shared_ptr< gui::zoom_slider > find_slider(const std::string &id)
Definition: display.cpp:846
theme & get_theme()
Definition: display.hpp:385
void set_scroll_start(int x, int y)
Called when the middle click scrolling.
bool dragging_started_
Actual drag flag.
virtual bool right_click_show_menu(int x, int y, const bool browse)
Called in the default right_click when the context menu is about to be shown, can be used for preproc...
virtual void right_drag_end(int x, int y, const bool browse)
Called whenever the right mouse drag has "ended".
virtual void mouse_wheel_down(int x, int y, const bool browse)
Called when the mouse wheel is scrolled down.
int scroll_speed()
map_location minimap_location_on(int x, int y)
given x,y co-ordinates of the mouse, will return the location of the hex in the minimap that the mous...
Definition: display.cpp:723
virtual bool allow_mouse_wheel_scroll(int x, int y)
Derived classes can override this to disable mousewheel scrolling under some circumstances, e.g.
const 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:577
GLint GLint GLint GLint GLint GLint y
Definition: glew.h:1220
virtual void mouse_motion(int x, int y, const bool browse, bool update=false, map_location new_loc=map_location::null_location())=0
Called when a mouse motion event takes place.
virtual void draw()
Draws invalidated items.
Definition: display.cpp:2706
void mouse_motion_event(const SDL_MouseMotionEvent &event, const bool browse)
virtual void mouse_wheel_up(int x, int y, const bool browse)
Called when the mouse wheel is scrolled up.
virtual void mouse_press(const SDL_MouseButtonEvent &event, const bool browse)
virtual bool left_click(int x, int y, const bool browse)
Overridden in derived classes, called on a left click (mousedown).
virtual bool right_click(int x, int y, const bool browse)
Overridden in derived classes, called on a right click (mousedown).
void process(int mousex, int mousey)
Definition: tooltips.cpp:198
bool minimap_scrolling_
minimap scrolling (scroll-drag) state flag
void set_dragging(bool drag)
Definition: cursor.cpp:174
bool valid() const
Definition: location.hpp:69
virtual void right_mouse_up(int x, int y, const bool browse)
Called when the right mouse button is up.
virtual void mouse_wheel_right(int x, int y, const bool browse)
Called when the mouse wheel is scrolled right.
bool show_menu_
Show context menu flag.
map_location drag_from_hex_
Drag start map location.
map_display and display: classes which take care of displaying the map and game-data on the screen...
const menu * context_menu() const
Definition: theme.hpp:267
bool dragging_left_
LMB drag init flag.
static lg::log_domain log_display("display")
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:47
Encapsulates the map of the game.
Definition: location.hpp:38
bool click(int mousex, int mousey)
Definition: tooltips.cpp:216
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:2434
virtual void mouse_wheel_left(int x, int y, const bool browse)
Called when the mouse wheel is scrolled left.
bool middle_click_scrolls()
static bool command_active()
GLint GLint GLint GLint GLint x
Definition: glew.h:1220
virtual void mouse_wheel(int xscroll, int yscroll, bool browse)
Called when scrolling with the mouse wheel.
Handling of system events.
Definition: manager.hpp:42
map_location last_hex_
last highlighted hex
Contains the SDL_Rect helper code.
const GLdouble * m
Definition: glew.h:6968
cl_event event
Definition: glew.h:3070
void init_dragging(bool &dragging_flag)
virtual display & gui()=0
Reference to the used display objects.
Standard logging facilities (interface).
virtual int drag_threshold() const
bool is_right_click(const SDL_MouseButtonEvent &event) const
virtual void move_action(bool browse)
Overridden in derived class.
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
GLdouble s
Definition: glew.h:1358
void mouse_update(const bool browse, map_location loc)
update the mouse with a fake mouse motion
virtual void left_drag_end(int x, int y, const bool browse)
Called whenever the left mouse drag has "ended".
bool scroll(int xmov, int ymov, bool force=false)
Scrolls the display by xmov,ymov pixels.
Definition: display.cpp:2206
bool simple_warp_
MMB click (on game map) state flag.
bool is_middle_click(const SDL_MouseButtonEvent &event) const
int drag_from_y_
Drag start position y.