From 4cad82db9f907fb8ffd42303527a976ca226cedd Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 12:46:33 +0000 Subject: Fix caret placement in multi-line textareas. --- desktop/textarea.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 31effdc3c..0f42a9f30 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -1058,12 +1058,12 @@ void textarea_redraw(struct textarea *ta, int x, int y, /* There is no selection and caret is in horizontal * clip range. */ int caret_height = ta->line_height - 1; - y += ta->caret_y + text_y_offset; - if (y + caret_height >= clip->y0 && y <= clip->y1) + r.y0 = y + ta->caret_y + text_y_offset; + if (r.y0 + caret_height >= clip->y0 && r.y0 <= clip->y1) /* Caret in vertical clip range; plot */ - plot->line(x + ta->caret_x, y + ta->caret_y, + plot->line(x + ta->caret_x, r.y0, x + ta->caret_x, - y + ta->caret_y + caret_height, + r.y0 + caret_height, &pstyle_stroke_caret); } } @@ -1082,7 +1082,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) line = ta->caret_pos.line; readonly = (ta->flags & TEXTAREA_READONLY ? true:false); - if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) { /* normal character insertion */ length = utf8_from_ucs4(key, utf8); -- cgit v1.2.3 From eddb0f17d183cec2013d23e613e70cc03345e57f Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 15:06:05 +0000 Subject: Simplfy caret placement and redraw. --- desktop/textarea.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 0f42a9f30..79b1ed436 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -831,9 +831,9 @@ bool textarea_set_caret(struct textarea *ta, int caret) b_off - ta->lines[ta->caret_pos.line].b_start, &x); - x += MARGIN_LEFT - ta->scroll_x; + x += MARGIN_LEFT; ta->caret_x = x; - y = ta->line_height * ta->caret_pos.line - ta->scroll_y; + y = ta->line_height * ta->caret_pos.line; ta->caret_y = y; if (textarea_scroll_visible(ta)) { @@ -1051,20 +1051,17 @@ void textarea_redraw(struct textarea *ta, int x, int y, &ta->fstyle); } - if ((ta->sel_end == -1 || - ta->sel_start == ta->sel_end) && - x + ta->caret_x >= clip->x0 && - x + ta->caret_x <= clip->x1) { - /* There is no selection and caret is in horizontal - * clip range. */ - int caret_height = ta->line_height - 1; - r.y0 = y + ta->caret_y + text_y_offset; - if (r.y0 + caret_height >= clip->y0 && r.y0 <= clip->y1) - /* Caret in vertical clip range; plot */ - plot->line(x + ta->caret_x, r.y0, - x + ta->caret_x, - r.y0 + caret_height, - &pstyle_stroke_caret); + x -= ta->scroll_x; + y -= ta->scroll_y; + + if (ta->sel_end == -1 || ta->sel_start == ta->sel_end) { + /* There is no selection; draw caret */ + int caret_y = y + ta->caret_y + text_y_offset; + int caret_height = caret_y + ta->line_height - 1; + + plot->line(x + ta->caret_x, caret_y, + x + ta->caret_x, caret_height, + &pstyle_stroke_caret); } } -- cgit v1.2.3 From 2158ef60a871a434450021fd5588820ff93fbefa Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 17:42:43 +0000 Subject: Improve reflow in multiline textareas. --- desktop/textarea.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 79b1ed436..e5f140dfa 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -335,6 +335,12 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) ta->vis_width - MARGIN_LEFT - MARGIN_RIGHT, &b_off, &x); + if (b_off == 0) { + /* Text wasn't split */ + b_off = len; + } + /* b_off now marks space, or end of text */ + if (line_count > 0 && line_count % LINE_CHUNK_SIZE == 0) { struct line_info *temp = realloc(ta->lines, (line_count + LINE_CHUNK_SIZE) * @@ -352,8 +358,9 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) if (*space == '\n') break; } + /* space now marks newline, or b_off -- whichever's first */ - if (space <= text + b_off) { + if (space < text + b_off) { /* Found newline; use it */ ta->lines[line_count].b_start = text - ta->text; ta->lines[line_count++].b_length = space - text; @@ -368,10 +375,9 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) } continue; - } - if (len - b_off > 0) { - /* find last space (if any) */ + } else if (len - b_off > 0) { + /* soft wraped, find last space (if any) */ for (space = text + b_off; space > text; space--) if (*space == ' ') break; -- cgit v1.2.3 From d3973b29917e049198badebf65f9e6290734b883 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 18:36:25 +0000 Subject: Fix previous caret position redraw. --- desktop/textarea.c | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index e5f140dfa..828503f69 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -568,7 +568,7 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start, diff = end - start; /* find byte offset of replace start */ - for (b_start = 0; start-- > 0; + for (b_start = 0; start > 0; b_start = utf8_next(ta->text, ta->text_len, b_start)) ; /* do nothing */ @@ -608,7 +608,7 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start, /* Insert new text */ memcpy(ta->text + b_start, rep, rep_len); - ta->text_len += rep_len - (b_end - b_start); + ta->text_len += (int)rep_len - (b_end - b_start); ta->text_utf8_len = utf8_length(ta->text); textarea_normalise_text(ta, b_start, rep_len); @@ -763,36 +763,8 @@ bool textarea_set_caret(struct textarea *ta, int caret) /* Delete the old caret */ if (ta->caret_pos.char_off != -1) { - index = textarea_get_caret(ta); - if (index == -1) - return false; - - /* the redraw might happen in response to a text-change and - the caret position might be beyond the current text */ - if ((unsigned)index > c_len) - index = c_len; - - /* find byte offset of caret position */ - for (b_off = 0; index-- > 0; - b_off = utf8_next(ta->text, - ta->text_len, b_off)) - ; /* do nothing */ - - nsfont.font_width(&ta->fstyle, - ta->text + - ta->lines[ta->caret_pos.line].b_start, - b_off - ta->lines[ta->caret_pos.line].b_start, - &x); - - x += MARGIN_LEFT - ta->scroll_x; - - y = ta->line_height * ta->caret_pos.line - ta->scroll_y; - - /* set the caret coordinate beyond the redraw rectangle */ - ta->caret_x = x - 2; - - x0 = x - 1; - y0 = y + text_y_offset; + x0 = ta->caret_x - ta->scroll_x; + y0 = ta->caret_y - ta->scroll_y; width = 2; height = ta->line_height; -- cgit v1.2.3 From 694c1e7eeadccd40017ca22a95136f3895347ddf Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 18:42:56 +0000 Subject: Fix silly. --- desktop/textarea.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 828503f69..9cec5b0d3 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -568,7 +568,7 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start, diff = end - start; /* find byte offset of replace start */ - for (b_start = 0; start > 0; + for (b_start = 0; start-- > 0; b_start = utf8_next(ta->text, ta->text_len, b_start)) ; /* do nothing */ -- cgit v1.2.3 From ab5d165659d0867213217f81794d985efa5d87c1 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 19:43:22 +0000 Subject: More wrap behaviour improvement. --- desktop/textarea.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 9cec5b0d3..a12ed3282 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -301,7 +301,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) unsigned int len; size_t b_off; int x; - char *space; + char *space, *para_end; unsigned int line_count = 0; /** \todo pay attention to line parameter */ @@ -331,15 +331,22 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) for (len = ta->text_len - 1, text = ta->text; len > 0; len -= b_off, text += b_off) { - nsfont.font_split(&ta->fstyle, text, len, + /* Find end of paragraph */ + for (para_end = text; para_end < text + len; para_end++) { + if (*para_end == '\n') + break; + } + + /* Wrap current line in paragraph */ + nsfont.font_split(&ta->fstyle, text, para_end - text, ta->vis_width - MARGIN_LEFT - MARGIN_RIGHT, &b_off, &x); if (b_off == 0) { /* Text wasn't split */ - b_off = len; + b_off = para_end - text; } - /* b_off now marks space, or end of text */ + /* b_off now marks space, or end of paragraph */ if (line_count > 0 && line_count % LINE_CHUNK_SIZE == 0) { struct line_info *temp = realloc(ta->lines, @@ -353,19 +360,14 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) ta->lines = temp; } - /* handle LF */ - for (space = text; space <= text + b_off; space++) { - if (*space == '\n') - break; - } - /* space now marks newline, or b_off -- whichever's first */ - - if (space < text + b_off) { - /* Found newline; use it */ + if (para_end == text + b_off && *para_end == '\n') { + /* Not found any spaces to wrap at, and we + * have a newline char */ ta->lines[line_count].b_start = text - ta->text; - ta->lines[line_count++].b_length = space - text; + ta->lines[line_count++].b_length = para_end - text; - b_off = space + 1 - text; + /* Jump newline */ + b_off++; if (len - b_off == 0) { /* reached end of input => add last line */ -- cgit v1.2.3 From ac89e5210918839b5d29cc0f030a79636b900e76 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 23:20:42 +0000 Subject: Simplify routine to scroll ta so that caret is visible. --- desktop/textarea.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index a12ed3282..0d0542ed6 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -238,7 +238,6 @@ static bool textarea_select_fragment(struct textarea * ta) static bool textarea_scroll_visible(struct textarea *ta) { int x0, x1, y0, y1, x, y; - int index, b_off; bool scrolled = false; if (ta->caret_pos.char_off == -1) @@ -249,21 +248,8 @@ static bool textarea_scroll_visible(struct textarea *ta) y0 = 0; y1 = ta->vis_height; - index = textarea_get_caret(ta); - - /* find byte offset of caret position */ - for (b_off = 0; index-- > 0; - b_off = utf8_next(ta->text, ta->text_len, b_off)) - ; /* do nothing */ - - nsfont.font_width(&ta->fstyle, - ta->text + ta->lines[ta->caret_pos.line].b_start, - b_off - ta->lines[ta->caret_pos.line].b_start, - &x); - - /* top-left of caret */ - x += MARGIN_LEFT - ta->scroll_x; - y = ta->line_height * ta->caret_pos.line - ta->scroll_y; + x = ta->caret_x - ta->scroll_x; + y = ta->caret_y - ta->scroll_y; /* check and change vertical scroll */ if (y < y0) { -- cgit v1.2.3 From ac03806a50f292fc13930a2fdb3c8744bcaa954a Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 10 Jan 2013 23:21:47 +0000 Subject: Fix redraw of caret when scroll offsets are non-zero, only caret has moved, and we're not getting a full textarea redraw. --- desktop/textarea.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 0d0542ed6..16c2f4616 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -803,10 +803,14 @@ bool textarea_set_caret(struct textarea *ta, int caret) ta->caret_y = y; if (textarea_scroll_visible(ta)) { + /* Scrolled; redraw everything */ ta->redraw_request(ta->data, 0, 0, ta->vis_width, ta->vis_height); } else { + /* Just caret moved, redraw it */ + x -= ta->scroll_x; + y -= ta->scroll_y; x0 = max(x - 1, MARGIN_LEFT); y0 = max(y + text_y_offset, 0); x1 = min(x + 1, ta->vis_width - MARGIN_RIGHT); -- cgit v1.2.3 From 5124b8a02a2adb72a7352f14e06dc2a773afbc1f Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sat, 12 Jan 2013 20:46:01 +0000 Subject: Add textarea_setup struct to textarea_create API. --- desktop/textarea.c | 43 +++++++++++++++++++++++++++++++++---------- desktop/textarea.h | 23 +++++++++++++++++++++-- desktop/tree.c | 20 ++++++++++++++++++-- 3 files changed, 72 insertions(+), 14 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 16c2f4616..3ab8c5af5 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -75,6 +75,17 @@ struct textarea { int vis_width; /**< Visible width, in pixels */ int vis_height; /**< Visible height, in pixels */ + int pad_top; + int pad_right; + int pad_bottom; + int pad_left; + + int border_width; + colour border_col; + + plot_font_style_t fstyle; /**< Text style */ + plot_font_style_t sel_fstyle; /**< Text style */ + char *text; /**< UTF-8 text */ unsigned int text_alloc; /**< Size of allocated text */ unsigned int text_len; /**< Length of text, in bytes */ @@ -92,8 +103,6 @@ struct textarea { int sel_start; /**< Character index of sel start(inclusive) */ int sel_end; /**< Character index of sel end(exclusive) */ - plot_font_style_t fstyle; /**< Text style */ - int line_count; /**< Count of lines */ #define LINE_CHUNK_SIZE 16 struct line_info *lines; /**< Line info array */ @@ -608,8 +617,7 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start, /* exported interface, documented in textarea.h */ -struct textarea *textarea_create(int width, int height, - textarea_flags flags, const plot_font_style_t *style, +struct textarea *textarea_create(const textarea_setup *setup, textarea_redraw_request_callback redraw_request, void *data) { struct textarea *ret; @@ -627,14 +635,30 @@ struct textarea *textarea_create(int width, int height, ret->redraw_request = redraw_request; ret->data = data; - ret->vis_width = width; - ret->vis_height = height; + + ret->flags = setup->flags; + ret->vis_width = setup->width; + ret->vis_height = setup->height; + + ret->pad_top = setup->pad_top; + ret->pad_right = setup->pad_right; + ret->pad_bottom = setup->pad_bottom; + ret->pad_left = setup->pad_left; + + ret->border_width = setup->border_width; + ret->border_col = setup->border_col; + + ret->fstyle = setup->text; + + ret->sel_fstyle = setup->text; + ret->sel_fstyle.foreground = setup->selected_text; + ret->sel_fstyle.background = setup->selected_bg; + ret->scroll_x = 0; ret->scroll_y = 0; ret->drag_start_char = 0; - ret->flags = flags; ret->text = malloc(64); if (ret->text == NULL) { LOG(("malloc failed")); @@ -646,11 +670,10 @@ struct textarea *textarea_create(int width, int height, ret->text_len = 1; ret->text_utf8_len = 0; - ret->fstyle = *style; - ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, - INTTOFIX((style->size / FONT_SIZE_SCALE))))), F_72)); + INTTOFIX((setup->text.size / + FONT_SIZE_SCALE))))), F_72)); ret->caret_pos.line = ret->caret_pos.char_off = 0; ret->caret_x = MARGIN_LEFT; diff --git a/desktop/textarea.h b/desktop/textarea.h index e4fa2c7aa..a798e7c9f 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -36,6 +36,26 @@ typedef enum textarea_flags { TEXTAREA_READONLY = (1 << 2) } textarea_flags; +typedef struct textarea_setup { + textarea_flags flags; + + int width; + int height; + + int pad_top; + int pad_right; + int pad_bottom; + int pad_left; + + int border_width; + colour border_col; + + colour selected_text; + colour selected_bg; + plot_font_style_t text; + +} textarea_setup; + struct textarea; @@ -54,8 +74,7 @@ typedef void(*textarea_redraw_request_callback)(void *data, int x, int y, * \param data user specified data which will be passed to redraw callbacks * \return Opaque handle for textarea or 0 on error */ -struct textarea *textarea_create(int width, int height, - textarea_flags flags, const plot_font_style_t *style, +struct textarea *textarea_create(const textarea_setup *setup, textarea_redraw_request_callback redraw_request, void *data); /** diff --git a/desktop/tree.c b/desktop/tree.c index 250bdd861..df2e9263f 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -2935,6 +2935,7 @@ void tree_start_edit(struct tree *tree, struct node_element *element) { struct node *parent; int width, height; + textarea_setup ta_setup; assert(tree != NULL); assert(element != NULL); @@ -2959,8 +2960,23 @@ void tree_start_edit(struct tree *tree, struct node_element *element) if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON) width -= NODE_INSTEP; - tree->textarea = textarea_create(width, height, TEXTAREA_DEFAULT, - &plot_fstyle, tree_textarea_redraw_request, tree); + ta_setup.flags = TEXTAREA_DEFAULT; + ta_setup.width = width; + ta_setup.height = height; + ta_setup.pad_top = 0; + ta_setup.pad_right = 4; + ta_setup.pad_bottom = 0; + ta_setup.pad_left = 4; + ta_setup.border_width = 1; + ta_setup.border_col = 0x000000; + ta_setup.selected_text = 0xffffff; + ta_setup.selected_bg = 0x000000; + ta_setup.text = plot_fstyle; + ta_setup.text.foreground = 0x000000; + ta_setup.text.background = 0xffffff; + + tree->textarea = textarea_create(&ta_setup, + tree_textarea_redraw_request, tree); if (tree->textarea == NULL) { tree_stop_edit(tree, false); return; -- cgit v1.2.3 From c7a37392e49deb5007dc3679e0aa7e65b4ff0c8b Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sat, 12 Jan 2013 20:59:32 +0000 Subject: Add background colour to textarea_redraw API. Add source comments. --- desktop/textarea.c | 2 +- desktop/textarea.h | 46 +++++++++++++++++++++------------------------- desktop/tree.c | 5 ++++- 3 files changed, 26 insertions(+), 27 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 3ab8c5af5..9b14773cf 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -874,7 +874,7 @@ int textarea_get_caret(struct textarea *ta) /* exported interface, documented in textarea.h */ -void textarea_redraw(struct textarea *ta, int x, int y, +void textarea_redraw(struct textarea *ta, int x, int y, colour bg, const struct rect *clip, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; diff --git a/desktop/textarea.h b/desktop/textarea.h index a798e7c9f..641d39c73 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -37,22 +37,22 @@ typedef enum textarea_flags { } textarea_flags; typedef struct textarea_setup { - textarea_flags flags; + textarea_flags flags; /**< Setup flags */ - int width; - int height; + int width; /**< Textarea width */ + int height; /**< Textarea height */ - int pad_top; - int pad_right; - int pad_bottom; - int pad_left; + int pad_top; /**< Textarea top padding */ + int pad_right; /**< Textarea right padding */ + int pad_bottom; /**< Textarea bottom padding */ + int pad_left; /**< Textarea left padding */ - int border_width; - colour border_col; + int border_width; /**< Textarea border width */ + colour border_col; /**< Textarea border colour */ - colour selected_text; - colour selected_bg; - plot_font_style_t text; + colour selected_text; /**< Textarea selected text colour */ + colour selected_bg; /**< Textarea selection background colour */ + plot_font_style_t text; /**< Font and textarea background colour */ } textarea_setup; @@ -65,13 +65,9 @@ typedef void(*textarea_redraw_request_callback)(void *data, int x, int y, /** * Create a text area * - * \param width width of the text area - * \param height width of the text area - * \param flags text area flags - * \param style font style - * \param redraw_start_callback will be called when textarea wants to redraw - * \param redraw_end_callback will be called when textarea finisjes redrawing - * \param data user specified data which will be passed to redraw callbacks + * \param setup textarea settings and style + * \param redraw_callback will be called when textarea wants to redraw + * \param data user specified data which will be passed to callbacks * \return Opaque handle for textarea or 0 on error */ struct textarea *textarea_create(const textarea_setup *setup, @@ -125,14 +121,14 @@ int textarea_get_caret(struct textarea *ta); /** * Handle redraw requests for text areas * - * \param redraw Redraw request block - * \param x0 left X coordinate of redraw area - * \param y0 top Y coordinate of redraw area - * \param x1 right X coordinate of redraw area - * \param y1 bottom Y coordinate of redraw area + * \param ta textarea to render + * \param x x coordinate of textarea top + * \param y y coordinate of textarea left + * \param bg background colour under textarea + * \param clip clip rectangle * \param ctx current redraw context */ -void textarea_redraw(struct textarea *ta, int x, int y, +void textarea_redraw(struct textarea *ta, int x, int y, colour bg, const struct rect *clip, const struct redraw_context *ctx); /** diff --git a/desktop/tree.c b/desktop/tree.c index df2e9263f..a48b615a0 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -2078,7 +2078,10 @@ void tree_draw(struct tree *tree, int x, int y, y = y + tree->editing->box.y; if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON) x += NODE_INSTEP; - textarea_redraw(tree->textarea, x, y, &clip, &new_ctx); + textarea_redraw(tree->textarea, x, y, + plot_style_fill_tree_background. + fill_colour, + &clip, &new_ctx); } } -- cgit v1.2.3 From 740559ab52c0f7cf4123eddd4a1d96196843a8cb Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sun, 13 Jan 2013 14:51:26 +0000 Subject: Rewrite redraw to handle selection properly. (Now text can change colour inside selection, rather than just rendering a rectangle under the normal line of text. This removes colour restrictions, allowing e.g. inversion for selected text.) --- desktop/textarea.c | 197 ++++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 93 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 9b14773cf..606618c6e 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -38,16 +38,9 @@ #define MARGIN_RIGHT 4 #define CARET_COLOR 0x0000FF /* background color for readonly textarea */ -#define READONLY_BG 0xD9D9D9 -#define BACKGROUND_COL 0xFFFFFF #define BORDER_COLOR 0x000000 #define SELECTION_COL 0xFFDDDD -static plot_style_t pstyle_fill_selection = { - .fill_type = PLOT_OP_TYPE_SOLID, - .fill_colour = SELECTION_COL, -}; - static plot_style_t pstyle_stroke_border = { .stroke_type = PLOT_OP_TYPE_SOLID, .stroke_colour = BORDER_COLOR, @@ -878,15 +871,21 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, const struct rect *clip, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; - int line0, line1, line; - int chars, offset, text_y_offset, text_y_offset_baseline; - unsigned int c_pos, c_len, b_start, b_end, line_len; + int line0, line1, line, left, right; + int chars, text_y_offset, text_y_offset_baseline; + unsigned int c_pos, c_len, c_len_part, b_start, b_end, line_len; + unsigned int sel_start, sel_end; char *line_text; - struct rect r; - plot_style_t plot_style_fill_bg = { - .fill_type = PLOT_OP_TYPE_SOLID, - .fill_colour = BACKGROUND_COL, - }; + struct rect r, s; + bool selected = false; + plot_font_style_t *fstyle; + plot_style_t plot_style_fill_bg = { + .stroke_type = PLOT_OP_TYPE_NONE, + .stroke_width = 0, + .stroke_colour = NS_TRANSPARENT, + .fill_type = PLOT_OP_TYPE_SOLID, + .fill_colour = ta->fstyle.background + }; r = *clip; @@ -899,9 +898,6 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, /* Nothing to redraw */ return; - if (ta->flags & TEXTAREA_READONLY) - plot_style_fill_bg.fill_colour = READONLY_BG; - line0 = (r.y0 - y + ta->scroll_y) / ta->line_height - 1; line1 = (r.y1 - y + ta->scroll_y) / ta->line_height + 1; @@ -928,14 +924,13 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, plot->clip(&r); plot->rectangle(r.x0, r.y0, r.x1, r.y1, &plot_style_fill_bg); plot->rectangle(x, y, - x + ta->vis_width - 1, y + ta->vis_height - 1, - &pstyle_stroke_border); + x + ta->vis_width - 1, y + ta->vis_height - 1, + &pstyle_stroke_border); if (r.x0 < x + MARGIN_LEFT) r.x0 = x + MARGIN_LEFT; if (r.x1 > x + ta->vis_width - MARGIN_RIGHT) r.x1 = x + ta->vis_width - MARGIN_RIGHT; - plot->clip(&r); if (line0 > 0) c_pos = utf8_bounded_length(ta->text, @@ -953,97 +948,113 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, text_y_offset_baseline = (ta->vis_height * 3 + 2) / 4; } + plot_style_fill_bg.fill_colour = ta->sel_fstyle.background; + for (line = line0; (line <= line1) && (y + line * ta->line_height <= r.y1 + ta->scroll_y); line++) { if (ta->lines[line].b_length == 0) continue; + plot->clip(&r); + c_len = utf8_bounded_length( &(ta->text[ta->lines[line].b_start]), ta->lines[line].b_length); - /* if there is a newline between the lines count it too */ - if (line < ta->line_count - 1 && ta->lines[line + 1].b_start != - ta->lines[line].b_start + - ta->lines[line].b_length) - c_len++; - - /* check if a part of the line is selected, won't happen if no - selection (ta->sel_end = -1) */ - if (ta->sel_end != -1 && - c_pos < (unsigned)ta->sel_end && - c_pos + c_len > (unsigned)ta->sel_start) { + b_end = 0; + right = x + MARGIN_LEFT; + + do { + sel_start = ta->sel_start; + sel_end = ta->sel_end; + /* get length of part of line */ + if (ta->sel_end == -1 || ta->sel_end == ta->sel_start || + sel_end <= c_pos || + sel_start > c_pos + c_len) { + /* rest of line unselected */ + selected = false; + c_len_part = c_len; + fstyle = &ta->fstyle; + + } else if (sel_start <= c_pos && + sel_end > c_pos + c_len) { + /* rest of line selected */ + selected = true; + c_len_part = c_len; + fstyle = &ta->sel_fstyle; + + } else if (sel_start > c_pos) { + /* next part of line unselected */ + selected = false; + c_len_part = sel_start - c_pos; + fstyle = &ta->fstyle; + + } else if (sel_end > c_pos) { + /* next part of line selected */ + selected = true; + c_len_part = sel_end - c_pos; + fstyle = &ta->sel_fstyle; - /* offset from the beginning of the line */ - offset = ta->sel_start - c_pos; - chars = ta->sel_end - c_pos - - (offset > 0 ? offset:0); + } else { + assert(0); + } line_text = &(ta->text[ta->lines[line].b_start]); line_len = ta->lines[line].b_length; - if (offset > 0) { - - /* find byte start of the selected part */ - for (b_start = 0; offset > 0; offset--) - b_start = utf8_next(line_text, - line_len, - b_start); - nsfont.font_width(&ta->fstyle, line_text, - b_start, &r.x0); - r.x0 += x + MARGIN_LEFT; - } - else { - r.x0 = x + MARGIN_LEFT; - b_start = 0; - } - - - if (chars >= 0) { - - /* find byte end of the selected part */ - for (b_end = b_start; chars > 0 && - b_end < line_len; - chars--) { - b_end = utf8_next(line_text, line_len, - b_end); - } + /* find b_start and b_end for this part of the line */ + b_start = b_end; + + chars = c_len_part; + for (b_end = b_start; chars > 0; chars--) + b_end = utf8_next(line_text, line_len, b_end); + + /* find clip left/right for this part of line */ + left = right; + nsfont.font_width(&ta->fstyle, line_text, + b_end, &right); + right += x + MARGIN_LEFT; + + /* set clip */ + s = r; + if (s.x0 < left) + s.x0 = left; + if (s.x1 > right) + s.x1 = right; + plot->clip(&s); + + if (selected) { + /* draw selection fill */ + plot->rectangle(s.x0 - ta->scroll_x, + y + line * ta->line_height + 1 - + ta->scroll_y + text_y_offset, + s.x1 - ta->scroll_x, + y + (line + 1) * ta->line_height + 1 - + ta->scroll_y + text_y_offset, + &plot_style_fill_bg); } - else - b_end = ta->lines[line].b_length; - - b_end -= b_start; - nsfont.font_width(&ta->fstyle, - &(ta->text[ta->lines[line].b_start + - b_start]), - b_end, &r.x1); - r.x1 += r.x0; - plot->rectangle(r.x0 - ta->scroll_x, y + - line * ta->line_height + - 1 - ta->scroll_y + text_y_offset, - r.x1 - ta->scroll_x, - y + (line + 1) * ta->line_height - - 1 - ta->scroll_y + text_y_offset, - &pstyle_fill_selection); - - } - c_pos += c_len; + /* draw text */ + plot->text(x + MARGIN_LEFT - ta->scroll_x, + y + line * ta->line_height + + text_y_offset_baseline - ta->scroll_y, + ta->text + ta->lines[line].b_start, + ta->lines[line].b_length, fstyle); - r.y0 = y + line * ta->line_height + text_y_offset_baseline; + c_pos += c_len_part; + c_len -= c_len_part; - ta->fstyle.background = - (ta->flags & TEXTAREA_READONLY) ? - READONLY_BG : BACKGROUND_COL, + } while (c_pos < c_pos + c_len); - plot->text(x + MARGIN_LEFT - ta->scroll_x, - r.y0 - ta->scroll_y, - ta->text + ta->lines[line].b_start, - ta->lines[line].b_length, - &ta->fstyle); + /* if there is a newline between the lines, skip it */ + if (line < ta->line_count - 1 && ta->lines[line + 1].b_start != + ta->lines[line].b_start + + ta->lines[line].b_length) + c_pos++; } + plot->clip(&r); x -= ta->scroll_x; y -= ta->scroll_y; @@ -1099,10 +1110,10 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) case KEY_SELECT_ALL: caret = ta->text_utf8_len; - ta->sel_start = 0; + ta->sel_start = 0; ta->sel_end = ta->text_utf8_len; - redraw = true; - break; + redraw = true; + break; case KEY_COPY_SELECTION: if (ta->sel_start != -1) { if (!textarea_replace_text(ta, -- cgit v1.2.3 From 2b7bc02961a3fa251f58618b73527968cecda8ef Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sun, 13 Jan 2013 23:01:29 +0000 Subject: Implement most of the styling needed for HTML. Allow caret to be hidden. --- desktop/textarea.c | 107 ++++++++++++++++++++++++++++++----------------------- desktop/textarea.h | 2 +- 2 files changed, 62 insertions(+), 47 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 606618c6e..94d9b96c1 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -34,18 +34,7 @@ #include "utils/utf8.h" #include "utils/utils.h" -#define MARGIN_LEFT 4 -#define MARGIN_RIGHT 4 #define CARET_COLOR 0x0000FF -/* background color for readonly textarea */ -#define BORDER_COLOR 0x000000 -#define SELECTION_COL 0xFFDDDD - -static plot_style_t pstyle_stroke_border = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_colour = BORDER_COLOR, - .stroke_width = 1, -}; static plot_style_t pstyle_stroke_caret = { .stroke_type = PLOT_OP_TYPE_SOLID, @@ -245,8 +234,8 @@ static bool textarea_scroll_visible(struct textarea *ta) if (ta->caret_pos.char_off == -1) return false; - x0 = MARGIN_LEFT; - x1 = ta->vis_width - MARGIN_RIGHT; + x0 = ta->border_width + ta->pad_left; + x1 = ta->vis_width - (ta->border_width + ta->pad_left); y0 = 0; y1 = ta->vis_height; @@ -267,8 +256,8 @@ static bool textarea_scroll_visible(struct textarea *ta) if (x < x0) { ta->scroll_x -= x0 - x ; scrolled = true; - } else if (x > x1 - 1) { - ta->scroll_x += x - (x1 - 1); + } else if (x > x1) { + ta->scroll_x += x - x1; scrolled = true; } @@ -291,6 +280,10 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) int x; char *space, *para_end; unsigned int line_count = 0; + int avail_width = ta->vis_width - 2 * ta->border_width - + ta->pad_left - ta->pad_right; + if (avail_width < 0) + avail_width = 0; /** \todo pay attention to line parameter */ /** \todo create horizontal scrollbar if needed */ @@ -327,8 +320,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) /* Wrap current line in paragraph */ nsfont.font_split(&ta->fstyle, text, para_end - text, - ta->vis_width - MARGIN_LEFT - MARGIN_RIGHT, - &b_off, &x); + avail_width, &b_off, &x); if (b_off == 0) { /* Text wasn't split */ @@ -407,8 +399,8 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y, return; } - x = x - MARGIN_LEFT + ta->scroll_x; - y = y + ta->scroll_y; + x = x - ta->border_width - ta->pad_left + ta->scroll_x; + y = y - ta->border_width - ta->pad_top + ta->scroll_y; if (x < 0) x = 0; @@ -668,8 +660,8 @@ struct textarea *textarea_create(const textarea_setup *setup, INTTOFIX((setup->text.size / FONT_SIZE_SCALE))))), F_72)); - ret->caret_pos.line = ret->caret_pos.char_off = 0; - ret->caret_x = MARGIN_LEFT; + ret->caret_pos.line = ret->caret_pos.char_off = -1; + ret->caret_x = 0; ret->caret_y = 0; ret->sel_start = -1; ret->sel_end = -1; @@ -759,7 +751,7 @@ bool textarea_set_caret(struct textarea *ta, int caret) if (ta->flags & TEXTAREA_MULTILINE) { /* Multiline textarea */ - text_y_offset = 0; + text_y_offset = ta->border_width + ta->pad_top; } else { /* Single line text area; text is vertically centered */ text_y_offset = (ta->vis_height - ta->line_height + 1) / 2; @@ -813,7 +805,7 @@ bool textarea_set_caret(struct textarea *ta, int caret) b_off - ta->lines[ta->caret_pos.line].b_start, &x); - x += MARGIN_LEFT; + x += ta->border_width + ta->pad_left; ta->caret_x = x; y = ta->line_height * ta->caret_pos.line; ta->caret_y = y; @@ -827,9 +819,9 @@ bool textarea_set_caret(struct textarea *ta, int caret) /* Just caret moved, redraw it */ x -= ta->scroll_x; y -= ta->scroll_y; - x0 = max(x - 1, MARGIN_LEFT); + x0 = max(x - 1, ta->border_width); y0 = max(y + text_y_offset, 0); - x1 = min(x + 1, ta->vis_width - MARGIN_RIGHT); + x1 = min(x + 1, ta->vis_width - ta->border_width); y1 = min(y + ta->line_height + text_y_offset, ta->vis_height); @@ -852,6 +844,9 @@ int textarea_get_caret(struct textarea *ta) { unsigned int c_off = 0, b_off; + /* Ensure caret isn't hidden */ + if (ta->caret_pos.char_off < 0) + textarea_set_caret(ta, 0); /* if the text is a trailing NUL only */ if (ta->text_utf8_len == 0) @@ -884,7 +879,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, .stroke_width = 0, .stroke_colour = NS_TRANSPARENT, .fill_type = PLOT_OP_TYPE_SOLID, - .fill_colour = ta->fstyle.background + .fill_colour = ta->border_col }; r = *clip; @@ -922,15 +917,29 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, r.y1 = y + ta->vis_height; plot->clip(&r); - plot->rectangle(r.x0, r.y0, r.x1, r.y1, &plot_style_fill_bg); - plot->rectangle(x, y, - x + ta->vis_width - 1, y + ta->vis_height - 1, - &pstyle_stroke_border); + if (ta->border_col != NS_TRANSPARENT && + ta->border_width > 0) { + /* Plot border */ + plot->rectangle(x, y, x + ta->vis_width, y + ta->vis_height, + &plot_style_fill_bg); + } + if (ta->fstyle.background != NS_TRANSPARENT) { + /* Plot background */ + plot_style_fill_bg.fill_colour = ta->fstyle.background; + plot->rectangle(x + ta->border_width, y + ta->border_width, + x + ta->vis_width - ta->border_width, + y + ta->vis_height - ta->border_width, + &plot_style_fill_bg); + } - if (r.x0 < x + MARGIN_LEFT) - r.x0 = x + MARGIN_LEFT; - if (r.x1 > x + ta->vis_width - MARGIN_RIGHT) - r.x1 = x + ta->vis_width - MARGIN_RIGHT; + if (r.x0 < x + ta->border_width) + r.x0 = x + ta->border_width; + if (r.x1 > x + ta->vis_width - ta->border_width) + r.x1 = x + ta->vis_width - ta->border_width; + if (r.y0 < y + ta->border_width) + r.y0 = y + ta->border_width; + if (r.y1 > y + ta->vis_width - ta->border_width) + r.y1 = y + ta->vis_height - ta->border_width; if (line0 > 0) c_pos = utf8_bounded_length(ta->text, @@ -938,14 +947,17 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, else c_pos = 0; + text_y_offset = text_y_offset_baseline = ta->border_width; if (ta->flags & TEXTAREA_MULTILINE) { /* Multiline textarea */ - text_y_offset = 0; - text_y_offset_baseline = (ta->line_height * 3 + 2) / 4; + text_y_offset += ta->pad_top; + text_y_offset_baseline += (ta->line_height * 3 + 2) / 4 + + ta->pad_top; } else { /* Single line text area; text is vertically centered */ - text_y_offset = (ta->vis_height - ta->line_height + 1) / 2; - text_y_offset_baseline = (ta->vis_height * 3 + 2) / 4; + int vis_height = ta->vis_height - 2 * ta->border_width; + text_y_offset += (vis_height - ta->line_height + 1) / 2; + text_y_offset_baseline += (vis_height * 3 + 2) / 4; } plot_style_fill_bg.fill_colour = ta->sel_fstyle.background; @@ -956,6 +968,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, if (ta->lines[line].b_length == 0) continue; + /* reset clip rectangle */ plot->clip(&r); c_len = utf8_bounded_length( @@ -963,7 +976,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, ta->lines[line].b_length); b_end = 0; - right = x + MARGIN_LEFT; + right = x + ta->border_width + ta->pad_left; do { sel_start = ta->sel_start; @@ -1014,9 +1027,9 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, left = right; nsfont.font_width(&ta->fstyle, line_text, b_end, &right); - right += x + MARGIN_LEFT; + right += x + ta->border_width + ta->pad_left; - /* set clip */ + /* set clip rectangle for line part */ s = r; if (s.x0 < left) s.x0 = left; @@ -1036,7 +1049,8 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, } /* draw text */ - plot->text(x + MARGIN_LEFT - ta->scroll_x, + plot->text(x + ta->border_width + ta->pad_left - + ta->scroll_x, y + line * ta->line_height + text_y_offset_baseline - ta->scroll_y, ta->text + ta->lines[line].b_start, @@ -1048,9 +1062,10 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, } while (c_pos < c_pos + c_len); /* if there is a newline between the lines, skip it */ - if (line < ta->line_count - 1 && ta->lines[line + 1].b_start != - ta->lines[line].b_start + - ta->lines[line].b_length) + if (line < ta->line_count - 1 && + ta->lines[line + 1].b_start != + ta->lines[line].b_start + + ta->lines[line].b_length) c_pos++; } @@ -1061,7 +1076,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, if (ta->sel_end == -1 || ta->sel_start == ta->sel_end) { /* There is no selection; draw caret */ int caret_y = y + ta->caret_y + text_y_offset; - int caret_height = caret_y + ta->line_height - 1; + int caret_height = caret_y + ta->line_height; plot->line(x + ta->caret_x, caret_y, x + ta->caret_x, caret_height, diff --git a/desktop/textarea.h b/desktop/textarea.h index 641d39c73..7624c3187 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -52,7 +52,7 @@ typedef struct textarea_setup { colour selected_text; /**< Textarea selected text colour */ colour selected_bg; /**< Textarea selection background colour */ - plot_font_style_t text; /**< Font and textarea background colour */ + plot_font_style_t text; /**< Textarea background colour and font */ } textarea_setup; -- cgit v1.2.3 From 700aea8b08c565926e35d1816ad8a1db36f1462c Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Mon, 14 Jan 2013 11:46:56 +0000 Subject: Fix caret removal redraw to take account of border width. Fix scroll_visible to take account of border width in vertical scroll. --- desktop/textarea.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 94d9b96c1..3241cf9d3 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -237,7 +237,7 @@ static bool textarea_scroll_visible(struct textarea *ta) x0 = ta->border_width + ta->pad_left; x1 = ta->vis_width - (ta->border_width + ta->pad_left); y0 = 0; - y1 = ta->vis_height; + y1 = ta->vis_height - 2 * ta->border_width; x = ta->caret_x - ta->scroll_x; y = ta->caret_y - ta->scroll_y; @@ -754,13 +754,14 @@ bool textarea_set_caret(struct textarea *ta, int caret) text_y_offset = ta->border_width + ta->pad_top; } else { /* Single line text area; text is vertically centered */ - text_y_offset = (ta->vis_height - ta->line_height + 1) / 2; + text_y_offset = ta->border_width; + text_y_offset += (ta->vis_height - ta->line_height + 1) / 2; } /* Delete the old caret */ if (ta->caret_pos.char_off != -1) { x0 = ta->caret_x - ta->scroll_x; - y0 = ta->caret_y - ta->scroll_y; + y0 = ta->caret_y + text_y_offset - ta->scroll_y; width = 2; height = ta->line_height; -- cgit v1.2.3 From 96264ca71ebddece12360c742ce4215011e5b282 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Mon, 14 Jan 2013 12:01:23 +0000 Subject: Use right padding. Thanks jmb. --- desktop/textarea.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 3241cf9d3..e782fd6fd 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -235,7 +235,7 @@ static bool textarea_scroll_visible(struct textarea *ta) return false; x0 = ta->border_width + ta->pad_left; - x1 = ta->vis_width - (ta->border_width + ta->pad_left); + x1 = ta->vis_width - (ta->border_width + ta->pad_right); y0 = 0; y1 = ta->vis_height - 2 * ta->border_width; -- cgit v1.2.3 From 348e9789a42ce5479dcd38057d9d9d37fedaff6f Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 15 Jan 2013 19:40:32 +0000 Subject: Add scrollbars to textarea, and improve scrolling to try to keep caret in centre. Currently the scrollbars are mostly decoration, although they show accuratly where you are scrolled to in the area. TODO: Pass mouse input to scrollbars. --- desktop/textarea.c | 428 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 310 insertions(+), 118 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index e782fd6fd..185a878d9 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -29,6 +29,7 @@ #include "desktop/textarea.h" #include "desktop/textinput.h" #include "desktop/plotters.h" +#include "desktop/scrollbar.h" #include "render/font.h" #include "utils/log.h" #include "utils/utf8.h" @@ -49,34 +50,34 @@ struct line_info { struct textarea { - int scroll_x, scroll_y; /**< scroll offsets of the textarea - * content - */ + int scroll_x, scroll_y; /**< scroll offsets for the textarea */ + + struct scrollbar *bar_x; /**< Horizontal scroll. */ + struct scrollbar *bar_y; /**< Vertical scroll. */ unsigned int flags; /**< Textarea flags */ int vis_width; /**< Visible width, in pixels */ int vis_height; /**< Visible height, in pixels */ - int pad_top; - int pad_right; - int pad_bottom; - int pad_left; + int pad_top; /**< Top padding, inside border, in pixels */ + int pad_right; /**< Right padding, inside border, in pixels */ + int pad_bottom; /**< Bottom padding, inside border, in pixels */ + int pad_left; /**< Left padding, inside border, in pixels */ - int border_width; - colour border_col; + int border_width; /**< Border width, in pixels */ + colour border_col; /**< Border colour */ - plot_font_style_t fstyle; /**< Text style */ - plot_font_style_t sel_fstyle; /**< Text style */ + plot_font_style_t fstyle; /**< Text style, inc. textarea bg col */ + plot_font_style_t sel_fstyle; /**< Selected text style */ char *text; /**< UTF-8 text */ unsigned int text_alloc; /**< Size of allocated text */ unsigned int text_len; /**< Length of text, in bytes */ unsigned int text_utf8_len; /**< Length of text, in characters - * without the trailing NUL */ + * without the trailing NULL */ struct { int line; /**< Line caret is on */ - int char_off; /**< Character index of caret within the - * specified line */ + int char_off; /**< Character index of caret on line */ } caret_pos; int caret_x; /**< cached X coordinate of the caret */ @@ -85,6 +86,8 @@ struct textarea { int sel_start; /**< Character index of sel start(inclusive) */ int sel_end; /**< Character index of sel end(exclusive) */ + int h_extent; /**< Width of content in px */ + int v_extent; /**< Height of content in px */ int line_count; /**< Count of lines */ #define LINE_CHUNK_SIZE 16 struct line_info *lines; /**< Line info array */ @@ -228,7 +231,11 @@ static bool textarea_select_fragment(struct textarea * ta) */ static bool textarea_scroll_visible(struct textarea *ta) { - int x0, x1, y0, y1, x, y; + int x0, x1, y0, y1; /* area we want caret inside */ + int xc, yc; /* area centre */ + int x, y; /* caret pos */ + int xs = ta->scroll_x; + int ys = ta->scroll_y; bool scrolled = false; if (ta->caret_pos.char_off == -1) @@ -237,58 +244,114 @@ static bool textarea_scroll_visible(struct textarea *ta) x0 = ta->border_width + ta->pad_left; x1 = ta->vis_width - (ta->border_width + ta->pad_right); y0 = 0; - y1 = ta->vis_height - 2 * ta->border_width; - - x = ta->caret_x - ta->scroll_x; - y = ta->caret_y - ta->scroll_y; + y1 = ta->vis_height - 2 * ta->border_width - + ta->pad_top - ta->pad_bottom; + xc = (x1 - x0) / 2 + x0; + yc = (y1 - y0) / 2 + y0; + + x = ta->caret_x - xs; + y = ta->caret_y + ta->line_height / 2 - ys; + + /* horizontal scroll; centre caret */ + xs += x - xc; + + /* force back into range */ + if (xs < 0) + xs = 0; + else if (xs > ta->h_extent - (x1 - x0)) + xs = ta->h_extent - (x1 - x0); + + /* If scrolled, set new pos. */ + if (xs != ta->scroll_x && ta->bar_x != NULL) { + scrollbar_set(ta->bar_x, xs, false); + ta->scroll_x = scrollbar_get_offset(ta->bar_x); + scrolled = true; - /* check and change vertical scroll */ - if (y < y0) { - ta->scroll_y -= y0 - y; + } else if (ta->flags & TEXTAREA_MULTILINE && ta->bar_x == NULL && + ta->scroll_x != 0) { + ta->scroll_x = 0; scrolled = true; - } else if (y + ta->line_height > y1) { - ta->scroll_y += y + ta->line_height - y1; + + } else if (xs != ta->scroll_x && !(ta->flags & TEXTAREA_MULTILINE)) { + ta->scroll_x = xs; scrolled = true; } - - /* check and change horizontal scroll */ - if (x < x0) { - ta->scroll_x -= x0 - x ; - scrolled = true; - } else if (x > x1) { - ta->scroll_x += x - x1; - scrolled = true; + /* check and change vertical scroll */ + if (ta->flags & TEXTAREA_MULTILINE) { + /* vertical scroll; centre caret */ + ys += y - yc; + + /* force back into range */ + if (ys < 0) + ys = 0; + else if (ys > ta->v_extent - (y1 - y0)) + ys = ta->v_extent - (y1 - y0); + + /* If scrolled, set new pos. */ + if (ys != ta->scroll_y && ta->bar_y != NULL) { + scrollbar_set(ta->bar_y, ys, false); + ta->scroll_y = scrollbar_get_offset(ta->bar_y); + scrolled = true; + + } else if (ta->bar_y == NULL && ta->scroll_y != 0) { + ta->scroll_y = 0; + scrolled = true; + } } return scrolled; } +/** + * Callback for scrollbar widget. + */ +static void textarea_scrollbar_callback(void *client_data, + struct scrollbar_msg_data *scrollbar_data) +{ + struct textarea *ta = client_data; + + switch(scrollbar_data->msg) { + case SCROLLBAR_MSG_MOVED: + /* Scrolled; redraw everything */ + ta->scroll_x = scrollbar_get_offset(ta->bar_x); + ta->scroll_y = scrollbar_get_offset(ta->bar_y); + + ta->redraw_request(ta->data, 0, 0, + ta->vis_width, + ta->vis_height); + break; + case SCROLLBAR_MSG_SCROLL_START: + /* TODO: Tell textarea client we're handling a drag */ + break; + case SCROLLBAR_MSG_SCROLL_FINISHED: + /* TODO: Tell textarea client drag finished */ + break; + } +} + + /** * Reflow a text area from the given line onwards * * \param ta Text area to reflow - * \param line Line number to begin reflow on + * \param start Line number to begin reflow on * \return true on success false otherwise */ -static bool textarea_reflow(struct textarea *ta, unsigned int line) +static bool textarea_reflow(struct textarea *ta, unsigned int start) { char *text; unsigned int len; size_t b_off; int x; char *space, *para_end; - unsigned int line_count = 0; - int avail_width = ta->vis_width - 2 * ta->border_width - - ta->pad_left - ta->pad_right; - if (avail_width < 0) - avail_width = 0; - - /** \todo pay attention to line parameter */ - /** \todo create horizontal scrollbar if needed */ - - ta->line_count = 0; + unsigned int line; /* line count */ + unsigned int scroll_lines; + int avail_width; + int h_extent; /* horizontal extent */ + int v_extent; /* vertical extent */ + bool restart; if (ta->lines == NULL) { ta->lines = @@ -301,78 +364,190 @@ static bool textarea_reflow(struct textarea *ta, unsigned int line) if (!(ta->flags & TEXTAREA_MULTILINE)) { /* Single line */ - ta->lines[line_count].b_start = 0; - ta->lines[line_count++].b_length = ta->text_len - 1; + int w = ta->vis_width - 2 * ta->border_width - + ta->pad_left - ta->pad_right; + ta->lines[0].b_start = 0; + ta->lines[0].b_length = ta->text_len - 1; - ta->line_count = line_count; + nsfont.font_width(&ta->fstyle, ta->text, ta->text_len, &x); + if (x > w) + w = x; + ta->h_extent = w + ta->pad_left - ta->pad_right; + ta->line_count = 1; return true; } - for (len = ta->text_len - 1, text = ta->text; len > 0; - len -= b_off, text += b_off) { + /* Find max number of lines before vertical scrollbar is required */ + scroll_lines = (ta->vis_height - 2 * ta->border_width - + ta->pad_top - ta->pad_bottom) / + ta->line_height; + + if ((signed)start > ta->line_count) + start = 0; + /** \todo pay attention to start param, for now force start at zero */ + start = 0; + + do { + /* Set line count to start point */ + line = start; + + /* Find available width */ + avail_width = ta->vis_width - 2 * ta->border_width - + ta->pad_left - ta->pad_right; + if (avail_width < 0) + avail_width = 0; + h_extent = avail_width; + + restart = false; + for (len = ta->text_len - 1, text = ta->text; len > 0; + len -= b_off, text += b_off) { + + /* Find end of paragraph */ + for (para_end = text; para_end < text + len; + para_end++) { + if (*para_end == '\n') + break; + } + + /* Wrap current line in paragraph */ + nsfont.font_split(&ta->fstyle, text, para_end - text, + avail_width, &b_off, &x); + /* b_off now marks space, or end of paragraph */ - /* Find end of paragraph */ - for (para_end = text; para_end < text + len; para_end++) { - if (*para_end == '\n') - break; - } + if (x > h_extent) { + h_extent = x; + } + if (x > avail_width && ta->bar_x == NULL) { + /* We need to insert a horizontal scrollbar */ + int w = ta->vis_width - 2 * ta->border_width; + if (!scrollbar_create(true, w, w, w, + ta, textarea_scrollbar_callback, + &(ta->bar_x))) + return false; + if (ta->bar_y != NULL) + scrollbar_make_pair(ta->bar_x, + ta->bar_y); + ta->pad_bottom += SCROLLBAR_WIDTH; + + /* Find new max visible lines */ + scroll_lines = (ta->vis_height - + 2 * ta->border_width - + ta->pad_top - ta->pad_bottom) / + ta->line_height; + } - /* Wrap current line in paragraph */ - nsfont.font_split(&ta->fstyle, text, para_end - text, - avail_width, &b_off, &x); + if (line > 0 && line % LINE_CHUNK_SIZE == 0) { + struct line_info *temp = realloc(ta->lines, + (line + LINE_CHUNK_SIZE) * + sizeof(struct line_info)); + if (temp == NULL) { + LOG(("realloc failed")); + return false; + } - if (b_off == 0) { - /* Text wasn't split */ - b_off = para_end - text; - } - /* b_off now marks space, or end of paragraph */ - - if (line_count > 0 && line_count % LINE_CHUNK_SIZE == 0) { - struct line_info *temp = realloc(ta->lines, - (line_count + LINE_CHUNK_SIZE) * - sizeof(struct line_info)); - if (temp == NULL) { - LOG(("realloc failed")); - return false; + ta->lines = temp; } - ta->lines = temp; - } + if (para_end == text + b_off && *para_end == '\n') { + /* Not found any spaces to wrap at, and we + * have a newline char */ + ta->lines[line].b_start = text - ta->text; + ta->lines[line++].b_length = para_end - text; + + /* Jump newline */ + b_off++; + + if (len - b_off == 0) { + /* reached end of input; + * add last line */ + ta->lines[line].b_start = + text + b_off - ta->text; + ta->lines[line++].b_length = 0; + } - if (para_end == text + b_off && *para_end == '\n') { - /* Not found any spaces to wrap at, and we - * have a newline char */ - ta->lines[line_count].b_start = text - ta->text; - ta->lines[line_count++].b_length = para_end - text; + if (line > scroll_lines && ta->bar_y == NULL) + break; + + continue; - /* Jump newline */ - b_off++; + } else if (len - b_off > 0) { + /* soft wraped, find last space (if any) */ + for (space = text + b_off; space > text; + space--) { + if (*space == ' ') + break; + } - if (len - b_off == 0) { - /* reached end of input => add last line */ - ta->lines[line_count].b_start = - text + b_off - ta->text; - ta->lines[line_count++].b_length = 0; + if (space != text) + b_off = space + 1 - text; } - continue; + ta->lines[line].b_start = text - ta->text; + ta->lines[line++].b_length = b_off; - } else if (len - b_off > 0) { - /* soft wraped, find last space (if any) */ - for (space = text + b_off; space > text; space--) - if (*space == ' ') - break; + if (line > scroll_lines && ta->bar_y == NULL) + break; + } + + if (h_extent <= avail_width && ta->bar_x != NULL) { + /* We need to remove a horizontal scrollbar */ + scrollbar_destroy(ta->bar_x); + ta->bar_x = NULL; + ta->pad_bottom -= SCROLLBAR_WIDTH; - if (space != text) - b_off = space + 1 - text; + /* Find new max visible lines */ + scroll_lines = (ta->vis_height - 2 * ta->border_width - + ta->pad_top - ta->pad_bottom) / + ta->line_height; } - ta->lines[line_count].b_start = text - ta->text; - ta->lines[line_count++].b_length = b_off; + if (line > scroll_lines && ta->bar_y == NULL) { + /* Add vertical scrollbar */ + int h = ta->vis_height - 2 * ta->border_width; + if (!scrollbar_create(false, h, h, h, + ta, textarea_scrollbar_callback, + &(ta->bar_y))) + return false; + if (ta->bar_x != NULL) + scrollbar_make_pair(ta->bar_x, + ta->bar_y); + ta->pad_right += SCROLLBAR_WIDTH; + restart = true; + + } else if (line <= scroll_lines && ta->bar_y != NULL) { + /* Remove vertical scrollbar */ + scrollbar_destroy(ta->bar_y); + ta->bar_y = NULL; + ta->pad_right -= SCROLLBAR_WIDTH; + restart = true; + } + } while (restart); + + h_extent += ta->pad_left + ta->pad_right - + (ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0); + v_extent = line * ta->line_height + ta->pad_top + + ta->pad_bottom - + (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0); + + if (ta->bar_x != NULL) { + /* Set horizontal scrollbar extents */ + int w = ta->vis_width - 2 * ta->border_width - + (ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0); + scrollbar_set_extents(ta->bar_x, w, w, h_extent); } - ta->line_count = line_count; + if (ta->bar_y != NULL) { + /* Set vertical scrollbar extents */ + int h = ta->vis_height - 2 * ta->border_width; + scrollbar_set_extents(ta->bar_y, h, + h - (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0), + v_extent); + } + + ta->h_extent = h_extent; + ta->v_extent = v_extent; + ta->line_count = line; return true; } @@ -641,6 +816,8 @@ struct textarea *textarea_create(const textarea_setup *setup, ret->scroll_x = 0; ret->scroll_y = 0; + ret->bar_x = NULL; + ret->bar_y = NULL; ret->drag_start_char = 0; @@ -676,6 +853,10 @@ struct textarea *textarea_create(const textarea_setup *setup, /* exported interface, documented in textarea.h */ void textarea_destroy(struct textarea *ta) { + if (ta->bar_x) + scrollbar_destroy(ta->bar_x); + if (ta->bar_y) + scrollbar_destroy(ta->bar_y); free(ta->text); free(ta->lines); free(ta); @@ -811,13 +992,8 @@ bool textarea_set_caret(struct textarea *ta, int caret) y = ta->line_height * ta->caret_pos.line; ta->caret_y = y; - if (textarea_scroll_visible(ta)) { - /* Scrolled; redraw everything */ - ta->redraw_request(ta->data, 0, 0, - ta->vis_width, - ta->vis_height); - } else { - /* Just caret moved, redraw it */ + if (!textarea_scroll_visible(ta)) { + /* No scroll, just caret moved, redraw it */ x -= ta->scroll_x; y -= ta->scroll_y; x0 = max(x - 1, ta->border_width); @@ -939,8 +1115,10 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, r.x1 = x + ta->vis_width - ta->border_width; if (r.y0 < y + ta->border_width) r.y0 = y + ta->border_width; - if (r.y1 > y + ta->vis_width - ta->border_width) - r.y1 = y + ta->vis_height - ta->border_width; + if (r.y1 > y + ta->vis_height - ta->border_width - + (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0)) + r.y1 = y + ta->vis_height - ta->border_width - + (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0); if (line0 > 0) c_pos = utf8_bounded_length(ta->text, @@ -977,7 +1155,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, ta->lines[line].b_length); b_end = 0; - right = x + ta->border_width + ta->pad_left; + right = x + ta->border_width + ta->pad_left - ta->scroll_x; do { sel_start = ta->sel_start; @@ -1028,7 +1206,8 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, left = right; nsfont.font_width(&ta->fstyle, line_text, b_end, &right); - right += x + ta->border_width + ta->pad_left; + right += x + ta->border_width + ta->pad_left - + ta->scroll_x; /* set clip rectangle for line part */ s = r; @@ -1040,10 +1219,10 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, if (selected) { /* draw selection fill */ - plot->rectangle(s.x0 - ta->scroll_x, + plot->rectangle(s.x0, y + line * ta->line_height + 1 - ta->scroll_y + text_y_offset, - s.x1 - ta->scroll_x, + s.x1, y + (line + 1) * ta->line_height + 1 - ta->scroll_y + text_y_offset, &plot_style_fill_bg); @@ -1070,19 +1249,32 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, c_pos++; } - plot->clip(&r); - x -= ta->scroll_x; - y -= ta->scroll_y; + plot->clip(clip); - if (ta->sel_end == -1 || ta->sel_start == ta->sel_end) { + if (ta->sel_end == -1 || ta->sel_start == ta->sel_end && + ta->caret_pos.char_off >= 0) { /* There is no selection; draw caret */ - int caret_y = y + ta->caret_y + text_y_offset; + int caret_y = y - ta->scroll_y + ta->caret_y + text_y_offset; int caret_height = caret_y + ta->line_height; - plot->line(x + ta->caret_x, caret_y, - x + ta->caret_x, caret_height, + plot->line(x - ta->scroll_x + ta->caret_x, caret_y, + x - ta->scroll_x + ta->caret_x, caret_height, &pstyle_stroke_caret); } + + if (ta->bar_x != NULL) + scrollbar_redraw(ta->bar_x, + x + ta->border_width, + y + ta->vis_height - ta->border_width - + SCROLLBAR_WIDTH, + clip, 1.0, ctx); + + if (ta->bar_y != NULL) + scrollbar_redraw(ta->bar_y, + x + ta->vis_width - ta->border_width - + SCROLLBAR_WIDTH, + y + ta->border_width, + clip, 1.0, ctx); } @@ -1352,7 +1544,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) break; if (ta->sel_start != -1) { if (!textarea_replace_text(ta, - ta->sel_start, + ta->sel_start, ta->sel_end, "", 0, false)) return false; @@ -1420,7 +1612,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) break; if (ta->sel_start != -1) { if (!textarea_replace_text(ta, - ta->sel_start, + ta->sel_start, ta->sel_end, "", 0, false)) return false; ta->sel_start = ta->sel_end = -1; @@ -1440,7 +1632,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) break; if (ta->sel_start != -1) { if (!textarea_replace_text(ta, - ta->sel_start, + ta->sel_start, ta->sel_end, "", 0, false)) return false; ta->sel_start = ta->sel_end = -1; -- cgit v1.2.3 From 7a0b3475634642194b256ef3c4a294c72e312a18 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 15 Jan 2013 19:50:36 +0000 Subject: Add parentheses. --- desktop/textarea.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 185a878d9..00c2ca4bc 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -1251,9 +1251,9 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, plot->clip(clip); - if (ta->sel_end == -1 || ta->sel_start == ta->sel_end && + if ((ta->sel_end == -1 || ta->sel_start == ta->sel_end) && ta->caret_pos.char_off >= 0) { - /* There is no selection; draw caret */ + /* There is no selection, and caret visible: draw caret */ int caret_y = y - ta->scroll_y + ta->caret_y + text_y_offset; int caret_height = caret_y + ta->line_height; -- cgit v1.2.3 From d25289695360d16c25e39a022e949c6f56245adc Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 15 Jan 2013 21:05:54 +0000 Subject: Ensure we know for sure if scrollbar widget will want to scroll us. Avoid double xy to offset conversion. --- desktop/textarea.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 00c2ca4bc..d3f031fe1 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -264,8 +264,11 @@ static bool textarea_scroll_visible(struct textarea *ta) /* If scrolled, set new pos. */ if (xs != ta->scroll_x && ta->bar_x != NULL) { scrollbar_set(ta->bar_x, xs, false); - ta->scroll_x = scrollbar_get_offset(ta->bar_x); - scrolled = true; + xs = scrollbar_get_offset(ta->bar_x); + if (xs != ta->scroll_x) { + ta->scroll_x = xs; + scrolled = true; + } } else if (ta->flags & TEXTAREA_MULTILINE && ta->bar_x == NULL && ta->scroll_x != 0) { @@ -291,8 +294,11 @@ static bool textarea_scroll_visible(struct textarea *ta) /* If scrolled, set new pos. */ if (ys != ta->scroll_y && ta->bar_y != NULL) { scrollbar_set(ta->bar_y, ys, false); - ta->scroll_y = scrollbar_get_offset(ta->bar_y); - scrolled = true; + ys = scrollbar_get_offset(ta->bar_y); + if (ys != ta->scroll_y) { + ta->scroll_y = ys; + scrolled = true; + } } else if (ta->bar_y == NULL && ta->scroll_y != 0) { ta->scroll_y = 0; @@ -1673,10 +1679,10 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, /* mouse button pressed above the text area, move caret */ if (mouse & BROWSER_MOUSE_PRESS_1) { if (!(ta->flags & TEXTAREA_READONLY)) { - textarea_set_caret_xy(ta, x, y); - textarea_get_xy_offset(ta, x, y, &b_off, &c_off); ta->drag_start_char = c_off; + + textarea_set_caret(ta, c_off); } if (ta->sel_start != -1) { /* remove selection */ -- cgit v1.2.3 From 9995ef583f0820013e4e870f572b794bd46b4b13 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Fri, 18 Jan 2013 23:32:53 +0000 Subject: Early scrollbar mouse handling. --- desktop/textarea.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 7 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index d3f031fe1..d10039a2f 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -48,6 +48,18 @@ struct line_info { unsigned int b_length; /**< Byte length of line */ }; +typedef enum textarea_drag_type_internal { + TEXTAREA_DRAG_NONE, + TEXTAREA_DRAG_SCROLLBAR, + TEXTAREA_DRAG_SELECTION +} textarea_drag_type_internal; +struct textarea_drag { + textarea_drag_type_internal type; + union { + struct scrollbar* scrollbar; + } data; +}; + struct textarea { int scroll_x, scroll_y; /**< scroll offsets for the textarea */ @@ -83,8 +95,8 @@ struct textarea { int caret_x; /**< cached X coordinate of the caret */ int caret_y; /**< cached Y coordinate of the caret */ - int sel_start; /**< Character index of sel start(inclusive) */ - int sel_end; /**< Character index of sel end(exclusive) */ + int sel_start; /**< Character index of sel start (inclusive) */ + int sel_end; /**< Character index of sel end (exclusive) */ int h_extent; /**< Width of content in px */ int v_extent; /**< Height of content in px */ @@ -96,9 +108,10 @@ struct textarea { /** Callback function for a redraw request */ textarea_redraw_request_callback redraw_request; - void *data; /** < Callback data for both callback functions */ + void *data; /**< Client data for callback */ - int drag_start_char; /**< Character index of drag start */ + int drag_start_char; /**< Character index of drag start */ + struct textarea_drag drag_info; /**< Drag information */ }; @@ -327,10 +340,16 @@ static void textarea_scrollbar_callback(void *client_data, ta->vis_width, ta->vis_height); break; + case SCROLLBAR_MSG_SCROLL_START: + ta->drag_info.type = TEXTAREA_DRAG_SCROLLBAR; + ta->drag_info.data.scrollbar = + scrollbar_data->scrollbar; /* TODO: Tell textarea client we're handling a drag */ break; + case SCROLLBAR_MSG_SCROLL_FINISHED: + ta->drag_info.type = TEXTAREA_DRAG_NONE; /* TODO: Tell textarea client drag finished */ break; } @@ -825,6 +844,7 @@ struct textarea *textarea_create(const textarea_setup *setup, ret->bar_x = NULL; ret->bar_y = NULL; ret->drag_start_char = 0; + ret->drag_info.type = TEXTAREA_DRAG_NONE; ret->text = malloc(64); @@ -1378,6 +1398,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) size_t clipboard_chars; gui_get_clipboard(&clipboard, &clipboard_length); + if (clipboard == NULL) + return false; clipboard_chars = utf8_bounded_length(clipboard, clipboard_length); @@ -1673,9 +1695,51 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, int x, int y) { int c_start, c_end; + int sx, sy; /* xy coord offset for scrollbar */ + int sl; /* scrollbar length */ size_t b_off; unsigned int c_off; + if (ta->drag_info.type == TEXTAREA_DRAG_SCROLLBAR) { + if (ta->drag_info.data.scrollbar == ta->bar_x) { + x -= ta->border_width; + y -= ta->vis_height - ta->border_width - + SCROLLBAR_WIDTH; + } else { + x -= ta->vis_width - ta->border_width - + SCROLLBAR_WIDTH; + y -= ta->border_width; + } + scrollbar_mouse_action(ta->drag_info.data.scrollbar, + mouse, x, y); + return true; + } + + /* Horizontal scrollbar */ + if (ta->bar_x != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) { + sx = x - ta->border_width; + sy = y - (ta->vis_height - ta->border_width - SCROLLBAR_WIDTH); + sl = ta->vis_width - 2 * ta->border_width - + (ta->bar_y != NULL ? SCROLLBAR_WIDTH : 0); + + if (sx >= 0 && sy >= 0 && sx < sl && sy < SCROLLBAR_WIDTH) { + scrollbar_mouse_action(ta->bar_x, mouse, sx, sy); + return true; + } + } + + /* Vertical scrollbar */ + if (ta->bar_y != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) { + sx = x - (ta->vis_width - ta->border_width - SCROLLBAR_WIDTH); + sy = y - ta->border_width; + sl = ta->vis_height - 2 * ta->border_width; + + if (sx >= 0 && sy >= 0 && sx < SCROLLBAR_WIDTH && sy < sl) { + scrollbar_mouse_action(ta->bar_y, mouse, sx, sy); + return true; + } + } + /* mouse button pressed above the text area, move caret */ if (mouse & BROWSER_MOUSE_PRESS_1) { if (!(ta->flags & TEXTAREA_READONLY)) { @@ -1702,6 +1766,7 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, textarea_get_xy_offset(ta, x, y, &b_off, &c_off); c_start = ta->drag_start_char; c_end = c_off; + ta->drag_info.type = TEXTAREA_DRAG_SELECTION; return textarea_select(ta, c_start, c_end); } @@ -1717,9 +1782,32 @@ bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse, size_t b_off; unsigned int c_off; - textarea_get_xy_offset(ta, x, y, &b_off, &c_off); - c_end = c_off; - return textarea_select(ta, ta->drag_start_char, c_end); + switch (ta->drag_info.type) { + case TEXTAREA_DRAG_SCROLLBAR: + if (ta->drag_info.data.scrollbar == ta->bar_x) { + x -= ta->border_width; + y -= ta->vis_height - ta->border_width - + SCROLLBAR_WIDTH; + } else { + x -= ta->vis_width - ta->border_width - + SCROLLBAR_WIDTH; + y -= ta->border_width; + } + scrollbar_mouse_drag_end(ta->drag_info.data.scrollbar, + mouse, x, y); + return true; + + case TEXTAREA_DRAG_SELECTION: + textarea_get_xy_offset(ta, x, y, &b_off, &c_off); + c_end = c_off; + ta->drag_info.type = TEXTAREA_DRAG_NONE; + return textarea_select(ta, ta->drag_start_char, c_end); + + default: + break; + } + + return false; } -- cgit v1.2.3 From 2f94b0a949eeceb61a9a06d4d825e54e6fa3f254 Mon Sep 17 00:00:00 2001 From: François Revol Date: Sun, 20 Jan 2013 17:59:55 +0100 Subject: textarea: C89 --- desktop/textarea.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index d10039a2f..e94360e5b 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -1391,12 +1391,13 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) break; case KEY_PASTE: { - if (readonly) - break; char *clipboard; size_t clipboard_length; size_t clipboard_chars; + if (readonly) + break; + gui_get_clipboard(&clipboard, &clipboard_length); if (clipboard == NULL) return false; -- cgit v1.2.3 From 93cc123200f1e4856ad5b5c608d8deeb34522053 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 29 Jan 2013 17:34:08 +0000 Subject: Update textarea to inform client what it's doing with drags. Now single callback for both redraw requests and drag reports. Update treeview to use new textarea API. Update Atari URL bar to use new textarea API. (Ignores drag reports, currently.) Minor textarea fixes. --- atari/toolbar.c | 23 ++++- desktop/textarea.c | 254 +++++++++++++++++++++++++++++++++++++---------------- desktop/textarea.h | 52 +++++++---- desktop/tree.c | 93 +++++++++++--------- 4 files changed, 282 insertions(+), 140 deletions(-) (limited to 'desktop/textarea.c') diff --git a/atari/toolbar.c b/atari/toolbar.c index 82dc047fa..d30382842 100755 --- a/atari/toolbar.c +++ b/atari/toolbar.c @@ -651,7 +651,26 @@ static void tb_txt_request_redraw(void *data, int x, int y, int w, int h) t->url.rdw_area.g_h = ( oldy1 > newy1 ) ? oldy1 - t->url.rdw_area.g_y : newy1 - t->url.rdw_area.g_y; } -} +} + + +static void tb_txt_callback(void *data, struct textarea_msg *msg) +{ + switch (msg->type) { + case TEXTAREA_MSG_DRAG_REPORT: + break; + + case TEXTAREA_MSG_REDRAW_REQUEST: + tb_txt_redraw_request(data, + msg->data.redraw.x0, msg->data.redraw.y0, + msg->data.redraw.x1 - msg->data.redraw.x0, + msg->data.redraw.y1 - msg->data.redraw.y0); + break; + + default: + break; + } +} void tb_url_redraw( struct gui_window * gw ) { @@ -785,7 +804,7 @@ CMP_TOOLBAR tb_create( struct gui_window * gw ) ta_setup.text = font_style_url; ta_setup.text.foreground = 0x000000; ta_setup.text.background = 0xffffff; - t->url.textarea = textarea_create( &ta_setup, tb_txt_request_redraw, t ); + t->url.textarea = textarea_create( &ta_setup, tb_txt_callback, t ); if( t->url.textarea != NULL ){ textarea_set_text(t->url.textarea, "http://"); } diff --git a/desktop/textarea.c b/desktop/textarea.c index e94360e5b..725c911b7 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -43,18 +43,14 @@ static plot_style_t pstyle_stroke_caret = { .stroke_width = 1, }; +static struct textarea_msg msg; + struct line_info { unsigned int b_start; /**< Byte offset of line start */ unsigned int b_length; /**< Byte length of line */ }; - -typedef enum textarea_drag_type_internal { - TEXTAREA_DRAG_NONE, - TEXTAREA_DRAG_SCROLLBAR, - TEXTAREA_DRAG_SELECTION -} textarea_drag_type_internal; struct textarea_drag { - textarea_drag_type_internal type; + textarea_drag_type type; union { struct scrollbar* scrollbar; } data; @@ -106,7 +102,7 @@ struct textarea { int line_height; /**< Line height obtained from style */ /** Callback function for a redraw request */ - textarea_redraw_request_callback redraw_request; + textarea_client_callback callback; void *data; /**< Client data for callback */ @@ -179,7 +175,14 @@ static bool textarea_select(struct textarea *ta, int c_start, int c_end) ta->sel_start = c_start; ta->sel_end = c_end; - ta->redraw_request(ta->data, 0, 0, ta->vis_width, ta->vis_height); + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = 0; + msg.data.redraw.y0 = 0; + msg.data.redraw.x1 = ta->vis_width; + msg.data.redraw.y1 = ta->vis_height; + + ta->callback(ta->data, &msg); return true; } @@ -322,6 +325,7 @@ static bool textarea_scroll_visible(struct textarea *ta) return scrolled; } + /** * Callback for scrollbar widget. */ @@ -331,27 +335,46 @@ static void textarea_scrollbar_callback(void *client_data, struct textarea *ta = client_data; switch(scrollbar_data->msg) { - case SCROLLBAR_MSG_MOVED: - /* Scrolled; redraw everything */ - ta->scroll_x = scrollbar_get_offset(ta->bar_x); - ta->scroll_y = scrollbar_get_offset(ta->bar_y); + case SCROLLBAR_MSG_MOVED: + /* Scrolled; redraw everything */ + ta->scroll_x = scrollbar_get_offset(ta->bar_x); + ta->scroll_y = scrollbar_get_offset(ta->bar_y); + + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = 0; + msg.data.redraw.y0 = 0; + msg.data.redraw.x1 = ta->vis_width; + msg.data.redraw.y1 = ta->vis_height; + + ta->callback(ta->data, &msg); + break; - ta->redraw_request(ta->data, 0, 0, - ta->vis_width, - ta->vis_height); - break; + case SCROLLBAR_MSG_SCROLL_START: + ta->drag_info.type = TEXTAREA_DRAG_SCROLLBAR; + ta->drag_info.data.scrollbar = scrollbar_data->scrollbar; - case SCROLLBAR_MSG_SCROLL_START: - ta->drag_info.type = TEXTAREA_DRAG_SCROLLBAR; - ta->drag_info.data.scrollbar = - scrollbar_data->scrollbar; - /* TODO: Tell textarea client we're handling a drag */ - break; + msg.ta = ta; + msg.type = TEXTAREA_MSG_DRAG_REPORT; + msg.data.drag = ta->drag_info.type; - case SCROLLBAR_MSG_SCROLL_FINISHED: - ta->drag_info.type = TEXTAREA_DRAG_NONE; - /* TODO: Tell textarea client drag finished */ - break; + /* Tell client we're handling a drag */ + ta->callback(ta->data, &msg); + break; + + case SCROLLBAR_MSG_SCROLL_FINISHED: + ta->drag_info.type = TEXTAREA_DRAG_NONE; + + msg.ta = ta; + msg.type = TEXTAREA_MSG_DRAG_REPORT; + msg.data.drag = ta->drag_info.type; + + /* Tell client we finished handling the drag */ + ta->callback(ta->data, &msg); + break; + + default: + break; } } @@ -799,15 +822,79 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start, } +/** + * Handles the end of a drag operation + * + * \param ta Text area + * \param mouse the mouse state at drag end moment + * \param x X coordinate + * \param y Y coordinate + * \return true if drag end was handled false otherwise + */ +static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse, + int x, int y) +{ + int c_end; + size_t b_off; + unsigned int c_off; + + assert(ta->drag_info.type != TEXTAREA_DRAG_NONE); + + switch (ta->drag_info.type) { + case TEXTAREA_DRAG_SCROLLBAR: + if (ta->drag_info.data.scrollbar == ta->bar_x) { + x -= ta->border_width; + y -= ta->vis_height - ta->border_width - + SCROLLBAR_WIDTH; + } else { + x -= ta->vis_width - ta->border_width - + SCROLLBAR_WIDTH; + y -= ta->border_width; + } + scrollbar_mouse_drag_end(ta->drag_info.data.scrollbar, + mouse, x, y); + assert(ta->drag_info.type == TEXTAREA_DRAG_NONE); + + /* Return, since drag end already reported to textarea client */ + return true; + + case TEXTAREA_DRAG_SELECTION: + ta->drag_info.type = TEXTAREA_DRAG_NONE; + + textarea_get_xy_offset(ta, x, y, &b_off, &c_off); + c_end = c_off; + + if (!textarea_select(ta, ta->drag_start_char, c_end)) + return false; + + break; + + default: + return false; + } + + /* Report drag end to client, if not already reported */ + assert(ta->drag_info.type == TEXTAREA_DRAG_NONE); + + msg.ta = ta; + msg.type = TEXTAREA_MSG_DRAG_REPORT; + msg.data.drag = ta->drag_info.type; + + ta->callback(ta->data, &msg); + + return true; +} + + /* exported interface, documented in textarea.h */ struct textarea *textarea_create(const textarea_setup *setup, - textarea_redraw_request_callback redraw_request, void *data) + textarea_client_callback callback, void *data) { struct textarea *ret; - if (redraw_request == NULL) { + if (callback == NULL) { LOG(("no callback provided")); return NULL; } @@ -818,7 +905,7 @@ struct textarea *textarea_create(const textarea_setup *setup, return NULL; } - ret->redraw_request = redraw_request; + ret->callback = callback; ret->data = data; ret->flags = setup->flags; @@ -972,7 +1059,14 @@ bool textarea_set_caret(struct textarea *ta, int caret) width = 2; height = ta->line_height; - ta->redraw_request(ta->data, x0, y0, width, height); + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = x0; + msg.data.redraw.y0 = y0; + msg.data.redraw.x1 = x0 + width; + msg.data.redraw.y1 = y0 + height; + + ta->callback(ta->data, &msg); } /* check if the caret has to be drawn at all */ @@ -1032,8 +1126,14 @@ bool textarea_set_caret(struct textarea *ta, int caret) height = y1 - y0; if (width > 0 && height > 0) { - ta->redraw_request(ta->data, x0, y0, - width, height); + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = x0; + msg.data.redraw.y0 = y0; + msg.data.redraw.x1 = x0 + width; + msg.data.redraw.y1 = y0 + height; + + ta->callback(ta->data, &msg); } } } @@ -1147,8 +1247,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, (ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0); if (line0 > 0) - c_pos = utf8_bounded_length(ta->text, - ta->lines[line0].b_start - 1); + c_pos = utf8_bounded_length(ta->text, ta->lines[line0].b_start); else c_pos = 0; @@ -1683,8 +1782,14 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) textarea_set_caret(ta, caret); //TODO:redraw only the important part if (redraw) { - ta->redraw_request(ta->data, 0, 0, - ta->vis_width, ta->vis_height); + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = 0; + msg.data.redraw.y0 = 0; + msg.data.redraw.x1 = ta->vis_width; + msg.data.redraw.y1 = ta->vis_height; + + ta->callback(ta->data, &msg); } return true; @@ -1701,7 +1806,14 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, size_t b_off; unsigned int c_off; + if (ta->drag_info.type != TEXTAREA_DRAG_NONE && + mouse == BROWSER_MOUSE_HOVER) { + /* There is a drag that we must end */ + textarea_drag_end(ta, mouse, x, y); + } + if (ta->drag_info.type == TEXTAREA_DRAG_SCROLLBAR) { + /* Scrollbar drag in progress; pass input to scrollbar */ if (ta->drag_info.data.scrollbar == ta->bar_x) { x -= ta->border_width; y -= ta->vis_height - ta->border_width - @@ -1718,6 +1830,8 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, /* Horizontal scrollbar */ if (ta->bar_x != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) { + /* No drag happening, but mouse input is over scrollbar; + * pass input to scrollbar */ sx = x - ta->border_width; sy = y - (ta->vis_height - ta->border_width - SCROLLBAR_WIDTH); sl = ta->vis_width - 2 * ta->border_width - @@ -1731,6 +1845,8 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, /* Vertical scrollbar */ if (ta->bar_y != NULL && ta->drag_info.type == TEXTAREA_DRAG_NONE) { + /* No drag happening, but mouse input is over scrollbar; + * pass input to scrollbar */ sx = x - (ta->vis_width - ta->border_width - SCROLLBAR_WIDTH); sy = y - ta->border_width; sl = ta->vis_height - 2 * ta->border_width; @@ -1752,9 +1868,15 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, if (ta->sel_start != -1) { /* remove selection */ ta->sel_start = ta->sel_end = -1; - ta->redraw_request(ta->data, 0, 0, - ta->vis_width, - ta->vis_height); + + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = 0; + msg.data.redraw.y0 = 0; + msg.data.redraw.x1 = ta->vis_width; + msg.data.redraw.y1 = ta->vis_height; + + ta->callback(ta->data, &msg); } } else if (mouse & BROWSER_MOUSE_DOUBLE_CLICK) { @@ -1768,47 +1890,17 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, c_start = ta->drag_start_char; c_end = c_off; ta->drag_info.type = TEXTAREA_DRAG_SELECTION; - return textarea_select(ta, c_start, c_end); - } - - return true; -} - - -/* exported interface, documented in textarea.h */ -bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse, - int x, int y) -{ - int c_end; - size_t b_off; - unsigned int c_off; - switch (ta->drag_info.type) { - case TEXTAREA_DRAG_SCROLLBAR: - if (ta->drag_info.data.scrollbar == ta->bar_x) { - x -= ta->border_width; - y -= ta->vis_height - ta->border_width - - SCROLLBAR_WIDTH; - } else { - x -= ta->vis_width - ta->border_width - - SCROLLBAR_WIDTH; - y -= ta->border_width; - } - scrollbar_mouse_drag_end(ta->drag_info.data.scrollbar, - mouse, x, y); - return true; + msg.ta = ta; + msg.type = TEXTAREA_MSG_DRAG_REPORT; + msg.data.drag = ta->drag_info.type; - case TEXTAREA_DRAG_SELECTION: - textarea_get_xy_offset(ta, x, y, &b_off, &c_off); - c_end = c_off; - ta->drag_info.type = TEXTAREA_DRAG_NONE; - return textarea_select(ta, ta->drag_start_char, c_end); + ta->callback(ta->data, &msg); - default: - break; + return textarea_select(ta, c_start, c_end); } - return false; + return true; } @@ -1828,5 +1920,13 @@ void textarea_set_dimensions(struct textarea *ta, int width, int height) ta->vis_width = width; ta->vis_height = height; textarea_reflow(ta, 0); - ta->redraw_request(ta->data, 0, 0, ta->vis_width, ta->vis_height); + + msg.ta = ta; + msg.type = TEXTAREA_MSG_REDRAW_REQUEST; + msg.data.redraw.x0 = 0; + msg.data.redraw.y0 = 0; + msg.data.redraw.x1 = ta->vis_width; + msg.data.redraw.y1 = ta->vis_height; + + ta->callback(ta->data, &msg); } diff --git a/desktop/textarea.h b/desktop/textarea.h index 7624c3187..fb8b13425 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -29,13 +29,37 @@ #include "desktop/browser.h" #include "desktop/plot_style.h" + +struct textarea; + /* Text area flags */ -typedef enum textarea_flags { +typedef enum { TEXTAREA_DEFAULT = (1 << 0), TEXTAREA_MULTILINE = (1 << 1), TEXTAREA_READONLY = (1 << 2) } textarea_flags; +typedef enum { + TEXTAREA_DRAG_NONE, + TEXTAREA_DRAG_SCROLLBAR, + TEXTAREA_DRAG_SELECTION +} textarea_drag_type; + +typedef enum { + TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */ + TEXTAREA_MSG_REDRAW_REQUEST /**< Textarea redraw request */ +} textarea_msg_type; + +struct textarea_msg { + struct textarea *ta; + + textarea_msg_type type; + union { + textarea_drag_type drag; + struct rect redraw; + } data; +}; + typedef struct textarea_setup { textarea_flags flags; /**< Setup flags */ @@ -56,11 +80,13 @@ typedef struct textarea_setup { } textarea_setup; - -struct textarea; - -typedef void(*textarea_redraw_request_callback)(void *data, int x, int y, - int width, int height); +/** + * Client callback for the textarea + * + * \param data user data passed at textarea creation + * \param textarea_msg textarea message data + */ +typedef void(*textarea_client_callback)(void *data, struct textarea_msg *msg); /** * Create a text area @@ -71,7 +97,7 @@ typedef void(*textarea_redraw_request_callback)(void *data, int x, int y, * \return Opaque handle for textarea or 0 on error */ struct textarea *textarea_create(const textarea_setup *setup, - textarea_redraw_request_callback redraw_request, void *data); + textarea_client_callback callback, void *data); /** * Destroy a text area @@ -152,18 +178,6 @@ bool textarea_keypress(struct textarea *ta, uint32_t key); bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, int x, int y); -/** - * Handles the end of a drag operation - * - * \param ta Text area - * \param mouse the mouse state at drag end moment - * \param x X coordinate - * \param y Y coordinate - * \return true if drag end was handled false otherwise - */ -bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse, - int x, int y); - /** * Gets the dimensions of a textarea * diff --git a/desktop/tree.c b/desktop/tree.c index a48b615a0..4f9170d06 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -160,8 +160,7 @@ struct tree { int height; /* Tree height */ unsigned int flags; /* Tree flags */ struct textarea *textarea; /* Handle for UTF-8 textarea */ - bool textarea_drag_start; /* whether the start of a mouse drag - was in the textarea */ + int ta_height; /* Textarea height */ struct node_element *editing; /* Node element being edited */ bool redraw; /* Flag indicating whether the tree @@ -263,7 +262,6 @@ struct tree *tree_create(unsigned int flags, tree->height = 0; tree->flags = flags; tree->textarea = NULL; - tree->textarea_drag_start = false; tree->editing = NULL; tree->redraw = false; tree->drag = TREE_NO_DRAG; @@ -2430,9 +2428,9 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x, x0 += NODE_INSTEP; x1 = tree->editing->box.x + tree->editing->box.width; y0 = tree->editing->box.y; - y1 = tree->editing->box.y + tree->editing->box.height; + y1 = tree->editing->box.y + tree->ta_height; - if (tree->textarea_drag_start && + if (tree->drag == TREE_TEXTAREA_DRAG && (mouse & (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2))) { /* Track the drag path */ @@ -2441,19 +2439,7 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x, return true; } - - if ((x >= x0) && (x < x1) && (y >= y0) && (y < y1)) { - /* Inside the textarea */ - if (mouse & (BROWSER_MOUSE_DRAG_1 | - BROWSER_MOUSE_DRAG_2)) { - /* Drag starting */ - tree->textarea_drag_start = true; - tree->drag = TREE_TEXTAREA_DRAG; - } else { - /* Other action */ - tree->textarea_drag_start = false; - } textarea_mouse_action(tree->textarea, mouse, x - x0, y - y0); return true; @@ -2461,8 +2447,6 @@ bool tree_mouse_action(struct tree *tree, browser_mouse_state mouse, int x, } } - tree->textarea_drag_start = false; - /* we are not interested in the drag path, return */ if (mouse & (BROWSER_MOUSE_HOLDING_1 | BROWSER_MOUSE_HOLDING_2)) return true; @@ -2835,25 +2819,25 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0, struct node *node; int x, y; - if (tree->textarea_drag_start) { + switch (tree->drag) { + case TREE_NO_DRAG: + case TREE_UNKNOWN_DRAG: + break; + + case TREE_TEXTAREA_DRAG: x = tree->editing->box.x; y = tree->editing->box.y; if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON) x += NODE_INSTEP; - textarea_drag_end(tree->textarea, mouse, x1 - x, y1 - y); - } - - tree->textarea_drag_start = false; - - switch (tree->drag) { - case TREE_NO_DRAG: - case TREE_TEXTAREA_DRAG: - case TREE_UNKNOWN_DRAG: + textarea_mouse_action(tree->textarea, BROWSER_MOUSE_HOVER, + x1 - x, y1 - y); break; + case TREE_SELECT_DRAG: tree_handle_selection_area(tree, y0, y1 - y0, (mouse | BROWSER_MOUSE_HOLDING_2)); break; + case TREE_MOVE_DRAG: if (!(tree->flags & TREE_MOVABLE)) return; @@ -2875,7 +2859,6 @@ void tree_drag_end(struct tree *tree, browser_mouse_state mouse, int x0, int y0, */ bool tree_keypress(struct tree *tree, uint32_t key) { - if (tree->editing != NULL) switch (key) { case KEY_ESCAPE: @@ -2912,19 +2895,43 @@ int tree_alphabetical_sort(struct node *n1, struct node *n2) * check the redraw flag of the tree before requesting a redraw and change the * position to tree origin relative. */ -static void tree_textarea_redraw_request(void *data, int x, int y, - int width, int height) + +static void tree_textarea_callback(void *data, struct textarea_msg *msg) { struct tree *tree = data; - x = x + tree->editing->box.x; - y = y + tree->editing->box.y; - if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON) - x += NODE_INSTEP; + int x, y; - if (tree->redraw) - tree->callbacks->redraw_request(x, y, - width, height, - tree->client_data); + switch (msg->type) { + case TEXTAREA_MSG_DRAG_REPORT: + if (msg->data.drag == TEXTAREA_DRAG_NONE) { + /* Textarea drag finished */ + tree->drag = TREE_NO_DRAG; + } else { + /* Textarea drag started */ + tree->drag = TREE_TEXTAREA_DRAG; + } + break; + + case TEXTAREA_MSG_REDRAW_REQUEST: + x = msg->data.redraw.x0 + tree->editing->box.x; + y = msg->data.redraw.y0 + tree->editing->box.y; + + if (tree->editing->type == NODE_ELEMENT_TEXT_PLUS_ICON) + x += NODE_INSTEP; + + /* Redraw the textarea */ + if (tree->redraw) + tree->callbacks->redraw_request(x, y, + msg->data.redraw.x1 - + msg->data.redraw.x0, + msg->data.redraw.y1 - + msg->data.redraw.y0, + tree->client_data); + break; + + default: + break; + } } @@ -2963,9 +2970,11 @@ void tree_start_edit(struct tree *tree, struct node_element *element) if (element->type == NODE_ELEMENT_TEXT_PLUS_ICON) width -= NODE_INSTEP; + tree->ta_height = height; + ta_setup.flags = TEXTAREA_DEFAULT; ta_setup.width = width; - ta_setup.height = height; + ta_setup.height = tree->ta_height; ta_setup.pad_top = 0; ta_setup.pad_right = 4; ta_setup.pad_bottom = 0; @@ -2979,7 +2988,7 @@ void tree_start_edit(struct tree *tree, struct node_element *element) ta_setup.text.background = 0xffffff; tree->textarea = textarea_create(&ta_setup, - tree_textarea_redraw_request, tree); + tree_textarea_callback, tree); if (tree->textarea == NULL) { tree_stop_edit(tree, false); return; -- cgit v1.2.3 From af7a5d2d67a2eb42e67a1775ba4a83d9b5ce6939 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 29 Jan 2013 20:28:10 +0000 Subject: Don't redraw if selection is unchanged. --- desktop/textarea.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 725c911b7..872c6382b 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -172,6 +172,9 @@ static bool textarea_select(struct textarea *ta, int c_start, int c_end) c_end = swap; } + if (ta->sel_start == c_start && ta->sel_end == c_end) + return true; + ta->sel_start = c_start; ta->sel_end = c_end; -- cgit v1.2.3 From 5eb417fff49348f4421de8e2d5f773ae029a4c28 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Tue, 29 Jan 2013 22:52:21 +0000 Subject: Create textarea_msg struct on stack, rather than using global. --- desktop/textarea.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'desktop/textarea.c') diff --git a/desktop/textarea.c b/desktop/textarea.c index 872c6382b..cef2c6c70 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -43,8 +43,6 @@ static plot_style_t pstyle_stroke_caret = { .stroke_width = 1, }; -static struct textarea_msg msg; - struct line_info { unsigned int b_start; /**< Byte offset of line start */ unsigned int b_length; /**< Byte length of line */ @@ -164,6 +162,7 @@ static void textarea_normalise_text(struct textarea *ta, static bool textarea_select(struct textarea *ta, int c_start, int c_end) { int swap; + struct textarea_msg msg; /* Ensure start is the beginning of the selection */ if (c_start > c_end) { @@ -336,6 +335,7 @@ static void textarea_scrollbar_callback(void *client_data, struct scrollbar_msg_data *scrollbar_data) { struct textarea *ta = client_data; + struct textarea_msg msg; switch(scrollbar_data->msg) { case SCROLLBAR_MSG_MOVED: @@ -840,6 +840,7 @@ static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse, int c_end; size_t b_off; unsigned int c_off; + struct textarea_msg msg; assert(ta->drag_info.type != TEXTAREA_DRAG_NONE); @@ -1037,6 +1038,7 @@ bool textarea_set_caret(struct textarea *ta, int caret) int x0, y0, x1, y1; int text_y_offset; int width, height; + struct textarea_msg msg; if (ta->flags & TEXTAREA_READONLY) return true; @@ -1409,6 +1411,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, /* exported interface, documented in textarea.h */ bool textarea_keypress(struct textarea *ta, uint32_t key) { + struct textarea_msg msg; char utf8[6]; unsigned int caret, caret_init, length, l_len, b_off, b_len; int c_line, c_chars, line; @@ -1808,6 +1811,7 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse, int sl; /* scrollbar length */ size_t b_off; unsigned int c_off; + struct textarea_msg msg; if (ta->drag_info.type != TEXTAREA_DRAG_NONE && mouse == BROWSER_MOUSE_HOVER) { @@ -1920,6 +1924,8 @@ void textarea_get_dimensions(struct textarea *ta, int *width, int *height) /* exported interface, documented in textarea.h */ void textarea_set_dimensions(struct textarea *ta, int width, int height) { + struct textarea_msg msg; + ta->vis_width = width; ta->vis_height = height; textarea_reflow(ta, 0); -- cgit v1.2.3 From 663191791eda7034c3d7d99a4039eca8ba02b441 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Wed, 30 Jan 2013 18:01:01 +0000 Subject: Add move caret msg. Add flag to choose internal caret or caret move msgs. --- atari/toolbar.c | 2 +- desktop/textarea.c | 31 ++++++++++++++++++++++++++----- desktop/textarea.h | 16 ++++++++++++---- desktop/tree.c | 2 +- 4 files changed, 40 insertions(+), 11 deletions(-) (limited to 'desktop/textarea.c') diff --git a/atari/toolbar.c b/atari/toolbar.c index d4feaabfb..cf68194d6 100755 --- a/atari/toolbar.c +++ b/atari/toolbar.c @@ -790,7 +790,7 @@ CMP_TOOLBAR tb_create( struct gui_window * gw ) int ta_height = toolbar_styles[t->style].height; ta_height -= (TOOLBAR_URL_MARGIN_TOP + TOOLBAR_URL_MARGIN_BOTTOM); textarea_setup ta_setup; - ta_setup.flags = TEXTAREA_DEFAULT; + ta_setup.flags = TEXTAREA_INTERNAL_CARET; ta_setup.width = 300; ta_setup.height = ta_height; ta_setup.pad_top = 0; diff --git a/desktop/textarea.c b/desktop/textarea.c index cef2c6c70..2c7b7484d 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -1173,6 +1173,7 @@ int textarea_get_caret(struct textarea *ta) void textarea_redraw(struct textarea *ta, int x, int y, colour bg, const struct rect *clip, const struct redraw_context *ctx) { + struct textarea_msg msg; const struct plotter_table *plot = ctx->plot; int line0, line1, line, left, right; int chars, text_y_offset, text_y_offset_baseline; @@ -1383,13 +1384,33 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, if ((ta->sel_end == -1 || ta->sel_start == ta->sel_end) && ta->caret_pos.char_off >= 0) { - /* There is no selection, and caret visible: draw caret */ + /* There is no selection, and caret visible: show caret */ int caret_y = y - ta->scroll_y + ta->caret_y + text_y_offset; - int caret_height = caret_y + ta->line_height; - plot->line(x - ta->scroll_x + ta->caret_x, caret_y, - x - ta->scroll_x + ta->caret_x, caret_height, - &pstyle_stroke_caret); + if (ta->flags & TEXTAREA_INTERNAL_CARET) { + /* Render our own caret */ + plot->line(x - ta->scroll_x + ta->caret_x, caret_y, + x - ta->scroll_x + ta->caret_x, + caret_y + ta->line_height, + &pstyle_stroke_caret); + } else { + /* Tell client where caret should be placed */ + msg.ta = ta; + msg.type = TEXTAREA_MSG_MOVED_CARET; + msg.data.caret.hidden = false; + msg.data.caret.x = x - ta->scroll_x + ta->caret_x; + msg.data.caret.y = caret_y; + msg.data.caret.height = ta->line_height; + + ta->callback(ta->data, &msg); + } + } else if (!(ta->flags & TEXTAREA_INTERNAL_CARET)) { + /* Caret hidden, and client is responsible: tell client */ + msg.ta = ta; + msg.type = TEXTAREA_MSG_MOVED_CARET; + msg.data.caret.hidden = true; + + ta->callback(ta->data, &msg); } if (ta->bar_x != NULL) diff --git a/desktop/textarea.h b/desktop/textarea.h index fb8b13425..6a1a4714d 100644 --- a/desktop/textarea.h +++ b/desktop/textarea.h @@ -34,9 +34,10 @@ struct textarea; /* Text area flags */ typedef enum { - TEXTAREA_DEFAULT = (1 << 0), - TEXTAREA_MULTILINE = (1 << 1), - TEXTAREA_READONLY = (1 << 2) + TEXTAREA_DEFAULT = (1 << 0), /**< Standard input */ + TEXTAREA_MULTILINE = (1 << 1), /**< Multiline area */ + TEXTAREA_READONLY = (1 << 2), /**< Non-editable */ + TEXTAREA_INTERNAL_CARET = (1 << 3) /**< Render own caret */ } textarea_flags; typedef enum { @@ -47,7 +48,8 @@ typedef enum { typedef enum { TEXTAREA_MSG_DRAG_REPORT, /**< Textarea drag start/end report */ - TEXTAREA_MSG_REDRAW_REQUEST /**< Textarea redraw request */ + TEXTAREA_MSG_REDRAW_REQUEST, /**< Textarea redraw request */ + TEXTAREA_MSG_MOVED_CARET /**< Textarea caret moved */ } textarea_msg_type; struct textarea_msg { @@ -57,6 +59,12 @@ struct textarea_msg { union { textarea_drag_type drag; struct rect redraw; + struct { + bool hidden; + int x; + int y; + int height; + } caret; } data; }; diff --git a/desktop/tree.c b/desktop/tree.c index 4f9170d06..959b9870a 100644 --- a/desktop/tree.c +++ b/desktop/tree.c @@ -2972,7 +2972,7 @@ void tree_start_edit(struct tree *tree, struct node_element *element) tree->ta_height = height; - ta_setup.flags = TEXTAREA_DEFAULT; + ta_setup.flags = TEXTAREA_INTERNAL_CARET; ta_setup.width = width; ta_setup.height = tree->ta_height; ta_setup.pad_top = 0; -- cgit v1.2.3