summaryrefslogtreecommitdiff
path: root/src/user
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2021-03-11 22:00:22 -0500
committerBenji Dial <benji6283@gmail.com>2021-03-11 22:00:22 -0500
commit5fcf57739e68a8b5053e03778aaee0eed445babd (patch)
treee7a8bab18668d112e58b1b48190195035c71fa8a /src/user
parent0f2398d1f622cce37925f52d978d92e6cce1c7a9 (diff)
downloadportland-os-5fcf57739e68a8b5053e03778aaee0eed445babd.tar.gz
settings editor, and lots of changes in service of that
Diffstat (limited to 'src/user')
-rw-r--r--src/user/include/cxx/raleigh/d/dialog.h37
-rw-r--r--src/user/include/cxx/raleigh/d/saving_window.h20
-rw-r--r--src/user/include/cxx/raleigh/runtime.h1
-rw-r--r--src/user/include/cxx/raleigh/w/button.h9
-rw-r--r--src/user/include/cxx/raleigh/w/colorpicker.h1
-rw-r--r--src/user/include/cxx/raleigh/w/entry.h7
-rw-r--r--src/user/include/cxx/raleigh/w/multicontainer.h3
-rw-r--r--src/user/include/cxx/raleigh/w/vbox.h2
-rw-r--r--src/user/include/cxx/raleigh/window.h23
-rw-r--r--src/user/include/cxx/structs/alist.h41
-rw-r--r--src/user/include/cxx/structs/dllist.h38
-rw-r--r--src/user/include/cxx/structs/map.h39
-rw-r--r--src/user/include/knob/file.h9
-rw-r--r--src/user/include/pland/pcrt.h4
-rw-r--r--src/user/include/popups/info.h22
-rw-r--r--src/user/include/popups/popup.h22
-rw-r--r--src/user/knob/block.c5
-rw-r--r--src/user/knob/file.c7
-rw-r--r--src/user/knob/heap.c14
-rw-r--r--src/user/mdemo/main.c42
-rw-r--r--src/user/meminfo/meminfo.cpp6
-rw-r--r--src/user/mkpopup/main.c36
-rw-r--r--src/user/mkpopup/main.cpp43
-rw-r--r--src/user/popups/info.c77
-rw-r--r--src/user/popups/popup.c43
-rw-r--r--src/user/raleigh/d/dialog.cpp74
-rw-r--r--src/user/raleigh/d/saving_window.cpp55
-rw-r--r--src/user/raleigh/runtime.cpp19
-rw-r--r--src/user/raleigh/util.cpp6
-rw-r--r--src/user/raleigh/w/button.cpp6
-rw-r--r--src/user/raleigh/w/colorpicker.cpp6
-rw-r--r--src/user/raleigh/w/entry.cpp33
-rw-r--r--src/user/raleigh/w/multicontainer.cpp16
-rw-r--r--src/user/raleigh/widget.cpp2
-rw-r--r--src/user/raleigh/window.cpp51
-rw-r--r--src/user/rhello/main.cpp75
-rw-r--r--src/user/settings/color_editor.cpp16
-rw-r--r--src/user/settings/color_editor.h19
-rw-r--r--src/user/settings/editor.cpp30
-rw-r--r--src/user/settings/editor.h20
-rw-r--r--src/user/settings/main.cpp191
-rw-r--r--src/user/settings/model.cpp4
-rw-r--r--src/user/settings/model.h24
-rw-r--r--src/user/settings/str_editor.cpp17
-rw-r--r--src/user/settings/str_editor.h19
-rw-r--r--src/user/ttt/main.c271
46 files changed, 844 insertions, 661 deletions
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 <raleigh/w/vbox.h>
+#include <raleigh/window.h>
+#include <structs/alist.h>
+#include <structs/duple.h>
+#include <stdint.h>
+
+namespace raleigh {
+ typedef uint32_t diag_result_t;
+ enum : diag_result_t {
+ NONE = 0,
+ YES,
+ NO,
+ CANCEL,
+ RETRY
+ };
+ extern alist<duple<const char *, diag_result_t>> &yes_no_cancel;
+ extern alist<duple<const char *, diag_result_t>> &yes_no_retry;
+ class dialog : public window {
+ public:
+ //button names are copied
+ //alist isn't needed past constructor
+ dialog(widget &top_part, alist<duple<const char *, diag_result_t>> 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 <raleigh/w/vbox.h>
+#include <raleigh/window.h>
+
+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<window &> open_windows;
+ extern dllist<window &> 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 <raleigh/widget.h>
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<widget &> widgets);
+ vbox(dllist<widget &> widgets=dllist<widget &>());
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 <stdint.h>
+
namespace raleigh {
class window;
}
#include <raleigh/runtime.h>
#include <raleigh/widget.h>
-#include <structs/dllist.h>
-#include <structs/duple.h>
#include <pland/syscall.h>
#include <raleigh/util.h>
+#include <structs/map.h>
+#include <knob/key.h>
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<duple<struct key_packet, void (*)(window &)>> keybinds;
+ bool (*on_close)(window_tag_t);
+ window_tag_t tag;
+ map<struct key_packet, void (*)(window_tag_t), &match_side_agnostic> 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 <knob/format.h>
+#include <knob/block.h>
+#include <knob/panic.h>
+#include <knob/heap.h>
+#include <stdint.h>
+
+template<class data>
+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 <stdint.h>
+
template<class data>
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 <structs/alist.h>
+
+template<class type>
+bool default_equals(type a, type b) {
+ return a == b;
+}
+
+template<class key, class value, bool (*equals)(key, key) = &default_equals<key>>
+class map {
+public:
+ alist<key> keys;
+ alist<value> 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 <stdint.h>
#include <pland/syscall.h>
@@ -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 <popups/popup.h>
-
-#include <pland/syscall.h>
-
-#include <stdarg.h>
-
-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 <pland/syscall.h>
-
-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 <knob/panic.h>
+#include <knob/heap.h>
#include <stdbool.h>
#include <stdint.h>
-#include <knob/heap.h>
//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);
@@ -110,6 +110,11 @@ int32_t seek_file_by(struct file *f, int32_t by) {
}
__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 <pland/syscall.h>
-#include <popups/info.h>
-
-#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 <popups/info.h>
-
-#include <knob/heap.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-
-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 <raleigh/w/padding.h>
+#include <raleigh/w/label.h>
+#include <raleigh/w/vbox.h>
+#include <raleigh/window.h>
+#include <knob/block.h>
+
+using namespace raleigh;
+
+widget *make_line(const char *str) {
+ return new label(str);
+}
+
+void main(const char *text) {
+ dllist<widget &> 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 <popups/popup.h>
-
-#include <libfont/fonts.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-
-#include <stdint.h>
-#include <stdarg.h>
-
-#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 <popups/popup.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-
-#include <pland/syscall.h>
-
-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 <raleigh/d/dialog.h>
+
+#include <raleigh/w/padding.h>
+#include <raleigh/w/button.h>
+#include <raleigh/w/label.h>
+#include <raleigh/w/hbox.h>
+
+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<duple<const char *, diag_result_t>> buttons)
+ : window(*new vbox(), RGB(bf, bf, bf), &on_diag_close), result(0), main_box((vbox *)&root) {
+ dllist<widget &> *button_row = new dllist<widget &>();
+ for (duple<const char *, diag_result_t> *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<duple<const char *, diag_result_t>> &mk_yes_no_cancel() {
+ alist<duple<const char *, diag_result_t>> *list = new alist<duple<const char *, diag_result_t>>(3, 1);
+ list->add_back(duple<const char *, diag_result_t>("Yes", YES));
+ list->add_back(duple<const char *, diag_result_t>("No", NO));
+ list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL));
+ return *list;
+}
+
+alist<duple<const char *, diag_result_t>> &mk_yes_no_retry() {
+ alist<duple<const char *, diag_result_t>> *list = new alist<duple<const char *, diag_result_t>>(3, 1);
+ list->add_back(duple<const char *, diag_result_t>("Yes", YES));
+ list->add_back(duple<const char *, diag_result_t>("No", NO));
+ list->add_back(duple<const char *, diag_result_t>("Retry", RETRY));
+ return *list;
+}
+
+alist<duple<const char *, diag_result_t>> &raleigh::yes_no_cancel(mk_yes_no_cancel());
+alist<duple<const char *, diag_result_t>> &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 <raleigh/d/saving_window.h>
+#include <raleigh/d/dialog.h>
+
+#include <raleigh/w/padding.h>
+#include <raleigh/w/button.h>
+#include <raleigh/w/label.h>
+#include <raleigh/w/hbox.h>
+#include <raleigh/w/vbox.h>
+
+#include <structs/dllist.h>
+
+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<widget &> 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<window &> open_windows;
+ dllist<window &> to_be_deleted;
__attribute__ ((noreturn))
void start_runtime() {
while (1) {
+ for (dllist<window &>::node *w = open_windows.first; w; w = w->next)
+ w->d.consume_actions();
+ l:
+ for (dllist<window &>::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<window &>::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 <raleigh/util.h>
-#include <popups/info.h>
+#include <knob/format.h>
#include <pland/pcrt.h>
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 <raleigh/w/button.h>
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 <knob/key.h>
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 <knob/format.h>
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<duple<struct key_packet, void (*)(window &)>>::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<struct key_packet, void (*)(window &)>(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 <raleigh/w/colorpicker.h>
-#include <raleigh/w/padding.h>
-#include <raleigh/w/button.h>
-#include <raleigh/w/label.h>
-#include <raleigh/w/entry.h>
-#include <raleigh/w/hbox.h>
-#include <raleigh/w/vbox.h>
-
-#include <raleigh/runtime.h>
-#include <raleigh/window.h>
-
-#include <knob/format.h>
-#include <pland/pcrt.h>
-
-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<widget &> 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<widget &> 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 <knob/format.h>
+
+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 <raleigh/w/colorpicker.h>
+
+#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 <raleigh/w/padding.h>
+#include <raleigh/w/button.h>
+#include <raleigh/w/label.h>
+#include <raleigh/w/vbox.h>
+#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<widget &> *list = new dllist<widget &>();
+ 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 <raleigh/d/saving_window.h>
+
+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 <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
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<struct setting> 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 <raleigh/d/saving_window.h>
+#include <structs/alist.h>
+
+union setting_data {
+ char *string;
+ _pixel_t color;
+};
+
+struct setting {
+ enum {
+ STRING,
+ COLOR
+ } kind;
+ union setting_data data;
+ const char *name;
+};
+
+extern alist<struct setting> 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 <knob/block.h>
+
+#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 <raleigh/w/entry.h>
+
+#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 <pland/syscall.h>
-#include <popups/info.h>
-#include <knob/rand.h>
-
-#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