#include #include #include #include #include #include #include #include #include #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(file_head.main_entries + 10); dllist 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 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(); }