[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:
Adrian Lees 2006-02-15 23:09:55 +00:00
parent 07d55db910
commit dbfdafdf18
22 changed files with 1234 additions and 398 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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"

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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);

View File

@ -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.
*

View File

@ -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));

View File

@ -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;

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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