From 1a1901d19b07ea265840962877b34b1205f6b092 Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Wed, 20 Jul 2005 23:27:28 +0000 Subject: [project @ 2005-07-20 23:27:27 by adrianl] 2D scrolling of text areas/frames; First cut at selection in textareas; Further text editing actions (Word left/right; Page up/down; Cut block; Delete line start/end) svn path=/import/netsurf/; revision=1812 --- desktop/selection.c | 166 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 134 insertions(+), 32 deletions(-) (limited to 'desktop/selection.c') diff --git a/desktop/selection.c b/desktop/selection.c index 2942b895b..e72807d80 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -20,6 +20,7 @@ #include "netsurf/render/box.h" #include "netsurf/render/font.h" #include "netsurf/utils/log.h" +#include "netsurf/utils/utils.h" #define IS_TEXT(box) ((box)->text && !(box)->object) @@ -43,8 +44,12 @@ static unsigned selection_label_subtree(struct selection *s, struct box *node, u static bool save_handler(struct box *box, int offset, size_t length, void *handle); 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); +void set_start(struct selection *s, unsigned offset); +void set_end(struct selection *s, unsigned offset); + /** * Decides whether the char at byte offset 'a_idx' in the box 'a' lies after * position 'b' within the textual representation of the content. @@ -120,8 +125,12 @@ void selection_reinit(struct selection *s, struct box *root) assert(s); s->root = root; - if (root) - s->max_idx = selection_label_subtree(s, root, 0); + if (root) { + int root_idx = 0; + if (root->gadget) root_idx = 0x10000000; + + s->max_idx = selection_label_subtree(s, root, root_idx); + } else s->max_idx = 0; @@ -143,6 +152,9 @@ void selection_reinit(struct selection *s, struct box *root) void selection_init(struct selection *s, struct box *root) { + if (s->defined) + selection_clear(s, true); + s->defined = false; s->start_idx = 0; s->end_idx = 0; @@ -169,7 +181,6 @@ 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++; @@ -319,7 +330,9 @@ void selection_track(struct selection *s, struct box *box, case DRAG_START: if (after(box, idx, s->end_idx)) { + unsigned old_end = s->end_idx; selection_set_end(s, box, idx); + set_start(s, old_end); s->drag_state = DRAG_END; } else @@ -328,7 +341,9 @@ void selection_track(struct selection *s, struct box *box, case DRAG_END: if (before(box, idx, s->start_idx)) { + unsigned old_start = s->start_idx; selection_set_start(s, box, idx); + set_end(s, old_start); s->drag_state = DRAG_START; } else @@ -386,6 +401,9 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, if (box->byte_offset >= end_idx) return true; + /* 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 && @@ -426,7 +444,6 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, this is important at the top-levels of the tree for pruning subtrees that lie entirely before the selection */ - child = box->children; if (child) { struct box *next = child->next; @@ -436,9 +453,13 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, } while (child) { + /* read before calling the handler in case it modifies the tree */ + struct box *next = child->next; + if (!traverse_tree(child, start_idx, end_idx, handler, handle)) return false; - child = child->next; + + child = next; } } @@ -563,7 +584,7 @@ void selection_clear(struct selection *s, bool redraw) void selection_select_all(struct selection *s) { - int old_start, old_end; + unsigned old_start, old_end; bool was_defined; assert(s); @@ -584,25 +605,17 @@ void selection_select_all(struct selection *s) } -/** - * Set the start position of the current selection, updating the screen. - * - * \param s selection object - * \param box box object containing start point - * \param idx byte offset of starting point within box - */ - -void selection_set_start(struct selection *s, struct box *box, int idx) +void set_start(struct selection *s, unsigned offset) { - int old_start = s->start_idx; bool was_defined = selection_defined(s); + unsigned old_start = s->start_idx; - s->start_idx = box->byte_offset + idx; + s->start_idx = offset; s->last_was_end = false; s->defined = (s->start_idx < s->end_idx); if (was_defined) { - if (before(box, idx, old_start)) + if (offset < old_start) selection_redraw(s, s->start_idx, old_start); else selection_redraw(s, old_start, s->start_idx); @@ -612,25 +625,17 @@ void selection_set_start(struct selection *s, struct box *box, int idx) } -/** - * Set the end position of the current selection, updating the screen. - * - * \param s selection object - * \param box box object containing end point - * \param idx byte offset of end point within box - */ - -void selection_set_end(struct selection *s, struct box *box, int idx) +void set_end(struct selection *s, unsigned offset) { - int old_end = s->end_idx; bool was_defined = selection_defined(s); + unsigned old_end = s->end_idx; - s->end_idx = box->byte_offset + idx; + s->end_idx = offset; s->last_was_end = true; s->defined = (s->start_idx < s->end_idx); if (was_defined) { - if (before(box, idx, old_end)) + if (offset < old_end) selection_redraw(s, s->end_idx, old_end); else selection_redraw(s, old_end, s->end_idx); @@ -640,6 +645,101 @@ void selection_set_end(struct selection *s, struct box *box, int idx) } +/** + * Set the start position of the current selection, updating the screen. + * + * \param s selection object + * \param box box object containing start point + * \param idx byte offset of starting point within box + */ + +void selection_set_start(struct selection *s, struct box *box, int idx) +{ + set_start(s, box->byte_offset + idx); +} + + +/** + * Set the end position of the current selection, updating the screen. + * + * \param s selection object + * \param box box object containing end point + * \param idx byte offset of end point within box + */ + +void selection_set_end(struct selection *s, struct box *box, int idx) +{ + set_end(s, box->byte_offset + idx); +} + + +/** + * Get the box and index of the specified byte offset within the + * textual representation. + * + * \param b root node of search + * \param offset byte offset within textual representation + * \param pidx receives byte index of selection start point within box + * \return ptr to box, or NULL if no selection defined + */ + +struct box *get_box(struct box *b, unsigned offset, int *pidx) +{ + struct box *child = b->children; + + if (b->text && !b->object) { + + if (offset >= b->byte_offset && + offset < b->byte_offset + b->length + b->space) { + + /* it's in this box */ + *pidx = offset - b->byte_offset; + return b; + } + } + + /* find the first child that could contain this offset */ + if (child) { + struct box *next = child->next; + while (next && next->byte_offset < offset) { + child = next; + next = child->next; + } + return get_box(child, offset, pidx); + } + + return NULL; +} + + +/** + * Get the box and index of the selection start, if defined. + * + * \param s selection object + * \param pidx receives byte index of selection start point within box + * \return ptr to box, or NULL if no selection defined + */ + +struct box *selection_get_start(struct selection *s, int *pidx) +{ + return (s->defined ? get_box(s->root, s->start_idx, pidx) : NULL); +} + + +/** + * Get the box and index of the selection end, if defined. + * + * \param s selection object + * \param pidx receives byte index of selection end point within box + * \return ptr to box, or NULL if no selection defined. + */ + +struct box *selection_get_end(struct selection *s, int *pidx) +{ + return (s->defined ? get_box(s->root, s->end_idx, pidx) : NULL); +} + + /** * Tests whether a text box lies partially within the selection, if there is * a selection defined, returning the start and end indexes of the bytes @@ -703,10 +803,12 @@ bool save_handler(struct box *box, int offset, size_t length, void *handle) assert(out); if (box) { - if (fwrite(box->text + offset, 1, length, out) < length) + size_t len = min(length, box->length - offset); + + if (fwrite(box->text + offset, 1, len, out) < len) return false; - if (box->space) + if (box->space && length > len) return (EOF != fputc(' ', out)); return true; -- cgit v1.2.3