diff options
Diffstat (limited to 'src/user/raleigh')
-rw-r--r-- | src/user/raleigh/d/dialog.cpp | 27 | ||||
-rw-r--r-- | src/user/raleigh/s/text_flower.cpp | 96 | ||||
-rw-r--r-- | src/user/raleigh/util.cpp | 16 | ||||
-rw-r--r-- | src/user/raleigh/w/entry.cpp | 362 | ||||
-rw-r--r-- | src/user/raleigh/w/label.cpp | 49 | ||||
-rw-r--r-- | src/user/raleigh/window.cpp | 8 |
6 files changed, 317 insertions, 241 deletions
diff --git a/src/user/raleigh/d/dialog.cpp b/src/user/raleigh/d/dialog.cpp index 38ca310..33f137e 100644 --- a/src/user/raleigh/d/dialog.cpp +++ b/src/user/raleigh/d/dialog.cpp @@ -54,21 +54,36 @@ dialog::dialog(widget &top_part, alist<duple<const char *, diag_result_t>> butto 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); +button_list &mk_yes_no_cancel() { + button_list *list = new button_list(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); +button_list &mk_yes_no_retry() { + button_list *list = new button_list(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 +button_list &mk_okay_cancel() { + button_list *list = new button_list(2, 1); + list->add_back(duple<const char *, diag_result_t>("Okay", OKAY)); + list->add_back(duple<const char *, diag_result_t>("Cancel", CANCEL)); + return *list; +} + +button_list &mk_okay() { + button_list *list = new button_list(1, 1); + list->add_back(duple<const char *, diag_result_t>("Okay", OKAY)); + return *list; +} + +button_list &raleigh::yes_no_cancel(mk_yes_no_cancel()); +button_list &raleigh::yes_no_retry(mk_yes_no_retry()); +button_list &raleigh::okay_cancel(mk_okay_cancel()); +button_list &raleigh::okay(mk_okay());
\ No newline at end of file diff --git a/src/user/raleigh/s/text_flower.cpp b/src/user/raleigh/s/text_flower.cpp new file mode 100644 index 0000000..bd4ecd8 --- /dev/null +++ b/src/user/raleigh/s/text_flower.cpp @@ -0,0 +1,96 @@ +#include <raleigh/s/text_flower.h> +#include <knob/block.h> + +namespace raleigh { + text_flower::text_flower(const char *s, uint32_t cols, uint32_t max_rows) + : s(s), lines(max_rows ? max_rows : 10), offsets(max_rows ? max_rows : 10), + max_rows(max_rows), cols(cols) { + flow_text(); + } + + __attribute__ ((pure)) + uint32_t text_flower::get_n_lines() { + return lines.n_entries; + } + + __attribute__ ((pure)) + char *text_flower::get_nth_line(uint32_t n) { + return lines.buf[n]; + } + + __attribute__ ((pure)) + uint32_t text_flower::get_line_offset(uint32_t n) { + return offsets.buf[n]; + } + + void text_flower::draw_text(_pixel_t *start, uint32_t pitch, const struct font_info *fi, _pixel_t color) { + for (uint32_t y = 0; y < lines.n_entries; ++y) { + const char *line = lines.buf[y]; + for (uint32_t x = 0; line[x]; ++x) + put_char_no_bg(fi, line[x], start + y * fi->space_height * pitch + x * fi->space_width, pitch, color); + } + } + + void text_flower::push_line() { + lines.add_back(strndup(line_start, row_len)); + offsets.add_back(line_start - s); + line_start = on_char; + row_len = 0; + if (max_rows && (lines.n_entries == max_rows)) + on_char = ""; + } + + void text_flower::flow_text() { + for (uint32_t i = 0; i < lines.n_entries; ++i) + free_block(lines.buf[i]); + + lines.n_entries = 0; + offsets.n_entries = 0; + line_start = on_char = s; + row_len = 0; + + while (*on_char) { + if (*on_char == '\n') { + ++on_char; + push_line(); + } + + else if (*on_char == ' ') { + ++on_char; + if (row_len != 0) { + if (++row_len == cols) + push_line(); + } + else + ++line_start; + } + + else { + uint32_t word_len = str_find_any(on_char, " \n"); + if (!cols) { + row_len += word_len; + on_char += word_len; + } + + else if (row_len + word_len <= cols) { + row_len += word_len; + on_char += word_len; + if (row_len == cols) + push_line(); + } + + else if (word_len > cols) { + on_char += cols - row_len; + row_len = cols; + push_line(); + } + + else + push_line(); + } + } + + if (row_len && (!max_rows || (lines.n_entries != max_rows))) + push_line(); + } +}
\ No newline at end of file diff --git a/src/user/raleigh/util.cpp b/src/user/raleigh/util.cpp index a300d01..1687ea6 100644 --- a/src/user/raleigh/util.cpp +++ b/src/user/raleigh/util.cpp @@ -1,3 +1,5 @@ +#include <raleigh/d/dialog.h> +#include <raleigh/w/label.h> #include <raleigh/util.h> #include <knob/format.h> #include <pland/pcrt.h> @@ -17,4 +19,18 @@ namespace raleigh { __pcrt_quit(); } + + __attribute__ ((noreturn)) + void show_error_popup_and_quitf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + char *ch = format_v(fmt, args); + label l(ch); + + dialog d(l, okay); + d.show_modal(); + + __pcrt_quit(); + } }
\ No newline at end of file diff --git a/src/user/raleigh/w/entry.cpp b/src/user/raleigh/w/entry.cpp index 3053413..54535cc 100644 --- a/src/user/raleigh/w/entry.cpp +++ b/src/user/raleigh/w/entry.cpp @@ -1,274 +1,210 @@ +#include <raleigh/s/text_flower.h> #include <raleigh/w/entry.h> -#include <knob/format.h> -#include <knob/block.h> -#include <knob/heap.h> -#include <knob/key.h> namespace raleigh { - 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, s, cl); - data[cl] = '\0'; - - line_indices[0] = 0; - get_indices(0, 0, 0); - 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) { + const struct font_info *fi, _pixel_t bg, _pixel_t fg, + _pixel_t border_color) + : fi(fi), border_color(border_color), fg(fg), bg(bg), rows(rows), + cols(cols), text_back(default_text, strlen(default_text) + 1), + flower(text_back.buf, cols, rows) { size = coord(fi->space_width * (cols - 1) + fi->char_width + 6, - fi->space_height * (rows - 1) + fi->char_height + 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) { - while (1) { - const uint32_t ln = str_find_any(data + from_d, " \n"); - bool quit_after = !data[from_d + ln]; - if ((from_x + ln <= cols) || (ln >= cols)) { - from_x += ln; - from_d += ln; - if (data[from_d] == '\n') { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d + 1; - } - else - ++from_x; - ++from_d; - if (from_x >= cols) { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d; - } - if (quit_after) - break; - } - else { - ++from_y; - from_x = 0; - line_indices[from_y] = from_d; - } - } - line_indices[from_y + 1] = from_d; - end_y = from_y; - end_x = from_x; - end_d = from_d; + __attribute__ ((pure)) + const char *entry::get_contents() { + return text_back.buf; } - void entry::notify_window_change() {} - - void entry::paint_text(_pixel_t *pixbuf, uint32_t pitch) { - for (uint32_t y = 0; y <= end_y; ++y) { - const char *const line = data + line_indices[y]; - const uint32_t len = line_indices[y + 1] - line_indices[y] >= cols ? cols : line_indices[y + 1] - line_indices[y]; - for (uint32_t x = 0; x < len; ++x) - if ((line[x] != '\n') && line[x]) - put_char_no_bg(fi, line[x], pixbuf + (window_offset.y + 3 + y * fi->space_height) * pitch + (window_offset.x + 3 + x * fi->space_width), pitch, fg); - } + void entry::set_contents(const char *s) { + text_back.copy_from(s, strlen(s) + 1); + on_text_change(); } void entry::paint(_pixel_t *pixbuf, uint32_t pitch) { - _pixel_t *const cur_ptr = pixbuf + (window_offset.y + 3 + cur_y * fi->space_height) * pitch + (window_offset.x + 3 + cur_x * fi->space_width); - _pixel_t *const old_cur_ptr = pixbuf + (window_offset.y + 3 + cur_y_last_paint * fi->space_height) * pitch + (window_offset.x + 3 + cur_x_last_paint * fi->space_width); - if (next_paint_full) { - next_paint_full = false; - - for (uint32_t x = 0; x < size.x; ++x) { - pixbuf[(window_offset.y) * pitch + window_offset.x + x] = border_color; - pixbuf[(window_offset.y + size.y - 1) * pitch + window_offset.x + x] = border_color; + for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) { + pixbuf[window_offset.y * pitch + x] = border_color; + pixbuf[(window_offset.y + size.y - 1) * pitch + x] = border_color; } - for (uint32_t y = 1; y < size.y - 1; ++y) { - pixbuf[(window_offset.y + y) * pitch + window_offset.x] = border_color; - pixbuf[(window_offset.y + y) * pitch + window_offset.x + size.x - 1] = border_color; + for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y) { + pixbuf[y * pitch + window_offset.x] = border_color; + pixbuf[y * pitch + window_offset.x + size.x - 1] = border_color; } + for (uint32_t y = window_offset.y + 1; y < window_offset.y + size.y - 1; ++y) + for (uint32_t x = window_offset.x + 1; x < window_offset.x + size.x - 1; ++x) + pixbuf[y * pitch + x] = bg; + } - for (uint32_t y = 1; y < size.y - 1; ++y) - for (uint32_t x = 1; x < size.x - 1; ++x) - pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg; - - paint_text(pixbuf, pitch); + if (next_paint_full || text_change) { + for (uint32_t y = window_offset.y + 3; y < window_offset.y + size.y - 3; ++y) + for (uint32_t x = window_offset.x + 3; x < window_offset.x + size.x - 3; ++x) + pixbuf[y * pitch + x] = bg; + flower.draw_text(pixbuf + (window_offset.y + 3) * pitch + window_offset.x + 3, pitch, fi, fg); } - else if (text_changed_since_last_paint) { - for (uint32_t y = 3; y < size.y - 3; ++y) - for (uint32_t x = 3; x < size.x - 3; ++x) - pixbuf[(window_offset.y + y) * pitch + (window_offset.x + x)] = bg; - paint_text(pixbuf, pitch); - text_changed_since_last_paint = false; + else if ((cursor_change || !is_cur) && was_cur_before) { + const uint32_t y_start = window_offset.y + 3 + fi->space_height * old_cur_y; + const uint32_t x_start = window_offset.x + 3 + fi->space_width * old_cur_x; + if (old_cur_x == cols) + for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) { + pixbuf[y * pitch + x_start] = bg; + pixbuf[y * pitch + x_start + 1] = bg; + } + else + put_char(fi, flower.get_nth_line(old_cur_y)[old_cur_x], + pixbuf + y_start * pitch + x_start, pitch, bg, fg); } - else if (had_focus_last_paint) { - for (uint32_t y = 0; y < fi->char_height; ++y) { - old_cur_ptr[y * pitch] = bg; - old_cur_ptr[y * pitch + 1] = bg; - } - if (data[cur_d_last_paint] && (data[cur_d_last_paint] != '\n') && (cur_d_last_paint < line_indices[cur_y_last_paint + 1])) - put_char_no_bg(fi, data[cur_d_last_paint], old_cur_ptr, pitch, fg); + if (is_cur) { + const uint32_t y_start = window_offset.y + 3 + fi->space_height * cur_y; + const uint32_t x_start = window_offset.x + 3 + fi->space_width * cur_x; + if (old_cur_x == cols) + for (uint32_t y = y_start; y < y_start + fi->char_height; ++y) { + pixbuf[y * pitch + x_start] = fg; + pixbuf[y * pitch + x_start + 1] = fg; + } } - if (has_focus) - for (uint32_t y = 0; y < fi->char_height; ++y) { - cur_ptr[y * pitch] = fg; - cur_ptr[y * pitch + 1] = fg; - } + next_paint_full = false; + text_change = false; + cursor_change = false; - cur_y_last_paint = cur_y; - cur_x_last_paint = cur_x; - cur_d_last_paint = cur_d; - had_focus_last_paint = has_focus; + was_cur_before = is_cur; + old_cur_x = cur_x; + old_cur_y = cur_y; } - void entry::ensure_cursor_in_line() { - cur_d = line_indices[cur_y] + cur_x; - if (cur_d >= line_indices[cur_y + 1]) { - cur_d = line_indices[cur_y + 1] - 1; - if (data[cur_d] && (data[cur_d] != '\n')) - ++cur_d; - cur_x = cur_d - line_indices[cur_y]; - } - } + void entry::notify_has_opaque_parent(widget *parent) {} void entry::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) { if (up || (click_type != mouse_packet::LEFT)) return; - if (window_coords.x - window_offset.x < 3) - window_coords.x = 3 + window_offset.x; - else if (window_coords.x - window_offset.x > size.x - 4) - window_coords.x = size.x - 4 + window_offset.x; - if (window_coords.y - window_offset.y < 3) - window_coords.y = 3 + window_offset.y; - else if (window_coords.y - window_offset.y > size.y - 4) - window_coords.y = size.y - 4 + window_offset.y; + if (window_coords.x < window_offset.x) + window_coords.x = window_offset.x; + if (window_coords.y < window_offset.y) + window_coords.y = window_offset.y; - cur_y = (window_coords.y - window_offset.y - 3) / fi->space_height; - cur_x = (window_coords.x - window_offset.x - 3) / fi->space_width; - if (cur_y > end_y) { - cur_y = end_y; - cur_x = end_x; - } - ensure_cursor_in_line(); + cur_x = (window_coords.x - window_offset.x) / fi->space_width; + cur_y = (window_coords.y - window_offset.y) / fi->space_height; - if (has_focus) - w->notify_needs_paint(*this); - else - w->focus(*this); + check_y(); + check_x(); + on_cursor_change(); } - void entry::notify_has_opaque_parent(widget *parent) {} + void entry::check_y() { + if (cur_y >= flower.get_n_lines()) + cur_y = flower.get_n_lines() - 1; + } - bool entry::cursor_left() { - if (cur_x) { - --cur_x; - --cur_d; - return true; - } - if (!cur_y) - return false; + void entry::check_x() { + if (cur_x > strlen(flower.get_nth_line(cur_y))) + cur_x = strlen(flower.get_nth_line(cur_y)); + } - --cur_y; - cur_x = line_indices[cur_y + 1] - line_indices[cur_y] - 1; - if (cur_x == cols) - --cur_x; - cur_d = line_indices[cur_y] + cur_x; - return true; + void entry::on_text_change() { + flower.s = text_back.buf; + flower.flow_text(); + text_change = true; + w->notify_needs_paint(*this); } - bool entry::cursor_right() { - if (cur_d >= (end_d - 1)) - return false; + void entry::on_cursor_change() { + cursor_change = true; + w->notify_needs_paint(*this); + } - ++cur_d; - ++cur_x; + void entry::handle_key(struct key_packet kp) { + const uint32_t pos = flower.get_line_offset(cur_y) + cur_x; + const char ch = key_to_char(kp); + + if (kp.key_id == kp.KEY_BSPACE) { + if (pos) { + text_back.remove(pos - 1); + left(); + on_text_change(); + } + } - if (cur_d >= line_indices[cur_y + 1]) { - cur_x = 0; - ++cur_y; - cur_d = line_indices[cur_y]; + else if (kp.key_id == kp.KEY_DELETE) { + if (pos != text_back.n_entries - 1) { + text_back.remove(pos); + on_text_change(); + } } - return true; + else if (kp.key_id == kp.KEY_LEFT_ARROW) + left(); + else if (kp.key_id == kp.KEY_RIGHT_ARROW) + right(); + else if (kp.key_id == kp.KEY_UP_ARROW) + up(); + else if (kp.key_id == kp.KEY_DOWN_ARROW) + down(); + + else if (ch) { + text_back.insert(pos, ch); + on_text_change(); + } } - bool entry::cursor_up() { - if (!cur_y) - return false; - - --cur_y; - ensure_cursor_in_line(); - return true; + void entry::left() { + if (cur_x) + --cur_x; + else if (cur_y) { + --cur_y; + check_x(); + } + else + return; + on_cursor_change(); } - bool entry::cursor_down() { - if (cur_y == end_y) - return false; + void entry::right() { + if (++cur_x <= strlen(flower.get_nth_line(cur_y))) + on_cursor_change(); + else if (cur_y != flower.get_n_lines()) { + ++cur_y; + cur_x = 0; + on_cursor_change(); + } + } - ++cur_y; - ensure_cursor_in_line(); - return true; + void entry::up() { + if (cur_y) { + --cur_y; + check_x(); + on_cursor_change(); + } + else if (!cur_x) { + cur_x = 0; + on_cursor_change(); + } } - void entry::handle_key(struct key_packet kp) { - switch (kp.key_id) { - case kp.KEY_LEFT_ARROW: - if (cursor_left() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_RIGHT_ARROW: - if (cursor_right() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_DOWN_ARROW: - if (cursor_down() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_UP_ARROW: - if (cursor_up() && has_focus) - w->notify_needs_paint(*this); - break; - case kp.KEY_HOME: - if (cur_x) { - cur_x = 0; - if (has_focus) - w->notify_needs_paint(*this); - } - break; - case kp.KEY_END: - cur_x = cols; - ensure_cursor_in_line(); - if (has_focus) - w->notify_needs_paint(*this); - break; - default: - break; + void entry::down() { + if (cur_y != flower.get_n_lines()) { + ++cur_y; + check_x(); + on_cursor_change(); + } + else if (cur_x < strlen(flower.get_nth_line(cur_y))) { + cur_x = strlen(flower.get_nth_line(cur_y)); + on_cursor_change(); } } void entry::on_focus() { - has_focus = true; + is_cur = true; w->notify_needs_paint(*this); } void entry::on_unfocus() { - has_focus = false; + is_cur = 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/label.cpp b/src/user/raleigh/w/label.cpp index 21df2a2..e8be703 100644 --- a/src/user/raleigh/w/label.cpp +++ b/src/user/raleigh/w/label.cpp @@ -3,26 +3,36 @@ #include <knob/block.h> namespace raleigh { - label::label(const char *value, const char *font, bool bg_transparent, _pixel_t fg, _pixel_t bg) - : fi(get_font(font)), bg_transparent(bg_transparent), fg(fg), bg(bg) { + coord label::determine_size() { + uint32_t longest = 0; - v_size = strlen(value) + 1; - this->value = new char[v_size]; - blockcpy(this->value, value, v_size); - size = coord(fi->space_width * (v_size - 2) + fi->char_width, fi->char_height); + for (uint32_t i = 0; i < tf.get_n_lines(); ++i) + if (strlen(tf.get_nth_line(i)) > longest) + longest = strlen(tf.get_nth_line(i)); - closest_opaque = 0; + const int32_t width = fi->space_width * (longest - 1) + fi->char_width; + const int32_t height = fi->space_height * (tf.get_n_lines() - 1) + fi->char_height; + return coord(width < 0 ? 0 : width, height < 0 ? 0 : height); + } + + label::label(const char *value, const char *font, uint32_t cols, + bool bg_transparent, _pixel_t fg, _pixel_t bg) + : fi(get_font(font)), cols(cols), bg_transparent(bg_transparent), + fg(fg), bg(bg), tf(strdup(value), cols) { + + size = determine_size(); + closest_opaque = bg_transparent ? 0 : this; + } + + label::~label() { + free_block(tf.s); } void label::change_value(const char *new_value) { - delete[] value; - const uint32_t ns = strlen(new_value) + 1; - if (ns != v_size) { - v_size = ns; - value = new char[ns]; - set_size(coord(fi->space_width * (ns - 2) + fi->char_width, fi->char_height)); - } - blockcpy(value, new_value, ns); + free_block(tf.s); + tf.s = strdup(new_value); + tf.flow_text(); + set_size(determine_size()); w->notify_needs_paint(*this); } @@ -31,14 +41,11 @@ namespace raleigh { for (uint32_t y = window_offset.y; y < window_offset.y + size.y; ++y) for (uint32_t x = window_offset.x; x < window_offset.x + size.x; ++x) pixbuf[y * pitch + x] = bg; - _pixel_t *ptr = pixbuf + window_offset.y * pitch + window_offset.x; - for (const char *c = value; *c; ++c) { - put_char_no_bg(fi, *c, ptr, pitch, fg); - ptr += fi->space_width; - } + tf.draw_text(pixbuf + window_offset.y * pitch + window_offset.x, pitch, fi, fg); } void label::notify_has_opaque_parent(widget *parent) { - closest_opaque = parent; + if (bg_transparent) + closest_opaque = parent; } }
\ No newline at end of file diff --git a/src/user/raleigh/window.cpp b/src/user/raleigh/window.cpp index 5fa82c3..607b58e 100644 --- a/src/user/raleigh/window.cpp +++ b/src/user/raleigh/window.cpp @@ -74,7 +74,13 @@ namespace raleigh { } void window::paint_full() { - for (uint32_t i = 0; i < size.x * size.y; ++i) + //syslogf("paint_full called with"); + //syslogf(" pixbuf = 0x%x", pixbuf); + //syslogf(" size.x = %u", size.x); + //syslogf(" size.y = %u", size.y); + + const uint32_t n = size.x * size.y; + for (uint32_t i = 0; i < n; ++i) pixbuf[i] = bg_color; root.next_paint_full = true; root.paint(pixbuf, size.x); |