From 5fcf57739e68a8b5053e03778aaee0eed445babd Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Thu, 11 Mar 2021 22:00:22 -0500 Subject: settings editor, and lots of changes in service of that --- fs-skel/sys/startup.rc | 2 +- makefile | 50 +++-- src/kernel/main.c | 2 + src/kernel/settings.c | 8 + src/kernel/settings.h | 1 + src/kernel/window.c | 8 +- src/user/include/cxx/raleigh/d/dialog.h | 37 ++++ src/user/include/cxx/raleigh/d/saving_window.h | 20 ++ src/user/include/cxx/raleigh/runtime.h | 1 + src/user/include/cxx/raleigh/w/button.h | 9 +- src/user/include/cxx/raleigh/w/colorpicker.h | 1 + src/user/include/cxx/raleigh/w/entry.h | 7 +- src/user/include/cxx/raleigh/w/multicontainer.h | 3 + src/user/include/cxx/raleigh/w/vbox.h | 2 +- src/user/include/cxx/raleigh/window.h | 23 +- src/user/include/cxx/structs/alist.h | 41 ++++ src/user/include/cxx/structs/dllist.h | 38 +++- src/user/include/cxx/structs/map.h | 39 ++++ src/user/include/knob/file.h | 9 + src/user/include/pland/pcrt.h | 4 +- src/user/include/popups/info.h | 22 -- src/user/include/popups/popup.h | 22 -- src/user/knob/block.c | 5 +- src/user/knob/file.c | 7 +- src/user/knob/heap.c | 14 ++ src/user/mdemo/main.c | 42 ---- src/user/meminfo/meminfo.cpp | 6 +- src/user/mkpopup/main.c | 36 ---- src/user/mkpopup/main.cpp | 43 ++++ src/user/popups/info.c | 77 ------- src/user/popups/popup.c | 43 ---- src/user/raleigh/d/dialog.cpp | 74 +++++++ src/user/raleigh/d/saving_window.cpp | 55 +++++ src/user/raleigh/runtime.cpp | 19 +- src/user/raleigh/util.cpp | 6 +- src/user/raleigh/w/button.cpp | 6 +- src/user/raleigh/w/colorpicker.cpp | 6 + src/user/raleigh/w/entry.cpp | 33 ++- src/user/raleigh/w/multicontainer.cpp | 16 ++ src/user/raleigh/widget.cpp | 2 +- src/user/raleigh/window.cpp | 51 ++--- src/user/rhello/main.cpp | 75 ------- src/user/settings/color_editor.cpp | 16 ++ src/user/settings/color_editor.h | 19 ++ src/user/settings/editor.cpp | 30 +++ src/user/settings/editor.h | 20 ++ src/user/settings/main.cpp | 191 +++++++++++++++++ src/user/settings/model.cpp | 4 + src/user/settings/model.h | 24 +++ src/user/settings/str_editor.cpp | 17 ++ src/user/settings/str_editor.h | 19 ++ src/user/ttt/main.c | 271 ------------------------ 52 files changed, 887 insertions(+), 689 deletions(-) create mode 100644 src/user/include/cxx/raleigh/d/dialog.h create mode 100644 src/user/include/cxx/raleigh/d/saving_window.h create mode 100644 src/user/include/cxx/structs/alist.h create mode 100644 src/user/include/cxx/structs/map.h delete mode 100644 src/user/include/popups/info.h delete mode 100644 src/user/include/popups/popup.h delete mode 100644 src/user/mdemo/main.c delete mode 100644 src/user/mkpopup/main.c create mode 100644 src/user/mkpopup/main.cpp delete mode 100644 src/user/popups/info.c delete mode 100644 src/user/popups/popup.c create mode 100644 src/user/raleigh/d/dialog.cpp create mode 100644 src/user/raleigh/d/saving_window.cpp delete mode 100644 src/user/rhello/main.cpp create mode 100644 src/user/settings/color_editor.cpp create mode 100644 src/user/settings/color_editor.h create mode 100644 src/user/settings/editor.cpp create mode 100644 src/user/settings/editor.h create mode 100644 src/user/settings/main.cpp create mode 100644 src/user/settings/model.cpp create mode 100644 src/user/settings/model.h create mode 100644 src/user/settings/str_editor.cpp create mode 100644 src/user/settings/str_editor.h delete mode 100644 src/user/ttt/main.c diff --git a/fs-skel/sys/startup.rc b/fs-skel/sys/startup.rc index 321292d..b66cb8c 100644 --- a/fs-skel/sys/startup.rc +++ b/fs-skel/sys/startup.rc @@ -1 +1 @@ -bin/mkpopup Welcome to Portland OS v0.0.11!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Escape to close this window. \ No newline at end of file +bin/mkpopup Welcome to Portland OS v0.0.11!\n\nPress Win+Space to open a terminal with a shell.\nClick on a window to bring it to the top of the stack.\nLeft click and drag a window while holding Alt to move it.\nRight click on a window while holding Alt to send it to the bottom.\nType "dirlist bin" into a shell for a list of programs.\n\nPress Alt+F4 to close this window. \ No newline at end of file diff --git a/makefile b/makefile index d6dfca1..8973b99 100644 --- a/makefile +++ b/makefile @@ -5,6 +5,7 @@ nasmargs = -f elf32 partlink = -r -m elf_i386 clink = -T src/user/runtimes/c/elf.ld cxxlink = ${clink} src/user/runtimes/cxx/extra.ld +asmlink = -T src/user/runtimes/asm/elf.ld out/disk.vdi: out/disk.img rm out/disk.vdi || true @@ -39,8 +40,8 @@ out/fs/bin/%: obj/%.elf out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo \ out/fs/bin/terminal out/fs/bin/hello out/fs/bin/mkpopup \ - out/fs/bin/dirlist out/fs/bin/ttt out/fs/bin/time \ - out/fs/bin/filetest out/fs/bin/mdemo out/fs/bin/rhello + out/fs/bin/dirlist out/fs/bin/time \ + out/fs/bin/filetest out/fs/bin/settings touch out/fs cp -r fs-skel/* out/fs/ @@ -99,15 +100,13 @@ obj/libfont.so: obj/libfont/bdf.o obj/libfont/pbf.o obj/libfont/fonts.o \ obj/libfont/filist.o ld ${partlink} $^ -o $@ -obj/popups.so: obj/popups/info.o obj/popups/popup.o - ld ${partlink} $^ -o $@ - -obj/raleigh.so: obj/raleigh/runtime.po obj/raleigh/window.po \ - obj/raleigh/widget.po obj/raleigh/util.po \ - obj/raleigh/w/padding.po obj/raleigh/w/button.po \ - obj/raleigh/w/vbox.po obj/raleigh/w/entry.po \ - obj/raleigh/w/label.po obj/raleigh/w/colorpicker.po \ - obj/raleigh/w/hbox.po obj/raleigh/w/multicontainer.po +obj/raleigh.so: obj/raleigh/runtime.po obj/raleigh/window.po \ + obj/raleigh/widget.po obj/raleigh/util.po \ + obj/raleigh/w/padding.po obj/raleigh/w/button.po \ + obj/raleigh/w/vbox.po obj/raleigh/w/entry.po \ + obj/raleigh/w/label.po obj/raleigh/w/colorpicker.po \ + obj/raleigh/w/hbox.po obj/raleigh/w/multicontainer.po \ + obj/raleigh/d/dialog.po obj/raleigh/d/saving_window.po ld ${partlink} $^ -o $@ obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto @@ -118,8 +117,8 @@ obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \ obj/c.rto ld ${clink} $^ -o $@ -obj/meminfo.elf: obj/meminfo/meminfo.po obj/raleigh.so obj/popups.so \ - obj/libfont.so obj/knob.so obj/cxx.rto +obj/meminfo.elf: obj/meminfo/meminfo.po obj/raleigh.so obj/libfont.so \ + obj/knob.so obj/cxx.rto ld ${cxxlink} $^ -o $@ obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \ @@ -127,19 +126,19 @@ obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \ ld ${clink} $^ -o $@ obj/hello.elf: obj/hello/hello.ao - ld ${clink} $^ -o $@ + ld ${asmlink} $^ -o $@ -obj/mkpopup.elf: obj/mkpopup/main.o obj/popups.so obj/libfont.so \ - obj/knob.so obj/c.rto - ld ${clink} $^ -o $@ +obj/mkpopup.elf: obj/mkpopup/main.po obj/raleigh.so obj/libfont.so \ + obj/knob.so obj/cxx.rto + ld ${cxxlink} $^ -o $@ obj/dirlist.elf: obj/dirlist/main.o obj/libterm.so obj/knob.so \ obj/c.rto ld ${clink} $^ -o $@ -obj/ttt.elf: obj/ttt/main.o obj/popups.so obj/libfont.so \ - obj/knob.so obj/c.rto - ld ${clink} $^ -o $@ +#obj/ttt.elf: obj/ttt/main.o obj/popups.so obj/libfont.so \ +# obj/knob.so obj/c.rto +# ld ${clink} $^ -o $@ obj/time.elf: obj/time/time.o obj/libterm.so obj/knob.so \ obj/c.rto @@ -149,10 +148,9 @@ obj/filetest.elf: obj/filetest/filetest.o obj/libterm.so obj/knob.so \ obj/c.rto ld ${clink} $^ -o $@ -obj/mdemo.elf: obj/mdemo/main.o obj/popups.so obj/libfont.so \ - obj/knob.so obj/c.rto - ld ${clink} $^ -o $@ - -obj/rhello.elf: obj/rhello/main.po obj/raleigh.so obj/popups.so \ - obj/libfont.so obj/knob.so obj/cxx.rto +obj/settings.elf: obj/settings/main.po obj/settings/str_editor.po \ + obj/settings/model.po obj/settings/color_editor.po \ + obj/settings/editor.po \ + obj/raleigh.so obj/libfont.so \ + obj/knob.so obj/cxx.rto ld ${cxxlink} $^ -o $@ \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 9699029..951e37f 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -47,6 +47,8 @@ void main() { init_idt(); init_win(); + close_settings(); + logf(LOG_INFO, "Kernel initialization done."); logf(LOG_INFO, "Available kernel memory: %dk", kernel_pages_left * 4); logf(LOG_INFO, "Available user memory: %dk", user_pages_left * 4); diff --git a/src/kernel/settings.c b/src/kernel/settings.c index 699196b..419341a 100644 --- a/src/kernel/settings.c +++ b/src/kernel/settings.c @@ -36,6 +36,11 @@ struct main_entry { static file_id_t fid; static uint32_t main_end; +void close_settings() { + drives->free_file(drives, fid); + fid = 0; +} + void init_settings() { fid = drives->get_file(drives, SETTINGS_FILE); if (!fid) @@ -47,6 +52,9 @@ void init_settings() { } bool try_find_setting(const char *name, struct main_entry *entry_out) { + if (!fid) + PANIC("setting requested after settings file closed"); + uint16_t name_len = 0; while (name[name_len]) if (++name_len == 256) diff --git a/src/kernel/settings.h b/src/kernel/settings.h index f25d4df..ec5e9f5 100644 --- a/src/kernel/settings.h +++ b/src/kernel/settings.h @@ -7,6 +7,7 @@ #include void init_settings(); +void close_settings(); //lengths do not include null terminator. if setting value is too long, it is cropped. bool try_get_sz_setting(const char *name, char *out, uint32_t max_len, uint32_t *len_out); diff --git a/src/kernel/window.c b/src/kernel/window.c index 4b01bc4..69babe4 100644 --- a/src/kernel/window.c +++ b/src/kernel/window.c @@ -330,9 +330,15 @@ got_window: } static void del_no_paint(struct window *w) { + if ((w < windows) || (w >= windows + MAX_WINDOWS) || (((void *)w - (void *)windows) % sizeof(struct window))) { + logf(LOG_WARN, "Refusing to delete bad window pointer 0x%h", w); + return; + } + if (w == top_window) { top_window = w->below; - send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER}); + if (top_window) + send_action(top_window, (struct window_action){.action_type = FOCUS_ENTER}); } if (w == bottom_window) bottom_window = w->above; diff --git a/src/user/include/cxx/raleigh/d/dialog.h b/src/user/include/cxx/raleigh/d/dialog.h new file mode 100644 index 0000000..f207033 --- /dev/null +++ b/src/user/include/cxx/raleigh/d/dialog.h @@ -0,0 +1,37 @@ +#ifndef RALEIGH_D_DIALOG_H +#define RALEIGH_D_DIALOG_H + +#include +#include +#include +#include +#include + +namespace raleigh { + typedef uint32_t diag_result_t; + enum : diag_result_t { + NONE = 0, + YES, + NO, + CANCEL, + RETRY + }; + extern alist> &yes_no_cancel; + extern alist> &yes_no_retry; + class dialog : public window { + public: + //button names are copied + //alist isn't needed past constructor + dialog(widget &top_part, alist> buttons); + + //zero means not set yet + diag_result_t result; + + void show_modal(); + + private: + vbox *main_box; + }; +} + +#endif \ No newline at end of file diff --git a/src/user/include/cxx/raleigh/d/saving_window.h b/src/user/include/cxx/raleigh/d/saving_window.h new file mode 100644 index 0000000..84b6f69 --- /dev/null +++ b/src/user/include/cxx/raleigh/d/saving_window.h @@ -0,0 +1,20 @@ +#ifndef RALEIGH_D_SAVING_WINDOW_H +#define RALEIGH_D_SAVING_WINDOW_H + +#include +#include + +namespace raleigh { + typedef void *save_tag_t; + class saving_window : public window { + public: + //save_func returns true if saving was successful + saving_window(bool (*save_func)(save_tag_t), save_tag_t save_tag, widget &root, _pixel_t bg_color=RGB(bf, bf, bf)); + bool is_saved; + + bool (*save_func)(save_tag_t); + save_tag_t save_tag; + }; +}; + +#endif \ No newline at end of file diff --git a/src/user/include/cxx/raleigh/runtime.h b/src/user/include/cxx/raleigh/runtime.h index 92bd230..4342beb 100644 --- a/src/user/include/cxx/raleigh/runtime.h +++ b/src/user/include/cxx/raleigh/runtime.h @@ -7,6 +7,7 @@ namespace raleigh { void start_runtime() __attribute__ ((noreturn)); extern dllist open_windows; + extern dllist to_be_deleted; } #endif \ No newline at end of file diff --git a/src/user/include/cxx/raleigh/w/button.h b/src/user/include/cxx/raleigh/w/button.h index 71ccae2..c56a6e3 100644 --- a/src/user/include/cxx/raleigh/w/button.h +++ b/src/user/include/cxx/raleigh/w/button.h @@ -4,10 +4,12 @@ #include namespace raleigh { + typedef void *button_tag_t; class button : public widget { public: - button(widget &inner, void (*on_click)(button &), _pixel_t border_color=RGB(00, 00, 00), - _pixel_t bg_color=RGB(bf, bf, bf), _pixel_t pressed_color=RGB(9f, 9f, 9f)); + button(widget &inner, void (*on_click)(button_tag_t), button_tag_t tag=0, + _pixel_t border_color=RGB(00, 00, 00), _pixel_t bg_color=RGB(bf, bf, bf), + _pixel_t pressed_color=RGB(9f, 9f, 9f)); void notify_window_change() override; void paint(_pixel_t *pixbuf, uint32_t pitch) override; @@ -16,7 +18,8 @@ namespace raleigh { void notify_has_opaque_parent(widget *parent) override; private: widget &inner; - void (*on_click)(button &); + void (*on_click)(button_tag_t); + button_tag_t tag; _pixel_t border_color; _pixel_t bg_color; _pixel_t pressed_color; diff --git a/src/user/include/cxx/raleigh/w/colorpicker.h b/src/user/include/cxx/raleigh/w/colorpicker.h index 471787d..f791b2a 100644 --- a/src/user/include/cxx/raleigh/w/colorpicker.h +++ b/src/user/include/cxx/raleigh/w/colorpicker.h @@ -8,6 +8,7 @@ namespace raleigh { public: colorpicker(_pixel_t default_color=RGB(20, 70, 30), uint8_t resolution=4); _pixel_t get_picked_color() __attribute__ ((pure)); + void set_picked_color(_pixel_t c); void paint(_pixel_t *pixbuf, uint32_t pitch) override; void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override; diff --git a/src/user/include/cxx/raleigh/w/entry.h b/src/user/include/cxx/raleigh/w/entry.h index 001cae2..c86b281 100644 --- a/src/user/include/cxx/raleigh/w/entry.h +++ b/src/user/include/cxx/raleigh/w/entry.h @@ -8,10 +8,15 @@ namespace raleigh { class entry : public widget { public: //default_text's data is copied, so it's okay if it changes or if the memory is freed - entry(uint32_t rows, uint32_t cols, const char *default_text="", + entry(uint32_t rows=25, uint32_t cols=25, const char *default_text="", const char *font="fixed-10", _pixel_t bg=RGB(ff, ff, ff), _pixel_t fg=RGB(00, 00, 00), _pixel_t border_color=RGB(00, 00, 00)); + //not a copy + const char *get_contents(); + //s's data is copied + void set_contents(const char *s); + void notify_window_change() override; void paint(_pixel_t *pixbuf, uint32_t pitch) override; void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override; diff --git a/src/user/include/cxx/raleigh/w/multicontainer.h b/src/user/include/cxx/raleigh/w/multicontainer.h index 8a3497f..729f6a1 100644 --- a/src/user/include/cxx/raleigh/w/multicontainer.h +++ b/src/user/include/cxx/raleigh/w/multicontainer.h @@ -7,6 +7,9 @@ namespace raleigh { class multicontainer : public widget { public: + void add_end(widget &w); + void add_start(widget &w); + void notify_window_change() override; void paint(_pixel_t *pixbuf, uint32_t pitch) override; void handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) override; diff --git a/src/user/include/cxx/raleigh/w/vbox.h b/src/user/include/cxx/raleigh/w/vbox.h index d51e61d..6bace59 100644 --- a/src/user/include/cxx/raleigh/w/vbox.h +++ b/src/user/include/cxx/raleigh/w/vbox.h @@ -7,7 +7,7 @@ namespace raleigh { class vbox : public multicontainer { public: //do not modify this list afterward - vbox(dllist widgets); + vbox(dllist widgets=dllist()); private: coord determine_size() override; diff --git a/src/user/include/cxx/raleigh/window.h b/src/user/include/cxx/raleigh/window.h index 2b759d5..3448536 100644 --- a/src/user/include/cxx/raleigh/window.h +++ b/src/user/include/cxx/raleigh/window.h @@ -1,45 +1,50 @@ #ifndef RALEIGH_WINDOW_H #define RALEIGH_WINDOW_H +#include + namespace raleigh { class window; } #include #include -#include -#include #include #include +#include +#include namespace raleigh { + typedef void *window_tag_t; class window { friend void start_runtime(); public: //pass on_close to specify a close handler. if on_close returns false, the window will not be closed. - window(widget &root, _pixel_t bg_color=RGB(bf, bf, bf), bool (*on_close)(window &)=0); - void add_keybind(struct key_packet kp, void (*handler)(window &)); + window(widget &root, _pixel_t bg_color=RGB(bf, bf, bf), bool (*on_close)(window_tag_t)=0, window_tag_t tag=0); + void add_keybind(struct key_packet kp, void (*handler)(window_tag_t)); void notify_needs_paint(widget &from); void notify_widget_size_change(widget &from, coord old_size); void notify_wants_movements(widget &from, enum mouse_packet::mouse_button while_down); - enum try_actions_return_t {NONE, GOOD, DELETE}; - try_actions_return_t try_actions(); + void consume_actions(); void show(); void focus(widget &w); + + protected: + widget &root; private: _window_handle_t handle; _pixel_t *pixbuf; coord size; - widget &root; widget *focussed; widget *drag_reciever; enum mouse_packet::mouse_button drag_until; _pixel_t bg_color; bool needs_repaint; void paint_full(); - bool (*on_close)(window &); - dllist> keybinds; + bool (*on_close)(window_tag_t); + window_tag_t tag; + map keybinds; }; } diff --git a/src/user/include/cxx/structs/alist.h b/src/user/include/cxx/structs/alist.h new file mode 100644 index 0000000..050f775 --- /dev/null +++ b/src/user/include/cxx/structs/alist.h @@ -0,0 +1,41 @@ +#ifndef STRUCTS_ALIST_H +#define STRUCTS_ALIST_H + +#include +#include +#include +#include +#include + +template +class alist { +public: + uint32_t n_entries; + uint32_t buf_size; + uint32_t expand_by; + data *buf; + + alist(uint32_t default_size=10, uint32_t expand_by=10) + : n_entries(0), buf_size(default_size), expand_by(expand_by), + buf((data *)get_block(default_size * sizeof(data))) {} + + void add_back(data d) { + if (n_entries == buf_size) { + data *const new_buf = (data *)get_block((buf_size += expand_by) * sizeof(data)); + blockcpy(new_buf, buf, n_entries * sizeof(data)); + free_block(buf); + buf = new_buf; + } + buf[n_entries++] = d; + } + + //returns -1 if not found + uint32_t index_of(data d) { + for (uint32_t i = 0; i < n_entries; ++i) + if (buf[i] == d) + return i; + return -1; + } +}; + +#endif \ No newline at end of file diff --git a/src/user/include/cxx/structs/dllist.h b/src/user/include/cxx/structs/dllist.h index 5783364..91b0369 100644 --- a/src/user/include/cxx/structs/dllist.h +++ b/src/user/include/cxx/structs/dllist.h @@ -1,6 +1,8 @@ #ifndef STRUCTS_DLLIST_H #define STRUCTS_DLLIST_H +#include + template class dllist { public: @@ -13,20 +15,34 @@ public: : next(next), prev(prev), d(d) {} }; node *first; + node *last; - dllist() : first(0) {} + dllist() : first(0), last(0) {} void add_front(data d) { node *const n = new node(first, 0, d); if (first) first->prev = n; first = n; + if (!last) + last = n; + } + + void add_back(data d) { + node *const n = new node(0, last, d); + if (last) + last->next = n; + last = n; + if (!first) + first = n; } //return previous, or zero if this is the first node *remove_in_place(node *n) { if (n == first) first = n->next; + if (n == last) + last = n->prev; if (n->next) n->next->prev = n->prev; if (n->prev) @@ -34,6 +50,26 @@ public: delete n; return n->prev; } + + bool try_remove_by_ref(data d) { + for (node *n = first; n; n = n->next) + if (&n->d == &d) { + remove_in_place(n); + return true; + } + return false; + } + + //returns -1 if it isn't found + uint32_t index_of(data d) { + uint32_t i = 0; + for (const node *n = first; n; n = n->next) + if (d == n->d) + return i; + else + ++i; + return -1; + } }; #endif \ No newline at end of file diff --git a/src/user/include/cxx/structs/map.h b/src/user/include/cxx/structs/map.h new file mode 100644 index 0000000..f9c477f --- /dev/null +++ b/src/user/include/cxx/structs/map.h @@ -0,0 +1,39 @@ +#ifndef STRUCTS_MAP_H +#define STRUCTS_MAP_H + +#include + +template +bool default_equals(type a, type b) { + return a == b; +} + +template> +class map { +public: + alist keys; + alist values; + + map(uint32_t default_size=10, uint32_t expand_by=10) + : keys(default_size, expand_by), values(default_size, expand_by) {} + + void add_pair(key k, value v) { + for (key *i = keys.buf; i < keys.buf + keys.n_entries; ++i) + if (equals(k, *i)) { + values.buf[i - keys.buf] = v; + return; + } + keys.add_back(k); + values.add_back(v); + } + + __attribute__ ((pure)) + value transform(key k, value fallback=value()) { + for (key *i = keys.buf; i < keys.buf + keys.n_entries; ++i) + if (equals(k, *i)) + return values.buf[i - keys.buf]; + return fallback; + } +}; + +#endif \ No newline at end of file diff --git a/src/user/include/knob/file.h b/src/user/include/knob/file.h index d283288..04fc201 100644 --- a/src/user/include/knob/file.h +++ b/src/user/include/knob/file.h @@ -1,6 +1,10 @@ #ifndef KNOB_FILE_H #define KNOB_FILE_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include @@ -18,10 +22,15 @@ uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length); uint32_t seek_file_to(struct file *f, uint32_t to); int32_t seek_file_by(struct file *f, int32_t by); +uint32_t get_file_pos(struct file *f) __attribute__ ((pure)); uint32_t file_size(struct file *f) __attribute__ ((pure)); void trunc_file(struct file *f); //return value must be manually freed, unless it is a null pointer _dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out); +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h index 6581cbe..4888494 100644 --- a/src/user/include/pland/pcrt.h +++ b/src/user/include/pland/pcrt.h @@ -9,12 +9,12 @@ extern "C" { #define BEFORE_MAIN(f) \ __attribute__ ((section (".__pcrt_before_main"))) \ - __attribute__ ((unused)) \ + __attribute__ ((used)) \ void (*const __pcrt_bm_##f)() = &f; #define BEFORE_QUIT(f) \ __attribute__ ((section (".__pcrt_before_quit"))) \ - __attribute__ ((unused)) \ + __attribute__ ((used)) \ void (*const __pcrt_bq_##f)() = &f; void __pcrt_quit() __attribute__ ((noreturn)); diff --git a/src/user/include/popups/info.h b/src/user/include/popups/info.h deleted file mode 100644 index de6be57..0000000 --- a/src/user/include/popups/info.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef POPUPS_INFO_H -#define POPUPS_INFO_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#include - -#include - -void info_popup(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg); -void info_popupf(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, ...); -void info_popupf_v(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, va_list args); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h deleted file mode 100644 index cf4315b..0000000 --- a/src/user/include/popups/popup.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef POPUPS_POPUP_H -#define POPUPS_POPUP_H - -#include - -struct popup { - _window_handle_t handle; - _pixel_t *pixbuf; - - bool has_quit; - struct key_packet quit_as; - - //terminated by one with .key_id == 0 - const struct key_packet *quit_binds; -}; - -void handle_actions(struct popup *p); -//deletes popup before returning -void make_modal(struct popup *p); -void delete_popup(struct popup *p); - -#endif \ No newline at end of file diff --git a/src/user/knob/block.c b/src/user/knob/block.c index 5b4590f..9f3f353 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -1,6 +1,7 @@ +#include +#include #include #include -#include //unsophisticated, should copy by dwords where available void blockcpy(void *to, const void *from, uint32_t size) { @@ -31,6 +32,8 @@ char *strdup(const char *from) { while (*(end++)) ; char *buf = get_block(end - from); + if (!buf) + PANIC("get_block returned 0 in strdup"); blockcpy(buf, from, end - from); return buf; } diff --git a/src/user/knob/file.c b/src/user/knob/file.c index db38e52..999778e 100644 --- a/src/user/knob/file.c +++ b/src/user/knob/file.c @@ -73,7 +73,7 @@ uint32_t read_from_file(struct file *f, uint32_t max, void *buf) { return read; } -uint32_t write_to_file(struct file *f, uint32_t max, void *buf) { +uint32_t write_to_file(struct file *f, uint32_t max, const void *buf) { if (f->position + max > f->length) _set_file_size(f->handle, f->length = f->position + max); @@ -109,6 +109,11 @@ int32_t seek_file_by(struct file *f, int32_t by) { return to - old; } +__attribute__ ((pure)) +uint32_t get_file_pos(struct file *f) { + return f->position; +} + __attribute__ ((pure)) uint32_t file_size(struct file *f) { return f->length; diff --git a/src/user/knob/heap.c b/src/user/knob/heap.c index b770542..6e57000 100644 --- a/src/user/knob/heap.c +++ b/src/user/knob/heap.c @@ -25,8 +25,18 @@ static void add_header(struct block_header *bh) { first_block = bh; } +//static const char *const hextab = "0123456789abcdef"; +//static char *const get_debug = "getting 0x........ byte block"; +//static char *const free_debug = "freeing 0x........ byte block"; + __attribute__ ((malloc)) void *get_block(uint32_t bytes) { + if (!bytes) + return 0; +//for (uint8_t i = 0; i < 8; ++i) +// get_debug[10 + 7 - i] = hextab[(bytes >> (i * 4)) & 0xf]; +//_system_log(get_debug); + struct block_header *header = 0; for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) { if (ptr->allocated) @@ -88,6 +98,10 @@ static void remove_header(struct block_header *bh) { void free_block(void *block) { struct block_header *header = block - sizeof(struct block_header); +//for (uint8_t i = 0; i < 8; ++i) +// free_debug[10 + 7 - i] = hextab[(header->length >> (i * 4)) & 0xf]; +//_system_log(free_debug); + header->allocated = false; void *after = block + header->length; diff --git a/src/user/mdemo/main.c b/src/user/mdemo/main.c deleted file mode 100644 index fc7de80..0000000 --- a/src/user/mdemo/main.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#define TEXT_COLOR ((_pixel_t){.r = 0x00, .g = 0x00, .b = 0x00}) -#define BG_COLOR ((_pixel_t){.r = 0xbf, .g = 0xbf, .b = 0xbf}) - -static const char *const mb_names[] = { - "left", "right", "middle" -}; - -void main() { - struct popup main_win; - info_popup(&main_win, "Click me!", TEXT_COLOR, BG_COLOR); - - while (1) { - struct window_action winact; - _get_win_action(main_win.handle, &winact); - - switch (winact.action_type) { - struct popup modal; - case NOT_READY: - _wait_for_action(); - _yield_task(); - continue; - - case KEY_DOWN: - return; - - case MOUSE_DOWN: - info_popupf(&modal, - "Got %s click at (%d, %d)!", - TEXT_COLOR, BG_COLOR, - mb_names[winact.as_mouse.which], - winact.as_mouse.x, winact.as_mouse.y); - make_modal(&modal); - continue; - - default: - continue; - } - } -} \ No newline at end of file diff --git a/src/user/meminfo/meminfo.cpp b/src/user/meminfo/meminfo.cpp index 2b035a4..03f7ae9 100644 --- a/src/user/meminfo/meminfo.cpp +++ b/src/user/meminfo/meminfo.cpp @@ -14,7 +14,7 @@ using namespace raleigh; label *kmem; label *umem; -void refresh(window &w) { +void refresh(window_tag_t) { char *const kstr = format("kernel memory free: %uk", _kernel_dynamic_area_left() * 4); char *const ustr = format("userspace memory free: %uk / %uk", _total_userspace_left() * 4, _total_userspace_size() * 4); @@ -41,10 +41,10 @@ void main() { vbox box(ll); padding pbox(box, 3); - window w(pbox, RGB(bf, bf, bf), (bool (*)(window &))&__pcrt_quit); + window w(pbox); w.add_keybind((struct key_packet){.key_id = key_packet::KEY_F5, .modifiers = key_packet::NO_MODS}, &refresh); - refresh(w); + refresh(0); w.show(); start_runtime(); diff --git a/src/user/mkpopup/main.c b/src/user/mkpopup/main.c deleted file mode 100644 index 05ea4e3..0000000 --- a/src/user/mkpopup/main.c +++ /dev/null @@ -1,36 +0,0 @@ -#include - -#include - -#include -#include - -void main(const char *text) { - uint32_t required_new_length = 0; - bool needs_new = false; - for (const char *c = text; c[0]; ++c) { - ++required_new_length; - if ((c[0] == '\\') && (c[1] == 'n')) { - ++c; - needs_new = true; - } - } - - if (needs_new) { - char *new_text = get_block(required_new_length); - const char *ci; - char *co; - for (ci = text, co = new_text; *ci; ++ci, ++co) - if ((ci[0] == '\\') && (ci[1] == 'n')) { - *co = '\n'; - ++ci; - } - else - *co = *ci; - text = new_text; - } - - struct popup p; - info_popup(&p, text, (_pixel_t){.r = 0, .g = 0, .b = 0}, (_pixel_t){.r = 0xbf, .g = 0xbf, .b = 0xbf}); - make_modal(&p); -} \ No newline at end of file diff --git a/src/user/mkpopup/main.cpp b/src/user/mkpopup/main.cpp new file mode 100644 index 0000000..5e3310c --- /dev/null +++ b/src/user/mkpopup/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +using namespace raleigh; + +widget *make_line(const char *str) { + return new label(str); +} + +void main(const char *text) { + dllist box_widgets; + + char *const data = strdup(text); + + char *this_string = data; + while (*this_string) { + char *i = this_string; + while (1) { + if (!i[0]) { + box_widgets.add_back(*make_line(this_string)); + this_string = i; + break; + } + if ((i[0] == '\\') && (i[1] == 'n')) { + i[0] = '\0'; + box_widgets.add_back(*make_line(this_string)); + this_string = i + 2; + break; + } + ++i; + } + } + + vbox box(box_widgets); + padding p(box, 4); + window w(p); + + w.show(); + start_runtime(); +} \ No newline at end of file diff --git a/src/user/popups/info.c b/src/user/popups/info.c deleted file mode 100644 index eac155b..0000000 --- a/src/user/popups/info.c +++ /dev/null @@ -1,77 +0,0 @@ -#include - -#include - -#include -#include - -#include -#include - -#define PADDING 6 -#define FONT "fixed-10" - -static const struct font_info *info_font = 0; - -static const struct key_packet info_quits[] = { - { .key_id = KEY_ESCAPE, .modifiers = NO_MODS }, - { .key_id = 0 } -}; - -void info_popup(struct popup *into, const char *msg, _pixel_t fg, _pixel_t bg) { - if (!info_font) - info_font = get_font(FONT); - - uint32_t w = 0, h = 1, lw = 0; - for (const char *i = msg; *i; ++i) - if (*i == '\n') { - ++h; - if (lw > w) - w = lw; - lw = 0; - } - else - ++lw; - if (lw > w) - w = lw; - - into->has_quit = false; - into->quit_binds = (struct key_packet *)info_quits; - - const uint32_t pitch = info_font->space_width * w + 2 * PADDING; - const uint32_t height = info_font->space_height * h + 2 * PADDING; - - _pixel_t *const pixbuf = get_block(pitch * height * 4); - - for (uint32_t y = 0; y < height; ++y) - for (uint32_t x = 0; x < pitch; ++x) - pixbuf[y * pitch + x] = bg; - - uint32_t my = 0; - uint32_t mx = 0; - --msg; - while (*++msg) { - if (*msg == '\n') { - ++my; - mx = 0; - } - else - put_char(info_font, *msg, pixbuf + (my * info_font->space_height + PADDING) * pitch + mx++ * info_font->space_width + PADDING, pitch, bg, fg); - } - - into->pixbuf = pixbuf; - into->handle = _new_window(pitch, height, pixbuf); -} - -void info_popupf_v(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, va_list args) { - char *const msg = format_v(text, args); - info_popup(into, msg, fg, bg); - free_block(msg); -} - -void info_popupf(struct popup *into, const char *text, _pixel_t fg, _pixel_t bg, ...) { - va_list args; - va_start(args, bg); - info_popupf_v(into, text, fg, bg, args); - va_end(args); -} \ No newline at end of file diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c deleted file mode 100644 index 9cdccb4..0000000 --- a/src/user/popups/popup.c +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#include -#include - -#include - -void handle_actions(struct popup *p) { - if (p->has_quit) - return; - struct window_action a; - while (1) { - _get_win_action(p->handle, &a); - if (a.action_type == NOT_READY) - return; - if ((a.action_type == KEY_DOWN)) { - //syslogf("got key 0x%2x, 0x%3x", a.as_key.key_id, a.as_key.modifiers); - for (const struct key_packet *kp = p->quit_binds; kp->key_id; ++kp) { - //syslogf("checking against 0x%2x, 0x%3x", kp->key_id, kp->modifiers); - if ((a.as_key.key_id == kp->key_id) && (a.as_key.modifiers == kp->modifiers)) { - p->has_quit = true; - p->quit_as = a.as_key; - return; - } - } - } - } -} - -void delete_popup(struct popup *p) { - _delete_window(p->handle); - free_block(p->pixbuf); -} - -void make_modal(struct popup *p) { - handle_actions(p); - while (!p->has_quit) { - _wait_for_action(); - _yield_task(); - handle_actions(p); - } - delete_popup(p); -} \ No newline at end of file diff --git a/src/user/raleigh/d/dialog.cpp b/src/user/raleigh/d/dialog.cpp new file mode 100644 index 0000000..38ca310 --- /dev/null +++ b/src/user/raleigh/d/dialog.cpp @@ -0,0 +1,74 @@ +#include + +#include +#include +#include +#include + +using namespace raleigh; + +void dialog::show_modal() { + show(); + do { + _wait_for_action(); + _yield_task(); + consume_actions(); + } while (!result); + to_be_deleted.add_back(*this); +} + +static bool on_diag_close(window_tag_t) { + return false; +} + +struct diag_and_result { + dialog *d; + diag_result_t r; + diag_and_result(dialog *d, diag_result_t r) + : d(d), r(r) {} +}; + +static void set_diag_result(button_tag_t tag) { + const diag_and_result *const cast = (const diag_and_result *)tag; + cast->d->result = cast->r; + //TODO: go through all of raleigh and add destructors + //in this case, delete all of these tags when the window is closed +} + +dialog::dialog(widget &top_part, alist> buttons) + : window(*new vbox(), RGB(bf, bf, bf), &on_diag_close), result(0), main_box((vbox *)&root) { + dllist *button_row = new dllist(); + for (duple *i = buttons.buf; i < buttons.buf + buttons.n_entries; ++i) { + label *l = new label(i->a); + padding *p = new padding(*l, 4); + button *b = new button(*p, &set_diag_result, new diag_and_result(this, i->b)); + padding *pb = new padding(*b, 2); + button_row->add_back(*pb); + } + hbox *button_box = new hbox(*button_row); + + padding *ptop = new padding(top_part, 2); + padding *pbot = new padding(*button_box, 2); + + main_box->add_end(*ptop); + main_box->add_end(*pbot); +} + +alist> &mk_yes_no_cancel() { + alist> *list = new alist>(3, 1); + list->add_back(duple("Yes", YES)); + list->add_back(duple("No", NO)); + list->add_back(duple("Cancel", CANCEL)); + return *list; +} + +alist> &mk_yes_no_retry() { + alist> *list = new alist>(3, 1); + list->add_back(duple("Yes", YES)); + list->add_back(duple("No", NO)); + list->add_back(duple("Retry", RETRY)); + return *list; +} + +alist> &raleigh::yes_no_cancel(mk_yes_no_cancel()); +alist> &raleigh::yes_no_retry(mk_yes_no_retry()); \ No newline at end of file diff --git a/src/user/raleigh/d/saving_window.cpp b/src/user/raleigh/d/saving_window.cpp new file mode 100644 index 0000000..a2d57e4 --- /dev/null +++ b/src/user/raleigh/d/saving_window.cpp @@ -0,0 +1,55 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace raleigh { + bool on_saving_window_close(window_tag_t tag) { + saving_window *const sw = (saving_window *)tag; + if (sw->is_saved) + return true; + + label text("There is unsaved content in this window."); + label text2("Would you like to save before closing it?"); + + dllist rows; + rows.add_back(text); + rows.add_back(text2); + vbox vb(rows); + padding vbp(vb, 2); + + dialog diag(vbp, yes_no_cancel); + diag.show_modal(); + + switch (diag.result) { + case YES: + save: + if (!sw->save_func(sw->save_tag)) { + label text3("Failing saved. Still quit?"); + dialog diag2(text3, yes_no_retry); + diag2.show_modal(); + switch (diag2.result) { + case YES: + return true; + case RETRY: + goto save; + default: + return false; + } + } + case NO: + return true; + default: + return false; + } + } + + saving_window::saving_window(bool (*save_func)(save_tag_t), save_tag_t save_tag, widget &root, _pixel_t bg_color) + : window(root, bg_color, &on_saving_window_close, (window_tag_t)this), is_saved(true), save_func(save_func), save_tag(save_tag) {} +} \ No newline at end of file diff --git a/src/user/raleigh/runtime.cpp b/src/user/raleigh/runtime.cpp index 6dafed1..d021537 100644 --- a/src/user/raleigh/runtime.cpp +++ b/src/user/raleigh/runtime.cpp @@ -4,19 +4,24 @@ namespace raleigh { dllist open_windows; + dllist to_be_deleted; __attribute__ ((noreturn)) void start_runtime() { while (1) { + for (dllist::node *w = open_windows.first; w; w = w->next) + w->d.consume_actions(); + l: + for (dllist::node *w = to_be_deleted.first; w; w = w->next) { + _delete_window(w->d.handle); + w->d.handle = 0; + open_windows.try_remove_by_ref(w->d); + w = to_be_deleted.remove_in_place(w); + if (!w) + goto l; + } if (!open_windows.first) __pcrt_quit(); - for (dllist::node *w = open_windows.first; w; w = w->next) - if (w->d.try_actions() == window::DELETE) { - _delete_window(w->d.handle); - w->d.handle = 0; - if (!(w = open_windows.remove_in_place(w))) - break; - } _wait_for_action(); _yield_task(); } diff --git a/src/user/raleigh/util.cpp b/src/user/raleigh/util.cpp index db0982b..a300d01 100644 --- a/src/user/raleigh/util.cpp +++ b/src/user/raleigh/util.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace raleigh { @@ -13,9 +13,7 @@ namespace raleigh { va_list args; va_start(args, fmt); - struct popup info; - info_popupf_v(&info, fmt, RGB(7f, 00, 00), RGB(bf, bf, bf), args); - make_modal(&info); + syslogf_v(fmt, args); __pcrt_quit(); } diff --git a/src/user/raleigh/w/button.cpp b/src/user/raleigh/w/button.cpp index 5b5f756..b035ee2 100644 --- a/src/user/raleigh/w/button.cpp +++ b/src/user/raleigh/w/button.cpp @@ -1,9 +1,9 @@ #include namespace raleigh { - button::button(widget &inner, void (*on_click)(button &), + button::button(widget &inner, void (*on_click)(button_tag_t), button_tag_t tag, _pixel_t border_color, _pixel_t bg_color, _pixel_t pressed_color) - : inner(inner), on_click(on_click), border_color(border_color), + : inner(inner), on_click(on_click), tag(tag), border_color(border_color), bg_color(bg_color), pressed_color(pressed_color), is_pressed(false) { size = coord(inner.size.x + 2, inner.size.y + 2); closest_opaque = this; @@ -44,7 +44,7 @@ namespace raleigh { inner.window_offset = coord(window_offset.x + 1, window_offset.y + 1); inner.notify_window_change(); w->notify_needs_paint(*this); - on_click(*this); + on_click(tag); } else { is_pressed = true; diff --git a/src/user/raleigh/w/colorpicker.cpp b/src/user/raleigh/w/colorpicker.cpp index 5a9aa82..281eaaf 100644 --- a/src/user/raleigh/w/colorpicker.cpp +++ b/src/user/raleigh/w/colorpicker.cpp @@ -32,6 +32,12 @@ namespace raleigh { pb_ptr[y * pitch + x] = picked_color; } + void colorpicker::set_picked_color(_pixel_t c) { + picked_color = c; + if (w) + w->notify_needs_paint(*this); + } + void colorpicker::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) { if (up || (click_type != mouse_packet::LEFT)) return; diff --git a/src/user/raleigh/w/entry.cpp b/src/user/raleigh/w/entry.cpp index 991d75a..3053413 100644 --- a/src/user/raleigh/w/entry.cpp +++ b/src/user/raleigh/w/entry.cpp @@ -5,18 +5,10 @@ #include namespace raleigh { - entry::entry(uint32_t rows, uint32_t cols, const char *default_text, - const char *font, _pixel_t bg, _pixel_t fg, _pixel_t border_color) - : rows(rows), cols(cols), bg(bg), fg(fg), border_color(border_color), - fi(get_font(font)), data(new char[rows * cols]), - line_indices(new uint32_t[rows + 1]), has_focus(false) { - size = coord(fi->space_width * (cols - 1) + fi->char_width + 6, - fi->space_height * (rows - 1) + fi->char_height + 6); - closest_opaque = this; - - const uint32_t l = strlen(default_text); + void entry::set_contents(const char *s) { + const uint32_t l = strlen(s); const uint32_t cl = l > rows * cols - 1 ? rows * cols - 1 : l; - blockcpy(data, default_text, cl); + blockcpy(data, s, cl); data[cl] = '\0'; line_indices[0] = 0; @@ -24,6 +16,21 @@ namespace raleigh { cur_x = end_x; cur_y = end_y; cur_d = end_d; + + next_paint_full = true; + if (w) + w->notify_needs_paint(*this); + } + + entry::entry(uint32_t rows, uint32_t cols, const char *default_text, + const char *font, _pixel_t bg, _pixel_t fg, _pixel_t border_color) + : rows(rows), cols(cols), bg(bg), fg(fg), border_color(border_color), + fi(get_font(font)), data(new char[rows * cols]), + line_indices(new uint32_t[rows + 1]), has_focus(false) { + size = coord(fi->space_width * (cols - 1) + fi->char_width + 6, + fi->space_height * (rows - 1) + fi->char_height + 6); + closest_opaque = this; + set_contents(default_text); } void entry::get_indices(uint32_t from_y, uint32_t from_x, uint32_t from_d) { @@ -260,4 +267,8 @@ namespace raleigh { has_focus = false; w->notify_needs_paint(*this); } + + const char *entry::get_contents() { + return data; + } } \ No newline at end of file diff --git a/src/user/raleigh/w/multicontainer.cpp b/src/user/raleigh/w/multicontainer.cpp index edc60aa..d713f51 100644 --- a/src/user/raleigh/w/multicontainer.cpp +++ b/src/user/raleigh/w/multicontainer.cpp @@ -39,4 +39,20 @@ namespace raleigh { set_size(determine_size()); set_child_offsets(); } + + void multicontainer::add_end(widget &n) { + widgets.add_back(n); + set_size(determine_size()); + set_child_offsets(); + if (w) + w->notify_needs_paint(*this); + } + + void multicontainer::add_start(widget &n) { + widgets.add_front(n); + set_size(determine_size()); + set_child_offsets(); + if (w) + w->notify_needs_paint(*this); + } } \ No newline at end of file diff --git a/src/user/raleigh/widget.cpp b/src/user/raleigh/widget.cpp index df9c661..48a0496 100644 --- a/src/user/raleigh/widget.cpp +++ b/src/user/raleigh/widget.cpp @@ -4,7 +4,7 @@ namespace raleigh { widget::widget() - : parent(0), next_paint_full(true) {} + : parent(0), w(0), next_paint_full(true) {} void widget::notify_window_change() {} void widget::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) {} diff --git a/src/user/raleigh/window.cpp b/src/user/raleigh/window.cpp index b99346d..5fa82c3 100644 --- a/src/user/raleigh/window.cpp +++ b/src/user/raleigh/window.cpp @@ -5,25 +5,26 @@ #include namespace raleigh { - window::window(widget &root, _pixel_t bg_color, bool (*on_close)(window &)) - : handle(0), size(root.size), root(root), focussed(&root), - drag_reciever(0), bg_color(bg_color), on_close(on_close) { + window::window(widget &root, _pixel_t bg_color, bool (*on_close)(window_tag_t), window_tag_t tag) + : root(root), handle(0), pixbuf(0), size(root.size), focussed(&root), + drag_reciever(0), bg_color(bg_color), on_close(on_close), tag(tag) { root.w = this; root.window_offset = coord(0, 0); root.notify_window_change(); - pixbuf = new _pixel_t[size.x * size.y]; - if (!pixbuf) - show_error_and_quitf("Failed to create %d byte pixel buffer\nfor requested %dx%d pixel window.", size.x * size.y * sizeof(_pixel_t), size.x, size.y); + if (size.x && size.y) { + pixbuf = new _pixel_t[size.x * size.y]; + if (!pixbuf) + show_error_and_quitf("Failed to create %d byte pixel buffer\nfor requested %dx%d pixel window.", size.x * size.y * sizeof(_pixel_t), size.x, size.y); + } paint_full(); root.on_focus(); needs_repaint = false; } - window::try_actions_return_t window::try_actions() { + void window::consume_actions() { struct window_action wa; - window::try_actions_return_t got = NONE; while (1) { _get_win_action(handle, &wa); if (!wa.action_type) { @@ -31,15 +32,17 @@ namespace raleigh { needs_repaint = false; _paint_window(handle); } - return got; + return; } if ((wa.action_type == wa.KEY_DOWN) && (wa.as_key.modifiers & wa.as_key.ALTS) && - (wa.as_key.key_id == wa.as_key.KEY_F4)) - if (!on_close || on_close(*this)) - return DELETE; - got = GOOD; - if (wa.action_type == wa.MOUSE_DOWN) + (wa.as_key.key_id == wa.as_key.KEY_F4)) { + if (!on_close || on_close(tag)) { + to_be_deleted.add_back(*this); + return; + } + } + else if (wa.action_type == wa.MOUSE_DOWN) root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, false); else if (wa.action_type == wa.MOUSE_UP) { if (drag_reciever && (wa.as_mouse.which == drag_until)) @@ -47,14 +50,11 @@ namespace raleigh { root.handle_click(coord(wa.as_mouse.x, wa.as_mouse.y), wa.as_mouse.which, true); } else if (wa.action_type == wa.KEY_DOWN) { - for (dllist>::node *n = keybinds.first; n; n = n->next) - if (match_side_agnostic(wa.as_key, n->d.a)) { - n->d.b(*this); - goto next_loop; - } - focussed->handle_key(wa.as_key); - next_loop: - ; + void (*const f)(window_tag_t) = keybinds.transform(wa.as_key); + if (f) + f(tag); + else + focussed->handle_key(wa.as_key); } else if (wa.action_type == wa.FOCUS_ENTER) focussed->on_focus(); @@ -103,7 +103,8 @@ namespace raleigh { from.parent->notify_child_size_change(from, old_size); else { size = root.size; - delete[] pixbuf; + if (pixbuf) + delete[] pixbuf; pixbuf = new _pixel_t[size.x * size.y]; if (!pixbuf) show_error_and_quitf("Failed to allocate %u byte buffer while\nresizing window to %ux%u pixels.", size.x * size.y, size.x, size.y); @@ -112,8 +113,8 @@ namespace raleigh { } } - void window::add_keybind(struct key_packet kp, void (*handler)(window &)) { - keybinds.add_front(duple(kp, handler)); + void window::add_keybind(struct key_packet kp, void (*handler)(window_tag_t)) { + keybinds.add_pair(kp, handler); } void window::notify_wants_movements(widget &from, enum mouse_packet::mouse_button while_down) { diff --git a/src/user/rhello/main.cpp b/src/user/rhello/main.cpp deleted file mode 100644 index 8ea0bf0..0000000 --- a/src/user/rhello/main.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -using namespace raleigh; - -colorpicker *cp; -label *p_l; -window *p_w; -label *l; - -void onclick(button &from) { - const _pixel_t pc = cp->get_picked_color(); - char *const text = format("Selected color is #%2x%2x%2x", pc.r, pc.g, pc.b); - p_l->change_value(text); - free_block(text); - p_w->show(); -} - -void onclick2(button &from) { - l->change_value("I can be changed on the fly."); -} - -void main() { - l = new label("Hello, world! Close me with Alt+F4."); - padding pl(*l, 2); - - label bl("Click me!"); - padding pbl(bl, 4); - button b(pbl, &onclick); - padding pb(b, 2); - - label b2l("Click me too!"); - padding pb2l(b2l, 4); - button b2(pb2l, &onclick2); - padding pb2(b2, 2); - - dllist bbl; - bbl.add_front(pb2); - bbl.add_front(pb); - hbox bb(bbl); - - entry e(8, 31, "This window is made with the Raleigh widget toolkit for Portland OS.\n\nI am a text entry widget. You can move my cursor, but I cannot yet be edited."); - padding pe(e, 2); - - cp = new colorpicker(); - padding pcp(*cp, 2); - - dllist wl; - wl.add_front(bb); - wl.add_front(pcp); - wl.add_front(pe); - wl.add_front(pl); - vbox vb(wl); - padding pvb(vb, 2); - - window w(pvb, RGB(bf, bf, bf), (bool (*)(window &))&__pcrt_quit); - - p_l = new label(""); - padding p_pl(*p_l, 4); - p_w = new window(p_pl); - - w.show(); - start_runtime(); -} \ No newline at end of file diff --git a/src/user/settings/color_editor.cpp b/src/user/settings/color_editor.cpp new file mode 100644 index 0000000..1673824 --- /dev/null +++ b/src/user/settings/color_editor.cpp @@ -0,0 +1,16 @@ +#include "color_editor.h" + +color_editor::color_editor(struct setting *s, const char *sname) + : c(&s->data.color), p(s->data.color) { + editing_widget_ready(p, sname); +} + +#include + +void color_editor::set_data() { + const _pixel_t new_c = p.get_picked_color(); + if ((c->r != new_c.r) || (c->g != new_c.g) || (c->b != new_c.b)) { + *c = new_c; + main_w->is_saved = false; + } +} \ No newline at end of file diff --git a/src/user/settings/color_editor.h b/src/user/settings/color_editor.h new file mode 100644 index 0000000..c41ec3f --- /dev/null +++ b/src/user/settings/color_editor.h @@ -0,0 +1,19 @@ +#ifndef COLOR_EDITOR_H +#define COLOR_EDITOR_H + +#include + +#include "editor.h" +#include "model.h" + +class color_editor : public editor { +public: + color_editor(struct setting *s, const char *sname); + void set_data() override; + +private: + _pixel_t *c; + colorpicker p; +}; + +#endif \ No newline at end of file diff --git a/src/user/settings/editor.cpp b/src/user/settings/editor.cpp new file mode 100644 index 0000000..1804a85 --- /dev/null +++ b/src/user/settings/editor.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "editor.h" + +bool editor_save(window_tag_t e) { + ((editor *)e)->set_data(); + return true; +} + +editor::editor() + : w(0) {} + +void editor::editing_widget_ready(widget &e, const char *s) { + label *l = new label(s); + padding *p = new padding(*l, 4); + + dllist *list = new dllist(); + list->add_back(*p); + list->add_back(e); + + vbox *box = new vbox(*list); + + w = new window(*box, RGB(bf, bf, bf), &editor_save, this); +} + +void editor::show() { + w->show(); +} \ No newline at end of file diff --git a/src/user/settings/editor.h b/src/user/settings/editor.h new file mode 100644 index 0000000..2980884 --- /dev/null +++ b/src/user/settings/editor.h @@ -0,0 +1,20 @@ +#ifndef EDITOR_H +#define EDITOR_H + +#include + +using namespace raleigh; + +class editor { + friend bool editor_save(window_tag_t e); +public: + void show(); +protected: + editor(); + void editing_widget_ready(widget &e, const char *sname); + virtual void set_data() = 0; +private: + window *w; +}; + +#endif \ No newline at end of file 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 +#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(); +} \ No newline at end of file diff --git a/src/user/settings/model.cpp b/src/user/settings/model.cpp new file mode 100644 index 0000000..e27de0d --- /dev/null +++ b/src/user/settings/model.cpp @@ -0,0 +1,4 @@ +#include "model.h" + +alist settings; +raleigh::saving_window *main_w; \ No newline at end of file diff --git a/src/user/settings/model.h b/src/user/settings/model.h new file mode 100644 index 0000000..0c9b1d2 --- /dev/null +++ b/src/user/settings/model.h @@ -0,0 +1,24 @@ +#ifndef MODEL_H +#define MODEL_H + +#include +#include + +union setting_data { + char *string; + _pixel_t color; +}; + +struct setting { + enum { + STRING, + COLOR + } kind; + union setting_data data; + const char *name; +}; + +extern alist settings; +extern raleigh::saving_window *main_w; + +#endif \ No newline at end of file diff --git a/src/user/settings/str_editor.cpp b/src/user/settings/str_editor.cpp new file mode 100644 index 0000000..5e86e96 --- /dev/null +++ b/src/user/settings/str_editor.cpp @@ -0,0 +1,17 @@ +#include + +#include "str_editor.h" + +str_editor::str_editor(struct setting *s, const char *sname) + : e(10, 25, s->data.string), s(&s->data.string) { + editing_widget_ready(e, sname); +} + +void str_editor::set_data() { + const char *const contents = e.get_contents(); + if (strequ(contents, *s)) + return; + delete *s; + *s = strdup(contents); + main_w->is_saved = false; +} \ No newline at end of file diff --git a/src/user/settings/str_editor.h b/src/user/settings/str_editor.h new file mode 100644 index 0000000..02bd7d8 --- /dev/null +++ b/src/user/settings/str_editor.h @@ -0,0 +1,19 @@ +#ifndef STR_EDITOR_H +#define STR_EDITOR_H + +#include + +#include "editor.h" +#include "model.h" + +class str_editor : public editor { +public: + str_editor(struct setting *s, const char *sname); + void set_data() override; + +private: + entry e; + char **s; +}; + +#endif \ No newline at end of file diff --git a/src/user/ttt/main.c b/src/user/ttt/main.c deleted file mode 100644 index 655bf8e..0000000 --- a/src/user/ttt/main.c +++ /dev/null @@ -1,271 +0,0 @@ -#include -#include -#include - -#define SPACE_SIZE 20 -#define BORDER_SIZE 4 -#define WIDTH (SPACE_SIZE * 3 + BORDER_SIZE * 4) - -#define BG ((_pixel_t){.r = 0xd6, .g = 0xd6, .b = 0xd6}) -#define FG ((_pixel_t){.r = 0x33, .g = 0x33, .b = 0x33}) -#define XC ((_pixel_t){.r = 0x60, .g = 0x06, .b = 0x43}) -#define OC ((_pixel_t){.r = 0x2c, .g = 0x77, .b = 0x30}) -#define SL ((_pixel_t){.r = 0x9d, .g = 0x99, .b = 0xc2}) - -static const bool x_pic[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, - 0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0, - 0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0, - 0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0, - 0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0, - 0,0,0,0,0,0,1,1,1,0,0,1,1,1,0,0,0,0,0,0, - 0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0, - 0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0, - 0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0, - 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - -static const bool o_pic[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, - 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - -static const bool b_pic[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - -typedef enum {B, X, O} trit; - -static const bool *pics[] = {b_pic, x_pic, o_pic}; -static const _pixel_t colors[] = {FG, XC, OC}; - -static _window_handle_t w; -static _pixel_t pbuf[WIDTH * WIDTH]; -static trit board_state[9]; -static uint8_t cursor; -static trit playing_as; -static uint8_t filled_squares; - -__attribute__ ((__pure__)) -static bool is_win(uint8_t hint) { - const uint8_t c = hint % 3; - if ((board_state[c] == board_state[c + 3]) && (board_state[c] == board_state[c + 6])) - return true; - const uint8_t r = hint - c; - if ((board_state[r] == board_state[r + 1]) && (board_state[r] == board_state[r + 2])) - return true; - return board_state[4] && ( - ((board_state[0] == board_state[4]) && (board_state[0] == board_state[8])) || - ((board_state[2] == board_state[4]) && (board_state[2] == board_state[6])) - ); -} - -static void draw_rect(uint8_t y, uint8_t x, uint8_t h, uint8_t w, _pixel_t color) { - for (uint8_t yy = y; yy < y + h; ++yy) - for (uint8_t xx = x; xx < x + w; ++xx) - pbuf[yy * WIDTH + xx] = color; -} - -static void draw_spot(uint8_t n) { - const _pixel_t bg_c = n == cursor ? SL : BG; - const _pixel_t fg_c = colors[board_state[n]]; - const bool *const pic = pics[board_state[n]]; - - const uint8_t ys = BORDER_SIZE + (n / 3) * (BORDER_SIZE + SPACE_SIZE); - const uint8_t xs = BORDER_SIZE + (n % 3) * (BORDER_SIZE + SPACE_SIZE); - for (uint8_t y = 0; y < SPACE_SIZE; ++y) - for (uint8_t x = 0; x < SPACE_SIZE; ++x) - pbuf[(ys + y) * WIDTH + xs + x] = pic[y * SPACE_SIZE + x] ? fg_c : bg_c; -} - -static void ai_turn(); - -static void reset_board() { - cursor = 4; - playing_as = gen_rand() % 2 + 1; - filled_squares = 0; - for (uint8_t i = 0; i < 9; ++i) { - board_state[i] = B; - draw_spot(i); - } - - if (gen_rand() % 2) - ai_turn(); -} - -static uint32_t start_time; - -static void on_win() { - struct popup p; - info_popupf(&p, "You win! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); - make_modal(&p); - reset_board(); - _paint_window(w); - start_time = _get_timestamp(); -} - -static void on_tie() { - struct popup p; - info_popupf(&p, "Tie! Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); - make_modal(&p); - reset_board(); - _paint_window(w); - start_time = _get_timestamp(); -} - -static void ai_turn() { - //super easy mode - uint8_t n; - do - n = gen_rand() % 9; - while (board_state[n]); - board_state[n] = playing_as == O ? X : O; - draw_spot(n); - _paint_window(w); - if (is_win(n)) { - struct popup p; - info_popupf(&p, "You lose. Time: %us\nPress escape to play again.", FG, BG, _get_timestamp() - start_time); - make_modal(&p); - reset_board(); - _paint_window(w); - start_time = _get_timestamp(); - } - else if (++filled_squares == 9) - on_tie(); -} - -void main() { - struct popup controls; - info_popup(&controls, - "Tic-Tac-Toe Controls:\n\n" - "Arrow keys: move selection\n" - "Spacebar: confirm selection\n" - "Escape: quit\n\n" - "Press escape to start.", FG, BG); - make_modal(&controls); - - for (uint16_t i = 0; i < WIDTH * WIDTH; ++i) - pbuf[i] = BG; - - draw_rect(SPACE_SIZE + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG); - draw_rect(BORDER_SIZE, SPACE_SIZE + BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG); - draw_rect(SPACE_SIZE * 2 + BORDER_SIZE * 2, BORDER_SIZE, BORDER_SIZE, WIDTH - 2 * BORDER_SIZE, FG); - draw_rect(BORDER_SIZE, SPACE_SIZE * 2 + BORDER_SIZE * 2, WIDTH - 2 * BORDER_SIZE, BORDER_SIZE, FG); - - reset_board(); - - w = _new_window(WIDTH, WIDTH, pbuf); - start_time = _get_timestamp(); - - while (1) { - struct window_action wa; - _get_win_action(w, &wa); - if (!wa.action_type) { - _wait_for_action(); - _yield_task(); - continue; - } - - if (wa.action_type != KEY_DOWN) - continue; - - switch (wa.as_key.key_id) { - case KEY_UP_ARROW: - if (cursor >= 3) { - cursor -= 3; - draw_spot(cursor + 3); - draw_spot(cursor); - _paint_window(w); - } - break; - case KEY_DOWN_ARROW: - if (cursor < 6) { - cursor += 3; - draw_spot(cursor - 3); - draw_spot(cursor); - _paint_window(w); - } - break; - case KEY_LEFT_ARROW: - if (cursor % 3) { - --cursor; - draw_spot(cursor + 1); - draw_spot(cursor); - _paint_window(w); - } - break; - case KEY_RIGHT_ARROW: - if (cursor % 3 != 2) { - ++cursor; - draw_spot(cursor - 1); - draw_spot(cursor); - _paint_window(w); - } - break; - case KEY_ESCAPE: - return; - case KEY_SPACE: - if (!board_state[cursor]) { - board_state[cursor] = playing_as; - draw_spot(cursor); - _paint_window(w); - if (is_win(cursor)) - on_win(); - else if (++filled_squares == 9) - on_tie(); - else - ai_turn(); - } - break; - default: - break; - } - } -} \ No newline at end of file -- cgit v1.2.3