[project @ 2006-02-15 23:09:53 by adrianl]
Extend text selection, copying, saving and searching code to handle textplain contents; modified textplain code to accept other line terminators svn path=/import/netsurf/; revision=2081
This commit is contained in:
parent
07d55db910
commit
dbfdafdf18
|
@ -35,8 +35,10 @@
|
|||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/imagemap.h"
|
||||
#include "netsurf/render/layout.h"
|
||||
#include "netsurf/render/textplain.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/messages.h"
|
||||
#include "netsurf/utils/talloc.h"
|
||||
|
@ -62,8 +64,12 @@ static void download_window_callback(fetch_msg msg, void *p, const char *data,
|
|||
unsigned long size);
|
||||
static void browser_window_mouse_action_html(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y);
|
||||
static void browser_window_mouse_action_text(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y);
|
||||
static void browser_window_mouse_track_html(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y);
|
||||
static void browser_window_mouse_track_text(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y);
|
||||
static const char *browser_window_scrollbar_click(struct browser_window *bw,
|
||||
browser_mouse_state mouse, struct box *box,
|
||||
int box_x, int box_y, int x, int y);
|
||||
|
@ -328,8 +334,16 @@ void browser_window_callback(content_msg msg, struct content *c,
|
|||
global_history_add(url_content);
|
||||
}
|
||||
}
|
||||
if (c->type == CONTENT_HTML)
|
||||
selection_init(bw->sel, bw->current_content->data.html.layout);
|
||||
switch (c->type) {
|
||||
case CONTENT_HTML:
|
||||
selection_init(bw->sel, bw->current_content->data.html.layout);
|
||||
break;
|
||||
case CONTENT_TEXTPLAIN:
|
||||
selection_init(bw->sel, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CONTENT_MSG_DONE:
|
||||
|
@ -729,6 +743,10 @@ void browser_window_mouse_click(struct browser_window *bw,
|
|||
browser_window_mouse_action_html(bw, mouse, x, y);
|
||||
break;
|
||||
|
||||
case CONTENT_TEXTPLAIN:
|
||||
browser_window_mouse_action_text(bw, mouse, x, y);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (mouse & BROWSER_MOUSE_MOD_2) {
|
||||
if (mouse & BROWSER_MOUSE_DRAG_2)
|
||||
|
@ -752,7 +770,7 @@ void browser_window_mouse_click(struct browser_window *bw,
|
|||
* Handle mouse clicks and movements in an HTML content window.
|
||||
*
|
||||
* \param bw browser window
|
||||
* \param click type of mouse click
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param x coordinate of mouse
|
||||
* \param y coordinate of mouse
|
||||
*
|
||||
|
@ -919,7 +937,17 @@ void browser_window_mouse_action_html(struct browser_window *bw,
|
|||
}
|
||||
|
||||
if (text_box) {
|
||||
selection_click(bw->sel, text_box, mouse, x - box_x, y - box_y);
|
||||
int pixel_offset;
|
||||
int idx;
|
||||
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
x - box_x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
selection_click(bw->sel, mouse, text_box->byte_offset + idx);
|
||||
|
||||
if (selection_dragging(bw->sel)) {
|
||||
bw->drag_type = DRAGGING_SELECTION;
|
||||
|
@ -943,12 +971,21 @@ void browser_window_mouse_action_html(struct browser_window *bw,
|
|||
y - gadget_box_y);
|
||||
}
|
||||
else if (text_box) {
|
||||
if (mouse & (BROWSER_MOUSE_DRAG_1 |
|
||||
BROWSER_MOUSE_DRAG_2))
|
||||
int pixel_offset;
|
||||
int idx;
|
||||
|
||||
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2))
|
||||
selection_init(bw->sel, gadget_box);
|
||||
|
||||
selection_click(bw->sel, text_box, mouse,
|
||||
x - box_x, y - box_y);
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
x - box_x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
selection_click(bw->sel, mouse, text_box->byte_offset + idx);
|
||||
|
||||
if (selection_dragging(bw->sel))
|
||||
bw->drag_type = DRAGGING_SELECTION;
|
||||
}
|
||||
|
@ -1016,6 +1053,7 @@ void browser_window_mouse_action_html(struct browser_window *bw,
|
|||
}
|
||||
|
||||
} else {
|
||||
bool done = false;
|
||||
|
||||
/* if clicking in the main page, remove the selection from any text areas */
|
||||
if (text_box &&
|
||||
|
@ -1023,22 +1061,34 @@ void browser_window_mouse_action_html(struct browser_window *bw,
|
|||
selection_root(bw->sel) != c->data.html.layout)
|
||||
selection_init(bw->sel, c->data.html.layout);
|
||||
|
||||
if (text_box && selection_click(bw->sel, text_box, mouse,
|
||||
x - box_x, y - box_y)) {
|
||||
if (text_box) {
|
||||
int pixel_offset;
|
||||
int idx;
|
||||
|
||||
/* key presses must be directed at the main browser
|
||||
* window, paste text operations ignored */
|
||||
if (bw->caret_callback) bw->caret_callback = NULL;
|
||||
if (bw->paste_callback) bw->paste_callback = NULL;
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
x - box_x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
if (selection_dragging(bw->sel)) {
|
||||
bw->drag_type = DRAGGING_SELECTION;
|
||||
status = messages_get("Selecting");
|
||||
} else
|
||||
status = c->status_message;
|
||||
if (selection_click(bw->sel, mouse, text_box->byte_offset + idx)) {
|
||||
/* key presses must be directed at the main browser
|
||||
* window, paste text operations ignored */
|
||||
if (bw->caret_callback) bw->caret_callback = NULL;
|
||||
if (bw->paste_callback) bw->paste_callback = NULL;
|
||||
|
||||
if (selection_dragging(bw->sel)) {
|
||||
bw->drag_type = DRAGGING_SELECTION;
|
||||
status = messages_get("Selecting");
|
||||
} else
|
||||
status = c->status_message;
|
||||
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (!done) {
|
||||
if (title)
|
||||
status = title;
|
||||
else if (bw->loading_content)
|
||||
|
@ -1076,6 +1126,63 @@ void browser_window_mouse_action_html(struct browser_window *bw,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle mouse clicks and movements in a TEXTPLAIN content window.
|
||||
*
|
||||
* \param bw browser window
|
||||
* \param click type of mouse click
|
||||
* \param x coordinate of mouse
|
||||
* \param y coordinate of mouse
|
||||
*
|
||||
* This function handles both hovering and clicking. It is important that the
|
||||
* code path is identical (except that hovering doesn't carry out the action),
|
||||
* so that the status bar reflects exactly what will happen. Having separate
|
||||
* code paths opens the possibility that an attacker will make the status bar
|
||||
* show some harmless action where clicking will be harmful.
|
||||
*/
|
||||
|
||||
void browser_window_mouse_action_text(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y)
|
||||
{
|
||||
struct content *c = bw->current_content;
|
||||
gui_pointer_shape pointer = GUI_POINTER_DEFAULT;
|
||||
const char *status = 0;
|
||||
size_t idx;
|
||||
int dir = 0;
|
||||
|
||||
bw->drag_type = DRAGGING_NONE;
|
||||
|
||||
if (!bw->sel) return;
|
||||
|
||||
idx = textplain_offset_from_coords(c, x, y, dir);
|
||||
if (selection_click(bw->sel, mouse, idx)) {
|
||||
|
||||
if (selection_dragging(bw->sel)) {
|
||||
bw->drag_type = DRAGGING_SELECTION;
|
||||
status = messages_get("Selecting");
|
||||
}
|
||||
else
|
||||
status = c->status_message;
|
||||
}
|
||||
else {
|
||||
if (bw->loading_content)
|
||||
status = bw->loading_content->status_message;
|
||||
else
|
||||
status = c->status_message;
|
||||
|
||||
if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
|
||||
browser_window_page_drag_start(bw, x, y);
|
||||
pointer = GUI_POINTER_MOVE;
|
||||
}
|
||||
}
|
||||
|
||||
assert(status);
|
||||
|
||||
browser_window_set_status(bw, status);
|
||||
browser_window_set_pointer(pointer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle mouse movements in a browser window.
|
||||
*
|
||||
|
@ -1118,6 +1225,10 @@ void browser_window_mouse_track(struct browser_window *bw,
|
|||
browser_window_mouse_track_html(bw, mouse, x, y);
|
||||
break;
|
||||
|
||||
case CONTENT_TEXTPLAIN:
|
||||
browser_window_mouse_track_text(bw, mouse, x, y);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1128,6 +1239,7 @@ void browser_window_mouse_track(struct browser_window *bw,
|
|||
* Handle mouse tracking (including drags) in an HTML content window.
|
||||
*
|
||||
* \param bw browser window
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param x coordinate of mouse
|
||||
* \param y coordinate of mouse
|
||||
*/
|
||||
|
@ -1189,8 +1301,19 @@ void browser_window_mouse_track_html(struct browser_window *bw,
|
|||
|
||||
box = browser_window_pick_text_box(bw, mouse, x, y,
|
||||
&dx, &dy, dir);
|
||||
if (box)
|
||||
selection_track(bw->sel, box, mouse, dx, dy);
|
||||
if (box) {
|
||||
int pixel_offset;
|
||||
int idx;
|
||||
|
||||
nsfont_position_in_string(box->style,
|
||||
box->text,
|
||||
box->length,
|
||||
dx,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
selection_track(bw->sel, mouse, box->byte_offset + idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1201,6 +1324,39 @@ void browser_window_mouse_track_html(struct browser_window *bw,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle mouse tracking (including drags) in a TEXTPLAIN content window.
|
||||
*
|
||||
* \param bw browser window
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param x coordinate of mouse
|
||||
* \param y coordinate of mouse
|
||||
*/
|
||||
|
||||
void browser_window_mouse_track_text(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y)
|
||||
{
|
||||
switch (bw->drag_type) {
|
||||
|
||||
case DRAGGING_SELECTION: {
|
||||
struct content *c = bw->current_content;
|
||||
int dir = -1;
|
||||
size_t idx;
|
||||
|
||||
if (selection_dragging_start(bw->sel)) dir = 1;
|
||||
|
||||
idx = textplain_offset_from_coords(c, x, y, dir);
|
||||
selection_track(bw->sel, mouse, idx);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
browser_window_mouse_action_text(bw, mouse, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles the end of a drag operation in a browser window.
|
||||
*
|
||||
|
@ -1215,15 +1371,44 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
|
|||
{
|
||||
switch (bw->drag_type) {
|
||||
case DRAGGING_SELECTION: {
|
||||
int dx, dy;
|
||||
struct box *box;
|
||||
int dir = -1;
|
||||
struct content *c = bw->current_content;
|
||||
if (c) {
|
||||
bool found = true;
|
||||
int dir = -1;
|
||||
int idx;
|
||||
|
||||
if (selection_dragging_start(bw->sel)) dir = 1;
|
||||
if (selection_dragging_start(bw->sel)) dir = 1;
|
||||
|
||||
box = browser_window_pick_text_box(bw, mouse, x, y,
|
||||
&dx, &dy, dir);
|
||||
selection_drag_end(bw->sel, box, mouse, dx, dy);
|
||||
if (c->type == CONTENT_HTML) {
|
||||
int pixel_offset;
|
||||
struct box *box;
|
||||
int dx, dy;
|
||||
|
||||
box = browser_window_pick_text_box(bw, mouse, x, y,
|
||||
&dx, &dy, dir);
|
||||
if (box) {
|
||||
nsfont_position_in_string(box->style,
|
||||
box->text,
|
||||
box->length,
|
||||
dx,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
idx += box->byte_offset;
|
||||
selection_track(bw->sel, mouse, idx);
|
||||
}
|
||||
else
|
||||
found = false;
|
||||
}
|
||||
else {
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
idx = textplain_offset_from_coords(c, x, y, dir);
|
||||
}
|
||||
|
||||
if (found)
|
||||
selection_track(bw->sel, mouse, idx);
|
||||
}
|
||||
selection_drag_end(bw->sel);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1438,9 +1623,11 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
|
|||
{
|
||||
struct content *c = bw->current_content;
|
||||
|
||||
if (c && c->type == CONTENT_HTML) {
|
||||
if (c) {
|
||||
union content_msg_data data;
|
||||
|
||||
LOG(("REDRAW %d,%d,%d,%d", x, y, width, height));
|
||||
|
||||
data.redraw.x = x;
|
||||
data.redraw.y = y;
|
||||
data.redraw.width = width;
|
||||
|
@ -1792,7 +1979,7 @@ struct box *browser_window_pick_text_box(struct browser_window *bw,
|
|||
if (!text_box) {
|
||||
box = browser_window_nearest_text_box(box, x - box_x, y - box_y, dir);
|
||||
|
||||
if (box->text && !box->object) {
|
||||
if (box && box->text && !box->object) {
|
||||
int w = (box->padding[LEFT] + box->width + box->padding[RIGHT]);
|
||||
int h = (box->padding[TOP] + box->height + box->padding[BOTTOM]);
|
||||
int x1, y1;
|
||||
|
|
|
@ -102,7 +102,8 @@ void gui_create_form_select_menu(struct browser_window *bw,
|
|||
|
||||
void gui_launch_url(const char *url);
|
||||
|
||||
bool gui_search_term_highlighted(struct gui_window *g, struct box *box,
|
||||
bool gui_search_term_highlighted(struct gui_window *g,
|
||||
unsigned start_offset, unsigned end_offset,
|
||||
unsigned *start_idx, unsigned *end_idx);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "netsurf/desktop/plotters.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/render/textplain.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/utf8.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
#define IS_TEXT(box) ((box)->text && !(box)->object)
|
||||
|
||||
#define IS_INPUT(box) ((box)->gadget && \
|
||||
#define IS_INPUT(box) ((box) && (box)->gadget && \
|
||||
((box)->gadget->type == GADGET_TEXTAREA || (box)->gadget->type == GADGET_TEXTBOX))
|
||||
|
||||
/** check whether the given text box is in the same number space as the
|
||||
|
@ -48,10 +48,7 @@
|
|||
|
||||
struct rdw_info {
|
||||
bool inited;
|
||||
int x0;
|
||||
int y0;
|
||||
int x1;
|
||||
int y1;
|
||||
struct rect r;
|
||||
};
|
||||
|
||||
|
||||
|
@ -62,12 +59,13 @@ struct save_state {
|
|||
size_t alloc;
|
||||
};
|
||||
|
||||
static inline bool after(const struct box *a, unsigned a_idx, unsigned b);
|
||||
static inline bool before(const struct box *a, unsigned a_idx, unsigned b);
|
||||
static bool redraw_handler(struct box *box, int offset, size_t length, void *handle);
|
||||
static bool redraw_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, void *handle);
|
||||
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 unsigned selection_label_subtree(struct selection *s, struct box *node,
|
||||
unsigned idx);
|
||||
static bool save_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, 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,
|
||||
|
@ -75,38 +73,6 @@ static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
|
|||
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.
|
||||
*
|
||||
* \param a box being tested
|
||||
* \param a_idx byte offset within text of box 'a'
|
||||
* \param b position within textual representation
|
||||
*/
|
||||
|
||||
inline bool after(const struct box *a, unsigned a_idx, unsigned b)
|
||||
{
|
||||
return (a->byte_offset + a_idx > b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decides whether the char at byte offset 'a_idx' in the box 'a' lies before
|
||||
* position 'b' within the textual representation of the content.
|
||||
*
|
||||
* \param a box being tested
|
||||
* \param a_idx byte offset within text of box 'a'
|
||||
* \param b position within textual representation
|
||||
*/
|
||||
|
||||
inline bool before(const struct box *a, unsigned a_idx, unsigned b)
|
||||
{
|
||||
return (a->byte_offset + a_idx < b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new selection object associated with a browser window.
|
||||
*
|
||||
|
@ -177,8 +143,13 @@ void selection_reinit(struct selection *s, struct box *root)
|
|||
if (root) {
|
||||
s->max_idx = selection_label_subtree(s, root, root_idx);
|
||||
}
|
||||
else
|
||||
s->max_idx = 0;
|
||||
else {
|
||||
struct content *c = s->bw->current_content;
|
||||
if (c && c->type == CONTENT_TEXTPLAIN)
|
||||
s->max_idx = textplain_size(c);
|
||||
else
|
||||
s->max_idx = 0;
|
||||
}
|
||||
|
||||
if (s->defined) {
|
||||
if (s->end_idx > s->max_idx) s->end_idx = s->max_idx;
|
||||
|
@ -244,35 +215,23 @@ unsigned selection_label_subtree(struct selection *s, struct box *node, unsigned
|
|||
* Handles mouse clicks (including drag starts) in or near a selection
|
||||
*
|
||||
* \param s selection object
|
||||
* \param box text box containing the mouse pointer
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param dx x position of mouse relative to top-left of box
|
||||
* \param dy y position of mouse relative to top-left of box
|
||||
* \param idx byte offset within textual representation
|
||||
*
|
||||
* \return true iff the click has been handled by the selection code
|
||||
*/
|
||||
|
||||
bool selection_click(struct selection *s, struct box *box,
|
||||
browser_mouse_state mouse, int dx, int dy)
|
||||
bool selection_click(struct selection *s, browser_mouse_state mouse, unsigned idx)
|
||||
{
|
||||
browser_mouse_state modkeys = (mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2));
|
||||
int pixel_offset;
|
||||
int pos = -1; /* 0 = inside selection, 1 = after it */
|
||||
int idx;
|
||||
|
||||
if (!s->root ||!SAME_SPACE(s, box->byte_offset))
|
||||
if (!SAME_SPACE(s, idx))
|
||||
return false; /* not our problem */
|
||||
|
||||
nsfont_position_in_string(box->style,
|
||||
box->text,
|
||||
box->length,
|
||||
dx,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
if (selection_defined(s)) {
|
||||
if (!before(box, idx, s->start_idx)) {
|
||||
if (before(box, idx, s->end_idx))
|
||||
if (idx >= s->start_idx) {
|
||||
if (idx < s->end_idx)
|
||||
pos = 0;
|
||||
else
|
||||
pos = 1;
|
||||
|
@ -280,7 +239,8 @@ bool selection_click(struct selection *s, struct box *box,
|
|||
}
|
||||
|
||||
if (!pos &&
|
||||
(mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2))) {
|
||||
((mouse & BROWSER_MOUSE_DRAG_1) ||
|
||||
(modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) {
|
||||
/* drag-saving selection */
|
||||
assert(s->bw);
|
||||
gui_drag_save_selection(s, s->bw->window);
|
||||
|
@ -291,8 +251,8 @@ bool selection_click(struct selection *s, struct box *box,
|
|||
/* start new selection drag */
|
||||
selection_clear(s, true);
|
||||
|
||||
selection_set_start(s, box, idx);
|
||||
selection_set_end(s, box, idx);
|
||||
selection_set_start(s, idx);
|
||||
selection_set_end(s, idx);
|
||||
|
||||
s->drag_state = DRAG_END;
|
||||
|
||||
|
@ -305,13 +265,13 @@ bool selection_click(struct selection *s, struct box *box,
|
|||
return false; /* ignore Adjust drags */
|
||||
|
||||
if (pos > 0 || (!pos && s->last_was_end)) {
|
||||
selection_set_end(s, box, idx);
|
||||
|
||||
selection_set_end(s, idx);
|
||||
|
||||
s->drag_state = DRAG_END;
|
||||
}
|
||||
else {
|
||||
selection_set_start(s, box, idx);
|
||||
|
||||
selection_set_start(s, idx);
|
||||
|
||||
s->drag_state = DRAG_START;
|
||||
}
|
||||
gui_start_selection(s->bw->window);
|
||||
|
@ -329,9 +289,9 @@ bool selection_click(struct selection *s, struct box *box,
|
|||
return false;
|
||||
|
||||
if (pos > 0 || (!pos && s->last_was_end))
|
||||
selection_set_end(s, box, idx);
|
||||
selection_set_end(s, idx);
|
||||
else
|
||||
selection_set_start(s, box, idx);
|
||||
selection_set_start(s, idx);
|
||||
s->drag_state = DRAG_NONE;
|
||||
}
|
||||
else
|
||||
|
@ -352,50 +312,37 @@ bool selection_click(struct selection *s, struct box *box,
|
|||
* end points.
|
||||
*
|
||||
* \param s selection object
|
||||
* \param box text box containing the mouse pointer
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param dx x position of mouse relative to top-left of box
|
||||
* \param dy y position of mouse relative to top-left of box
|
||||
* \param idx byte offset within text representation
|
||||
*/
|
||||
|
||||
void selection_track(struct selection *s, struct box *box,
|
||||
browser_mouse_state mouse, int dx, int dy)
|
||||
void selection_track(struct selection *s, browser_mouse_state mouse, unsigned idx)
|
||||
{
|
||||
int pixel_offset;
|
||||
int idx;
|
||||
|
||||
if (!SAME_SPACE(s, box->byte_offset))
|
||||
if (!SAME_SPACE(s, idx))
|
||||
return;
|
||||
|
||||
nsfont_position_in_string(box->style,
|
||||
box->text,
|
||||
box->length,
|
||||
dx,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
switch (s->drag_state) {
|
||||
|
||||
case DRAG_START:
|
||||
if (after(box, idx, s->end_idx)) {
|
||||
if (idx > s->end_idx) {
|
||||
unsigned old_end = s->end_idx;
|
||||
selection_set_end(s, box, idx);
|
||||
set_start(s, old_end);
|
||||
selection_set_end(s, idx);
|
||||
selection_set_start(s, old_end);
|
||||
s->drag_state = DRAG_END;
|
||||
}
|
||||
else
|
||||
selection_set_start(s, box, idx);
|
||||
selection_set_start(s, idx);
|
||||
break;
|
||||
|
||||
case DRAG_END:
|
||||
if (before(box, idx, s->start_idx)) {
|
||||
if (idx < s->start_idx) {
|
||||
unsigned old_start = s->start_idx;
|
||||
selection_set_start(s, box, idx);
|
||||
set_end(s, old_start);
|
||||
selection_set_start(s, idx);
|
||||
selection_set_end(s, old_start);
|
||||
s->drag_state = DRAG_START;
|
||||
}
|
||||
else
|
||||
selection_set_end(s, box, idx);
|
||||
selection_set_end(s, idx);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -404,29 +351,6 @@ void selection_track(struct selection *s, struct box *box,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles completion of a drag operation
|
||||
*
|
||||
* \param s selection object
|
||||
* \param box text box containing the mouse pointer
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param dx x position of mouse relative to top-left of box
|
||||
* \param dy y position of mouse relative to top-left of box
|
||||
*/
|
||||
|
||||
void selection_drag_end(struct selection *s, struct box *box,
|
||||
browser_mouse_state mouse, int dx, int dy)
|
||||
{
|
||||
if (box) {
|
||||
/* selection_track() does all that we need to do
|
||||
so avoid code duplication */
|
||||
selection_track(s, box, mouse, dx, dy);
|
||||
}
|
||||
|
||||
s->drag_state = DRAG_NONE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether a text box lies partially within the given range of
|
||||
* byte offsets, returning the start and end indexes of the bytes
|
||||
|
@ -510,15 +434,17 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
|
|||
unsigned end_offset;
|
||||
|
||||
if (selected_part(box, start_idx, end_idx, &start_offset, &end_offset) &&
|
||||
!handler(box, start_offset, end_offset - start_offset, handle))
|
||||
!handler(box->text + start_offset,
|
||||
min(box->length, end_offset) - start_offset,
|
||||
(end_offset >= box->length), box, handle))
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
/* make a guess at where the newlines should go */
|
||||
if (box->byte_offset >= start_idx &&
|
||||
box->byte_offset < end_idx) {
|
||||
|
||||
if (!handler(NULL, 0, 0, handle))
|
||||
|
||||
if (!handler(NULL, 0, false, NULL, handle))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -561,8 +487,23 @@ bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx,
|
|||
|
||||
bool selection_traverse(struct selection *s, seln_traverse_handler handler, void *handle)
|
||||
{
|
||||
if (s->root && selection_defined(s))
|
||||
struct content *c;
|
||||
|
||||
if (!selection_defined(s))
|
||||
return true; /* easy case, nothing to do */
|
||||
|
||||
if (s->root)
|
||||
return traverse_tree(s->root, s->start_idx, s->end_idx, handler, handle);
|
||||
|
||||
c = s->bw->current_content;
|
||||
if (!c) return true;
|
||||
|
||||
size_t length;
|
||||
const char *text = textplain_get_raw_data(c, s->start_idx, s->end_idx, &length);
|
||||
|
||||
if (text && !handler(text, length, false, NULL, handle))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -571,37 +512,41 @@ bool selection_traverse(struct selection *s, seln_traverse_handler handler, void
|
|||
* Selection traversal handler for redrawing the screen when the selection
|
||||
* has been altered.
|
||||
*
|
||||
* \param box pointer to text box being (partially) added
|
||||
* \param offset start offset of text within box (bytes)
|
||||
* \param text pointer to text string
|
||||
* \param length length of text to be appended (bytes)
|
||||
* \param space text string should be followed by a trailing space
|
||||
* \param box pointer to text box being (partially) added
|
||||
* \param handle unused handle, we don't need one
|
||||
* \return true iff successful and traversal should continue
|
||||
*/
|
||||
|
||||
bool redraw_handler(struct box *box, int offset, size_t length, void *handle)
|
||||
bool redraw_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, void *handle)
|
||||
{
|
||||
if (box) {
|
||||
struct rdw_info *r = (struct rdw_info*)handle;
|
||||
int width, height;
|
||||
int x, y;
|
||||
|
||||
/* \todo - it should be possible to reduce the redrawn area by
|
||||
considering the 'text', 'length' and 'space' parameters */
|
||||
box_coords(box, &x, &y);
|
||||
|
||||
width = box->padding[LEFT] + box->width + box->padding[RIGHT];
|
||||
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
|
||||
|
||||
if (r->inited) {
|
||||
if (x < r->x0) r->x0 = x;
|
||||
if (y < r->y0) r->y0 = y;
|
||||
if (x + width > r->x1) r->x1 = x + width;
|
||||
if (y + height > r->y1) r->y1 = y + height;
|
||||
if (x < r->r.x0) r->r.x0 = x;
|
||||
if (y < r->r.y0) r->r.y0 = y;
|
||||
if (x + width > r->r.x1) r->r.x1 = x + width;
|
||||
if (y + height > r->r.y1) r->r.y1 = y + height;
|
||||
}
|
||||
else {
|
||||
r->inited = true;
|
||||
r->x0 = x;
|
||||
r->y0 = y;
|
||||
r->x1 = x + width;
|
||||
r->y1 = y + height;
|
||||
r->r.x0 = x;
|
||||
r->r.y0 = y;
|
||||
r->r.x1 = x + width;
|
||||
r->r.y1 = y + height;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -620,14 +565,24 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
|
|||
{
|
||||
struct rdw_info rdw;
|
||||
|
||||
if (end_idx < start_idx) LOG(("*** asked to redraw from %d to %d", start_idx, end_idx));
|
||||
assert(end_idx >= start_idx);
|
||||
rdw.inited = false;
|
||||
if (traverse_tree(s->root, start_idx, end_idx, redraw_handler, &rdw) &&
|
||||
rdw.inited) {
|
||||
browser_window_redraw_rect(s->bw, rdw.x0, rdw.y0,
|
||||
rdw.x1 - rdw.x0, rdw.y1 - rdw.y0);
|
||||
|
||||
if (s->root) {
|
||||
if (!traverse_tree(s->root, start_idx, end_idx, redraw_handler, &rdw))
|
||||
return;
|
||||
}
|
||||
else {
|
||||
struct content *c = s->bw->current_content;
|
||||
if (c && c->type == CONTENT_TEXTPLAIN && end_idx > start_idx) {
|
||||
textplain_coords_from_range(c, start_idx, end_idx, &rdw.r);
|
||||
rdw.inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rdw.inited)
|
||||
browser_window_redraw_rect(s->bw, rdw.r.x0, rdw.r.y0,
|
||||
rdw.r.x1 - rdw.r.x0, rdw.r.y1 - rdw.r.y0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -689,7 +644,14 @@ void selection_select_all(struct selection *s)
|
|||
}
|
||||
|
||||
|
||||
void set_start(struct selection *s, unsigned offset)
|
||||
/**
|
||||
* Set the start position of the current selection, updating the screen.
|
||||
*
|
||||
* \param s selection object
|
||||
* \param offset byte offset within textual representation
|
||||
*/
|
||||
|
||||
void selection_set_start(struct selection *s, unsigned offset)
|
||||
{
|
||||
bool was_defined = selection_defined(s);
|
||||
unsigned old_start = s->start_idx;
|
||||
|
@ -709,7 +671,14 @@ void set_start(struct selection *s, unsigned offset)
|
|||
}
|
||||
|
||||
|
||||
void set_end(struct selection *s, unsigned offset)
|
||||
/**
|
||||
* Set the end position of the current selection, updating the screen.
|
||||
*
|
||||
* \param s selection object
|
||||
* \param offset byte offset within textual representation
|
||||
*/
|
||||
|
||||
void selection_set_end(struct selection *s, unsigned offset)
|
||||
{
|
||||
bool was_defined = selection_defined(s);
|
||||
unsigned old_end = s->end_idx;
|
||||
|
@ -729,34 +698,6 @@ void set_end(struct selection *s, unsigned offset)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -825,63 +766,64 @@ struct box *selection_get_end(struct selection *s, int *pidx)
|
|||
|
||||
|
||||
/**
|
||||
* Tests whether a text box lies partially within the selection, if there is
|
||||
* Tests whether a text range lies partially within the selection, if there is
|
||||
* a selection defined, returning the start and end indexes of the bytes
|
||||
* that should be selected.
|
||||
*
|
||||
* \param s the selection object
|
||||
* \param box the box to be tested
|
||||
* \param start byte offset of start of text
|
||||
* \param start_idx receives the start index (in bytes) of the highlighted portion
|
||||
* \param end_idx receives the end index (in bytes)
|
||||
* \return true iff part of the given box lies within the selection
|
||||
*/
|
||||
|
||||
bool selection_highlighted(struct selection *s, struct box *box,
|
||||
bool selection_highlighted(struct selection *s, unsigned start, unsigned end,
|
||||
unsigned *start_idx, unsigned *end_idx)
|
||||
{
|
||||
/* caller should have checked first for efficiency */
|
||||
assert(s);
|
||||
assert(selection_defined(s));
|
||||
|
||||
assert(box);
|
||||
assert(IS_TEXT(box));
|
||||
if (end <= s->start_idx || start >= s->end_idx)
|
||||
return false;
|
||||
|
||||
return selected_part(box, s->start_idx, s->end_idx, start_idx, end_idx);
|
||||
*start_idx = (s->start_idx >= start) ? (s->start_idx - start) : 0;
|
||||
*end_idx = min(end, s->end_idx) - start;
|
||||
|
||||
return true;
|
||||
|
||||
// assert(box);
|
||||
// assert(IS_TEXT(box));
|
||||
|
||||
// return selected_part(box, s->start_idx, s->end_idx, start_idx, end_idx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Selection traversal handler for saving the text to a file.
|
||||
*
|
||||
* \param box pointer to text box being (partially) added
|
||||
* \param offset start offset of text within box (bytes)
|
||||
* \param text pointer to text being added, or NULL for newline
|
||||
* \param length length of text to be appended (bytes)
|
||||
* \param handle unused handle, we don't need one
|
||||
* \param space trailing space required after text
|
||||
* \param box pointer to text box (or NULL for textplain content)
|
||||
* \param handle our save_state workspace pointer
|
||||
* \return true iff the file writing succeeded and traversal should continue.
|
||||
*/
|
||||
|
||||
bool save_handler(struct box *box, int offset, size_t length, void *handle)
|
||||
bool save_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, void *handle)
|
||||
{
|
||||
struct save_state *sv = handle;
|
||||
size_t new_length;
|
||||
const char *text;
|
||||
int space = 0;
|
||||
size_t len;
|
||||
|
||||
assert(sv);
|
||||
|
||||
if (box) {
|
||||
len = min(length, box->length - offset);
|
||||
text = box->text + offset;
|
||||
|
||||
if (box->space && length > len) space = 1;
|
||||
}
|
||||
else {
|
||||
if (!text) {
|
||||
text = "\n";
|
||||
len = 1;
|
||||
length = 1;
|
||||
}
|
||||
|
||||
new_length = sv->length + len + space;
|
||||
new_length = sv->length + length + space;
|
||||
if (new_length >= sv->alloc) {
|
||||
size_t new_alloc = sv->alloc + (sv->alloc / 4);
|
||||
char *new_block;
|
||||
|
@ -895,8 +837,8 @@ bool save_handler(struct box *box, int offset, size_t length, void *handle)
|
|||
sv->alloc = new_alloc;
|
||||
}
|
||||
|
||||
memcpy(sv->block + sv->length, text, len);
|
||||
sv->length += len;
|
||||
memcpy(sv->block + sv->length, text, length);
|
||||
sv->length += length;
|
||||
|
||||
if (space)
|
||||
sv->block[sv->length++] = ' ';
|
||||
|
@ -915,11 +857,14 @@ bool save_handler(struct box *box, int offset, size_t length, void *handle)
|
|||
|
||||
bool selection_save_text(struct selection *s, const char *path)
|
||||
{
|
||||
struct content *c = s->bw->current_content;
|
||||
struct save_state sv = { NULL, 0, 0 };
|
||||
utf8_convert_ret ret;
|
||||
char *result;
|
||||
FILE *out;
|
||||
|
||||
assert(c);
|
||||
|
||||
if (!selection_traverse(s, save_handler, &sv)) {
|
||||
free(sv.block);
|
||||
return false;
|
||||
|
|
|
@ -44,8 +44,8 @@ struct selection
|
|||
};
|
||||
|
||||
|
||||
typedef bool (*seln_traverse_handler)(struct box *b, int offset,
|
||||
size_t length, void *handle);
|
||||
typedef bool (*seln_traverse_handler)(const char *text, size_t length,
|
||||
bool space, struct box *box, void *handle);
|
||||
|
||||
|
||||
struct selection *selection_create(struct browser_window *bw);
|
||||
|
@ -70,24 +70,23 @@ void selection_reinit(struct selection *s, struct box *root);
|
|||
void selection_clear(struct selection *s, bool redraw);
|
||||
void selection_select_all(struct selection *s);
|
||||
|
||||
void selection_set_start(struct selection *s, struct box *box, int idx);
|
||||
void selection_set_end(struct selection *s, struct box *box, int idx);
|
||||
void selection_set_start(struct selection *s, unsigned idx);
|
||||
void selection_set_end(struct selection *s, unsigned idx);
|
||||
|
||||
struct box *selection_get_start(struct selection *s, int *pidx);
|
||||
struct box *selection_get_end(struct selection *s, int *pidx);
|
||||
|
||||
bool selection_click(struct selection *s, struct box *box, browser_mouse_state mouse,
|
||||
int dx, int dy);
|
||||
void selection_track(struct selection *s, struct box *box, browser_mouse_state mouse,
|
||||
int dx, int dy);
|
||||
bool selection_click(struct selection *s, browser_mouse_state mouse, unsigned idx);
|
||||
void selection_track(struct selection *s, browser_mouse_state mouse, unsigned idx);
|
||||
|
||||
void selection_drag_end(struct selection *s, struct box *box,
|
||||
browser_mouse_state mouse, int dx, int dy);
|
||||
/** Handles completion of a drag operation */
|
||||
/* void selection_drag_end(struct selection *s); */
|
||||
#define selection_drag_end(s) ((s)->drag_state = DRAG_NONE)
|
||||
|
||||
bool selection_traverse(struct selection *s, seln_traverse_handler handler,
|
||||
void *handle);
|
||||
|
||||
bool selection_highlighted(struct selection *s, struct box *box,
|
||||
bool selection_highlighted(struct selection *s, unsigned start, unsigned end,
|
||||
unsigned *start_idx, unsigned *end_idx);
|
||||
|
||||
bool selection_save_text(struct selection *s, const char *path);
|
||||
|
|
|
@ -74,6 +74,60 @@ static bool word_left(const char *text, int *poffset, int *pchars);
|
|||
static bool word_right(const char *text, int len, int *poffset, int *pchars);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given text caret from the window by invalidating it
|
||||
* and causing its former position to be redrawn.
|
||||
*
|
||||
* \param c structure describing text caret
|
||||
*/
|
||||
|
||||
void caret_remove(struct caret *c)
|
||||
{
|
||||
if (c->defined) {
|
||||
int w = (c->height + 7) / 8;
|
||||
int xc = c->x;
|
||||
c->defined = false;
|
||||
browser_window_redraw_rect(c->bw, xc - w, c->y, 2 * w, c->height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the given text caret's position within the window (text box
|
||||
* and byte/pixel offsets within the UTF-8 content of that text box)
|
||||
* and draw it.
|
||||
*
|
||||
* \param c structure describing text caret
|
||||
* \param bw browser window containing caret
|
||||
* \param box INLINE box containing caret
|
||||
* \param char_offset byte offset within UTF-8 representation
|
||||
* \param pixel_offset from left side of box
|
||||
*/
|
||||
|
||||
void caret_set_position(struct caret *c, struct browser_window *bw,
|
||||
struct box *text_box, int char_offset, int pixel_offset)
|
||||
{
|
||||
struct rect r;
|
||||
int xc;
|
||||
int w;
|
||||
|
||||
box_bounds(text_box, &r);
|
||||
|
||||
c->bw = bw;
|
||||
c->text_box = text_box;
|
||||
c->char_offset = char_offset;
|
||||
|
||||
c->x = xc = r.x0 + pixel_offset;
|
||||
c->y = r.y0;
|
||||
c->height = r.y1 - r.y0;
|
||||
w = (c->height + 7) / 8;
|
||||
|
||||
c->defined = true;
|
||||
|
||||
browser_window_redraw_rect(c->bw, xc - w, c->y, w * 2, c->height);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given the x,y co-ordinates of a point within a textarea, return the
|
||||
* INLINE box pointer, and the character and pixel offsets within that
|
||||
|
|
27
render/box.c
27
render/box.c
|
@ -47,8 +47,9 @@ struct box * box_create(struct css_style *style,
|
|||
struct box *box;
|
||||
|
||||
box = talloc(context, struct box);
|
||||
if (!box)
|
||||
if (!box) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
box->type = BOX_INLINE;
|
||||
box->style = style;
|
||||
|
@ -231,6 +232,27 @@ void box_coords(struct box *box, int *x, int *y)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the bounds of a box.
|
||||
*
|
||||
* \param box the box to calculate bounds of
|
||||
* \param r receives bounds
|
||||
*/
|
||||
|
||||
void box_bounds(struct box *box, struct rect *r)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
box_coords(box, &r->x0, &r->y0);
|
||||
|
||||
width = box->padding[LEFT] + box->width + box->padding[RIGHT];
|
||||
height = box->padding[TOP] + box->height + box->padding[BOTTOM];
|
||||
|
||||
r->x1 = r->x0 + width;
|
||||
r->y1 = r->y0 + height;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the boxes at a point.
|
||||
*
|
||||
|
@ -244,7 +266,7 @@ void box_coords(struct box *box, int *x, int *y)
|
|||
* \param content updated to content of object that returned box is in, if any
|
||||
* \return box at given point, or 0 if none found
|
||||
*
|
||||
* To find all the boxes in the heirarchy at a certain point, use code like
|
||||
* To find all the boxes in the hierarchy at a certain point, use code like
|
||||
* this:
|
||||
* \code
|
||||
* struct box *box = top_of_document_to_search;
|
||||
|
@ -469,6 +491,7 @@ void box_dump(struct box *box, unsigned int depth)
|
|||
default: fprintf(stderr, "Unknown box type ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "ofst %d", box->byte_offset);
|
||||
if (box->text)
|
||||
fprintf(stderr, "'%.*s' ", (int) box->length, box->text);
|
||||
if (box->space)
|
||||
|
|
|
@ -96,6 +96,12 @@ typedef enum {
|
|||
BOX_INLINE_END
|
||||
} box_type;
|
||||
|
||||
struct rect {
|
||||
int x0, y0;
|
||||
int x1, y1;
|
||||
};
|
||||
|
||||
|
||||
/** Node in box tree. All dimensions are in pixels. */
|
||||
struct box {
|
||||
/** Type of box. */
|
||||
|
@ -254,6 +260,7 @@ void box_unlink_and_free(struct box *box);
|
|||
void box_free(struct box *box);
|
||||
void box_free_box(struct box *box);
|
||||
void box_free_object_params(struct object_params *op);
|
||||
void box_bounds(struct box *box, struct rect *r);
|
||||
void box_coords(struct box *box, int *x, int *y);
|
||||
struct box *box_at_point(struct box *box, int x, int y,
|
||||
int *box_x, int *box_y,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "netsurf/css/css.h"
|
||||
|
||||
struct box;
|
||||
struct rect;
|
||||
struct browser_window;
|
||||
struct content;
|
||||
struct form_successful_control;
|
||||
|
@ -125,4 +126,17 @@ bool html_redraw(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, unsigned long background_colour);
|
||||
|
||||
|
||||
/* redraw a short text string, complete with highlighting
|
||||
(for selection/search) and ghost caret */
|
||||
|
||||
bool text_redraw(const char *utf8_text, size_t utf8_len,
|
||||
size_t offset, bool space,
|
||||
struct css_style *style,
|
||||
int x, int y,
|
||||
struct rect *clip,
|
||||
int height,
|
||||
float scale, colour current_background_color,
|
||||
bool excluded);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/plotters.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/form.h"
|
||||
|
@ -34,6 +35,8 @@ static bool html_redraw_box(struct box *box,
|
|||
static bool html_redraw_text_box(struct box *box, int x, int y,
|
||||
int x0, int y0, int x1, int y1,
|
||||
float scale, colour current_background_color);
|
||||
static bool html_redraw_caret(struct caret *caret,
|
||||
os_colour current_background_color, float scale);
|
||||
static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
|
||||
int padding_width, int padding_height, float scale);
|
||||
static bool html_redraw_border_plot(int i, int *p, colour c,
|
||||
|
@ -369,26 +372,77 @@ bool html_redraw_box(struct box *box,
|
|||
bool html_redraw_text_box(struct box *box, int x, int y,
|
||||
int x0, int y0, int x1, int y1,
|
||||
float scale, colour current_background_color)
|
||||
{
|
||||
bool excluded = (box->object != NULL);
|
||||
struct rect clip;
|
||||
|
||||
clip.x0 = x0;
|
||||
clip.y0 = y0;
|
||||
clip.x1 = x1;
|
||||
clip.y1 = y1;
|
||||
|
||||
if (!text_redraw(box->text, box->length, box->byte_offset,
|
||||
box->space, box->style, x, y,
|
||||
&clip, box->height, scale,
|
||||
current_background_color, excluded))
|
||||
return false;
|
||||
|
||||
/* does this textbox contain the ghost caret? */
|
||||
if (ghost_caret.defined && box == ghost_caret.text_box) {
|
||||
|
||||
if (!html_redraw_caret(&ghost_caret, current_background_color, scale))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Redraw a short text string, complete with highlighting
|
||||
* (for selection/search) and ghost caret
|
||||
*
|
||||
* \param utf8_text pointer to UTF-8 text string
|
||||
* \param utf8_len length of string, in bytes
|
||||
* \param offset byte offset within textual representation
|
||||
* \param space indicates whether string is followed by a space
|
||||
* \param style text style to use
|
||||
* \param x x ordinate at which to plot text
|
||||
* \param y y ordinate at which to plot text
|
||||
* \param clip pointer to current clip rectangle
|
||||
* \param height height of text string
|
||||
* \param scale current display scale (1.0 = 100%)
|
||||
* \param current_background_color
|
||||
* \param excluded exclude this text string from the selection
|
||||
* \return true iff successful and redraw should proceed
|
||||
*/
|
||||
|
||||
bool text_redraw(const char *utf8_text, size_t utf8_len,
|
||||
size_t offset, bool space, struct css_style *style,
|
||||
int x, int y, struct rect *clip,
|
||||
int height,
|
||||
float scale, colour current_background_color,
|
||||
bool excluded)
|
||||
{
|
||||
bool highlighted = false;
|
||||
|
||||
/* is this box part of a selection? */
|
||||
if (!box->object && current_redraw_browser) {
|
||||
if (!excluded && current_redraw_browser) {
|
||||
unsigned len = utf8_len + (space ? 1 : 0);
|
||||
unsigned start_idx;
|
||||
unsigned end_idx;
|
||||
|
||||
/* first try the browser window's current selection */
|
||||
if (selection_defined(current_redraw_browser->sel) &&
|
||||
selection_highlighted(current_redraw_browser->sel,
|
||||
box, &start_idx, &end_idx)) {
|
||||
offset, offset + len, &start_idx, &end_idx)) {
|
||||
highlighted = true;
|
||||
}
|
||||
|
||||
/* what about the current search operation, if any */
|
||||
/* what about the current search operation, if any? */
|
||||
if (!highlighted &&
|
||||
search_current_window == current_redraw_browser->window &&
|
||||
gui_search_term_highlighted(current_redraw_browser->window,
|
||||
box, &start_idx, &end_idx)) {
|
||||
offset, offset + len, &start_idx, &end_idx)) {
|
||||
highlighted = true;
|
||||
}
|
||||
|
||||
|
@ -400,23 +454,23 @@ bool html_redraw_text_box(struct box *box, int x, int y,
|
|||
bool text_visible = true;
|
||||
int startx, endx;
|
||||
|
||||
if (end_idx > box->length) {
|
||||
/* adjust for trailing space, not present in box->text */
|
||||
assert(end_idx == box->length + 1);
|
||||
endtxt_idx = box->length;
|
||||
if (end_idx > utf8_len) {
|
||||
/* adjust for trailing space, not present in utf8_text */
|
||||
assert(end_idx == utf8_len + 1);
|
||||
endtxt_idx = utf8_len;
|
||||
}
|
||||
|
||||
if (!nsfont_width(box->style, box->text, start_idx, &startx))
|
||||
if (!nsfont_width(style, utf8_text, start_idx, &startx))
|
||||
startx = 0;
|
||||
|
||||
if (!nsfont_width(box->style, box->text, endtxt_idx, &endx))
|
||||
if (!nsfont_width(style, utf8_text, endtxt_idx, &endx))
|
||||
endx = 0;
|
||||
|
||||
/* is there a trailing space that should be highlighted as well? */
|
||||
if (end_idx > box->length) {
|
||||
if (end_idx > utf8_len) {
|
||||
int spc_width;
|
||||
/* \todo is there a more elegant/efficient solution? */
|
||||
if (nsfont_width(box->style, " ", 1, &spc_width))
|
||||
if (nsfont_width(style, " ", 1, &spc_width))
|
||||
endx += spc_width;
|
||||
}
|
||||
|
||||
|
@ -427,10 +481,10 @@ bool html_redraw_text_box(struct box *box, int x, int y,
|
|||
|
||||
/* draw any text preceding highlighted portion */
|
||||
if (start_idx > 0 &&
|
||||
!plot.text(x, y + (int) (box->height * 0.75 * scale),
|
||||
box->style, box->text, start_idx,
|
||||
!plot.text(x, y + (int) (height * 0.75 * scale),
|
||||
style, utf8_text, start_idx,
|
||||
current_background_color,
|
||||
/*print_text_black ? 0 :*/ box->style->color))
|
||||
/*print_text_black ? 0 :*/ style->color))
|
||||
return false;
|
||||
|
||||
/* decide whether highlighted portion is to be white-on-black or
|
||||
|
@ -442,16 +496,16 @@ bool html_redraw_text_box(struct box *box, int x, int y,
|
|||
hfore_col = hback_col ^ 0xffffff;
|
||||
|
||||
/* highlighted portion */
|
||||
if (!plot.fill(x + startx, y, x + endx, y + box->height * scale,
|
||||
if (!plot.fill(x + startx, y, x + endx, y + height * scale,
|
||||
hback_col))
|
||||
return false;
|
||||
|
||||
if (start_idx > 0) {
|
||||
int px0 = max(x + startx, x0);
|
||||
int px1 = min(x + endx, x1);
|
||||
int px0 = max(x + startx, clip->x0);
|
||||
int px1 = min(x + endx, clip->x1);
|
||||
|
||||
if (px0 < px1) {
|
||||
if (!plot.clip(px0, y0, px1, y1))
|
||||
if (!plot.clip(px0, clip->y0, px1, clip->y1))
|
||||
return false;
|
||||
clip_changed = true;
|
||||
} else
|
||||
|
@ -459,46 +513,75 @@ bool html_redraw_text_box(struct box *box, int x, int y,
|
|||
}
|
||||
|
||||
if (text_visible &&
|
||||
!plot.text(x, y + (int) (box->height * 0.75 * scale),
|
||||
box->style, box->text, endtxt_idx,
|
||||
!plot.text(x, y + (int) (height * 0.75 * scale),
|
||||
style, utf8_text, endtxt_idx,
|
||||
hback_col, hfore_col))
|
||||
return false;
|
||||
|
||||
/* draw any text succeeding highlighted portion */
|
||||
if (endtxt_idx < box->length) {
|
||||
int px0 = max(x + endx, x0);
|
||||
if (px0 < x1) {
|
||||
if (endtxt_idx < utf8_len) {
|
||||
int px0 = max(x + endx, clip->x0);
|
||||
if (px0 < clip->x1) {
|
||||
|
||||
if (!plot.clip(px0, y0, x1, y1))
|
||||
if (!plot.clip(px0, clip->y0, clip->x1, clip->y1))
|
||||
return false;
|
||||
|
||||
clip_changed = true;
|
||||
|
||||
if (!plot.text(x, y + (int) (box->height * 0.75 * scale),
|
||||
box->style, box->text, box->length,
|
||||
if (!plot.text(x, y + (int) (height * 0.75 * scale),
|
||||
style, utf8_text, utf8_len,
|
||||
current_background_color,
|
||||
/*print_text_black ? 0 :*/ box->style->color))
|
||||
/*print_text_black ? 0 :*/ style->color))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (clip_changed && !plot.clip(x0, y0, x1, y1))
|
||||
if (clip_changed &&
|
||||
!plot.clip(clip->x0, clip->y0, clip->x1, clip->y1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!highlighted) {
|
||||
if (!plot.text(x, y + (int) (box->height * 0.75 * scale),
|
||||
box->style, box->text, box->length,
|
||||
if (!plot.text(x, y + (int) (height * 0.75 * scale),
|
||||
style, utf8_text, utf8_len,
|
||||
current_background_color,
|
||||
/*print_text_black ? 0 :*/ box->style->color))
|
||||
/*print_text_black ? 0 :*/ style->color))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw text caret.
|
||||
*
|
||||
* \param c structure describing text caret
|
||||
* \param current_background_color background colour under the caret
|
||||
* \param scale current scale setting (1.0 = 100%)
|
||||
* \return true iff successful and redraw should proceed
|
||||
*/
|
||||
|
||||
bool html_redraw_caret(struct caret *c, os_colour current_background_color,
|
||||
float scale)
|
||||
{
|
||||
os_colour caret_color = 0x808080; /* todo - choose a proper colour */
|
||||
int xc = c->x, y = c->y;
|
||||
int h = c->height - 1;
|
||||
int w = (h + 7) / 8;
|
||||
|
||||
return (plot.line(xc * scale, y * scale,
|
||||
xc * scale, (y + h) * scale,
|
||||
0, caret_color, false, false) &&
|
||||
plot.line((xc - w) * scale, y * scale,
|
||||
(xc + w) * scale, y * scale,
|
||||
0, caret_color, false, false) &&
|
||||
plot.line((xc - w) * scale, (y + h) * scale,
|
||||
(xc + w) * scale, (y + h) * scale,
|
||||
0, caret_color, false, false));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw borders for a box.
|
||||
*
|
||||
|
@ -514,10 +597,17 @@ bool html_redraw_text_box(struct box *box, int x, int y,
|
|||
bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
|
||||
int padding_width, int padding_height, float scale)
|
||||
{
|
||||
int top = box->border[TOP] * scale;
|
||||
int right = box->border[RIGHT] * scale;
|
||||
int bottom = box->border[BOTTOM] * scale;
|
||||
int left = box->border[LEFT] * scale;
|
||||
int top = box->border[TOP];
|
||||
int right = box->border[RIGHT];
|
||||
int bottom = box->border[BOTTOM];
|
||||
int left = box->border[LEFT];
|
||||
|
||||
if (scale != 1.0) {
|
||||
top *= scale;
|
||||
right *= scale;
|
||||
bottom *= scale;
|
||||
left *= scale;
|
||||
}
|
||||
|
||||
assert(box->style);
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Content for text/plain (implementation).
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <iconv.h>
|
||||
|
@ -16,6 +18,7 @@
|
|||
#include "netsurf/css/css.h"
|
||||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/plotters.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/textplain.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
|
@ -76,8 +79,9 @@ bool textplain_create(struct content *c, const char *params[])
|
|||
c->data.textplain.utf8_data = utf8_data;
|
||||
c->data.textplain.utf8_data_size = 0;
|
||||
c->data.textplain.utf8_data_allocated = CHUNK;
|
||||
c->data.textplain.physical_line_start = 0;
|
||||
c->data.textplain.physical_line = 0;
|
||||
c->data.textplain.physical_line_count = 0;
|
||||
c->data.textplain.formatted_width = 0;
|
||||
|
||||
return true;
|
||||
|
||||
|
@ -169,11 +173,12 @@ void textplain_reformat(struct content *c, int width, int height)
|
|||
char *utf8_data = c->data.textplain.utf8_data;
|
||||
size_t utf8_data_size = c->data.textplain.utf8_data_size;
|
||||
unsigned long line_count = 0;
|
||||
size_t *line_start = c->data.textplain.physical_line_start;
|
||||
size_t *line_start1;
|
||||
struct textplain_line *line = c->data.textplain.physical_line;
|
||||
struct textplain_line *line1;
|
||||
size_t i, space, col;
|
||||
size_t columns = 80;
|
||||
int character_width;
|
||||
size_t line_start;
|
||||
|
||||
/* compute available columns (assuming monospaced font) - use 8
|
||||
* characters for better accuracy */
|
||||
|
@ -181,30 +186,49 @@ void textplain_reformat(struct content *c, int width, int height)
|
|||
return;
|
||||
columns = (width - MARGIN - MARGIN) * 8 / character_width;
|
||||
|
||||
c->data.textplain.formatted_width = width;
|
||||
|
||||
c->data.textplain.physical_line_count = 0;
|
||||
|
||||
if (!line_start) {
|
||||
c->data.textplain.physical_line_start = line_start =
|
||||
talloc_array(c, size_t, 1024 + 3);
|
||||
if (!line_start)
|
||||
if (!line) {
|
||||
c->data.textplain.physical_line = line =
|
||||
talloc_array(c, struct textplain_line, 1024 + 3);
|
||||
if (!line)
|
||||
goto no_memory;
|
||||
}
|
||||
|
||||
line_start[line_count++] = 0;
|
||||
line[line_count++].start = line_start = 0;
|
||||
space = 0;
|
||||
for (i = 0, col = 0; i != utf8_data_size; i++) {
|
||||
if (utf8_data[i] == '\n' || col + 1 == columns) {
|
||||
bool term = (utf8_data[i] == '\n' || utf8_data[i] == '\r');
|
||||
if (term || col + 1 == columns) {
|
||||
if (line_count % 1024 == 0) {
|
||||
line_start1 = talloc_realloc(c, line_start,
|
||||
size_t, line_count + 1024 + 3);
|
||||
if (!line_start1)
|
||||
line1 = talloc_realloc(c, line,
|
||||
struct textplain_line, line_count + 1024 + 3);
|
||||
if (!line1)
|
||||
goto no_memory;
|
||||
c->data.textplain.physical_line_start =
|
||||
line_start = line_start1;
|
||||
}
|
||||
if (utf8_data[i] != '\n' && space)
|
||||
i = space;
|
||||
line_start[line_count++] = i + 1;
|
||||
c->data.textplain.physical_line =
|
||||
line = line1;
|
||||
}
|
||||
if (term) {
|
||||
line[line_count-1].length = i - line_start;
|
||||
|
||||
/* skip second char of CR/LF or LF/CR pair */
|
||||
if (i + 1 < utf8_data_size &&
|
||||
utf8_data[i+1] != utf8_data[i] &&
|
||||
(utf8_data[i+1] == '\n' || utf8_data[i+1] == '\r'))
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
if (space) {
|
||||
/* break at last space in line */
|
||||
i = space;
|
||||
line[line_count-1].length = (i + 1) - line_start;
|
||||
}
|
||||
else
|
||||
line[line_count-1].length = i - line_start;
|
||||
}
|
||||
line[line_count++].start = line_start = i + 1;
|
||||
col = 0;
|
||||
space = 0;
|
||||
} else {
|
||||
|
@ -213,7 +237,8 @@ void textplain_reformat(struct content *c, int width, int height)
|
|||
space = i;
|
||||
}
|
||||
}
|
||||
line_start[line_count] = utf8_data_size;
|
||||
line[line_count-1].length = i - line[line_count-1].start;
|
||||
line[line_count].start = utf8_data_size;
|
||||
|
||||
c->data.textplain.physical_line_count = line_count;
|
||||
c->width = width;
|
||||
|
@ -266,14 +291,21 @@ bool textplain_redraw(struct content *c, int x, int y,
|
|||
float scale, unsigned long background_colour)
|
||||
{
|
||||
char *utf8_data = c->data.textplain.utf8_data;
|
||||
long line;
|
||||
long lineno;
|
||||
unsigned long line_count = c->data.textplain.physical_line_count;
|
||||
float line_height = css_len2px(&textplain_style.font_size.value.length,
|
||||
&textplain_style) * 1.2 * scale;
|
||||
long line0 = clip_y0 / line_height - 1;
|
||||
long line1 = clip_y1 / line_height + 1;
|
||||
size_t *line_start = c->data.textplain.physical_line_start;
|
||||
&textplain_style) * 1.2;
|
||||
float scaled_line_height = line_height * scale;
|
||||
long line0 = clip_y0 / scaled_line_height - 1;
|
||||
long line1 = clip_y1 / scaled_line_height + 1;
|
||||
struct textplain_line *line = c->data.textplain.physical_line;
|
||||
size_t length;
|
||||
struct rect clip;
|
||||
|
||||
clip.x0 = clip_x0;
|
||||
clip.y0 = clip_y0;
|
||||
clip.x1 = clip_x1;
|
||||
clip.y1 = clip_y1;
|
||||
|
||||
if (line0 < 0)
|
||||
line0 = 0;
|
||||
|
@ -289,23 +321,219 @@ bool textplain_redraw(struct content *c, int x, int y,
|
|||
if (!plot.clg(0xffffff))
|
||||
return false;
|
||||
|
||||
if (!line_start)
|
||||
if (!line)
|
||||
return true;
|
||||
|
||||
x += MARGIN * scale;
|
||||
y += MARGIN * scale;
|
||||
for (line = line0; line != line1; line++) {
|
||||
length = line_start[line + 1] - line_start[line];
|
||||
for (lineno = line0; lineno != line1; lineno++) {
|
||||
length = line[lineno].length;
|
||||
if (!length)
|
||||
continue;
|
||||
if (utf8_data[line_start[line] + length - 1] == '\n')
|
||||
length--;
|
||||
if (!plot.text(x, y + (line + 1) * line_height,
|
||||
&textplain_style,
|
||||
utf8_data + line_start[line], length,
|
||||
0xffffff, 0x000000))
|
||||
if (!text_redraw(utf8_data + line[lineno].start, length,
|
||||
line[lineno].start, false, &textplain_style,
|
||||
x, y + (lineno * scaled_line_height),
|
||||
&clip, line_height, scale,
|
||||
background_colour, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return byte offset within UTF8 textplain content, given the co-ordinates
|
||||
* of a point within a textplain content. 'dir' specifies the direction in
|
||||
* which to search (-1 = above-left, +1 = below-right) if the co-ordinates are not
|
||||
* contained within a line.
|
||||
*
|
||||
* \param c content of type CONTENT_TEXTPLAIN
|
||||
* \param x x ordinate of point
|
||||
* \param y y ordinate of point
|
||||
* \param dir direction of search if not within line
|
||||
* \return ptr to start of line containing (or nearest to) point
|
||||
*/
|
||||
|
||||
unsigned textplain_offset_from_coords(struct content *c, int x, int y, int dir)
|
||||
{
|
||||
float line_height = css_len2px(&textplain_style.font_size.value.length,
|
||||
&textplain_style) * 1.2;
|
||||
struct textplain_line *line;
|
||||
int pixel_offset;
|
||||
unsigned nlines;
|
||||
int idx;
|
||||
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
|
||||
y = (int)((float)(y - MARGIN) / line_height);
|
||||
x -= MARGIN;
|
||||
|
||||
nlines = c->data.textplain.physical_line_count;
|
||||
if (!nlines)
|
||||
return 0;
|
||||
|
||||
if (y < 0) y = 0;
|
||||
else if (y >= nlines)
|
||||
y = nlines - 1;
|
||||
line = &c->data.textplain.physical_line[y];
|
||||
|
||||
if (x < 0) x = 0;
|
||||
|
||||
nsfont_position_in_string(&textplain_style,
|
||||
c->data.textplain.utf8_data + line->start,
|
||||
line->length,
|
||||
x,
|
||||
&idx,
|
||||
&pixel_offset);
|
||||
|
||||
return line->start + idx;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a byte offset within the text, return the line number
|
||||
* of the line containing that offset (or -1 if offset invalid)
|
||||
*
|
||||
* \param c content of type CONTENT_TEXTPLAIN
|
||||
* \param offset byte offset within textual representation
|
||||
* \return line number, or -1 if offset invalid (larger than size)
|
||||
*/
|
||||
|
||||
int textplain_find_line(struct content *c, unsigned offset)
|
||||
{
|
||||
struct textplain_line *line = c->data.textplain.physical_line;
|
||||
int nlines = c->data.textplain.physical_line_count;
|
||||
int lineno = 0;
|
||||
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
|
||||
if (offset > c->data.textplain.utf8_data_size)
|
||||
return -1;
|
||||
|
||||
/* \todo - implement binary search here */
|
||||
while (lineno < nlines && line[lineno].start < offset)
|
||||
lineno++;
|
||||
if (line[lineno].start > offset)
|
||||
lineno--;
|
||||
|
||||
return lineno;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a range of byte offsets within a UTF8 textplain content,
|
||||
* return a box that fully encloses the text
|
||||
*
|
||||
* \param c content of type CONTENT_TEXTPLAIN
|
||||
* \param start byte offset of start of text range
|
||||
* \param end byte offset of end
|
||||
* \param r rectangle to be completed
|
||||
*/
|
||||
|
||||
void textplain_coords_from_range(struct content *c, unsigned start, unsigned end,
|
||||
struct rect *r)
|
||||
{
|
||||
float line_height = css_len2px(&textplain_style.font_size.value.length,
|
||||
&textplain_style) * 1.2;
|
||||
char *utf8_data = c->data.textplain.utf8_data;
|
||||
struct textplain_line *line;
|
||||
unsigned lineno = 0;
|
||||
unsigned nlines;
|
||||
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
assert(start <= end);
|
||||
assert(end <= c->data.textplain.utf8_data_size);
|
||||
|
||||
nlines = c->data.textplain.physical_line_count;
|
||||
line = c->data.textplain.physical_line;
|
||||
|
||||
/* find start */
|
||||
lineno = textplain_find_line(c, start);
|
||||
|
||||
r->y0 = (int)(MARGIN + lineno * line_height);
|
||||
|
||||
if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
|
||||
/* \todo - it may actually be more efficient just to run
|
||||
forwards most of the time */
|
||||
|
||||
/* find end */
|
||||
lineno = textplain_find_line(c, end);
|
||||
|
||||
r->x0 = 0;
|
||||
r->x1 = c->data.textplain.formatted_width;
|
||||
}
|
||||
else {
|
||||
/* single line */
|
||||
nsfont_width(&textplain_style,
|
||||
utf8_data + line[lineno].start,
|
||||
start - line[lineno].start,
|
||||
&r->x0);
|
||||
|
||||
nsfont_width(&textplain_style,
|
||||
utf8_data + line[lineno].start,
|
||||
min(line[lineno].length, end - line[lineno].start),
|
||||
&r->x1);
|
||||
}
|
||||
|
||||
r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a pointer to the requested line of text.
|
||||
*
|
||||
* \param c content of type CONTENT_TEXTPLAIN
|
||||
* \param lineno line number
|
||||
* \param poffset receives byte offset of line start within text
|
||||
* \param plen receives length of returned line
|
||||
* \return pointer to text, or NULL if invalid line number
|
||||
*/
|
||||
|
||||
char *textplain_get_line(struct content *c, unsigned lineno,
|
||||
size_t *poffset, size_t *plen)
|
||||
{
|
||||
struct textplain_line *line;
|
||||
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
|
||||
if (lineno >= c->data.textplain.physical_line_count)
|
||||
return NULL;
|
||||
line = &c->data.textplain.physical_line[lineno];
|
||||
|
||||
*poffset = line->start;
|
||||
*plen = line->length;
|
||||
return c->data.textplain.utf8_data + line->start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a pointer to the raw UTF-8 data, as opposed to the reformatted
|
||||
* text to fit the window width. Thus only hard newlines are preserved
|
||||
* in the saved/copied text of a selection.
|
||||
*
|
||||
* \param c content of type CONTENT_TEXTPLAIN
|
||||
* \param start starting byte offset within UTF-8 text
|
||||
* \param end ending byte offset
|
||||
* \param plen receives validated length
|
||||
* \return pointer to text, or NULL if no text
|
||||
*/
|
||||
|
||||
char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
|
||||
size_t *plen)
|
||||
{
|
||||
size_t utf8_size = c->data.textplain.utf8_data_size;
|
||||
|
||||
assert(c->type == CONTENT_TEXTPLAIN);
|
||||
|
||||
/* any text at all? */
|
||||
if (!utf8_size) return NULL;
|
||||
|
||||
/* clamp to valid offset range */
|
||||
if (start >= utf8_size) start = utf8_size;
|
||||
if (end >= utf8_size) end = utf8_size;
|
||||
|
||||
*plen = end - start;
|
||||
|
||||
return c->data.textplain.utf8_data + start;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
|
@ -12,10 +13,16 @@
|
|||
#ifndef _NETSURF_RENDER_TEXTPLAIN_H_
|
||||
#define _NETSURF_RENDER_TEXTPLAIN_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <iconv.h>
|
||||
|
||||
struct content;
|
||||
|
||||
struct textplain_line {
|
||||
size_t start;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct content_textplain_data {
|
||||
const char *encoding;
|
||||
iconv_t iconv_cd;
|
||||
|
@ -24,7 +31,8 @@ struct content_textplain_data {
|
|||
size_t utf8_data_size;
|
||||
size_t utf8_data_allocated;
|
||||
unsigned long physical_line_count;
|
||||
size_t *physical_line_start;
|
||||
struct textplain_line *physical_line;
|
||||
int formatted_width;
|
||||
};
|
||||
|
||||
bool textplain_create(struct content *c, const char *params[]);
|
||||
|
@ -37,4 +45,17 @@ bool textplain_redraw(struct content *c, int x, int y,
|
|||
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
|
||||
float scale, unsigned long background_colour);
|
||||
|
||||
/* access to lines for text selection and searching */
|
||||
#define textplain_line_count(c) ((c)->data.textplain.physical_line_count)
|
||||
#define textplain_size(c) ((c)->data.textplain.utf8_data_size)
|
||||
|
||||
size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
|
||||
void textplain_coords_from_range(struct content *c,
|
||||
unsigned start, unsigned end, struct rect *r);
|
||||
char *textplain_get_line(struct content *c, unsigned lineno,
|
||||
size_t *poffset, size_t *plen);
|
||||
int textplain_find_line(struct content *c, unsigned offset);
|
||||
char *textplain_get_raw_data(struct content *c,
|
||||
unsigned start, unsigned end, size_t *plen);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "netsurf/riscos/gui.h"
|
||||
#include "netsurf/riscos/menus.h"
|
||||
#include "netsurf/riscos/options.h"
|
||||
#include "netsurf/riscos/save.h"
|
||||
#include "netsurf/riscos/theme.h"
|
||||
#include "netsurf/riscos/url_complete.h"
|
||||
#include "netsurf/riscos/wimp.h"
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/riscos/dialog.h"
|
||||
#include "netsurf/riscos/options.h"
|
||||
#include "netsurf/riscos/save.h"
|
||||
#include "netsurf/riscos/query.h"
|
||||
#include "netsurf/riscos/wimp.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
|
@ -1294,7 +1295,7 @@ bool ro_gui_download_window_destroy(struct gui_download_window *dw, bool quit)
|
|||
|
||||
struct gui_download_window *d = download_window_list;
|
||||
while (d) {
|
||||
ro_gui_open_window_at_front(d->window);
|
||||
ro_gui_dialog_open_top(d->window, NULL, 0, 0);
|
||||
d = d->next;
|
||||
}
|
||||
}
|
||||
|
|
28
riscos/gui.c
28
riscos/gui.c
|
@ -64,7 +64,9 @@
|
|||
#include "netsurf/riscos/print.h"
|
||||
#endif
|
||||
#include "netsurf/riscos/query.h"
|
||||
#include "netsurf/riscos/save.h"
|
||||
#include "netsurf/riscos/save_complete.h"
|
||||
#include "netsurf/riscos/textselection.h"
|
||||
#include "netsurf/riscos/theme.h"
|
||||
#include "netsurf/riscos/treeview.h"
|
||||
#ifdef WITH_URI
|
||||
|
@ -166,7 +168,7 @@ static struct {
|
|||
} prev_sigs;
|
||||
|
||||
/** Accepted wimp user messages. */
|
||||
static wimp_MESSAGE_LIST(38) task_messages = { {
|
||||
static wimp_MESSAGE_LIST(40) task_messages = { {
|
||||
message_HELP_REQUEST,
|
||||
message_DATA_SAVE,
|
||||
message_DATA_SAVE_ACK,
|
||||
|
@ -180,6 +182,8 @@ static wimp_MESSAGE_LIST(38) task_messages = { {
|
|||
message_MODE_CHANGE,
|
||||
message_CLAIM_ENTITY,
|
||||
message_DATA_REQUEST,
|
||||
message_DRAGGING,
|
||||
message_DRAG_CLAIM,
|
||||
#ifdef WITH_URI
|
||||
message_URI_PROCESS,
|
||||
message_URI_RETURN_RESULT,
|
||||
|
@ -396,6 +400,10 @@ void gui_init(int argc, char** argv)
|
|||
ro_msg_prequit);
|
||||
ro_message_register_route(message_SAVE_DESKTOP,
|
||||
ro_msg_save_desktop);
|
||||
ro_message_register_route(message_DRAGGING,
|
||||
ro_gui_selection_dragging);
|
||||
ro_message_register_route(message_DRAG_CLAIM,
|
||||
ro_gui_selection_drag_claim);
|
||||
/* end of handler registration */
|
||||
|
||||
nsfont_init();
|
||||
|
@ -930,6 +938,7 @@ void gui_multitask(void)
|
|||
ro_gui_handle_event(event, &block);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle Null_Reason_Code events.
|
||||
*/
|
||||
|
@ -963,6 +972,10 @@ void ro_gui_null_reason_code(void)
|
|||
ro_gui_window_mouse_at(gui_track_gui_window, &pointer);
|
||||
break;
|
||||
|
||||
// case GUI_DRAG_SAVE:
|
||||
// ro_gui_selection_send_dragging(&pointer);
|
||||
// break;
|
||||
|
||||
default:
|
||||
if (gui_track_wimp_w == history_window)
|
||||
ro_gui_history_mouse_at(&pointer);
|
||||
|
@ -1078,7 +1091,13 @@ void ro_gui_close_window_request(wimp_close *close)
|
|||
if (ro_gui_shift_pressed())
|
||||
return;
|
||||
ro_gui_url_complete_close(NULL, 0);
|
||||
|
||||
/* search must be closed before the main window so that
|
||||
the content still exists */
|
||||
ro_gui_dialog_close_persistent(close->w);
|
||||
browser_window_destroy(g->bw);
|
||||
return;
|
||||
|
||||
} else if ((dw = ro_gui_download_window_lookup(close->w)) != NULL) {
|
||||
ro_gui_download_window_destroy(dw, false);
|
||||
} else {
|
||||
|
@ -1106,8 +1125,9 @@ void ro_gui_pointer_leaving_window(wimp_leaving *leaving)
|
|||
switch (gui_current_drag_type) {
|
||||
case GUI_DRAG_SELECTION:
|
||||
case GUI_DRAG_SCROLL:
|
||||
case GUI_DRAG_SAVE:
|
||||
/* ignore Pointer_Leaving_Window event that the Wimp mysteriously
|
||||
issues when a Wimp_DragBox drag operations is started */
|
||||
issues when a Wimp_DragBox drag operation is started */
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1745,6 +1765,9 @@ void ro_msg_datasave(wimp_message *message)
|
|||
{
|
||||
wimp_full_message_data_xfer *dataxfer = (wimp_full_message_data_xfer*)message;
|
||||
|
||||
/* remove ghost caret if drag-and-drop protocol was used */
|
||||
// ro_gui_selection_drag_reset();
|
||||
|
||||
ro_msg_terminate_filename(dataxfer);
|
||||
|
||||
switch (dataxfer->file_type) {
|
||||
|
@ -1801,6 +1824,7 @@ void ro_msg_datasave_ack(wimp_message *message)
|
|||
|
||||
case GUI_DRAG_SAVE:
|
||||
ro_gui_save_datasave_ack(message);
|
||||
gui_current_drag_type = GUI_DRAG_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
20
riscos/gui.h
20
riscos/gui.h
|
@ -119,14 +119,6 @@ bool ro_gui_download_window_keypress(struct gui_download_window *dw, wimp_key *k
|
|||
/* in mouseactions.c */
|
||||
void ro_gui_mouse_action(struct gui_window *g);
|
||||
|
||||
/* in textselection.c */
|
||||
void ro_gui_selection_drag_end(struct gui_window *g, wimp_dragged *drag);
|
||||
void ro_gui_selection_claim_entity(wimp_full_message_claim_entity *claim);
|
||||
void ro_gui_selection_data_request(wimp_full_message_data_request *req);
|
||||
bool ro_gui_save_clipboard(const char *path);
|
||||
void ro_gui_selection_dragging(wimp_full_message_dragging *drag);
|
||||
void ro_gui_selection_drag_claim(wimp_full_message_drag_claim *drag);
|
||||
|
||||
/* in 401login.c */
|
||||
#ifdef WITH_AUTH
|
||||
void ro_gui_401login_init(void);
|
||||
|
@ -180,18 +172,6 @@ void ro_gui_hotlist_prepare_entry_dialog(struct node *node);
|
|||
bool ro_gui_hotlist_dialog_apply(wimp_w w);
|
||||
int ro_gui_hotlist_help(int x, int y);
|
||||
|
||||
/* in save.c */
|
||||
wimp_w ro_gui_saveas_create(const char *template_name);
|
||||
void ro_gui_saveas_quit(void);
|
||||
void ro_gui_save_prepare(gui_save_type save_type, struct content *c);
|
||||
void ro_gui_save_start_drag(wimp_pointer *pointer);
|
||||
void ro_gui_drag_icon(int x, int y, const char *sprite);
|
||||
void ro_gui_save_drag_end(wimp_dragged *drag);
|
||||
void ro_gui_send_datasave(gui_save_type save_type, wimp_full_message_data_xfer *message, wimp_t to);
|
||||
void ro_gui_save_datasave_ack(wimp_message *message);
|
||||
bool ro_gui_save_ok(wimp_w w);
|
||||
void ro_gui_convert_save_path(char *dp, size_t len, const char *p);
|
||||
|
||||
/* in filetype.c */
|
||||
int ro_content_filetype(struct content *content);
|
||||
int ro_content_filetype_from_type(content_type type);
|
||||
|
|
|
@ -67,6 +67,43 @@ bool ro_message_send_message(wimp_event_no event, wimp_message *message,
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a message and registers a return route for a bounce.
|
||||
*
|
||||
* \param event the message event type
|
||||
* \param message the message to register a route back for
|
||||
* \param to_w the window to send the message to
|
||||
* \param to_i the icon
|
||||
* \param callback the code to call on a bounce
|
||||
* \param to_t receives the task handle of the window's creator
|
||||
* \return true on success, false otherwise
|
||||
*/
|
||||
bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *message,
|
||||
wimp_w to_w, wimp_i to_i, void (*callback)(wimp_message *message),
|
||||
wimp_t *to_t) {
|
||||
os_error *error;
|
||||
|
||||
assert(message);
|
||||
|
||||
/* send a message */
|
||||
error = xwimp_send_message_to_window(event, message, to_w, to_i, to_t);
|
||||
if (error) {
|
||||
LOG(("xwimp_send_message_to_window: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* register the default bounce handler */
|
||||
if (callback) {
|
||||
assert(event == wimp_USER_MESSAGE_RECORDED);
|
||||
return ro_message_register_handler(message, message->action,
|
||||
callback);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a return route for a message.
|
||||
*
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
bool ro_message_send_message(wimp_event_no event, wimp_message *message,
|
||||
wimp_t task, void (*callback)(wimp_message *message));
|
||||
bool ro_message_send_message_to_window(wimp_event_no event, wimp_message *message,
|
||||
wimp_w to_w, wimp_i to_i, void (*callback)(wimp_message *message),
|
||||
wimp_t *to_t);
|
||||
bool ro_message_register_handler(wimp_message *message,
|
||||
unsigned int message_code,
|
||||
void (*callback)(wimp_message *message));
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
#include "netsurf/riscos/gui.h"
|
||||
#include "netsurf/riscos/menus.h"
|
||||
#include "netsurf/riscos/options.h"
|
||||
#include "netsurf/riscos/save.h"
|
||||
#include "netsurf/riscos/save_complete.h"
|
||||
#include "netsurf/riscos/save_draw.h"
|
||||
#include "netsurf/riscos/textselection.h"
|
||||
#include "netsurf/riscos/thumbnail.h"
|
||||
#include "netsurf/riscos/wimp.h"
|
||||
#include "netsurf/riscos/wimp_event.h"
|
||||
|
@ -49,6 +51,7 @@ static struct content *gui_save_content = NULL;
|
|||
static struct selection *gui_save_selection = NULL;
|
||||
static int gui_save_filetype;
|
||||
|
||||
static bool dragbox_active = false; /** there is a Wimp_DragBox or DragASprite call in progress */
|
||||
static bool using_dragasprite = true;
|
||||
static bool saving_from_dialog = true;
|
||||
static osspriteop_area *saveas_area = NULL;
|
||||
|
@ -365,6 +368,7 @@ void ro_gui_drag_icon(int x, int y, const char *sprite)
|
|||
|
||||
if (!error) {
|
||||
using_dragasprite = true;
|
||||
dragbox_active = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -386,6 +390,8 @@ void ro_gui_drag_icon(int x, int y, const char *sprite)
|
|||
error->errnum, error->errmess));
|
||||
warn_user("DragError", error->errmess);
|
||||
}
|
||||
else
|
||||
dragbox_active = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -413,6 +419,31 @@ void ro_gui_convert_save_path(char *dp, size_t len, const char *p)
|
|||
}
|
||||
|
||||
|
||||
void ro_gui_drag_box_cancel(void)
|
||||
{
|
||||
if (dragbox_active) {
|
||||
os_error *error;
|
||||
if (using_dragasprite) {
|
||||
error = xdragasprite_stop();
|
||||
if (error) {
|
||||
LOG(("xdragasprite_stop: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error = xwimp_drag_box(NULL);
|
||||
if (error) {
|
||||
LOG(("xwimp_drag_box: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
}
|
||||
}
|
||||
dragbox_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle User_Drag_Box event for a drag from the save dialog or browser window.
|
||||
*/
|
||||
|
@ -427,22 +458,8 @@ void ro_gui_save_drag_end(wimp_dragged *drag)
|
|||
char *local_name = NULL;
|
||||
utf8_convert_ret err;
|
||||
|
||||
if (using_dragasprite) {
|
||||
error = xdragasprite_stop();
|
||||
if (error) {
|
||||
LOG(("xdragasprite_stop: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
}
|
||||
}
|
||||
else {
|
||||
error = xwimp_drag_box(NULL);
|
||||
if (error) {
|
||||
LOG(("xwimp_drag_box: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
}
|
||||
}
|
||||
if (dragbox_active)
|
||||
ro_gui_drag_box_cancel();
|
||||
|
||||
error = xwimp_get_pointer_info(&pointer);
|
||||
if (error) {
|
||||
|
@ -488,7 +505,9 @@ void ro_gui_save_drag_end(wimp_dragged *drag)
|
|||
|
||||
ro_gui_convert_save_path(dp, ep - dp, name);
|
||||
|
||||
/* \todo - we're supposed to set this if drag-n-drop used */
|
||||
message.your_ref = 0;
|
||||
|
||||
message.action = message_DATA_SAVE;
|
||||
message.data.data_xfer.w = pointer.w;
|
||||
message.data.data_xfer.i = pointer.i;
|
||||
|
|
|
@ -14,12 +14,32 @@
|
|||
#include <string.h>
|
||||
#include "oslib/osfile.h"
|
||||
#include "oslib/wimp.h"
|
||||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/riscos/gui.h"
|
||||
#include "netsurf/riscos/message.h"
|
||||
#include "netsurf/riscos/save.h"
|
||||
#include "netsurf/riscos/textselection.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/utf8.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
|
||||
#ifndef wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX
|
||||
#define wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX ((wimp_drag_claim_flags) 0x2u)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/** Receive of Dragging message has claimed it */
|
||||
static bool dragging_claimed = false;
|
||||
static wimp_t dragging_claimant;
|
||||
static os_box dragging_box = { -34, -34, 34, 34 }; /* \todo - size properly */
|
||||
static wimp_drag_claim_flags last_claim_flags = 0;
|
||||
|
||||
|
||||
static bool drag_claimed = false;
|
||||
|
||||
static bool owns_clipboard = false;
|
||||
static bool owns_caret_and_selection = false;
|
||||
|
@ -29,9 +49,10 @@ static char *clipboard = NULL;
|
|||
static size_t clip_alloc = 0;
|
||||
static size_t clip_length = 0;
|
||||
|
||||
static bool copy_handler(struct box *box, int offset, size_t length,
|
||||
void *handle);
|
||||
static bool copy_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, void *handle);
|
||||
static void ro_gui_discard_clipboard_contents(void);
|
||||
static void ro_gui_dragging_bounced(wimp_message *message);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -166,30 +187,22 @@ void ro_gui_selection_drag_end(struct gui_window *g, wimp_dragged *drag)
|
|||
* Selection traversal routine for appending text to the current contents
|
||||
* of the clipboard.
|
||||
*
|
||||
* \param box pointer to text box being (partially) added (or NULL for newline)
|
||||
* \param offset start offset of text within box (bytes)
|
||||
* \param length length of text to be appended (bytes)
|
||||
* \param handle unused handle, we don't need one
|
||||
* \param text pointer to text being added, or NULL for newline
|
||||
* \param length length of text to be appended (bytes)
|
||||
* \param space trailing space required after text
|
||||
* \param box pointer to text box, or NULL if from textplain
|
||||
* \param handle unused handle, we don't need one
|
||||
* \return true iff successful and traversal should continue
|
||||
*/
|
||||
|
||||
bool copy_handler(struct box *box, int offset, size_t length, void *handle)
|
||||
bool copy_handler(const char *text, size_t length, bool space,
|
||||
struct box *box, void *handle)
|
||||
{
|
||||
bool space = false;
|
||||
const char *text;
|
||||
size_t len;
|
||||
|
||||
if (box) {
|
||||
len = min(length, box->length - offset);
|
||||
text = box->text + offset;
|
||||
if (box->space && length > len) space = true;
|
||||
}
|
||||
else {
|
||||
if (!text) {
|
||||
text = "\n";
|
||||
len = 1;
|
||||
length = 1;
|
||||
}
|
||||
|
||||
return gui_add_to_clipboard(text, len, space);
|
||||
return gui_add_to_clipboard(text, length, space);
|
||||
}
|
||||
|
||||
|
||||
|
@ -483,3 +496,221 @@ bool ro_gui_save_clipboard(const char *path)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for Message_Dragging, used to implement auto-scrolling and
|
||||
* ghost caret when a drag is in progress.
|
||||
*/
|
||||
|
||||
void ro_gui_selection_dragging(wimp_message *message)
|
||||
{
|
||||
wimp_full_message_dragging *drag = (wimp_full_message_dragging*)message;
|
||||
struct box *textarea = NULL;
|
||||
struct box *text_box = NULL;
|
||||
struct browser_window *bw;
|
||||
wimp_window_state state;
|
||||
struct content *content;
|
||||
int gadget_box_x = 0;
|
||||
int gadget_box_y = 0;
|
||||
struct gui_window *g;
|
||||
os_error *error;
|
||||
int box_x = 0;
|
||||
int box_y = 0;
|
||||
int x, y;
|
||||
|
||||
/* with autoscrolling, we will probably need to remember the gui_window and
|
||||
override the drag->w window handle which could be any window on the desktop */
|
||||
g = ro_gui_window_lookup(drag->w);
|
||||
|
||||
if ((drag->flags & wimp_DRAGGING_TERMINATE_DRAG) || !g) {
|
||||
|
||||
if (drag_claimed) {
|
||||
/* make sure that we erase the ghost caret */
|
||||
caret_remove(&ghost_caret);
|
||||
}
|
||||
|
||||
drag_claimed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
state.w = drag->w;
|
||||
error = xwimp_get_window_state(&state);
|
||||
if (error) {
|
||||
LOG(("xwimp_get_window_state: 0x%x: %s\n",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
drag_claimed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
x = window_x_units(drag->pos.x, &state) / 2 /
|
||||
g->option.scale;
|
||||
y = -window_y_units(drag->pos.y, &state) / 2 /
|
||||
g->option.scale;
|
||||
|
||||
bw = g->bw;
|
||||
content = bw->current_content;
|
||||
if (content && content->type == CONTENT_HTML &&
|
||||
content->data.html.layout) {
|
||||
|
||||
struct box *box = content->data.html.layout;
|
||||
|
||||
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
|
||||
if (box->style &&
|
||||
box->style->visibility == CSS_VISIBILITY_HIDDEN)
|
||||
continue;
|
||||
|
||||
if (box->gadget) {
|
||||
switch (box->gadget->type) {
|
||||
|
||||
case GADGET_TEXTAREA:
|
||||
textarea = box;
|
||||
gadget_box_x = box_x;
|
||||
gadget_box_y = box_y;
|
||||
case GADGET_TEXTBOX:
|
||||
case GADGET_PASSWORD:
|
||||
text_box = box;
|
||||
break;
|
||||
|
||||
default: /* appease compiler */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (textarea) {
|
||||
int pixel_offset;
|
||||
int char_offset;
|
||||
|
||||
/* draw/move the ghost caret */
|
||||
if (drag_claimed)
|
||||
caret_remove(&ghost_caret);
|
||||
else
|
||||
gui_window_set_pointer(GUI_POINTER_CARET);
|
||||
|
||||
text_box = textarea_get_position(textarea, x - gadget_box_x,
|
||||
y - gadget_box_y, &char_offset, &pixel_offset);
|
||||
|
||||
caret_set_position(&ghost_caret, bw, text_box, char_offset, pixel_offset);
|
||||
drag_claimed = true;
|
||||
}
|
||||
else {
|
||||
if (drag_claimed) {
|
||||
/* make sure that we erase the ghost caret */
|
||||
caret_remove(&ghost_caret);
|
||||
}
|
||||
drag_claimed = false;
|
||||
}
|
||||
|
||||
if (drag_claimed) {
|
||||
wimp_full_message_drag_claim claim;
|
||||
os_error *error;
|
||||
|
||||
claim.size = offsetof(wimp_full_message_drag_claim, file_types) + 8;
|
||||
claim.your_ref = drag->my_ref;
|
||||
claim.action = message_DRAG_CLAIM;
|
||||
claim.flags = wimp_DRAG_CLAIM_POINTER_CHANGED | wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX;
|
||||
claim.file_types[0] = osfile_TYPE_TEXT;
|
||||
claim.file_types[1] = ~0;
|
||||
|
||||
error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)&claim,
|
||||
drag->sender);
|
||||
if (error) {
|
||||
LOG(("xwimp_send_message: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
}
|
||||
drag_claimed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reset drag-and-drop state when drag completes (DataSave received)
|
||||
*/
|
||||
|
||||
void ro_gui_selection_drag_reset(void)
|
||||
{
|
||||
caret_remove(&ghost_caret);
|
||||
drag_claimed = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
void ro_gui_selection_drag_claim(wimp_message *message)
|
||||
{
|
||||
wimp_full_message_drag_claim *claim = (wimp_full_message_drag_claim*)message;
|
||||
|
||||
dragging_claimant = message->sender;
|
||||
dragging_claimed = true;
|
||||
|
||||
/* have we been asked to remove the drag box/sprite? */
|
||||
if (claim->flags & wimp_DRAG_CLAIM_SUPPRESS_DRAGBOX) {
|
||||
ro_gui_drag_box_cancel();
|
||||
}
|
||||
else {
|
||||
/* \todo - restore it here? */
|
||||
}
|
||||
|
||||
/* do we need to restore the default pointer shape? */
|
||||
if ((last_claim_flags & wimp_DRAG_CLAIM_POINTER_CHANGED) &&
|
||||
!(claim->flags & wimp_DRAG_CLAIM_POINTER_CHANGED)) {
|
||||
gui_window_set_pointer(GUI_POINTER_DEFAULT);
|
||||
}
|
||||
|
||||
last_claim_flags = claim->flags;
|
||||
}
|
||||
|
||||
|
||||
void ro_gui_selection_send_dragging(wimp_pointer *pointer)
|
||||
{
|
||||
wimp_full_message_dragging dragmsg;
|
||||
|
||||
LOG(("sending DRAGGING to %p, %d", pointer->w, pointer->i));
|
||||
|
||||
dragmsg.size = offsetof(wimp_full_message_dragging, file_types) + 8;
|
||||
dragmsg.your_ref = 0;
|
||||
dragmsg.action = message_DRAGGING;
|
||||
dragmsg.w = pointer->w;
|
||||
dragmsg.i = pointer->i;
|
||||
dragmsg.pos = pointer->pos;
|
||||
/* \todo - this is interesting because it depends upon not just the state of the
|
||||
shift key, but also whether it /can/ be deleted, ie. from text area/input
|
||||
rather than page contents */
|
||||
dragmsg.flags = wimp_DRAGGING_FROM_SELECTION;
|
||||
dragmsg.box = dragging_box;
|
||||
dragmsg.file_types[0] = osfile_TYPE_TEXT;
|
||||
dragmsg.file_types[1] = ~0;
|
||||
|
||||
/* if the message_dragmsg messages have been claimed we must address them
|
||||
to the claimant task, which is not necessarily the task that owns whatever
|
||||
window happens to be under the pointer */
|
||||
|
||||
if (dragging_claimed) {
|
||||
ro_message_send_message(wimp_USER_MESSAGE_RECORDED,
|
||||
(wimp_message*)&dragmsg, dragging_claimant, ro_gui_dragging_bounced);
|
||||
}
|
||||
else {
|
||||
ro_message_send_message_to_window(wimp_USER_MESSAGE_RECORDED,
|
||||
(wimp_message*)&dragmsg, pointer->w, pointer->i,
|
||||
ro_gui_dragging_bounced, &dragging_claimant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Our message_DRAGGING message was bounced, ie. the intended recipient does not
|
||||
* support the drag-and-drop protocol or cannot receive the data at the pointer
|
||||
* position.
|
||||
*/
|
||||
|
||||
void ro_gui_dragging_bounced(wimp_message *message)
|
||||
{
|
||||
dragging_claimed = false;
|
||||
}
|
||||
|
|
|
@ -451,7 +451,8 @@ utf8_convert_ret utf8_to_local_encoding(const char *string, size_t len,
|
|||
const char *enc;
|
||||
utf8_convert_ret err;
|
||||
|
||||
assert(string && result);
|
||||
assert(string);
|
||||
assert(result);
|
||||
|
||||
/* get length, if necessary */
|
||||
if (len == 0)
|
||||
|
|
|
@ -849,32 +849,3 @@ bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask) {
|
|||
}
|
||||
return state.flags & mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open/move a window to the front of the window stack.
|
||||
*/
|
||||
|
||||
bool ro_gui_open_window_at_front(wimp_w w) {
|
||||
wimp_window_state state;
|
||||
os_error *error;
|
||||
|
||||
state.w = w;
|
||||
error = xwimp_get_window_state(&state);
|
||||
if (error) {
|
||||
LOG(("xwimp_get_window_state: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
return false;
|
||||
}
|
||||
|
||||
state.next = wimp_TOP;
|
||||
error = xwimp_open_window((wimp_open*)&state);
|
||||
if (error) {
|
||||
LOG(("xwimp_open_window: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
warn_user("WimpError", error->errmess);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,5 @@ void ro_gui_user_redraw(wimp_draw *redraw, bool user_fill, os_colour user_colour
|
|||
void ro_gui_wimp_update_window_furniture(wimp_w w, wimp_window_flags bic_mask,
|
||||
wimp_window_flags xor_mask);
|
||||
bool ro_gui_wimp_check_window_furniture(wimp_w w, wimp_window_flags mask);
|
||||
bool ro_gui_open_window_at_front(wimp_w w);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue