diff options
Diffstat (limited to 'src/user/settings/main.cpp')
-rw-r--r-- | src/user/settings/main.cpp | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/user/settings/main.cpp b/src/user/settings/main.cpp new file mode 100644 index 0000000..2045137 --- /dev/null +++ b/src/user/settings/main.cpp @@ -0,0 +1,191 @@ +#include <raleigh/d/saving_window.h> +#include <raleigh/w/padding.h> +#include <raleigh/w/button.h> +#include <raleigh/w/label.h> +#include <raleigh/w/vbox.h> +#include <structs/map.h> +#include <knob/format.h> +#include <knob/file.h> +#include <stdint.h> + +#include "color_editor.h" +#include "str_editor.h" +#include "model.h" + +struct file_header { + uint32_t main_offset; + uint32_t main_entries; + uint32_t names_offset; + uint32_t data_offset; +} __attribute__ ((packed)); + +struct main_entry { + uint32_t name_offset; + uint8_t name_len; + enum : uint8_t { + STRING = 0, + COLOR + } kind; + uint16_t pad; + union { + struct { + uint32_t data_offset; + uint32_t data_len; + } as_string; + _pixel_t as_color; + }; +} __attribute__ ((packed)); + +#define SETTINGS_FILE "sys/settings.pls" + +using namespace raleigh; + +bool save(save_tag_t) { + struct file *f = open_file(SETTINGS_FILE); + struct file_header fh; + fh.main_offset = sizeof(struct file_header); + fh.main_entries = settings.n_entries; + fh.names_offset = fh.main_offset + sizeof(struct main_entry) * settings.n_entries; + + uint32_t name_i = 0; + uint32_t data_i = 0; + seek_file_to(f, sizeof(struct file_header)); + struct main_entry me; + + for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) { + me.name_offset = name_i; + me.name_len = strlen(i->name); + name_i += me.name_len; + + switch (i->kind) { + case setting::STRING: + me.kind = main_entry::STRING; + me.as_string.data_offset = data_i; + me.as_string.data_len = strlen(i->data.string); + data_i += me.as_string.data_len; + break; + case setting::COLOR: + me.kind = main_entry::COLOR; + me.as_color = i->data.color; + break; + } + + write_to_file(f, sizeof(struct main_entry), &me); + } + + seek_file_to(f, fh.names_offset); + for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) + write_to_file(f, strlen(i->name), (void *)i->name); + + fh.data_offset = get_file_pos(f); + for (struct setting *i = settings.buf; i < settings.buf + settings.n_entries; ++i) + switch (i->kind) { + case setting::STRING: + write_to_file(f, strlen(i->data.string), (void *)i->data.string); + break; + default: + break; + } + + trunc_file(f); + seek_file_to(f, 0); + write_to_file(f, sizeof(struct file_header), &fh); + close_file(f); + + main_w->is_saved = true; + return true; +} + +void on_button_click(button_tag_t n) { + struct setting *const s = settings.buf + (uint32_t)n; + editor *e; + switch (s->kind) { + case setting::STRING: + e = new str_editor(s, s->name); + break; + case setting::COLOR: + e = new color_editor(s, s->name); + break; + default: + show_error_and_quitf("Internal model corrupted: setting %s had type 0x%2x.", s->name, s->kind); + } + e->show(); +} + +button *make_button(uint32_t i) { + label *l = new label(settings.buf[i].name); + padding *p = new padding(*l, 2); + return new button(*p, &on_button_click, (button_tag_t)i); +} + +void main() { + struct file *f = open_file(SETTINGS_FILE); + + struct file_header file_head; + read_from_file(f, sizeof(struct file_header), &file_head); + + settings = alist<struct setting>(file_head.main_entries + 10); + + dllist<widget &> for_vbox; + + label l("Click a setting name below to edit its value."); + label l2("A restart is required for changes to take effect."); + + dllist<widget &> for_subbox; + for_subbox.add_back(l); + for_subbox.add_back(l2); + vbox subbox(for_subbox); + + padding p_subbox(subbox, 2); + for_vbox.add_back(p_subbox); + + for (uint32_t i = 0; i < file_head.main_entries; ++i) { + struct main_entry entry; + seek_file_to(f, file_head.main_offset + i * sizeof(struct main_entry)); + read_from_file(f, sizeof(struct main_entry), &entry); + + char *const sname = new char[entry.name_len + 1]; + seek_file_to(f, file_head.names_offset + entry.name_offset); + read_from_file(f, entry.name_len, sname); + sname[entry.name_len] = '\0'; + + switch (entry.kind) { + char *sz; + struct setting s; + case main_entry::STRING: + sz = new char[entry.as_string.data_len + 1]; + seek_file_to(f, file_head.data_offset + entry.as_string.data_offset); + read_from_file(f, entry.as_string.data_len, sz); + sz[entry.as_string.data_len] = '\0'; + + s.kind = setting::STRING; + s.data.string = sz; + s.name = sname; + settings.add_back(s); + break; + + case main_entry::COLOR: + s.kind = setting::COLOR; + s.data.color = entry.as_color; + s.name = sname; + settings.add_back(s); + break; + default: + show_error_and_quitf("Refusing to open " SETTINGS_FILE ":\n\"%s\" has unrecognized type id 0x%2x.\nHighest known is 0x01.", sname, entry.kind); + } + + button *const b = make_button(settings.n_entries - 1); + + padding *p = new padding(*b, 2); + for_vbox.add_back(*p); + } + + close_file(f); + + vbox box(for_vbox); + padding pbox(box, 2); + + main_w = new saving_window(&save, 0, pbox); + main_w->show(); + start_runtime(); +}
\ No newline at end of file |