Various text selection improvements:

+ Fix redraw bug where parts of old selections would get left behind
+ Enable selection of list marker boxes (bullet points and numbers)
+ Improve formatting of copied-to-clipboard or saved text selections
+ Select click anywhere outside current selection now clears current selection

svn path=/trunk/netsurf/; revision=4079
This commit is contained in:
Michael Drake 2008-04-07 09:00:21 +00:00
parent 8de0baae0b
commit 8b2a23081f
3 changed files with 98 additions and 39 deletions

View File

@ -312,7 +312,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
/* Compare new URL with existing one (ignoring fragments) */
if (bw->current_content && bw->current_content->url) {
res = url_compare(bw->current_content->url, url2,
res = url_compare(bw->current_content->url, url2,
true, &same_url);
if (res == URL_FUNC_NOMEM) {
free(url2);
@ -326,7 +326,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
/* if we're simply moving to another ID on the same page,
* don't bother to fetch, just update the window.
*/
if (same_url && !post_urlenc && !post_multipart &&
if (same_url && !post_urlenc && !post_multipart &&
!strchr(url2, '?')) {
free(url2);
browser_window_update(bw, false);
@ -652,7 +652,7 @@ void browser_window_refresh(void *p)
(bw->current_content->status == CONTENT_STATUS_READY ||
bw->current_content->status == CONTENT_STATUS_DONE));
/* Ignore if the refresh URL has gone
/* Ignore if the refresh URL has gone
* (may happen if a fetch error occurred) */
if (!bw->current_content->refresh)
return;
@ -1437,7 +1437,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
&idx,
&pixel_offset);
selection_click(bw->sel, mouse,
selection_click(bw->sel, mouse,
text_box->byte_offset + idx);
if (selection_dragging(bw->sel)) {
@ -1465,7 +1465,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
int pixel_offset;
size_t idx;
if (mouse & (BROWSER_MOUSE_DRAG_1 |
if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2))
selection_init(bw->sel, gadget_box);
@ -1476,7 +1476,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
&idx,
&pixel_offset);
selection_click(bw->sel, mouse,
selection_click(bw->sel, mouse,
text_box->byte_offset + idx);
if (selection_dragging(bw->sel))
@ -1564,17 +1564,17 @@ void browser_window_mouse_action_html(struct browser_window *bw,
&idx,
&pixel_offset);
if (selection_click(bw->sel, mouse,
if (selection_click(bw->sel, mouse,
text_box->byte_offset + idx)) {
/* key presses must be directed at the
* main browser window, paste text
/* key presses must be directed at the
* main browser window, paste text
* operations ignored */
browser_window_remove_caret(bw);
if (selection_dragging(bw->sel)) {
bw->drag_type =
bw->drag_type =
DRAGGING_SELECTION;
status =
status =
messages_get("Selecting");
} else
status = c->status_message;
@ -1582,6 +1582,8 @@ void browser_window_mouse_action_html(struct browser_window *bw,
done = true;
}
}
else if (mouse & BROWSER_MOUSE_CLICK_1)
selection_clear(bw->sel, true);
}
if (!done) {
@ -1827,7 +1829,7 @@ void browser_window_mouse_track_html(struct browser_window *bw,
&idx,
&pixel_offset);
selection_track(bw->sel, mouse,
selection_track(bw->sel, mouse,
box->byte_offset + idx);
}
}

View File

@ -31,6 +31,7 @@
#include "desktop/plotters.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
#include "render/textplain.h"
#include "utils/log.h"
@ -85,8 +86,7 @@ static bool redraw_handler(const char *text, size_t length, struct box *box,
size_t whitespace_length);
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 unsigned selection_label_subtree(struct box *box, unsigned idx);
static bool save_handler(const char *text, size_t length, struct box *box,
void *handle, const char *whitespace_text,
size_t whitespace_length);
@ -94,7 +94,8 @@ 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,
unsigned int num_space, seln_traverse_handler handler,
void *handle, seln_whitespace *before, bool *first);
void *handle, seln_whitespace *before, bool *first,
bool do_marker);
static struct box *get_box(struct box *b, unsigned offset, int *pidx);
@ -166,7 +167,7 @@ void selection_reinit(struct selection *s, struct box *root)
s->root = root;
if (root) {
s->max_idx = selection_label_subtree(s, root, root_idx);
s->max_idx = selection_label_subtree(root, root_idx);
}
else {
struct content *c = s->bw->current_content;
@ -216,19 +217,23 @@ void selection_init(struct selection *s, struct box *root)
* \return updated position
*/
unsigned selection_label_subtree(struct selection *s, struct box *node,
unsigned idx)
unsigned selection_label_subtree(struct box *box, unsigned idx)
{
struct box *child = node->children;
struct box *child = box->children;
node->byte_offset = idx;
box->byte_offset = idx;
if (node->text && !node->object)
idx += node->length + node->space;
if (box->text && !box->object)
idx += box->length + box->space;
while (child) {
if (!IS_INPUT(child))
idx = selection_label_subtree(s, child, idx);
if (!IS_INPUT(child)) {
if (child->list_marker)
idx = selection_label_subtree(
child->list_marker, idx);
idx = selection_label_subtree(child, idx);
}
child = child->next;
}
@ -258,7 +263,7 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
if (selection_defined(s)) {
if (idx > s->start_idx) {
if (idx < s->end_idx)
if (idx <= s->end_idx)
pos = 0;
else
pos = 1;
@ -442,19 +447,38 @@ bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx,
* \param handle handle to pass
* \param before type of whitespace to place before next encountered text
* \param first whether this is the first box with text
* \param do_marker whether deal enter any marker box
* \return false iff traversal abandoned part-way through
*/
bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
unsigned int num_space, seln_traverse_handler handler,
void *handle, seln_whitespace *before, bool *first)
void *handle, seln_whitespace *before, bool *first,
bool do_marker)
{
struct box *child;
const char *whitespace_text = "";
size_t whitespace_length = 0;
/* we can prune this subtree, it's after the selection */
assert(box);
/* If selection starts inside marker */
if (box->parent->list_marker == box && !do_marker) {
/* set box to main list element */
box = box->parent;
}
/* If box has a list marker */
if (box->list_marker) {
/* do the marker box before continuing with the rest of the
* list element */
if (!traverse_tree(box->list_marker, start_idx, end_idx,
num_space, handler, handle, before, first,
true))
return false;
}
/* we can prune this subtree, it's after the selection */
if (box->byte_offset >= end_idx)
return true;
@ -465,20 +489,23 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
* out what whitespace should be placed before the next bit of text */
if (before) {
if (*before < WHITESPACE_TWO_NEW_LINES &&
/* significant box type */
(box->type == BOX_BLOCK ||
box->type == BOX_TABLE ||
box->type == BOX_FLOAT_LEFT ||
box->type == BOX_FLOAT_RIGHT) &&
(!box->list_marker ||
box->list_marker &&
*before == WHITESPACE_TAB)) {
/* and not a list element */
!box->list_marker &&
/* and not a marker... */
(!do_marker ||
/* ...unless marker follows WHITESPACE_TAB */
(do_marker && *before == WHITESPACE_TAB))) {
*before = WHITESPACE_TWO_NEW_LINES;
}
else if (*before <= WHITESPACE_ONE_NEW_LINE &&
(box->type == BOX_TABLE_ROW ||
box->type == BOX_BR ||
(box->type != BOX_INLINE &&
box->list_marker) ||
(box->type != BOX_INLINE && do_marker) ||
(box->parent->style &&
(box->parent->style->white_space ==
CSS_WHITE_SPACE_PRE ||
@ -491,10 +518,10 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
*before = WHITESPACE_ONE_NEW_LINE;
}
else if (*before < WHITESPACE_TAB &&
box->type == BOX_TABLE_CELL) {
(box->type == BOX_TABLE_CELL ||
box->list_marker)) {
*before = WHITESPACE_TAB;
}
if (*first) {
whitespace_text = "";
} else {
@ -523,7 +550,6 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
else {
whitespace_text = NULL;
}
if (num_space == NUMBER_SPACE(box->byte_offset) &&
box->type != BOX_BR) {
unsigned start_offset;
@ -561,7 +587,7 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
struct box *next = child->next;
if (!traverse_tree(child, start_idx, end_idx, num_space,
handler, handle, before, first))
handler, handle, before, first, false))
return false;
child = next;
@ -594,7 +620,7 @@ bool selection_traverse(struct selection *s, seln_traverse_handler handler,
if (s->root)
return traverse_tree(s->root, s->start_idx, s->end_idx,
NUMBER_SPACE(s->max_idx), handler, handle,
&before, &first);
&before, &first, false);
c = s->bw->current_content;
if (!c) return true;
@ -630,7 +656,7 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
{
if (box) {
struct rdw_info *r = (struct rdw_info*)handle;
int width, height;
int width, height, space_width;
int x, y;
/* \todo - it should be possible to reduce the redrawn area by
@ -640,6 +666,10 @@ bool redraw_handler(const char *text, size_t length, struct box *box,
width = box->padding[LEFT] + box->width + box->padding[RIGHT];
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
if (box->type == BOX_TEXT && box->space &&
nsfont_width(box->style, " ", 1, &space_width))
width += space_width;
if (r->inited) {
if (x < r->r.x0) r->r.x0 = x;
if (y < r->r.y0) r->r.y0 = y;
@ -676,7 +706,7 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
if (s->root) {
if (!traverse_tree(s->root, start_idx, end_idx,
NUMBER_SPACE(s->max_idx), redraw_handler, &rdw,
NULL, NULL))
NULL, NULL, false))
return;
}
else {

View File

@ -335,6 +335,17 @@ non_float_children:
}
}
/* marker boxes */
if (box->list_marker) {
if (box_contains_point(box->list_marker, x - bx, y - by)) {
*box_x = bx + box->list_marker->x -
box->list_marker->scroll_x;
*box_y = by + box->list_marker->y -
box->list_marker->scroll_y;
return box->list_marker;
}
}
siblings:
/* siblings and siblings of ancestors */
while (box) {
@ -405,6 +416,22 @@ bool box_contains_point(struct box *box, int x, int y)
y < box->y + box->padding[TOP] + box->height +
box->border[BOTTOM] + box->padding[BOTTOM])
return true;
if (box->list_marker && box->list_marker->x <= x +
box->list_marker->border[LEFT] &&
x < box->list_marker->x +
box->list_marker->padding[LEFT] +
box->list_marker->width +
box->list_marker->border[RIGHT] +
box->list_marker->padding[RIGHT] &&
box->list_marker->y <= y +
box->list_marker->border[TOP] &&
y < box->list_marker->y +
box->list_marker->padding[TOP] +
box->list_marker->height +
box->list_marker->border[BOTTOM] +
box->list_marker->padding[BOTTOM]) {
return true;
}
} else {
if (box->x + box->descendant_x0 <= x &&
x < box->x + box->descendant_x1 &&