diff options
Diffstat (limited to 'src/user/raleigh/w/entry.cpp')
-rw-r--r-- | src/user/raleigh/w/entry.cpp | 215 |
1 files changed, 170 insertions, 45 deletions
diff --git a/src/user/raleigh/w/entry.cpp b/src/user/raleigh/w/entry.cpp index de8bd82..1c6f91e 100644 --- a/src/user/raleigh/w/entry.cpp +++ b/src/user/raleigh/w/entry.cpp @@ -2,55 +2,76 @@ #include <knob/format.h> #include <knob/block.h> #include <knob/heap.h> +#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]), first_paint(true) { - size = coord(fi->space_width * (cols - 1) + fi->char_width + 6, fi->space_height * (rows - 1) + fi->char_height + 6); + line_indices(new uint32_t[rows + 1]), first_paint(true), + 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; - end_x = 0; - end_y = 0; + const uint32_t l = strlen(default_text); + const uint32_t cl = l > rows * cols - 1 ? rows * cols - 1 : l; + blockcpy(data, default_text, cl); + data[cl] = '\0'; + line_indices[0] = 0; - for (end_d = 0; default_text[end_d]; ++end_d) { - if (end_d == rows * cols - 1) - break; - data[end_d] = default_text[end_d]; - if ((default_text[end_d] == '\n') || (++end_x == cols)) { - if (end_y == rows - 1) - break; - line_indices[++end_y] = end_d + 1; - end_x = 0; - } - } - line_indices[end_y + 1] = end_d; + get_indices(0, 0, 0); cur_x = end_x; cur_y = end_y; cur_d = end_d; - data[end_d] = '\0'; } - void entry::notify_window_change() {} - - void entry::paint_text(_pixel_t *pixbuf, uint32_t pitch) { - uint32_t y = 0; - uint32_t x = -1; - for (const char *i = data; *i; ++i) { - if (*i == '\n') { - ++y; - x = -1; + 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 { - if (++x == cols) { - ++y; - x = 0; - } - put_char_no_bg(fi, *i, pixbuf + (window_offset.y + 3 + y * fi->space_height) * pitch + (window_offset.x + 3 + x * fi->space_width), pitch, fg); + ++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; + } + + 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::paint(_pixel_t *pixbuf, uint32_t pitch) { @@ -83,28 +104,40 @@ namespace raleigh { text_changed_since_last_paint = false; } - else { + 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')) + 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); } - for (uint32_t y = 0; y < fi->char_height; ++y) { - cur_ptr[y * pitch] = fg; - cur_ptr[y * pitch + 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; + } cur_y_last_paint = cur_y; cur_x_last_paint = cur_x; cur_d_last_paint = cur_d; + had_focus_last_paint = has_focus; + } + + 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]; + } } - bool entry::try_handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) { + void entry::handle_click(coord window_coords, enum mouse_packet::mouse_button click_type, bool up) { if (up || (click_type != mouse_packet::LEFT)) - return false; + return; if (window_coords.x - window_offset.x < 3) window_coords.x = 3 + window_offset.x; @@ -121,18 +154,110 @@ namespace raleigh { cur_y = end_y; cur_x = end_x; } + ensure_cursor_in_line(); + + if (has_focus) + w->notify_needs_paint(*this); + else + w->focus(*this); + } + + void entry::notify_has_opaque_parent(widget *parent) {} + + bool entry::cursor_left() { + if (cur_x) { + --cur_x; + --cur_d; + return true; + } + if (!cur_y) + return false; + + --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; + } + + bool entry::cursor_right() { + if (cur_d >= (end_d - 1)) + return false; + + ++cur_d; + ++cur_x; if (cur_d >= line_indices[cur_y + 1]) { - cur_d = line_indices[cur_y + 1] - 1; - if (data[cur_d] != '\n') - ++cur_d; - cur_x = cur_d - line_indices[cur_y]; + cur_x = 0; + ++cur_y; + cur_d = line_indices[cur_y]; } - w->notify_needs_paint(*this); return true; } - void entry::notify_has_opaque_parent(widget *parent) {} + bool entry::cursor_up() { + if (!cur_y) + return false; + + --cur_y; + ensure_cursor_in_line(); + return true; + } + + bool entry::cursor_down() { + if (cur_y == end_y) + return false; + + ++cur_y; + ensure_cursor_in_line(); + return true; + } + + 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::on_focus() { + has_focus = true; + w->notify_needs_paint(*this); + } + + void entry::on_unfocus() { + has_focus = false; + w->notify_needs_paint(*this); + } }
\ No newline at end of file |