Skip to content

Commit

Permalink
Add shortcut GUI support
Browse files Browse the repository at this point in the history
Add pause menu shortcut
Add time speed up, time speed down, and time pause shortcuts
Replace WASD map movement with Shift+WASD map movement
  • Loading branch information
Spartan322 committed Dec 9, 2024
1 parent 8e2b288 commit 1b1e2dd
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 11 deletions.
95 changes: 93 additions & 2 deletions extension/src/openvic-extension/utility/UITools.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "UITools.hpp"
#include <cctype>

#include <godot_cpp/classes/color_rect.hpp>
#include <godot_cpp/classes/line_edit.hpp>
#include <godot_cpp/classes/os.hpp>
#include <godot_cpp/classes/panel.hpp>
#include <godot_cpp/classes/style_box_empty.hpp>
#include <godot_cpp/classes/style_box_texture.hpp>
Expand All @@ -22,6 +24,10 @@
#include "openvic-extension/singletons/AssetManager.hpp"
#include "openvic-extension/singletons/GameSingleton.hpp"
#include "openvic-extension/utility/Utilities.hpp"
#include "godot_cpp/classes/global_constants.hpp"
#include "godot_cpp/classes/input_event_key.hpp"
#include "godot_cpp/classes/shortcut.hpp"
#include "godot_cpp/core/error_macros.hpp"

using namespace godot;
using namespace OpenVic;
Expand Down Expand Up @@ -60,6 +66,60 @@ GUI::Position const* UITools::get_gui_position(String const& gui_scene, String c
return position;
}

static Array get_events_from_shortcut_key(String const& key) {
Array events;
if (key.length() == 0) {
return events;
}

Key key_value = OS::get_singleton()->find_keycode_from_string(key);
if (key_value == Key::KEY_UNKNOWN) {
if (key.nocasecmp_to("DEL") == 0) {
key_value = Key::KEY_DELETE;
} else if (key.nocasecmp_to("PAGE_UP") == 0) {
key_value = Key::KEY_PAGEUP;
} else if (key.nocasecmp_to("PAGE_DOWN") == 0) {
key_value = Key::KEY_PAGEDOWN;
} else if (key == "+") {
// on most keyboards + and = are on the same key, Godot does not see them as different
key_value = Key::KEY_EQUAL;
} else if (key == "-") {
key_value = Key::KEY_MINUS;
} else if (key == ">") {
// on many keyboards > and . are on the same key, Godot does not see them as different
key_value = Key::KEY_PERIOD;
}
}

if (key_value == Key::KEY_UNKNOWN) {
return events;
}

Ref<InputEventKey> event;
event.instantiate();
event->set_pressed(true);
events.append(event);

if (key.length() == 1) {
if (key_value >= Key::KEY_A && key_value <= Key::KEY_Z) {
event->set_shift_pressed(std::isupper(key[0]));
} else if (key == "+") {
event->set_shift_pressed(true);

Ref<InputEventKey> second_event;
second_event.instantiate();
second_event->set_pressed(true);
second_event->set_key_label(godot::KEY_KP_ADD);
events.append(second_event);
} else if (key == ">") {
event->set_shift_pressed(true);
}
}

event->set_key_label(key_value);
return events;
}

/* GUI::Element tree -> godot::Control tree conversion code below: */

namespace OpenVic {
Expand Down Expand Up @@ -217,9 +277,15 @@ static bool generate_icon(generate_gui_args_t&& args) {
static bool generate_button(generate_gui_args_t&& args) {
GUI::Button const& button = static_cast<GUI::Button const&>(args.element);

// TODO - shortcut, clicksound, rotation (?)
// TODO - clicksound, rotation (?)
const String button_name = Utilities::std_to_godot_string(button.get_name());
const String shortcut_key_name = Utilities::std_to_godot_string(button.get_shortcut());
Array event_array = get_events_from_shortcut_key(shortcut_key_name);

ERR_FAIL_COND_V_MSG(
shortcut_key_name.length() != 0 && event_array.size() == 0, false,
vformat("Unknown shortcut key '%s' for GUI button %s", shortcut_key_name, button_name)
);
ERR_FAIL_NULL_V_MSG(button.get_sprite(), false, vformat("Null sprite for GUI button %s", button_name));

GUIButton* gui_button = nullptr;
Expand Down Expand Up @@ -266,16 +332,31 @@ static bool generate_button(generate_gui_args_t&& args) {
ret &= gui_button->set_gfx_font(button.get_font()) == OK;
}

if (shortcut_key_name.length() != 0) {
Ref<Shortcut> shortcut;
shortcut.instantiate();
shortcut->set_events(event_array);
gui_button->set_shortcut(shortcut);
}

gui_button->set_shortcut_feedback(false);
gui_button->set_shortcut_in_tooltip(false);

args.result = gui_button;
return ret;
}

static bool generate_checkbox(generate_gui_args_t&& args) {
GUI::Checkbox const& checkbox = static_cast<GUI::Checkbox const&>(args.element);

// TODO - shortcut
const String checkbox_name = Utilities::std_to_godot_string(checkbox.get_name());
const String shortcut_key_name = Utilities::std_to_godot_string(checkbox.get_shortcut());
Array event_array = get_events_from_shortcut_key(shortcut_key_name);

ERR_FAIL_COND_V_MSG(
shortcut_key_name.length() != 0 && event_array.size() == 0, false,
vformat("Unknown shortcut key '%s' for GUI checkbox %s", shortcut_key_name, checkbox_name)
);
ERR_FAIL_NULL_V_MSG(checkbox.get_sprite(), false, vformat("Null sprite for GUI checkbox %s", checkbox_name));

GFX::IconTextureSprite const* texture_sprite = checkbox.get_sprite()->cast_to<GFX::IconTextureSprite>();
Expand Down Expand Up @@ -306,6 +387,16 @@ static bool generate_checkbox(generate_gui_args_t&& args) {
ret &= gui_icon_button->set_gfx_font(checkbox.get_font()) == OK;
}

if (shortcut_key_name.length() != 0) {
Ref<Shortcut> shortcut;
shortcut.instantiate();
shortcut->set_events(event_array);
gui_icon_button->set_shortcut(shortcut);
}

gui_icon_button->set_shortcut_feedback(false);
gui_icon_button->set_shortcut_in_tooltip(false);

args.result = gui_icon_button;
return ret;
}
Expand Down
13 changes: 9 additions & 4 deletions game/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,25 @@ theme/custom="res://assets/graphics/theme/default_theme.tres"
map_north={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
]
}
map_east={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":4194321,"key_label":4194321,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":68,"key_label":68,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":68,"key_label":68,"unicode":100,"location":0,"echo":false,"script":null)
]
}
map_south={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
]
}
map_west={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":4194319,"key_label":4194319,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":65,"key_label":65,"unicode":97,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":65,"key_label":65,"unicode":97,"location":0,"echo":false,"script":null)
]
}
map_zoom_in={
Expand Down Expand Up @@ -136,6 +136,11 @@ time_speed_decrease={
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194435,"physical_keycode":0,"key_label":0,"unicode":45,"location":0,"echo":false,"script":null)
]
}
menu_pause={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}

[internationalization]

Expand Down
14 changes: 10 additions & 4 deletions game/src/Game/GameSession/Menubar.gd
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ signal zoom_in_button_pressed
signal zoom_out_button_pressed
signal minimap_clicked(pos_clicked : Vector2)

var _menu_button : GUIIconButton

var _mapmode_button_group : ButtonGroup
# We use this instead of the ButtonGroup's get_buttons() as we can add null
# entries for any missing buttons, ensuring each button is at the right index.
Expand Down Expand Up @@ -53,10 +55,10 @@ func _ready() -> void:

# TODO: add keyboard shortcuts (and shortcut tooltips) where vanilla does by default + use key bindings in settings

var menu_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/menu_button")
if menu_button:
menu_button.tooltip_string = "M_MENU_BUTTON"
menu_button.pressed.connect(_on_game_session_menu_button_pressed)
_menu_button = get_gui_icon_button_from_nodepath(^"./menubar/menu_button")
if _menu_button:
_menu_button.tooltip_string = "M_MENU_BUTTON"
_menu_button.pressed.connect(_on_game_session_menu_button_pressed)

# TODO: implement ledger
var ledger_button : GUIIconButton = get_gui_icon_button_from_nodepath(^"./menubar/ledger_button")
Expand Down Expand Up @@ -93,6 +95,10 @@ func _ready() -> void:
# This will set the mapmode in GameSingleton which in turn updates the buttons so that the right one is pressed
_mapmode_pressed(0)

func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("menu_pause"):
_menu_button.pressed.emit()

# REQUIREMENTS:
# * UIFUN-10
func _on_game_session_menu_button_pressed() -> void:
Expand Down
12 changes: 12 additions & 0 deletions game/src/Game/GameSession/Topbar.gd
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,25 @@ func _ready() -> void:
if _speed_up_button:
_speed_up_button.pressed.connect(_on_increase_speed_button_pressed)
_speed_up_button.set_tooltip_string("TOPBAR_INC_SPEED")
var speed_up_action := InputEventAction.new()
speed_up_action.action = "time_speed_increase"
_speed_up_button.shortcut = Shortcut.new()
_speed_up_button.shortcut.events.append(speed_up_action)
_speed_down_button = get_gui_icon_button_from_nodepath(^"./topbar/button_speeddown")
if _speed_down_button:
_speed_down_button.pressed.connect(_on_decrease_speed_button_pressed)
_speed_down_button.set_tooltip_string("TOPBAR_DEC_SPEED")
var speed_down_action := InputEventAction.new()
speed_down_action.action = "time_speed_decrease"
_speed_down_button.shortcut = Shortcut.new()
_speed_down_button.shortcut.events.append(speed_down_action)
_pause_bg_button = get_gui_icon_button_from_nodepath(^"./topbar/pause_bg")
if _pause_bg_button:
_pause_bg_button.pressed.connect(_on_play_pause_button_pressed)
var time_pause_action := InputEventAction.new()
time_pause_action.action = "time_pause"
_pause_bg_button.shortcut = Shortcut.new()
_pause_bg_button.shortcut.events.append(time_pause_action)
_speed_indicator_button = get_gui_icon_button_from_nodepath(^"./topbar/speed_indicator")
if _speed_indicator_button:
_speed_indicator_button.pressed.connect(_on_play_pause_button_pressed)
Expand Down

0 comments on commit 1b1e2dd

Please sign in to comment.