diff --git a/src/controller_base.cpp b/src/controller_base.cpp index 9dbd829cc0c..b320a3a2187 100644 --- a/src/controller_base.cpp +++ b/src/controller_base.cpp @@ -34,6 +34,8 @@ controller_base::controller_base( : game_config_(game_config) , key_() , scrolling_(false) + , scrollx_(0) + , scrolly_(0) , joystick_manager_() { } @@ -129,11 +131,10 @@ void controller_base::process_keyup_event(const SDL_Event& /*event*/) { //no action by default } -bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse_flags, double x_axis, double y_axis) +bool controller_base::handle_scroll(int mousex, int mousey, int mouse_flags, double x_axis, double y_axis) { bool mouse_in_window = (SDL_GetAppState() & SDL_APPMOUSEFOCUS) != 0 || preferences::get("scroll_when_mouse_outside", true); - bool keyboard_focus = have_keyboard_focus(); int scroll_speed = preferences::scroll_speed(); int dx = 0, dy = 0; int scroll_threshold = (preferences::mouse_scroll_enabled()) @@ -143,26 +144,24 @@ bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse scroll_threshold = 0; } } - if ((key[SDLK_UP] && keyboard_focus) || - (mousey < scroll_threshold && mouse_in_window)) - { - dy -= scroll_speed; - } - if ((key[SDLK_DOWN] && keyboard_focus) || - (mousey > get_display().h() - scroll_threshold && mouse_in_window)) - { - dy += scroll_speed; - } - if ((key[SDLK_LEFT] && keyboard_focus) || - (mousex < scroll_threshold && mouse_in_window)) - { - dx -= scroll_speed; - } - if ((key[SDLK_RIGHT] && keyboard_focus) || - (mousex > get_display().w() - scroll_threshold && mouse_in_window)) - { - dx += scroll_speed; + + // scroll with keyboard + dx += scrollx_ * scroll_speed; + dy += scrolly_ * scroll_speed; + + // scroll if mouse is placed near the edge of the screen + if (mouse_in_window) { + if (mousey < scroll_threshold) + dy -= scroll_speed; + if (mousey > get_display().h() - scroll_threshold) + dy += scroll_speed; + if (mousex < scroll_threshold) + dx -= scroll_speed; + if (mousex > get_display().w() - scroll_threshold) + dx += scroll_speed; } + + // scroll with middle-mouse if enabled if ((mouse_flags & SDL_BUTTON_MMASK) != 0 && preferences::middle_click_scrolls()) { const map_location original_loc = get_mouse_handler_base().get_scroll_start(); @@ -186,6 +185,7 @@ bool controller_base::handle_scroll(CKey& key, int mousex, int mousey, int mouse } } + // scroll with joystick dx += round_double( x_axis * scroll_speed); dy += round_double( y_axis * scroll_speed); @@ -239,7 +239,7 @@ void controller_base::play_slice(bool is_delay_enabled) mousey += values.second * 10; SDL_WarpMouse(mousex, mousey); */ - scrolling_ = handle_scroll(key, mousex, mousey, mouse_flags, joystickx, joysticky); + scrolling_ = handle_scroll(mousex, mousey, mouse_flags, joystickx, joysticky); map_location highlighted_hex = get_display().mouseover_hex(); @@ -342,3 +342,11 @@ const config& controller_base::get_theme(const config& game_config, std::string static config empty; return empty; } + +void controller_base::keyboard_scroll(int x, int y) +{ + if (have_keyboard_focus()) { + scrollx_ += x; + scrolly_ += y; + } +} diff --git a/src/controller_base.hpp b/src/controller_base.hpp index 93dea82a36b..2329d9fc144 100644 --- a/src/controller_base.hpp +++ b/src/controller_base.hpp @@ -64,6 +64,8 @@ public: void play_slice(bool is_delay_enabled = true); static const config &get_theme(const config& game_config, std::string theme_name); + + void keyboard_scroll(int x, int y); protected: virtual bool is_browsing() const { return false; } @@ -105,7 +107,7 @@ protected: * @see scrolling_, which is set if the display is being scrolled * @return true when there was any scrolling, false otherwise */ - bool handle_scroll(CKey& key, int mousex, int mousey, int mouse_flags, double joystickx, double joysticky); + bool handle_scroll(int mousex, int mousey, int mouse_flags, double joystickx, double joysticky); /** * Process mouse- and keypress-events from SDL. @@ -141,6 +143,8 @@ protected: const config& game_config_; CKey key_; bool scrolling_; + int scrollx_; + int scrolly_; joystick_manager joystick_manager_; }; diff --git a/src/hotkey/command_executor.cpp b/src/hotkey/command_executor.cpp index baf9ebf69a4..d548de95abb 100644 --- a/src/hotkey/command_executor.cpp +++ b/src/hotkey/command_executor.cpp @@ -74,9 +74,47 @@ static void event_execute(const SDL_Event& event, command_executor* executor); bool command_executor::execute_command(const hotkey_command& cmd, int /*index*/, HOTKEY_EVENT_TYPE type) { - if (type == HOTKEY_EVENT_RELEASE) - return false; // nothing responds to a release yet + if (type == HOTKEY_EVENT_RELEASE) { + switch(cmd.id) { + // release a scroll key, un-apply scrolling in the given direction + case HOTKEY_SCROLL_UP: + keyboard_scroll(0, 1); + break; + case HOTKEY_SCROLL_DOWN: + keyboard_scroll(0, -1); + break; + case HOTKEY_SCROLL_LEFT: + keyboard_scroll(1, 0); + break; + case HOTKEY_SCROLL_RIGHT: + keyboard_scroll(-1, 0); + break; + default: + return false; // nothing else handles a hotkey release + } + return true; + } + + // special handling for scroll keys, which do not handle repeat + if (type == HOTKEY_EVENT_PRESS) { + switch(cmd.id) { + case HOTKEY_SCROLL_UP: + keyboard_scroll(0, -1); + return true; + case HOTKEY_SCROLL_DOWN: + keyboard_scroll(0, 1); + return true; + case HOTKEY_SCROLL_LEFT: + keyboard_scroll(-1, 0); + return true; + case HOTKEY_SCROLL_RIGHT: + keyboard_scroll(1, 0); + return true; + } + } + + // everything following responds to a press or repeat, but not release switch(cmd.id) { case HOTKEY_CYCLE_UNITS: cycle_units(); diff --git a/src/hotkey/command_executor.hpp b/src/hotkey/command_executor.hpp index 6b0b1a229d4..4718f554994 100644 --- a/src/hotkey/command_executor.hpp +++ b/src/hotkey/command_executor.hpp @@ -108,6 +108,7 @@ public: virtual void left_mouse_click() {} virtual void right_mouse_click() {} virtual void toggle_accelerated_speed() {} + virtual void keyboard_scroll(int /*x*/, int /*y*/) {} virtual void lua_console(); virtual void zoom_in() {} virtual void zoom_out() {} diff --git a/src/hotkey/hotkey_command.cpp b/src/hotkey/hotkey_command.cpp index 6d1a4f23b93..0d53957698d 100644 --- a/src/hotkey/hotkey_command.cpp +++ b/src/hotkey/hotkey_command.cpp @@ -35,6 +35,10 @@ namespace { hotkey::hk_scopes scope_main(1 << hotkey::SCOPE_MAIN_MENU); // this contains all static hotkeys hotkey::hotkey_command_temp hotkey_list_[] = { + { hotkey::HOTKEY_SCROLL_UP, "scroll-up", N_("Scroll Up"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_DOWN, "scroll-down", N_("Scroll Down"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_LEFT, "scroll-left", N_("Scroll Left"), false, scope_game | scope_editor, "" }, + { hotkey::HOTKEY_SCROLL_RIGHT, "scroll-right", N_("Scroll Right"), false, scope_game | scope_editor, "" }, { hotkey::HOTKEY_CANCEL, N_("cancel"), N_("Cancel"), false, scope_game | scope_editor | scope_main, "" }, { hotkey::HOTKEY_SELECT_HEX, "selecthex", N_("Select Hex"), false, scope_game, "" }, diff --git a/src/hotkey/hotkey_command.hpp b/src/hotkey/hotkey_command.hpp index 4df7c857e2f..f68f75e74fd 100644 --- a/src/hotkey/hotkey_command.hpp +++ b/src/hotkey/hotkey_command.hpp @@ -67,6 +67,9 @@ enum HOTKEY_COMMAND { HOTKEY_SELECT_HEX, HOTKEY_DESELECT_HEX, HOTKEY_MOVE_ACTION, HOTKEY_SELECT_AND_ACTION, + // Camera movement + HOTKEY_SCROLL_UP, HOTKEY_SCROLL_DOWN, HOTKEY_SCROLL_LEFT, HOTKEY_SCROLL_RIGHT, + // Dialog control HOTKEY_CANCEL, HOTKEY_OKAY, diff --git a/src/hotkey/hotkey_handler.cpp b/src/hotkey/hotkey_handler.cpp index 71a0b381c2c..3607a1bfc99 100644 --- a/src/hotkey/hotkey_handler.cpp +++ b/src/hotkey/hotkey_handler.cpp @@ -218,6 +218,11 @@ void play_controller::hotkey_handler::toggle_accelerated_speed() } } +void play_controller::hotkey_handler::keyboard_scroll(int x, int y) +{ + play_controller_.keyboard_scroll(x, y); +} + bool play_controller::hotkey_handler::execute_command(const hotkey::hotkey_command& cmd, int index, hotkey::HOTKEY_EVENT_TYPE type) { hotkey::HOTKEY_COMMAND command = cmd.id; @@ -302,6 +307,10 @@ bool play_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_c case hotkey::HOTKEY_SAVE_REPLAY: case hotkey::HOTKEY_LABEL_SETTINGS: case hotkey::LUA_CONSOLE: + case hotkey::HOTKEY_SCROLL_UP: + case hotkey::HOTKEY_SCROLL_DOWN: + case hotkey::HOTKEY_SCROLL_LEFT: + case hotkey::HOTKEY_SCROLL_RIGHT: return true; // Commands that have some preconditions: diff --git a/src/hotkey/hotkey_handler.hpp b/src/hotkey/hotkey_handler.hpp index 93662594c8e..e2e24a12d3a 100644 --- a/src/hotkey/hotkey_handler.hpp +++ b/src/hotkey/hotkey_handler.hpp @@ -117,6 +117,7 @@ public: virtual void toggle_grid(); virtual void search(); virtual void toggle_accelerated_speed(); + virtual void keyboard_scroll(int x, int y); virtual void replay_skip_animation() override { return play_controller_.toggle_skipping_replay(); }