From 25b27420642525d5b6f7677db7837e03d5208b7f Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Sun, 24 Jul 2005 06:13:25 +0000 Subject: [project @ 2005-07-24 06:13:25 by adrianl] Make selecting text easier by finding the nearest text above-left of the pointer; sort out issues with spaces in copied/saved text svn path=/import/netsurf/; revision=1820 --- desktop/browser.c | 90 +++++++++++++++++++++++++++++++--------- desktop/selection.c | 117 +++++++++++++++++++++++++++++----------------------- 2 files changed, 136 insertions(+), 71 deletions(-) (limited to 'desktop') diff --git a/desktop/browser.c b/desktop/browser.c index 5324ae984..7ab73fc6a 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -69,6 +69,7 @@ static void browser_radio_set(struct content *content, struct form_control *radio); static gui_pointer_shape get_pointer_shape(css_cursor cursor); +static struct box *browser_window_nearest_text_box(struct box *box, int x, int y); static struct box *browser_window_pick_text_box(struct browser_window *bw, browser_mouse_state mouse, int x, int y, int *dx, int *dy); static void browser_window_page_drag_start(struct browser_window *bw, int x, int y); @@ -745,6 +746,7 @@ void browser_window_mouse_action_html(struct browser_window *bw, struct form_control *gadget = 0; struct content *object = NULL; url_func_result res; + struct box *next_box; bw->drag_type = DRAGGING_NONE; bw->scrolling_box = NULL; @@ -753,8 +755,10 @@ void browser_window_mouse_action_html(struct browser_window *bw, * box with scrollbars */ box = c->data.html.layout; - while ((box = box_at_point(box, x, y, &box_x, &box_y, &content)) != + while ((next_box = box_at_point(box, x, y, &box_x, &box_y, &content)) != NULL) { + box = next_box; + if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN) continue; @@ -1621,6 +1625,42 @@ void browser_form_submit(struct browser_window *bw, struct form *form, } +/** + * Pick the text box child of 'box' that is closest to and above left of + * the point 'x,y' + * + * \param box parent box + * \param x x ordinate relative to parent box + * \param y y ordinate relative to parent box + * \return ptr to the nearest box, or NULL if none found + */ + +struct box *browser_window_nearest_text_box(struct box *box, int x, int y) +{ + struct box *child = box->children; + struct box *nearest = NULL; + int nr_yd = INT_MAX; + int nr_xd = INT_MAX; + + while (child) { + if (child->text && !child->object && child->y <= y && child->x <= x) { + int yd = y - (child->y + child->padding[TOP] + child->height + child->padding[BOTTOM]); + int xd = x - (child->x + child->padding[LEFT] + child->width + child->padding[RIGHT]); + + /* give y displacement precedence of x */ + if (yd < nr_yd || (yd == nr_yd && xd <= nr_xd)) { + nr_yd = yd; + nr_xd = xd; + nearest = child; + } + } + child = child->next; + } + + return nearest; +} + + /** * Peform pick text on browser window contents to locate the box under * the mouse pointer @@ -1639,29 +1679,41 @@ struct box *browser_window_pick_text_box(struct browser_window *bw, struct content *c = bw->current_content; struct box *text_box = NULL; - if (c) { - switch (c->type) { - case CONTENT_HTML: { - struct box *box = c->data.html.layout; - int box_x = 0, box_y = 0; - struct content *content; + if (c && c->type == CONTENT_HTML) { + struct box *box = c->data.html.layout; + int box_x = 0, box_y = 0; + struct content *content; + struct box *next_box; - while ((box = box_at_point(box, x, y, &box_x, &box_y, &content)) != - NULL) { + while ((next_box = box_at_point(box, x, y, &box_x, &box_y, &content)) != + NULL) { + box = next_box; - if (box->text && !box->object) - text_box = box; - } + if (box->text && !box->object) + text_box = box; + } - /* return coordinates relative to box */ - *dx = x - box_x; - *dy = y - box_y; - } - break; + if (!text_box) { + box = browser_window_nearest_text_box(box, x - box_x, y - box_y); - default: - break; + if (box->text && !box->object) { + + box_x += box->x - box->scroll_x; + box_y += box->y - box->scroll_y; + + int y1 = box_y + (box->padding[TOP] + box->height + box->padding[BOTTOM]); + int x1 = box_x + (box->padding[LEFT] + box->width + box->padding[RIGHT]); + + if (y > y1) y = y1; + if (x > x1) x = x1; + + text_box = box; + } } + + /* return coordinates relative to box */ + *dx = x - box_x; + *dy = y - box_y; } return text_box; diff --git a/desktop/selection.c b/desktop/selection.c index e72807d80..ea4b55ef1 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -42,6 +42,8 @@ static bool redraw_handler(struct box *box, int offset, size_t length, void *han static void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx); static unsigned selection_label_subtree(struct selection *s, struct box *node, unsigned idx); static bool save_handler(struct box *box, int offset, size_t length, void *handle); +static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx, + unsigned *start_offset, unsigned *end_offset); static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, seln_traverse_handler handler, void *handle); static struct box *get_box(struct box *b, unsigned offset, int *pidx); @@ -181,10 +183,8 @@ unsigned selection_label_subtree(struct selection *s, struct box *node, unsigned node->byte_offset = idx; - if (node->text && !node->object) { - idx += node->length; - if (node->space) idx++; - } + if (node->text && !node->object) + idx += node->length + node->space; while (child) { idx = selection_label_subtree(s, child, idx); @@ -379,6 +379,56 @@ void selection_drag_end(struct selection *s, struct box *box, } +/** + * Tests whether a text box lies partially within the given range of + * byte offsets, returning the start and end indexes of the bytes + * that are enclosed. + * + * \param box box to be tested + * \param start_idx byte offset of start of range + * \param end_idx byte offset of end of range + * \param start_offset receives the start offset of the selected part + * \param end_offset receives the end offset of the selected part + * \return true iff the range encloses at least part of the box + */ + +bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx, + unsigned *start_offset, unsigned *end_offset) +{ + size_t box_length = box->length + box->space; + + if (box->byte_offset >= start_idx && + box->byte_offset + box_length <= end_idx) { + + /* fully enclosed */ + *start_offset = 0; + *end_offset = box_length; + return true; + } + else if (box->byte_offset + box_length > start_idx && + box->byte_offset < end_idx) { + /* partly enclosed */ + int offset = 0; + int len; + + if (box->byte_offset < start_idx) + offset = start_idx - box->byte_offset; + + len = box_length - offset; + + if (box->byte_offset + box_length > end_idx) + len = end_idx - (box->byte_offset + offset); + + *start_offset = offset; + *end_offset = offset + len; + + return true; + } + + return false; +} + + /** * Traverse the given box subtree, calling the handler function (with its handle) * for all boxes that lie (partially) within the given range @@ -395,6 +445,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, seln_traverse_handler handler, void *handle) { struct box *child; + size_t box_length; /* we can prune this subtree, it's after the selection */ assert(box); @@ -404,31 +455,14 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, /* read before calling the handler in case it modifies the tree */ child = box->children; - if (IS_TEXT(box) && box->length > 0) { - - if (box->byte_offset >= start_idx && - box->byte_offset + box->length <= end_idx) { - /* fully enclosed */ - if (!handler(box, 0, box->length, handle)) - return false; - } - else if (box->byte_offset + box->length >= start_idx && - box->byte_offset < end_idx) { - /* partly enclosed */ - int offset = 0; - int len; - - if (box->byte_offset < start_idx) - offset = start_idx - box->byte_offset; - - len = box->length - offset; - - if (box->byte_offset + box->length > end_idx) - len = end_idx - (box->byte_offset + offset); + box_length = box->length + box->space; /* include trailing space */ + if (IS_TEXT(box)) { + unsigned start_offset; + unsigned end_offset; - if (!handler(box, offset, len, handle)) + if (selected_part(box, start_idx, end_idx, &start_offset, &end_offset) && + !handler(box, start_offset, end_offset - start_offset, handle)) return false; - } } else { /* make a guess at where the newlines should go */ @@ -756,34 +790,13 @@ bool selection_highlighted(struct selection *s, struct box *box, unsigned *start_idx, unsigned *end_idx) { /* caller should have checked first for efficiency */ + assert(s); assert(selection_defined(s)); - assert(s && box); - if (box->length > 0) { - unsigned box_len = box->length + (box->space ? 1 : 0); + assert(box); + assert(IS_TEXT(box)); - if (box->byte_offset < s->end_idx && - box->byte_offset + box_len > s->start_idx) { - unsigned offset = 0; - unsigned len; - - if (box->byte_offset < s->start_idx) - offset = s->start_idx - box->byte_offset; - - len = box_len - offset; - - if (box->byte_offset + box_len > s->end_idx) - len = s->end_idx - (box->byte_offset + offset); - - assert(offset <= box_len); - assert(offset + len <= box->length + 1); - - *start_idx = offset; - *end_idx = offset + len; - return true; - } - } - return false; + return selected_part(box, s->start_idx, s->end_idx, start_idx, end_idx); } -- cgit v1.2.3