diff --git a/src/controller_base.hpp b/src/controller_base.hpp index d802509341bb..c7db4a4c5089 100644 --- a/src/controller_base.hpp +++ b/src/controller_base.hpp @@ -101,7 +101,7 @@ class controller_base : public hotkey::command_executor, public events::handler virtual void process_keyup_event(const SDL_Event& event); /** - * Called after processing a muse button up or down event + * Called after processing a mouse button up or down event * Overriden in derived classes */ virtual void post_mouse_press(const SDL_Event& event); diff --git a/src/editor2/editor_controller.cpp b/src/editor2/editor_controller.cpp index fbb244c396da..0fb242c536ab 100644 --- a/src/editor2/editor_controller.cpp +++ b/src/editor2/editor_controller.cpp @@ -844,7 +844,7 @@ void editor_controller::mouse_motion(int x, int y, const bool browse, bool updat { if (mouse_handler_base::mouse_motion_default(x, y, update)) return; gamemap::location hex_clicked = gui().hex_clicked_on(x, y); - if (dragging_ && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT) != 0 + if (dragging_left_ && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT) != 0 && get_map().on_board_with_border(drag_from_hex_)) { if (!get_map().on_board_with_border(hex_clicked)) return; LOG_ED << "Mouse drag\n"; @@ -883,7 +883,7 @@ bool editor_controller::left_click(int x, int y, const bool browse) LOG_ED << "Left click action " << hex_clicked.x << " " << hex_clicked.y << "\n"; editor_action* a = get_mouse_action()->click(*gui_, x, y); perform_refresh_delete(a); - return true; + return false; } void editor_controller::left_drag_end(int x, int y, const bool browse) diff --git a/src/mouse_events.cpp b/src/mouse_events.cpp index 5cb8f2fdc97e..4d6be37967a5 100644 --- a/src/mouse_events.cpp +++ b/src/mouse_events.cpp @@ -71,13 +71,6 @@ mouse_handler::mouse_handler(game_display* gui, std::vector& teams, show_partial_move_(false) { singleton_ = this; - - minimap_scrolling_ = false; - dragging_ = false; - dragging_started_ = false; - drag_from_x_ = 0; - drag_from_y_ = 0; - show_menu_ = false; } mouse_handler::~mouse_handler() @@ -339,8 +332,10 @@ void mouse_handler::mouse_press(const SDL_MouseButtonEvent& event, const bool br mouse_handler_base::mouse_press(event, browse); } -bool mouse_handler::right_click_before_menu(int /*x*/, int /*y*/, const bool browse) +bool mouse_handler::right_click_show_menu(int /*x*/, int /*y*/, const bool browse) { + // The first right-click cancel the selection if any, + // the second open the context menu if (selected_hex_.valid() && find_unit(selected_hex_) != units_.end()) { select_hex(gamemap::location(), browse); return false; @@ -352,7 +347,7 @@ bool mouse_handler::right_click_before_menu(int /*x*/, int /*y*/, const bool bro bool mouse_handler::left_click(int x, int y, const bool browse) { undo_ = false; - if (mouse_handler_base::left_click(x, y, browse)) return true; + if (mouse_handler_base::left_click(x, y, browse)) return false; bool check_shroud = teams_[team_num_ - 1].auto_shroud_updates(); @@ -378,7 +373,7 @@ bool mouse_handler::left_click(int x, int y, const bool browse) if(!browse && !commands_disabled && attack_from.valid()) { if (attack_from == selected_hex_) { //no move needed if (attack_enemy(u, clicked_u) == false) { - return true; + return false; } } else if (move_unit_along_current_route(false, true)) {//move the unit without updating shroud @@ -409,7 +404,7 @@ bool mouse_handler::left_click(int x, int y, const bool browse) gui().select_hex(src); current_paths_ = orig_paths; gui().highlight_reach(current_paths_); - return true; + return false; } else //attack == true { @@ -431,7 +426,7 @@ bool mouse_handler::left_click(int x, int y, const bool browse) } } game_events::pump(); - return true; + return false; } } } @@ -444,7 +439,7 @@ bool mouse_handler::left_click(int x, int y, const bool browse) gui().draw(); } - return true; + return false; } //otherwise we're trying to move to a hex diff --git a/src/mouse_events.hpp b/src/mouse_events.hpp index e855d259e019..ec64ffbaf395 100644 --- a/src/mouse_events.hpp +++ b/src/mouse_events.hpp @@ -73,7 +73,7 @@ class mouse_handler : public mouse_handler_base { * Use update to force an update of the mouse state. */ void mouse_motion(int x, int y, const bool browse, bool update=false); - bool right_click_before_menu(int x, int y, const bool browse); + bool right_click_show_menu(int x, int y, const bool browse); bool left_click(int x, int y, const bool browse); void select_hex(const gamemap::location& hex, const bool browse); void clear_undo_stack(); diff --git a/src/mouse_handler_base.cpp b/src/mouse_handler_base.cpp index 1fcd6eb6bd74..f4dc4ad39114 100644 --- a/src/mouse_handler_base.cpp +++ b/src/mouse_handler_base.cpp @@ -47,8 +47,9 @@ static bool command_active() mouse_handler_base::mouse_handler_base(gamemap& map) : minimap_scrolling_(false), - dragging_(false), + dragging_left_(false), dragging_started_(false), + dragging_right_(false), drag_from_x_(0), drag_from_y_(0), drag_from_hex_(), @@ -58,6 +59,11 @@ mouse_handler_base::mouse_handler_base(gamemap& map) : { } +bool mouse_handler_base::is_dragging() const +{ + return dragging_left_ || dragging_right_; +} + void mouse_handler_base::mouse_motion_event(const SDL_MouseMotionEvent& event, const bool browse) { mouse_motion(event.x,event.y, browse); @@ -96,11 +102,14 @@ bool mouse_handler_base::mouse_motion_default(int x, int y, bool& /*update*/) // While we check the mouse buttons state, we also grab fresh position data. int mx = drag_from_x_; // some default value to prevent unlikely SDL bug int my = drag_from_y_; - if (dragging_ && !dragging_started_ && (SDL_GetMouseState(&mx,&my) & SDL_BUTTON_LEFT) != 0) { - const double drag_distance = std::pow((double) (drag_from_x_- mx), 2) + std::pow((double) (drag_from_y_- my), 2); - if (drag_distance > drag_threshold_*drag_threshold_) { - dragging_started_ = true; - cursor::set_dragging(true); + if (is_dragging() && !dragging_started_) { + if (dragging_left_ && (SDL_GetMouseState(&mx,&my) & SDL_BUTTON_LEFT) != 0 + || dragging_right_ && (SDL_GetMouseState(&mx,&my) & SDL_BUTTON_RIGHT) != 0) { + const double drag_distance = std::pow((double) (drag_from_x_- mx), 2) + std::pow((double) (drag_from_y_- my), 2); + if (drag_distance > drag_threshold_*drag_threshold_) { + dragging_started_ = true; + cursor::set_dragging(true); + } } } return false; @@ -113,47 +122,44 @@ void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bo int scrollx = 0; int scrolly = 0; - if(is_left_click(event) && event.state == SDL_RELEASED) { - minimap_scrolling_ = false; - dragging_ = false; - cursor::set_dragging(false); - if (dragging_started_ && !browse && !commands_disabled) { - left_drag_end(event.x, event.y, browse); - } - dragging_started_= false; - left_mouse_up(event.x, event.y, browse); - } else if(is_middle_click(event) && event.state == SDL_RELEASED) { - minimap_scrolling_ = false; - } else if(is_left_click(event) && event.state == SDL_PRESSED) { - left_click(event.x, event.y, browse); - if (!browse && !commands_disabled) { - dragging_ = true; - dragging_started_ = false; - SDL_GetMouseState(&drag_from_x_, &drag_from_y_); - drag_from_hex_ = gui().hex_clicked_on(drag_from_x_, drag_from_y_); + if (is_left_click(event)) { + if (event.state == SDL_PRESSED) { + clear_dragging(event, browse); + if (!left_click(event.x, event.y, browse)) { + if (!browse && !commands_disabled) { + init_dragging(dragging_left_); + } + } + } else if (event.state == SDL_RELEASED) { + minimap_scrolling_ = false; + clear_dragging(event, browse); + left_mouse_up(event.x, event.y, browse); } - } else if(is_right_click(event) && event.state == SDL_PRESSED) { - // The first right-click cancel the selection if any, - // the second open the context menu - dragging_ = false; - dragging_started_ = false; - cursor::set_dragging(false); - if (right_click_before_menu(event.x, event.y, browse)) { - gui().draw(); // redraw highlight (and maybe some more) - const theme::menu* const m = gui().get_theme().context_menu(); - if (m != NULL) - show_menu_ = true; - else - LOG_STREAM(warn, display) << "no context menu found...\n"; + } else if (is_right_click(event)) { + if (event.state == SDL_PRESSED) { + clear_dragging(event, browse); + if (!right_click(event.x, event.y, browse)) { + if (!browse && !commands_disabled) { + init_dragging(dragging_right_); + } + } + } else if (event.state == SDL_RELEASED) { + minimap_scrolling_ = false; + clear_dragging(event, browse); + right_mouse_up(event.x, event.y, browse); } - } else if(is_middle_click(event) && event.state == SDL_PRESSED) { - // clicked on a hex on the minimap? then initiate minimap scrolling - const gamemap::location& loc = gui().minimap_location_on(event.x,event.y); - minimap_scrolling_ = false; - if(loc.valid()) { - minimap_scrolling_ = true; - last_hex_ = loc; - gui().scroll_to_tile(loc,display::WARP,false); + } else if (is_middle_click(event)) { + if (event.state == SDL_PRESSED) { + // clicked on a hex on the minimap? then initiate minimap scrolling + const gamemap::location& loc = gui().minimap_location_on(event.x,event.y); + minimap_scrolling_ = false; + if(loc.valid()) { + minimap_scrolling_ = true; + last_hex_ = loc; + gui().scroll_to_tile(loc,display::WARP,false); + } + } else if (event.state == SDL_RELEASED) { + minimap_scrolling_ = false; } } else if (allow_mouse_wheel_scroll(event.x, event.y)) { if (event.button == SDL_BUTTON_WHEELUP) { @@ -175,7 +181,7 @@ void mouse_handler_base::mouse_press(const SDL_MouseButtonEvent& event, const bo else gui().scroll(scrollx,scrolly); } - if (!dragging_ && dragging_started_) { + if (!dragging_left_ && !dragging_right_ && dragging_started_) { dragging_started_ = false; cursor::set_dragging(false); } @@ -202,24 +208,20 @@ bool mouse_handler_base::allow_mouse_wheel_scroll(int /*x*/, int /*y*/) return true; } -bool mouse_handler_base::right_click_before_menu(int /*x*/, int /*y*/, const bool /*browse*/) +bool mouse_handler_base::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/) { return true; } bool mouse_handler_base::left_click(int x, int y, const bool /*browse*/) { - dragging_ = false; - dragging_started_ = false; - cursor::set_dragging(false); - // clicked on a hex on the minimap? then initiate minimap scrolling const gamemap::location& loc = gui().minimap_location_on(x, y); minimap_scrolling_ = false; if(loc.valid()) { minimap_scrolling_ = true; last_hex_ = loc; - gui().scroll_to_tile(loc,display::WARP,false); + gui().scroll_to_tile(loc,display::WARP, false); return true; } return false; @@ -234,10 +236,50 @@ void mouse_handler_base::left_mouse_up(int /*x*/, int /*y*/, const bool /*browse { } +bool mouse_handler_base::right_click(int x, int y, const bool browse) +{ + if (right_click_show_menu(x, y, browse)) { + gui().draw(); // redraw highlight (and maybe some more) + const theme::menu* const m = gui().get_theme().context_menu(); + if (m != NULL) { + show_menu_ = true; + } else { + LOG_STREAM(warn, display) << "no context menu found...\n"; + } + } + return true; +} + +void mouse_handler_base::right_drag_end(int x, int y, const bool browse) +{ + left_click(x, y, browse); +} -bool mouse_handler_base::right_click(int /*x*/, int /*y*/, const bool /*browse*/) +void mouse_handler_base::right_mouse_up(int /*x*/, int /*y*/, const bool /*browse*/) { - return false; +} + +void mouse_handler_base::init_dragging(bool& dragging_flag) +{ + dragging_flag = true; + SDL_GetMouseState(&drag_from_x_, &drag_from_y_); + drag_from_hex_ = gui().hex_clicked_on(drag_from_x_, drag_from_y_); +} + +void mouse_handler_base::clear_dragging(const SDL_MouseButtonEvent& event, bool browse) +{ + if (!browse && !commands_disabled && dragging_started_) { + if (dragging_left_) { + left_drag_end(event.x, event.y, browse); + } + if (dragging_right_) { + right_drag_end(event.x, event.y, browse); + } + } + dragging_left_ = false; + dragging_right_ = false; + dragging_started_ = false; + cursor::set_dragging(false); } diff --git a/src/mouse_handler_base.hpp b/src/mouse_handler_base.hpp index 3c70ce355f14..56522aa62f04 100644 --- a/src/mouse_handler_base.hpp +++ b/src/mouse_handler_base.hpp @@ -45,12 +45,16 @@ class mouse_handler_base { */ virtual const display& gui() const = 0; + /** + * @return true when the class in the "dragging" state. + */ + bool is_dragging() const; + void mouse_motion_event(const SDL_MouseMotionEvent& event, const bool browse); + /** update the mouse with a fake mouse motion */ void mouse_update(const bool browse); - bool is_dragging() { return dragging_; } - bool get_show_menu() const { return show_menu_; } /** @@ -59,6 +63,11 @@ class mouse_handler_base { * further (i.e. should return), false otherwise. */ bool mouse_motion_default(int x, int y, bool& update); + + /** + * Called when a mouse motion event takes place. Derived classes mustprovide an + * implementation, possibly using mouse_motion_default(). + */ virtual void mouse_motion(int x, int y, const bool browse, bool update=false) = 0; virtual void mouse_press(const SDL_MouseButtonEvent& event, const bool browse); @@ -66,37 +75,81 @@ class mouse_handler_base { bool is_middle_click(const SDL_MouseButtonEvent& event); bool is_right_click(const SDL_MouseButtonEvent& event); + /** + * Derived classes can overrid this to disable mousewheel scrolling under + * some circumstances, e.g. when the mouse wheel controls something else, + * but the event is also received by this class + */ virtual bool allow_mouse_wheel_scroll(int x, int y); /** - * @returns true when the (child) caller should not process the event further + * Overriden in derived classes, called on a right click (mousedown). + * Defaults to process (initiate) minimap scrolling. + * @returns true when the click should not process the event further. + * This means do not treat the call as a start of drag movement. */ virtual bool left_click(int x, int y, const bool browse); + /** + * Called whenever the left mouse drag has "ended". + */ virtual void left_drag_end(int x, int y, const bool browse); + /** + * Called when the left mouse button is up + */ virtual void left_mouse_up(int x, int y, const bool browse); + /** + * Overriden in derived classes, called on a right click (mousedown). + * Defaults to displaying the menu (by setting the appropriate flag) + * if right_click_show_menu returns true. + * @returns true when the click should not process the event further. + * This means do not treat the call as a start of drag movement. + */ virtual bool right_click(int x, int y, const bool browse); - + /** - * Called in right_click when the context menu is about to be shown, can be - * used for preprocessing and preventing the menu from being displayed. + * Called in the default right_click when the context menu is about to + * be shown, can be used for preprocessing and preventing the menu from + * being displayed without rewriting the right click function. * @returns true when the menu should be displayed and false otherwise */ - virtual bool right_click_before_menu(int x, int y, const bool browse); + virtual bool right_click_show_menu(int x, int y, const bool browse); + + /** + * Called whenever the right mouse drag has "ended". + */ + virtual void right_drag_end(int x, int y, const bool browse); + + /** + * Called when the right mouse button is up + */ + virtual void right_mouse_up(int x, int y, const bool browse); protected: + void clear_dragging(const SDL_MouseButtonEvent& event, bool browse); + void init_dragging(bool& dragging_flag); + + /** minimap scrolling (scroll-drag) state flag */ bool minimap_scrolling_; - bool dragging_; + /** LMB drag init flag */ + bool dragging_left_; + /** Actual drag flag */ bool dragging_started_; + /** RMB drag init flag */ + bool dragging_right_; + /** Drag start position x */ int drag_from_x_; + /** Drag start position y */ int drag_from_y_; + /** Drag start map location */ gamemap::location drag_from_hex_; - // last highlighted hex + /** last highlighted hex */ gamemap::location last_hex_; + /** Show context menu flag */ bool show_menu_; gamemap& map_;