power_play/src/settings.c

169 lines
6.9 KiB
C

#include "settings.h"
#include "sys.h"
#include "json.h"
#include "scratch.h"
#include "string.h"
#include "app.h"
#include "math.h"
/* TODO:
* Rework the whole settings system to be not so rigid.
* - Multi-threaded
* - Current settings state is readable & modifiable at any time
* - Can be done w/ a settings_open / settings_close block
* - Allow for dot notation in settings queries (should probably be implemented in the json layer).
* - "." denotes subindexing, IE: settings_get("window.width") (numbers can also be implemented for arrays).
* - "\." escapable
*/
#define SETTINGS_FILENAME "settings.json"
INTERNAL struct buffer serialize_window_settings(struct arena *arena, const struct sys_window_settings *settings)
{
__prof;
struct temp_arena scratch = scratch_begin(arena);
struct json_ir *root_obj = json_ir_object(scratch.arena);
struct json_ir *window_settings_obj = json_ir_object_set(root_obj, STR("window"), json_ir_object(scratch.arena));
json_ir_object_set(window_settings_obj, STR("minimized"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_MINIMIZED));
json_ir_object_set(window_settings_obj, STR("maximized"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED));
json_ir_object_set(window_settings_obj, STR("fullscreen"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN));
json_ir_object_set(window_settings_obj, STR("x"), json_ir_number(scratch.arena, settings->floating_x));
json_ir_object_set(window_settings_obj, STR("y"), json_ir_number(scratch.arena, settings->floating_y));
json_ir_object_set(window_settings_obj, STR("width"), json_ir_number(scratch.arena, settings->floating_width));
json_ir_object_set(window_settings_obj, STR("height"), json_ir_number(scratch.arena, settings->floating_height));
const struct json_val *formatted = json_format(scratch.arena, root_obj);
struct buffer buff = BUFFER_FROM_STRING(json_dump_to_string(arena, formatted, 2));
scratch_end(scratch);
return buff;
}
INTERNAL void deserialize_window_settings(struct buffer json_bytes, struct sys_window_settings *settings)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
struct string error = { 0 };
if (json_bytes.size <= 0) {
goto end;
}
struct string *parse_error = NULL;
const struct json_val *root_json = json_parse_and_format(scratch.arena, json_bytes, &parse_error);
if (parse_error) {
error = *parse_error;
goto end;
}
const struct json_val *window_settings_json = json_object_get(root_json, STR("window"));
if (!window_settings_json || !json_is_object(window_settings_json)) {
goto end;
}
const struct json_val *minimized = json_object_get(window_settings_json, STR("minimized"));
const struct json_val *maximized = json_object_get(window_settings_json, STR("maximized"));
const struct json_val *fullscreen = json_object_get(window_settings_json, STR("fullscreen"));
const struct json_val *width = json_object_get(window_settings_json, STR("width"));
const struct json_val *height = json_object_get(window_settings_json, STR("height"));
const struct json_val *x = json_object_get(window_settings_json, STR("x"));
const struct json_val *y = json_object_get(window_settings_json, STR("y"));
if (!(json_is_bool(minimized) && json_bool(minimized))) {
/* Only trust pos/size settings if window wasn't closed while minimized */
settings->floating_x = json_is_number(x) ? (i32)clamp_f64(json_number(x), I32_MIN, I32_MAX) : settings->floating_x;
settings->floating_y = json_is_number(y) ? (i32)clamp_f64(json_number(y), I32_MIN, I32_MAX) : settings->floating_y;
settings->floating_width = json_is_number(width) ? (i32)clamp_f64(json_number(width), I32_MIN, I32_MAX) : settings->floating_width;
settings->floating_height = json_is_number(height) ? (i32)clamp_f64(json_number(height), I32_MIN, I32_MAX) : settings->floating_height;
}
settings->flags = json_is_bool(maximized) ? (json_bool(maximized) ? (settings->flags | SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED) : (settings->flags & ~SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED)) : settings->flags;
settings->flags = json_is_bool(fullscreen) ? (json_bool(fullscreen) ? (settings->flags | SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN) : (settings->flags & ~SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN)) : settings->flags;
end:
if (error.len > 0) {
sys_message_box(
SYS_MESSAGE_BOX_KIND_WARNING,
string_format(
scratch.arena,
STR("Error loading settings file:\n%F"),
FMT_STR(error)
)
);
}
scratch_end(scratch);
}
struct sys_window_settings settings_default_window_settings(struct sys_window *window)
{
__prof;
struct v2 window_size = sys_window_get_size(window);
struct v2 monitor_size = sys_window_get_monitor_size(window);
i32 window_width = math_round(window_size.x);
i32 window_height = math_round(window_size.y);
i32 monitor_width = math_round(monitor_size.x);
i32 monitor_height = math_round(monitor_size.y);
i32 width = window_width / 2;
i32 height = window_height / 2;
i32 x = monitor_width / 2 - width / 2;
i32 y = monitor_height / 2 - height / 2;
return (struct sys_window_settings) {
#if RTC
# if DEVELOPER
.title = "Debug (Developer Build)",
# else
.title = "Debug",
# endif
#else
# if DEVELOPER
.title = "Power Play (Developer Build)",
# else
.title = "Power Play",
# endif
#endif
.floating_x = x,
.floating_y = y,
.floating_width = width,
.floating_height = height
};
}
void settings_read_from_file(struct sys_window_settings *default_settings)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
/* Read window settings file if it exists */
struct string window_settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
if (sys_is_file(window_settings_path)) {
struct sys_file settings_file = sys_file_open_read(window_settings_path);
struct buffer file_data = sys_file_read_all(scratch.arena, settings_file);
sys_file_close(settings_file);
deserialize_window_settings(file_data, default_settings);
}
scratch_end(scratch);
}
void settings_write_to_file(const struct sys_window_settings *settings)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
/* Write window settings to file */
struct buffer settings_file_data = serialize_window_settings(scratch.arena, settings);
if (settings_file_data.size > 0) {
struct string window_settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
struct sys_file settings_file = sys_file_open_write(window_settings_path);
sys_file_write(settings_file, settings_file_data);
sys_file_close(settings_file);
}
scratch_end(scratch);
}