summaryrefslogtreecommitdiff
path: root/src/user/raleigh/w/entry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/raleigh/w/entry.cpp')
-rw-r--r--src/user/raleigh/w/entry.cpp215
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