From 3026d4b71ded2cfc3123eb92a6a13d4e51e5aa68 Mon Sep 17 00:00:00 2001 From: dam Date: Thu, 16 Jun 2022 01:43:21 +0000 Subject: Added settings; Fixed virtual keyboard height bug with hack; Initial support of multiple themes. --- export_presets.cfg | 2 +- logic/database.gd | 1 + logic/menu.gd | 8 +++- logic/settings.gd | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.gd | 31 +++++++++++++- main.tscn | 2 +- project.godot | 12 +++++- themes/day.tres | 6 ++- 8 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 logic/settings.gd diff --git a/export_presets.cfg b/export_presets.cfg index 62e8bcb..bfadca3 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -29,7 +29,7 @@ keystore/release_user="" keystore/release_password="" one_click_deploy/clear_previous_install=false version/code=1 -version/name="1.0" +version/name="1.1" version/min_sdk=19 version/target_sdk=30 package/unique_name="com.gudinoff.$genname" diff --git a/logic/database.gd b/logic/database.gd index ed80ae7..5d8792f 100644 --- a/logic/database.gd +++ b/logic/database.gd @@ -15,6 +15,7 @@ onready var add_button := get_node("actions/add") as Button onready var popup := get_node("/root/main/popup") as ModalPopup onready var dialog := get_node("/root/main/dialog") as Dialog + func _init(): selected_idx = -1 staged_idx = -1 diff --git a/logic/menu.gd b/logic/menu.gd index 4b0b7b3..cc461b9 100644 --- a/logic/menu.gd +++ b/logic/menu.gd @@ -2,6 +2,7 @@ extends MenuButton const LOGS_FILE_PATH: String = "user://logs/godot.log" const menu_items: Array = [ + { label = "Toggle Theme", action = "toggle_theme_action" }, { label = "Import Option Sets", action = "import_option_sets_action" }, { label = "Export Option Sets", action = "export_option_sets_action" }, { label = "Clear Option Sets", action = "clear_option_sets_action" }, @@ -11,9 +12,8 @@ const menu_items: Array = [ { label = "Export App Log", action = "export_app_log_action" }, { label = "About", action = "about_action" }, ] -const license_font_b612: String = "res://licenses/font_b612.txt" -const license_godot: String = "res://licenses/godot.txt" +onready var main := get_node("/root/main") as Control onready var menu := get_popup() as PopupMenu onready var popup := get_node("/root/main/popup") as ModalPopup onready var dialog := get_node("/root/main/dialog") as Dialog @@ -32,6 +32,10 @@ func id_pressed(id: int): self.call_deferred(menu_items[id].action) +func toggle_theme_action(): + main.toggle_theme() + + func import_option_sets_action(): dialog.setup("All option sets from the dropdown menus will be replaced.", "Continue", "No") dialog.connect("accepted", self, "import_option_sets_action_accepted") diff --git a/logic/settings.gd b/logic/settings.gd new file mode 100644 index 0000000..51f0e30 --- /dev/null +++ b/logic/settings.gd @@ -0,0 +1,118 @@ +extends Reference +class_name Settings + +const SETTINGS_FILE_PATH := "user://settings.json" +const SETTINGS_FILE_VERSION := "SETTINGS_V1" + +var settings : Dictionary +var defer_save := false + + +func _init(): + load_settings() + + +func set_value(name: String, value) -> void: + settings[name] = value + if defer_save == false: + save_settings() + + +func get_value(name: String, default = null): + if settings.has(name) == false: + printerr("Setting '%s' not found." % name) + + return settings.get(name, default) + + +func remove_value(name: String) -> void: + settings.erase(name) + if defer_save == false: + save_settings() + + +func save_settings(file_path: String = SETTINGS_FILE_PATH): + match file_path.get_extension(): + "json": + export_json(file_path, settings) + + _: + printerr("Invalid settings file extension '%s', expected 'json'." % file_path.get_file()) + return + + +static func export_json(file_path: String, data: Dictionary): + var settings_file := { + "version": SETTINGS_FILE_VERSION, + "settings": data, + } + var indentation_char := "" if file_path == SETTINGS_FILE_PATH else "\t" + var file_content := JSON.print(settings_file, indentation_char) + + var file := File.new() + file.open(file_path, File.WRITE) + file.store_string(file_content) + file.close() + + +func load_settings(file_path: String = SETTINGS_FILE_PATH): + match file_path.get_extension(): + "json": + settings = import_json(file_path) + + _: + printerr("Invalid settings file extension '%s', expected 'json'." % file_path.get_file()) + return + + +static func import_json(file_path: String) -> Dictionary: + var result := {} + + var file := File.new() + var error := file.open(file_path, File.READ_WRITE) + if error != OK: + printerr("Failed to open settings file '%s' (error %d)." % [file_path, error]) + return result + var file_content = file.get_as_text() + file.close() + var parse_result = JSON.parse(file_content) + + # @DAM All these import/export json functions in database/state/settings could maybe be abstracted!? + +# if parse_result.error != OK: +# printerr("Failed to parse settings file '%s' (error %d)." % [file_path, parse_result.error]) +# elif typeof(parse_result.result) != TYPE_DICTIONARY: +# printerr("Invalid settings file type '%s', expected '%s'." % [typeof(parse_result.result), TYPE_DICTIONARY]) +# elif parse_result.result["version"] != SETTINGS_FILE_VERSION: +# printerr("Invalid settings file version '%s', expected '%s'." % [parse_result.result["version"], SETTINGS_FILE_VERSION]) +# elif typeof(parse_result.result["settings"]) != TYPE_ARRAY: +# printerr("Invalid settings content type '%s', expected '%s'." % [typeof(parse_result.result["settings"]), TYPE_DICTIONARY]) +# else: +# result = parse_result.result["settings"] + + +# WIP WIP WIP +# Decide on how to print errors. +# Maybe use error checking as defined above. +# Maybe create parameterized functions to import/export JSON files. + + if parse_result.error != OK: + printerr("Failed to parse settings file '%s' (error %d)." % [file_path, parse_result.error]) + return result + + if typeof(parse_result.result) != TYPE_DICTIONARY: + print_stack() # @DAM Decide on how to print errors ... once and for all! + printerr("Invalid settings file type '%s', expected '%s'." % [typeof(parse_result.result), TYPE_DICTIONARY]) + return result + + if parse_result.result["version"] != SETTINGS_FILE_VERSION: + printerr("Invalid settings file version '%s', expected '%s'." % [parse_result.result["version"], SETTINGS_FILE_VERSION]) + return result + + if typeof(parse_result.result["settings"]) != TYPE_DICTIONARY: + printerr("Invalid settings content type '%s', expected '%s'." % [typeof(parse_result.result["settings"]), TYPE_DICTIONARY]) + return result + + result = parse_result.result["settings"] + return result + diff --git a/main.gd b/main.gd index ec449df..c054940 100644 --- a/main.gd +++ b/main.gd @@ -1,7 +1,17 @@ extends Control -var power_throttle_timeout: float +var power_throttle_timeout : float +var keyboard_height_offset : int +var themes := [ + preload("res://themes/day.tres") as Theme, + preload("res://themes/night.tres") as Theme +] +var themes_color := [ + Color.white, + Color.black +] +onready var settings := Settings.new() onready var popup := get_node("/root/main/popup") as ModalPopup onready var file_picker := get_node("/root/main/file_picker") as FileDialog onready var stage := get_node("/root/main/stage") as Stage @@ -13,7 +23,6 @@ onready var controls_sensible_to_keyboard := [ func _init(): - Physics2DServer.set_active(false) PhysicsServer.set_active(false) @@ -26,10 +35,13 @@ func _init(): func _ready(): Input.set_use_accumulated_input(false) + apply_theme(settings.get_value("theme_index", 0)) + keyboard_height_offset = OS.get_virtual_keyboard_height() func _process(delta: float): var keyboard_height: int = OS.get_virtual_keyboard_height() + keyboard_height = max(0, keyboard_height - keyboard_height_offset) for it in controls_sensible_to_keyboard: it.margin_bottom = -keyboard_height @@ -47,6 +59,9 @@ func _input(event: InputEvent): func _unhandled_input(event: InputEvent): Engine.target_fps = 0 power_throttle_timeout = 3.5 + + if event is InputEventKey && event.is_echo() == false && event.is_pressed() && event.scancode == KEY_ESCAPE: + _notification(MainLoop.NOTIFICATION_WM_GO_BACK_REQUEST) func _notification(what: int): @@ -63,3 +78,15 @@ func _notification(what: int): get_tree().quit() +func toggle_theme(): + var theme_idx := settings.get_value("theme_index", 0) as int + var next_theme_idx = (theme_idx + 1) % themes.size() + apply_theme(next_theme_idx) + settings.set_value("theme_index", next_theme_idx) + + +func apply_theme(theme_idx: int) -> void: + self.theme = themes[theme_idx] + VisualServer.set_default_clear_color(themes_color[theme_idx]) + + diff --git a/main.tscn b/main.tscn index 2b69af7..ff3adb6 100644 --- a/main.tscn +++ b/main.tscn @@ -2,7 +2,7 @@ [ext_resource path="res://main.gd" type="Script" id=1] [ext_resource path="res://ui/date_picker/date_picker.tscn" type="PackedScene" id=2] -[ext_resource path="res://themes/night.tres" type="Theme" id=3] +[ext_resource path="res://themes/day.tres" type="Theme" id=3] [ext_resource path="res://logic/menu.gd" type="Script" id=4] [ext_resource path="res://logic/database.gd" type="Script" id=5] [ext_resource path="res://fonts/font_icons.tres" type="DynamicFont" id=6] diff --git a/project.godot b/project.godot index 0a05d3d..3eedf47 100644 --- a/project.godot +++ b/project.godot @@ -49,6 +49,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://ui/pointer_input_sensor.gd" }, { +"base": "Reference", +"class": "Settings", +"language": "GDScript", +"path": "res://logic/settings.gd" +}, { "base": "TouchVerticalContainer", "class": "Stage", "language": "GDScript", @@ -78,6 +83,7 @@ _global_script_class_icons={ "OptionSet": "", "OptionSetList": "", "PointerInputSensor": "", +"Settings": "", "Stage": "", "TouchItemList": "", "TouchVerticalContainer": "", @@ -106,12 +112,16 @@ window/handheld/orientation="portrait" [global] -version="1.0" +version="1.1" [input_devices] pointing/emulate_touch_from_mouse=true +[node] + +name_casing=2 + [physics] common/enable_pause_aware_picking=true diff --git a/themes/day.tres b/themes/day.tres index 875ee21..22fef09 100644 --- a/themes/day.tres +++ b/themes/day.tres @@ -58,7 +58,7 @@ border_width_bottom = 2 border_color = Color( 0.329412, 0.329412, 0.329412, 1 ) [sub_resource type="StyleBoxFlat" id=12] -bg_color = Color( 0.15, 0.15, 0.15, 1 ) +bg_color = Color( 0.85, 0.85, 0.85, 1 ) corner_radius_top_left = 15 corner_radius_top_right = 15 corner_radius_bottom_right = 15 @@ -101,6 +101,10 @@ content_margin_left = 20.0 [resource] default_font = ExtResource( 1 ) +Button/colors/font_color = Color( 0.121569, 0.121569, 0.121569, 1 ) +Button/colors/font_color_focus = Color( 0.06, 0.06, 0.06, 1 ) +Button/colors/font_color_hover = Color( 0.06, 0.06, 0.06, 1 ) +Button/colors/font_color_pressed = Color( 0, 0, 0, 1 ) Button/styles/disabled = SubResource( 10 ) Button/styles/focus = SubResource( 10 ) Button/styles/hover = SubResource( 11 ) -- cgit v1.2.3