diff --git a/.gitignore b/.gitignore index 94f5342..03ba703 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ godot_temp_* *.swo *~ +# Config — user overrides, not committed +config/config.json + # OS .DS_Store Thumbs.db diff --git a/autoload/config_manager.gd b/autoload/config_manager.gd index db01f5a..1d9bc8d 100644 --- a/autoload/config_manager.gd +++ b/autoload/config_manager.gd @@ -3,21 +3,77 @@ extends Node signal config_changed(key: String, value: Variant) -var _settings: Dictionary = { - "refresh_interval": 1.0, - "show_cpu": true, - "show_memory": true, - "show_network": true, - "show_disk": true, - "theme": "default", -} +var _settings: Dictionary = {} + + +func _ready() -> void: + _load_config() func get_setting(key: String, default_value: Variant = null) -> Variant: - return _settings.get(key, default_value) + return _settings.get(key, default_value) func set_setting(key: String, value: Variant) -> void: - if _settings.has(key) and _settings[key] != value: - _settings[key] = value - config_changed.emit(key, value) + if _settings.has(key) and _settings[key] != value: + _settings[key] = value + _save_user_config() + config_changed.emit(key, value) + + +## Parse a "r, g, b" string from config into a Color with alpha 1.0. +func get_color(key: String, default_color: Color = Color.WHITE) -> Color: + var raw: Variant = _settings.get(key) + if raw == null or typeof(raw) != TYPE_STRING: + return default_color + var parts: PackedStringArray = (raw as String).split(",", false) + if parts.size() < 3: + return default_color + var r: float = parts[0].strip_edges().to_float() + var g: float = parts[1].strip_edges().to_float() + var b: float = parts[2].strip_edges().to_float() + return Color(r, g, b, 1.0) + + +func _load_config() -> void: + # Load defaults, then overlay user config. + var defaults := _read_json_file("res://config/default.json") + var user := _read_json_file("res://config/config.json") + + _settings.clear() + if defaults != null and defaults is Dictionary: + _merge_dict(_settings, defaults as Dictionary) + if user != null and user is Dictionary: + _merge_dict(_settings, user as Dictionary) + + +static func _read_json_file(path: String) -> Variant: + var file := FileAccess.open(path, FileAccess.READ) + if file == null: + return null + var content: String = file.get_as_text() + var parsed: Variant = JSON.parse_string(content) + return parsed + + +static func _merge_dict(dst: Dictionary, src: Dictionary) -> void: + for key in src: + dst[key] = src[key] + + +func _save_user_config() -> void: + # Only persists settings that differ from defaults. + var defaults := _read_json_file("res://config/default.json") + if not (defaults is Dictionary): + return + + var diff: Dictionary = {} + for key in _settings: + if not defaults.has(key) or defaults[key] != _settings[key]: + diff[key] = _settings[key] + + var path: String = "res://config/config.json" + var json_str: String = JSON.stringify(diff, "\t") + var file := FileAccess.open(path, FileAccess.WRITE) + if file != null: + file.store_string(json_str) diff --git a/config/default.json b/config/default.json new file mode 100644 index 0000000..4f99234 --- /dev/null +++ b/config/default.json @@ -0,0 +1,9 @@ +{ + "background_color": "0.08, 0.08, 0.12", + "refresh_interval": 1.0, + "show_cpu": true, + "show_memory": true, + "show_network": true, + "show_disk": true, + "theme": "default" +} diff --git a/scenes/dashboard.gd b/scenes/dashboard.gd index ce2f206..b1244dc 100644 --- a/scenes/dashboard.gd +++ b/scenes/dashboard.gd @@ -1,5 +1,5 @@ @tool -extends Control +extends PanelContainer @onready var grid: DashboardGrid = %DashboardGrid @@ -8,16 +8,19 @@ var _modules: Array = [] func _ready() -> void: - if Engine.is_editor_hint(): - _set_background() - return _set_background() - _add_modules() + if not Engine.is_editor_hint(): + _add_modules() func _set_background() -> void: - var bg := StyleBoxFlat.new() - bg.bg_color = Color(0.08, 0.08, 0.12, 1.0) + var bg: StyleBoxFlat + if ConfigManager.has_method("get_color"): + bg = StyleBoxFlat.new() + bg.bg_color = ConfigManager.get_color("background_color", Color(0.08, 0.08, 0.12)) + else: + bg = StyleBoxFlat.new() + bg.bg_color = Color(0.08, 0.08, 0.12) add_theme_stylebox_override("panel", bg) diff --git a/scenes/dashboard.tscn b/scenes/dashboard.tscn index efec138..1e9ddc0 100644 --- a/scenes/dashboard.tscn +++ b/scenes/dashboard.tscn @@ -4,7 +4,7 @@ [ext_resource type="Script" path="res://scripts/dashboard_grid.gd" id="2"] [ext_resource type="Theme" path="res://themes/default_theme.tres" id="3"] -[node name="Dashboard" type="Control"] +[node name="Dashboard" type="PanelContainer"] anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 diff --git a/scenes/splash.gd b/scenes/splash.gd index 4a4e05a..c32bc55 100644 --- a/scenes/splash.gd +++ b/scenes/splash.gd @@ -1,6 +1,7 @@ extends Control +@onready var bg: ColorRect = %Bg @onready var v_label: Label = %VLabel @onready var panel_label: Label = %PanelLabel @onready var transition_overlay: ColorRect = %TransitionOverlay @@ -20,6 +21,10 @@ func _ready() -> void: var screen_size: Vector2 = get_viewport_rect().size + # Background color from config + if ConfigManager.has_method("get_color"): + bg.color = ConfigManager.get_color("background_color", Color(0.08, 0.08, 0.12)) + # Compute end font sizes as a large fraction of screen height. # Use set() to go through the property system directly. _v_end = maxi(1, int(screen_size.y * 0.28)) diff --git a/scenes/splash.tscn b/scenes/splash.tscn index 129abc9..10c865a 100644 --- a/scenes/splash.tscn +++ b/scenes/splash.tscn @@ -24,6 +24,7 @@ theme = ExtResource("3") script = ExtResource("1") [node name="Bg" type="ColorRect" parent="."] +unique_name_in_owner = true anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0