summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Lees <adrian@aemulor.com>2005-04-20 12:24:41 +0000
committerAdrian Lees <adrian@aemulor.com>2005-04-20 12:24:41 +0000
commit31c659a2ea8bf239569c8436e3b718786879df47 (patch)
tree4f934f55f0ba0151372135156e4bdb3ff461c6b4
parenta01210941b7717317cd4bd3c451596a845093d9c (diff)
downloadnetsurf-31c659a2ea8bf239569c8436e3b718786879df47.tar.gz
netsurf-31c659a2ea8bf239569c8436e3b718786879df47.tar.bz2
[project @ 2005-04-20 12:24:41 by adrianl]
text import from global clipboard, other apps & files and additional keys for editing text in textareas svn path=/import/netsurf/; revision=1673
-rw-r--r--desktop/browser.c9
-rw-r--r--desktop/browser.h17
-rw-r--r--desktop/gui.h1
-rw-r--r--desktop/textinput.c861
-rw-r--r--desktop/textinput.h35
-rw-r--r--gtk/gtk_window.c5
-rw-r--r--render/box.c30
-rw-r--r--render/box.h1
-rw-r--r--riscos/gui.h1
-rw-r--r--riscos/save.c1
-rw-r--r--riscos/textselection.c49
-rw-r--r--riscos/window.c170
12 files changed, 975 insertions, 205 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index 0a7775838..49d81dadd 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -97,6 +97,7 @@ void browser_window_create(const char *url, struct browser_window *clone,
bw->sel = selection_create(bw);
bw->throbbing = false;
bw->caret_callback = NULL;
+ bw->paste_callback = NULL;
bw->frag_id = NULL;
bw->drag_type = DRAGGING_NONE;
bw->scrolling_box = NULL;
@@ -292,6 +293,7 @@ void browser_window_callback(content_msg msg, struct content *c,
bw->current_content = c;
bw->loading_content = NULL;
bw->caret_callback = NULL;
+ bw->paste_callback = NULL;
bw->scrolling_box = NULL;
gui_window_new_content(bw->window);
if (bw->frag_id)
@@ -335,6 +337,7 @@ void browser_window_callback(content_msg msg, struct content *c,
else if (c == bw->current_content) {
bw->current_content = 0;
bw->caret_callback = NULL;
+ bw->paste_callback = NULL;
bw->scrolling_box = NULL;
selection_init(bw->sel, NULL);
}
@@ -384,6 +387,7 @@ void browser_window_callback(content_msg msg, struct content *c,
else if (c == bw->current_content) {
bw->current_content = 0;
bw->caret_callback = NULL;
+ bw->paste_callback = NULL;
bw->scrolling_box = NULL;
selection_init(bw->sel, NULL);
}
@@ -936,6 +940,11 @@ 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)) {
+ /* 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");
diff --git a/desktop/browser.h b/desktop/browser.h
index c8764da2c..f59974a39 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -25,6 +25,13 @@ struct form_successful_control;
struct gui_window;
struct history;
struct selection;
+struct browser_window;
+
+
+typedef void (*browser_caret_callback)(struct browser_window *bw,
+ wchar_t key, void *p);
+typedef bool (*browser_paste_callback)(struct browser_window *bw,
+ const char *utf8, unsigned utf8_len, bool last, void *p);
/** Browser window data. */
struct browser_window {
@@ -40,9 +47,11 @@ struct browser_window {
struct selection *sel;
/** Handler for keyboard input, or 0. */
- void (*caret_callback)(struct browser_window *bw,
- wchar_t key, void *p);
- /** User parameter for caret_callback. */
+ browser_caret_callback caret_callback;
+ /** Handler for pasting text, or 0. */
+ browser_paste_callback paste_callback;
+
+ /** User parameter for caret_callback and paste_callback */
void *caret_p;
/** Platform specific window data. */
@@ -125,6 +134,8 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
bool browser_window_key_press(struct browser_window *bw, wchar_t key);
+bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
+ unsigned utf8_len, bool last);
void browser_window_form_select(struct browser_window *bw,
struct form_control *control, int item);
void browser_redraw_box(struct content *c, struct box *box);
diff --git a/desktop/gui.h b/desktop/gui.h
index bcc39e21b..c56b2d504 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -85,6 +85,7 @@ void gui_drag_save_object(gui_save_type type, struct content *c,
void gui_drag_save_selection(struct selection *s, struct gui_window *g);
void gui_start_selection(struct gui_window *g);
+void gui_paste_from_clipboard(struct gui_window *g, int x, int y);
bool gui_copy_to_clipboard(struct selection *s);
void gui_create_form_select_menu(struct browser_window *bw,
diff --git a/desktop/textinput.c b/desktop/textinput.c
index 1fdd49ebe..9fb9f5ccf 100644
--- a/desktop/textinput.c
+++ b/desktop/textinput.c
@@ -6,6 +6,7 @@
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*/
/** \file
@@ -23,7 +24,7 @@
#include "netsurf/render/font.h"
#include "netsurf/render/form.h"
#include "netsurf/render/layout.h"
-#define NDEBUG
+//#define NDEBUG
#include "netsurf/utils/log.h"
#include "netsurf/utils/talloc.h"
#include "netsurf/utils/utf8.h"
@@ -35,9 +36,27 @@ static void browser_window_input_callback(struct browser_window *bw,
wchar_t key, void *p);
static void browser_window_place_caret(struct browser_window *bw,
int x, int y, int height,
- void (*callback)(struct browser_window *bw,
- wchar_t key, void *p),
+ browser_caret_callback caret_cb,
+ browser_paste_callback paste_cb,
void *p);
+static bool browser_window_textarea_paste_text(struct browser_window *bw,
+ const char *utf8, unsigned utf8_len, bool last, void *handle);
+static bool browser_window_input_paste_text(struct browser_window *bw,
+ const char *utf8, unsigned utf8_len, bool last, void *handle);
+static void input_update_display(struct browser_window *bw, struct box *input,
+ unsigned form_offset, unsigned box_offset, bool to_textarea,
+ bool redraw);
+static bool textbox_insert(struct browser_window *bw, struct box *text_box,
+ unsigned char_offset, const char *utf8, unsigned utf8_len);
+static bool textbox_delete(struct browser_window *bw, struct box *text_box,
+ unsigned char_offset, unsigned utf8_len);
+static struct box *textarea_insert_break(struct browser_window *bw,
+ struct box *text_box, size_t char_offset);
+static bool delete_handler(struct box *b, int offset, size_t length,
+ void *handle);
+static void textarea_reflow(struct browser_window *bw, struct box *textarea,
+ struct box *inline_container);
+
/**
* Handle clicks in a text area by placing the caret.
@@ -142,7 +161,9 @@ void browser_window_textarea_click(struct browser_window *bw,
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
- browser_window_textarea_callback, textarea);
+ browser_window_textarea_callback,
+ browser_window_textarea_paste_text,
+ textarea);
if (new_scroll_y != textarea->scroll_y) {
textarea->scroll_y = new_scroll_y;
@@ -165,16 +186,13 @@ void browser_window_textarea_callback(struct browser_window *bw,
struct box *inline_container =
textarea->gadget->caret_inline_container;
struct box *text_box = textarea->gadget->caret_text_box;
- struct box *new_br, *new_text, *t;
- struct box *prev;
+ struct box *new_text;
size_t char_offset = textarea->gadget->caret_box_offset;
int pixel_offset = textarea->gadget->caret_pixel_offset;
int new_scroll_y;
int box_x, box_y;
char utf8[6];
- unsigned int utf8_len, i;
- char *text;
- int width = 0, height = 0;
+ unsigned int utf8_len;
bool reflow = false;
/* box_dump(textarea, 0); */
@@ -189,65 +207,39 @@ void browser_window_textarea_callback(struct browser_window *bw,
/* normal character insertion */
utf8_len = utf8_from_ucs4(key, utf8);
- text = talloc_realloc(bw->current_content, text_box->text,
- char, text_box->length + 8);
- if (!text) {
- warn_user("NoMemory", 0);
+ if (!textbox_insert(bw, text_box, char_offset, utf8, utf8_len))
return;
- }
- text_box->text = text;
- memmove(text_box->text + char_offset + utf8_len,
- text_box->text + char_offset,
- text_box->length - char_offset);
- for (i = 0; i != utf8_len; i++)
- text_box->text[char_offset + i] = utf8[i];
- text_box->length += utf8_len;
- text_box->text[text_box->length] = 0;
- text_box->width = UNKNOWN_WIDTH;
- char_offset += utf8_len;
+ char_offset += utf8_len;
reflow = true;
} else switch (key) {
- case 8:
- case 127: /* delete to left */
+ case KEY_DELETE_LEFT:
if (char_offset == 0) {
/* at the start of a text box */
- if (!text_box->prev)
- /* at very beginning of text area: ignore */
- return;
+ struct box *prev;
- if (text_box->prev->type == BOX_BR) {
+ while (text_box->prev && text_box->prev->type == BOX_BR) {
/* previous box is BR: remove it */
- t = text_box->prev;
- t->prev->next = t->next;
- t->next->prev = t->prev;
- box_free(t);
+ box_unlink_and_free(text_box->prev);
}
+ if (!text_box->prev)
+ /* at very beginning of text area: ignore */
+ return;
+
/* delete space by merging with previous text box */
prev = text_box->prev;
+ assert(prev->type == BOX_INLINE);
assert(prev->text);
- text = talloc_realloc(bw->current_content,
- prev->text, char,
- prev->length + text_box->length + 1);
- if (!text) {
- warn_user("NoMemory", 0);
- return;
- }
- prev->text = text;
- memcpy(prev->text + prev->length, text_box->text,
- text_box->length);
+
char_offset = prev->length; /* caret at join */
- prev->length += text_box->length;
- prev->text[prev->length] = 0;
- prev->width = UNKNOWN_WIDTH;
- prev->next = text_box->next;
- if (prev->next)
- prev->next->prev = prev;
- else
- prev->parent->last = prev;
- box_free(text_box);
+
+ if (!textbox_insert(bw, prev, prev->length,
+ text_box->text, text_box->length))
+ return;
+
+ box_unlink_and_free(text_box);
/* place caret at join (see above) */
text_box = prev;
@@ -257,45 +249,54 @@ void browser_window_textarea_callback(struct browser_window *bw,
int prev_offset = char_offset;
char_offset = utf8_prev(text_box->text, char_offset);
- memmove(text_box->text + char_offset,
- text_box->text + prev_offset,
- text_box->length - prev_offset);
- text_box->length -= (prev_offset - char_offset);
- text_box->width = UNKNOWN_WIDTH;
+ textbox_delete(bw, text_box, char_offset, prev_offset - char_offset);
}
-
reflow = true;
break;
- case 10:
- case 13: /* paragraph break */
- text = talloc_array(bw->current_content, char,
- text_box->length + 1);
- if (!text) {
- warn_user("NoMemory", 0);
- return;
- }
+ case KEY_DELETE_RIGHT: /* delete to right */
+ if (char_offset >= text_box->length) {
+ /* at the end of a text box */
+ struct box *next;
- new_br = box_create(text_box->style, 0, text_box->title, 0,
- bw->current_content);
- new_text = talloc(bw->current_content, struct box);
- if (!new_text) {
- warn_user("NoMemory", 0);
- return;
- }
+ while (text_box->next && text_box->next->type == BOX_BR) {
+ /* next box is a BR: remove it */
+ box_unlink_and_free(text_box->next);
+ }
+
+ if (!text_box->next)
+ /* at very end of text area: ignore */
+ return;
+
+ /* delete space by merging with next text box */
+
+ next = text_box->next;
+ assert(next->type == BOX_INLINE);
+ assert(next->text);
+
+ if (!textbox_insert(bw, text_box, text_box->length,
+ next->text, next->length))
+ return;
- new_br->type = BOX_BR;
- box_insert_sibling(text_box, new_br);
+ box_unlink_and_free(next);
+
+ /* leave caret at join */
+ reflow = true;
+ }
+ else {
+ /* delete a character */
+ int next_offset = utf8_next(text_box->text, text_box->length,
+ char_offset);
+ textbox_delete(bw, text_box, char_offset,
+ next_offset - char_offset);
+ }
+ reflow = true;
+ break;
- memcpy(new_text, text_box, sizeof (struct box));
- new_text->clone = 1;
- new_text->text = text;
- memcpy(new_text->text, text_box->text + char_offset,
- text_box->length - char_offset);
- new_text->length = text_box->length - char_offset;
- text_box->length = char_offset;
- text_box->width = new_text->width = UNKNOWN_WIDTH;
- box_insert_sibling(new_br, new_text);
+ case 10:
+ case 13: /* paragraph break */
+ new_text = textarea_insert_break(bw, text_box, char_offset);
+ if (!new_text) return;
/* place caret at start of new text box */
text_box = new_text;
@@ -304,18 +305,52 @@ void browser_window_textarea_callback(struct browser_window *bw,
reflow = true;
break;
+ case 21: { /* Ctrl + U */
+ struct box *next;
+
+ /* run back to start of line */
+ while (text_box->prev && text_box->prev->type == BOX_INLINE)
+ text_box = text_box->prev;
+
+ /* run forwards to end */
+ next = text_box->next;
+ while (next && next->type == BOX_INLINE) {
+ box_unlink_and_free(text_box);
+ text_box = next;
+ next = text_box->next;
+ }
+
+ /* can we take out this last inline and and the following BR? */
+ if (next && next->type == BOX_BR && next->next) {
+ box_unlink_and_free(text_box);
+
+ /* place caret at start of next box */
+ text_box = next->next;
+ box_unlink_and_free(next);
+ }
+ else
+ textbox_delete(bw, text_box, 0, text_box->length);
+
+ char_offset = 0;
+ reflow = true;
+ }
+ break;
+
case 22: /* Ctrl + V */
-// gui_paste_from_clipboard();
+ gui_paste_from_clipboard(bw->window,
+ box_x + inline_container->x + text_box->x + pixel_offset,
+ box_y + inline_container->y + text_box->y);
break;
case 24: /* Ctrl + X */
if (gui_copy_to_clipboard(bw->sel)) {
- /** \todo block delete */
+ selection_traverse(bw->sel, delete_handler, bw);
+ reflow = true;
}
break;
- case 28: /* Right cursor -> */
- if ((unsigned int) char_offset != text_box->length) {
+ case KEY_RIGHT:
+ if ((unsigned int) char_offset < text_box->length) {
char_offset = utf8_next(text_box->text,
text_box->length, char_offset);
} else {
@@ -330,7 +365,7 @@ void browser_window_textarea_callback(struct browser_window *bw,
}
break;
- case 29: /* Left cursor <- */
+ case KEY_LEFT:
if (char_offset != 0) {
char_offset = utf8_prev(text_box->text, char_offset);
} else {
@@ -345,7 +380,7 @@ void browser_window_textarea_callback(struct browser_window *bw,
}
break;
- case 30: /* Up cursor */
+ case KEY_UP:
browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1,
textarea,
box_x, box_y,
@@ -353,7 +388,7 @@ void browser_window_textarea_callback(struct browser_window *bw,
inline_container->y + text_box->y - 1);
return;
- case 31: /* Down cursor */
+ case KEY_DOWN:
browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1,
textarea,
box_x, box_y,
@@ -362,6 +397,70 @@ void browser_window_textarea_callback(struct browser_window *bw,
text_box->height + 1);
return;
+ case KEY_LINE_START:
+ while (text_box->prev && text_box->prev->type == BOX_INLINE)
+ text_box = text_box->prev;
+ char_offset = 0;
+ break;
+
+ case KEY_LINE_END:
+ while (text_box->next && text_box->next->type == BOX_INLINE)
+ text_box = text_box->next;
+ char_offset = text_box->length;
+ break;
+
+ case KEY_TEXT_START:
+ assert(text_box->parent);
+
+ /* place caret at start of first box */
+ text_box = text_box->parent->children;
+ char_offset = 0;
+ break;
+
+ case KEY_TEXT_END:
+ assert(text_box->parent);
+
+ /* place caret at end of last box */
+ text_box = text_box->parent->last;
+ char_offset = text_box->length;
+ break;
+
+ case KEY_WORD_LEFT:
+// while () {
+// }
+ break;
+
+ case KEY_WORD_RIGHT:
+// while () {
+// }
+ break;
+
+ case KEY_PAGE_UP:
+// while () {
+// }
+ if (char_offset > text_box->length)
+ char_offset = text_box->length;
+ break;
+
+ case KEY_PAGE_DOWN:
+
+// while () {
+// }
+ if (char_offset > text_box->length)
+ char_offset = text_box->length;
+ break;
+
+ case KEY_DELETE_LINE_START:
+ textbox_delete(bw, text_box, 0, char_offset);
+ reflow = true;
+ break;
+
+ case KEY_DELETE_LINE_END:
+ textbox_delete(bw, text_box, char_offset,
+ text_box->length - char_offset);
+ reflow = true;
+ break;
+
default:
return;
}
@@ -384,18 +483,8 @@ void browser_window_textarea_callback(struct browser_window *bw,
}
} */
- if (reflow) {
- /* reflow textarea preserving width and height */
- width = textarea->width;
- height = textarea->height;
- if (!layout_inline_container(inline_container, width,
- textarea, 0, 0,
- bw->current_content))
- warn_user("NoMemory", 0);
- textarea->width = width;
- textarea->height = height;
- layout_calculate_descendant_bboxes(textarea);
- }
+ if (reflow)
+ textarea_reflow(bw, textarea, inline_container);
if (text_box->length < char_offset) {
/* the text box has been split and the caret is in the
@@ -406,6 +495,14 @@ void browser_window_textarea_callback(struct browser_window *bw,
assert(char_offset <= text_box->length);
}
+ nsfont_width(text_box->style, text_box->text,
+ char_offset, &pixel_offset);
+
+ textarea->gadget->caret_inline_container = inline_container;
+ textarea->gadget->caret_text_box = text_box;
+ textarea->gadget->caret_box_offset = char_offset;
+ textarea->gadget->caret_pixel_offset = pixel_offset;
+
/* scroll to place the caret in the centre of the visible region */
new_scroll_y = inline_container->y + text_box->y +
text_box->height / 2 -
@@ -416,19 +513,14 @@ void browser_window_textarea_callback(struct browser_window *bw,
new_scroll_y = 0;
box_y += textarea->scroll_y - new_scroll_y;
- nsfont_width(text_box->style, text_box->text,
- char_offset, &pixel_offset);
-
- textarea->gadget->caret_inline_container = inline_container;
- textarea->gadget->caret_text_box = text_box;
- textarea->gadget->caret_box_offset = char_offset;
- textarea->gadget->caret_pixel_offset = pixel_offset;
browser_window_place_caret(bw,
box_x + inline_container->x + text_box->x +
pixel_offset,
box_y + inline_container->y + text_box->y,
text_box->height,
- browser_window_textarea_callback, textarea);
+ browser_window_textarea_callback,
+ browser_window_textarea_paste_text,
+ textarea);
if (new_scroll_y != textarea->scroll_y || reflow) {
textarea->scroll_y = new_scroll_y;
@@ -508,7 +600,9 @@ void browser_window_input_click(struct browser_window* bw,
text_box->x + pixel_offset,
box_y + input->children->y + text_box->y,
text_box->height,
- browser_window_input_callback, input);
+ browser_window_input_callback,
+ browser_window_input_paste_text,
+ input);
if (dx)
browser_redraw_box(bw->current_content, input);
@@ -529,7 +623,7 @@ void browser_window_input_callback(struct browser_window *bw,
struct box *text_box = input->children->children;
unsigned int box_offset = input->gadget->caret_box_offset;
unsigned int form_offset = input->gadget->caret_form_offset;
- int pixel_offset, dx;
+ int pixel_offset = input->gadget->caret_pixel_offset;
int box_x, box_y;
struct form* form = input->gadget->form;
bool changed = false;
@@ -575,20 +669,9 @@ void browser_window_input_callback(struct browser_window *bw,
'*' : (key == ' ') ? 160 : key,
utf8);
- value = talloc_realloc(bw->current_content, text_box->text,
- char, text_box->length + utf8_len + 1);
- if (!value) {
- warn_user("NoMemory", 0);
+ if (!textbox_insert(bw, text_box, box_offset, utf8, utf8_len))
return;
- }
- text_box->text = value;
- memmove(text_box->text + box_offset + utf8_len,
- text_box->text + box_offset,
- text_box->length - box_offset);
- memcpy(text_box->text + box_offset, utf8, utf8_len);
- text_box->length += utf8_len;
- text_box->text[text_box->length] = 0;
box_offset += utf8_len;
nsfont_width(text_box->style, text_box->text,
@@ -596,8 +679,7 @@ void browser_window_input_callback(struct browser_window *bw,
changed = true;
} else switch (key) {
- case 8:
- case 127: { /* Delete to left */
+ case KEY_DELETE_LEFT: {
int prev_offset;
if (box_offset == 0)
@@ -620,11 +702,41 @@ void browser_window_input_callback(struct browser_window *bw,
/* Go to the previous valid UTF-8 character */
box_offset = utf8_prev(text_box->text, box_offset);
- memmove(text_box->text + box_offset,
- text_box->text + prev_offset,
- text_box->length - prev_offset);
- text_box->length -= prev_offset - box_offset;
- text_box->text[text_box->length] = 0;
+ textbox_delete(bw, text_box, box_offset,
+ prev_offset - box_offset);
+
+ nsfont_width(text_box->style, text_box->text,
+ text_box->length, &text_box->width);
+
+ changed = true;
+ }
+ break;
+
+ case KEY_DELETE_RIGHT: {
+ unsigned next_offset;
+
+ if (box_offset >= text_box->length)
+ return;
+
+ /* Gadget */
+ /* Go to the next valid UTF-8 character */
+ next_offset = utf8_next(input->gadget->value,
+ input->gadget->length,
+ form_offset);
+
+ memmove(input->gadget->value + form_offset,
+ input->gadget->value + next_offset,
+ input->gadget->length - next_offset);
+ input->gadget->length -= next_offset - form_offset;
+ input->gadget->value[input->gadget->length] = 0;
+
+ /* Text box */
+ /* Go to the next valid UTF-8 character */
+ next_offset = utf8_next(text_box->text, text_box->length,
+ box_offset);
+
+ textbox_delete(bw, text_box, box_offset,
+ next_offset - box_offset);
nsfont_width(text_box->style, text_box->text,
text_box->length, &text_box->width);
@@ -647,7 +759,6 @@ void browser_window_input_callback(struct browser_window *bw,
input = next_input->box;
text_box = input->children->children;
- box_coords(input, &box_x, &box_y);
form_offset = box_offset = 0;
to_textarea = next_input->type == GADGET_TEXTAREA;
}
@@ -673,7 +784,6 @@ void browser_window_input_callback(struct browser_window *bw,
input = prev_input->box;
text_box = input->children->children;
- box_coords(input, &box_x, &box_y);
form_offset = box_offset = 0;
to_textarea = prev_input->type == GADGET_TEXTAREA;
}
@@ -693,10 +803,12 @@ void browser_window_input_callback(struct browser_window *bw,
break;
case 22: /* Ctrl + V */
-// gui_paste_from_clipboard();
+ gui_paste_from_clipboard(bw->window,
+ box_x + input->children->x + text_box->x + pixel_offset,
+ box_y + input->children->y + text_box->y);
break;
- case 28: /* Right cursor -> */
+ case KEY_RIGHT:
/* Text box */
/* Go to the next valid UTF-8 character */
box_offset = utf8_next(text_box->text, text_box->length,
@@ -707,7 +819,7 @@ void browser_window_input_callback(struct browser_window *bw,
input->gadget->length, form_offset);
break;
- case 29: /* Left cursor -> */
+ case KEY_LEFT:
/* Text box */
/* Go to the previous valid UTF-8 character */
box_offset = utf8_prev(text_box->text, box_offset);
@@ -716,11 +828,11 @@ void browser_window_input_callback(struct browser_window *bw,
form_offset = utf8_prev(input->gadget->value, form_offset);
break;
- case 128: /* Ctrl + Left */
+ case KEY_LINE_START:
box_offset = form_offset = 0;
break;
- case 129: /* Ctrl + Right */
+ case KEY_LINE_END:
box_offset = text_box->length;
form_offset = input->gadget->length;
break;
@@ -729,39 +841,10 @@ void browser_window_input_callback(struct browser_window *bw,
return;
}
- nsfont_width(text_box->style, text_box->text, box_offset,
- &pixel_offset);
- dx = text_box->x;
- text_box->x = 0;
- if (input->width < text_box->width &&
- input->width / 2 < pixel_offset) {
- text_box->x = input->width / 2 - pixel_offset;
- if (text_box->x < input->width - text_box->width)
- text_box->x = input->width - text_box->width;
- }
- dx -= text_box->x;
- input->gadget->caret_pixel_offset = pixel_offset;
-
- if (to_textarea) {
- /* moving to textarea so need to set these up */
- input->gadget->caret_inline_container = input->children;
- input->gadget->caret_text_box = text_box;
- }
-
- input->gadget->caret_box_offset = box_offset;
input->gadget->caret_form_offset = form_offset;
- browser_window_place_caret(bw,
- box_x + input->children->x +
- text_box->x + pixel_offset,
- box_y + input->children->y + text_box->y,
- text_box->height,
- /* use the appropriate callback */
- to_textarea ? browser_window_textarea_callback
- : browser_window_input_callback, input);
-
- if (dx || changed)
- browser_redraw_box(bw->current_content, input);
+ input_update_display(bw, input, form_offset, box_offset,
+ to_textarea, changed);
}
@@ -771,18 +854,20 @@ void browser_window_input_callback(struct browser_window *bw,
* \param bw The browser window in which to place the caret
* \param x X coordinate of the caret
* \param y Y coordinate
- * \param height Height of caret
- * \param callback Callback function for keypresses
+ * \param height Height of caret
+ * \param caret_cb Callback function for keypresses
+ * \param paste_cb Callback function for pasting text
* \param p Callback private data pointer, passed to callback function
*/
void browser_window_place_caret(struct browser_window *bw,
int x, int y, int height,
- void (*callback)(struct browser_window *bw,
- wchar_t key, void *p),
+ browser_caret_callback caret_cb,
+ browser_paste_callback paste_cb,
void *p)
{
gui_window_place_caret(bw->window, x, y, height);
- bw->caret_callback = callback;
+ bw->caret_callback = caret_cb;
+ bw->paste_callback = paste_cb;
bw->caret_p = p;
}
@@ -828,7 +913,8 @@ bool browser_window_key_press(struct browser_window *bw, wchar_t key)
selection_clear(bw->sel, true);
return true;
}
- break;
+ /* if there's no selection, leave Escape for the caller */
+ return false;
}
/* pass on to the appropriate field */
@@ -837,3 +923,424 @@ bool browser_window_key_press(struct browser_window *bw, wchar_t key)
bw->caret_callback(bw, key, bw->caret_p);
return true;
}
+
+
+/**
+ * Paste a block of text into a browser window at the caret position.
+ *
+ * \param bw browser window
+ * \param utf8 pointer to block of text
+ * \param utf8_len length (bytes) of text block
+ * \param last true iff this is the last chunk (update screen too)
+ * \return true iff successful
+ */
+
+bool browser_window_paste_text(struct browser_window *bw, const char *utf8,
+ unsigned utf8_len, bool last)
+{
+ if (!bw->paste_callback)
+ return false;
+ return bw->paste_callback(bw, utf8, utf8_len, last, bw->caret_p);
+}
+
+
+/**
+ * Paste a block of text into a textarea at the
+ * current caret position.
+ *
+ * \param bw browser window
+ * \param utf8 pointer to block of text
+ * \param utf8_len length (bytes) of text block
+ * \param last true iff this is the last chunk (update screen too)
+ * \param handle pointer to textarea
+ * \return true iff successful
+ */
+
+bool browser_window_textarea_paste_text(struct browser_window *bw,
+ const char *utf8, unsigned utf8_len, bool last, void *handle)
+{
+ struct box *textarea = handle;
+ struct box *inline_container =
+ textarea->gadget->caret_inline_container;
+ struct box *text_box = textarea->gadget->caret_text_box;
+ size_t char_offset = textarea->gadget->caret_box_offset;
+ int pixel_offset = textarea->gadget->caret_pixel_offset;
+ const char *ep = utf8 + utf8_len;
+ const char *p = utf8;
+ bool success = true;
+ bool update = last;
+
+ while (p < ep) {
+ struct box *new_text;
+ unsigned utf8_len;
+
+ while (p < ep) {
+ if (*p == '\n' || *p == '\r') break;
+ p++;
+ }
+
+ utf8_len = p - utf8;
+ if (!textbox_insert(bw, text_box, char_offset, utf8, utf8_len))
+ return false;
+
+ char_offset += utf8_len;
+
+ new_text = textarea_insert_break(bw, text_box, char_offset);
+ if (!new_text) {
+ /* we still need to update the screen */
+ update = true;
+ success = false;
+ break;
+ }
+
+ /* place caret at start of new text box */
+ text_box = new_text;
+ char_offset = 0;
+
+ /* handle CR/LF and LF/CR terminations */
+ if ((*p == '\n' && p[1] == '\r') || (*p == '\r' && p[1] == '\n'))
+ p++;
+ utf8 = ++p;
+ }
+
+ if (update) {
+ int box_x, box_y;
+
+ /* reflow textarea preserving width and height */
+ textarea_reflow(bw, textarea, inline_container);
+
+ nsfont_width(text_box->style, text_box->text,
+ char_offset, &pixel_offset);
+
+ box_x -= textarea->scroll_x;
+ box_y -= textarea->scroll_y;
+
+ box_coords(textarea, &box_x, &box_y);
+
+ browser_window_place_caret(bw,
+ box_x + inline_container->x + text_box->x +
+ pixel_offset,
+ box_y + inline_container->y + text_box->y,
+ text_box->height,
+ browser_window_textarea_callback,
+ browser_window_textarea_paste_text,
+ textarea);
+
+ textarea->gadget->caret_pixel_offset = pixel_offset;
+
+ browser_redraw_box(bw->current_content, textarea);
+ }
+
+// textarea->gadget->caret_inline_container = inline_container;
+ textarea->gadget->caret_text_box = text_box;
+ textarea->gadget->caret_box_offset = char_offset;
+
+ return success;
+}
+
+
+/**
+ * Paste a block of text into an input field at the caret position.
+ *
+ * \param bw browser window
+ * \param utf8 pointer to block of text
+ * \param utf8_len length (bytes) of text block
+ * \param last true iff this is the last chunk (update screen too)
+ * \param p pointer to input box
+ * \return true iff successful
+ */
+
+bool browser_window_input_paste_text(struct browser_window *bw,
+ const char *utf8, unsigned utf8_len, bool last, void *handle)
+{
+ struct box *input = handle;
+ struct box *text_box = input->children->children;
+ unsigned int box_offset = input->gadget->caret_box_offset;
+ unsigned int form_offset = input->gadget->caret_form_offset;
+ unsigned int nchars = utf8_length(input->gadget->value);
+ const char *ep = utf8 + utf8_len;
+ const char *p = utf8;
+ bool success = true;
+ bool update = last;
+
+ /* keep adding chars until we've run out or would exceed
+ the maximum length of the field (in which we silently
+ ignore all others)
+ */
+ while (p < ep && nchars < input->gadget->maxlength) {
+ char buf[80 + 6];
+ int nbytes = 0;
+ unsigned utf8_len;
+ char *value;
+
+ /* how many more chars can we insert in one go? */
+ while (p < ep && nbytes < 80 &&
+ nchars < input->gadget->maxlength &&
+ *p != '\n' && *p != '\r') {
+ unsigned len = utf8_next(p, ep - p, 0);
+
+ if (input->gadget->type == GADGET_PASSWORD)
+ buf[nbytes++] = '*';
+ else if (*p == ' ')
+ nbytes += utf8_from_ucs4(160, &buf[nbytes]);
+ else {
+ memcpy(&buf[nbytes], p, len);
+ nbytes += len;
+ }
+
+ p += len;
+ nchars++;
+ }
+
+ utf8_len = p - utf8;
+
+ value = realloc(input->gadget->value,
+ input->gadget->length + utf8_len + 1);
+ if (!value) {
+ /* we still need to update the screen */
+ warn_user("NoMemory", 0);
+ update = true;
+ success = false;
+ break;
+ }
+ input->gadget->value = value;
+
+ memmove(input->gadget->value + form_offset + utf8_len,
+ input->gadget->value + form_offset,
+ input->gadget->length - form_offset);
+ memcpy(input->gadget->value + form_offset, utf8, utf8_len);
+ input->gadget->length += utf8_len;
+ input->gadget->value[input->gadget->length] = 0;
+ form_offset += utf8_len;
+
+ if (!textbox_insert(bw, text_box, box_offset, buf, nbytes)) {
+ /* we still need to update the screen */
+ update = true;
+ success = false;
+ break;
+ }
+ box_offset += nbytes;
+
+ /* handle CR/LF and LF/CR terminations */
+ if (*p == '\n') {
+ p++;
+ if (*p == '\r') p++;
+ }
+ else if (*p == '\r') {
+ p++;
+ if (*p == '\n') p++;
+ }
+ utf8 = p;
+ }
+
+ if (update) {
+
+ nsfont_width(text_box->style, text_box->text, text_box->length,
+ &text_box->width);
+
+ input_update_display(bw, input, form_offset, box_offset, false, true);
+ }
+
+ return success;
+}
+
+
+/**
+ * Update display to reflect modified input field
+ *
+ * \param bw browser window
+ * \param input input field
+ * \param form_offset
+ * \param box_offset offset of caret within text box
+ * \param to_textarea caret is to be moved to a textarea
+ * \param redraw force redraw even if field hasn't scrolled
+ */
+
+void input_update_display(struct browser_window *bw, struct box *input,
+ unsigned form_offset, unsigned box_offset, bool to_textarea,
+ bool redraw)
+{
+ struct box *text_box = input->children->children;
+ unsigned pixel_offset;
+ int box_x, box_y;
+ int dx;
+
+ box_coords(input, &box_x, &box_y);
+
+ nsfont_width(text_box->style, text_box->text, box_offset,
+ &pixel_offset);
+ dx = text_box->x;
+ text_box->x = 0;
+ if (input->width < text_box->width &&
+ input->width / 2 < pixel_offset) {
+ text_box->x = input->width / 2 - pixel_offset;
+ if (text_box->x < input->width - text_box->width)
+ text_box->x = input->width - text_box->width;
+ }
+ dx -= text_box->x;
+ input->gadget->caret_pixel_offset = pixel_offset;
+
+ if (to_textarea) {
+ /* moving to textarea so need to set these up */
+ input->gadget->caret_inline_container = input->children;
+ input->gadget->caret_text_box = text_box;
+ }
+
+ input->gadget->caret_box_offset = box_offset;
+ input->gadget->caret_form_offset = form_offset;
+
+ browser_window_place_caret(bw,
+ box_x + input->children->x +
+ text_box->x + pixel_offset,
+ box_y + input->children->y + text_box->y,
+ text_box->height,
+ /* use the appropriate callback */
+ to_textarea ? browser_window_textarea_callback
+ : browser_window_input_callback,
+ to_textarea ? browser_window_textarea_paste_text
+ : browser_window_input_paste_text,
+ input);
+
+ if (dx || redraw)
+ browser_redraw_box(bw->current_content, input);
+}
+
+
+/**
+ * Insert a number of chars into a text box
+ *
+ * \param bw browser window
+ * \param text_box text box
+ * \param char_offset offsets (bytes) at which to insert text
+ * \param utf8 UTF-8 text to insert
+ * \param utf8_len length (bytes) of UTF-8 text to insert
+ * \return true iff successful
+ */
+
+bool textbox_insert(struct browser_window *bw, struct box *text_box,
+ unsigned char_offset, const char *utf8, unsigned utf8_len)
+{
+ char *text = talloc_realloc(bw->current_content, text_box->text,
+ char, text_box->length + utf8_len + 1);
+ if (!text) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ text_box->text = text;
+ memmove(text_box->text + char_offset + utf8_len,
+ text_box->text + char_offset,
+ text_box->length - char_offset);
+ memcpy(text_box->text + char_offset, utf8, utf8_len);
+ text_box->length += utf8_len;
+
+ /* nothing should assume that the text is terminated, but just in case */
+ text_box->text[text_box->length] = 0;
+
+ text_box->width = UNKNOWN_WIDTH;
+
+ return true;
+}
+
+
+/**
+ * Delete a number of chars from a text box
+ *
+ * \param bw browser window
+ * \param text_box text box
+ * \param char_offset offset within text box (bytes) of first char to delete
+ * \param utf8_len length (bytes) of chars to be deleted
+ */
+
+bool textbox_delete(struct browser_window *bw, struct box *text_box,
+ unsigned char_offset, unsigned utf8_len)
+{
+ unsigned prev_offset = char_offset + utf8_len;
+ if (prev_offset <= text_box->length) {
+ memmove(text_box->text + char_offset,
+ text_box->text + prev_offset,
+ text_box->length - prev_offset);
+ text_box->length -= (prev_offset - char_offset);
+
+ /* nothing should assume that the text is terminated, but just in case */
+ text_box->text[text_box->length] = 0;
+
+ text_box->width = UNKNOWN_WIDTH;
+ return true;
+ }
+ return false;
+}
+
+
+bool delete_handler(struct box *b, int offset, size_t length, void *handle)
+{
+ struct browser_window *bw = handle;
+ return textbox_delete(bw, b, offset, length);
+}
+
+
+/**
+ * Break a text box into two
+ *
+ * \param bw browser window
+ * \param text_box text box to be split
+ * \param char_offset offset (in bytes) at which text box is to be split
+ */
+
+struct box *textarea_insert_break(struct browser_window *bw, struct box *text_box,
+ size_t char_offset)
+{
+ struct box *new_br, *new_text;
+ char *text = talloc_array(bw->current_content, char,
+ text_box->length + 1);
+ if (!text) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ new_br = box_create(text_box->style, 0, text_box->title, 0,
+ bw->current_content);
+ new_text = talloc(bw->current_content, struct box);
+ if (!new_text) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ new_br->type = BOX_BR;
+ box_insert_sibling(text_box, new_br);
+
+ memcpy(new_text, text_box, sizeof (struct box));
+ new_text->clone = 1;
+ new_text->text = text;
+ memcpy(new_text->text, text_box->text + char_offset,
+ text_box->length - char_offset);
+ new_text->length = text_box->length - char_offset;
+ text_box->length = char_offset;
+ text_box->width = new_text->width = UNKNOWN_WIDTH;
+ box_insert_sibling(new_br, new_text);
+
+ return new_text;
+}
+
+
+/**
+ * Reflow textarea preserving width and height
+ *
+ * \param bw browser window
+ * \param textarea text area box
+ * \param inline_container container holding text box
+ */
+
+void textarea_reflow(struct browser_window *bw, struct box *textarea,
+ struct box *inline_container)
+{
+ int width = textarea->width;
+ int height = textarea->height;
+ if (!layout_inline_container(inline_container, width,
+ textarea, 0, 0,
+ bw->current_content))
+ warn_user("NoMemory", 0);
+ textarea->width = width;
+ textarea->height = height;
+ layout_calculate_descendant_bboxes(textarea);
+}
+
diff --git a/desktop/textinput.h b/desktop/textinput.h
index 155f526a0..c599ca0e1 100644
--- a/desktop/textinput.h
+++ b/desktop/textinput.h
@@ -12,16 +12,51 @@
* Textual input handling (interface)
*/
+#ifndef _NETSURF_DESKTOP_TEXTINPUT_H_
+#define _NETSURF_DESKTOP_TEXTINPUT_H_
+
+#include <stdbool.h>
+
struct browser_window;
struct box;
+
+enum input_key {
+
+ KEY_DELETE_LEFT = 8,
+
+ /* cursor movement keys */
+ KEY_LEFT = 28,
+ KEY_RIGHT,
+ KEY_UP,
+ KEY_DOWN,
+
+ KEY_DELETE_RIGHT = 127,
+
+ KEY_LINE_START = 128,
+ KEY_LINE_END,
+ KEY_TEXT_START,
+ KEY_TEXT_END,
+ KEY_WORD_LEFT,
+ KEY_WORD_RIGHT,
+ KEY_PAGE_UP,
+ KEY_PAGE_DOWN,
+ KEY_DELETE_LINE_END,
+ KEY_DELETE_LINE_START,
+};
+
+
void browser_window_textarea_click(struct browser_window *bw,
browser_mouse_state mouse,
struct box *textarea,
int box_x, int box_y,
int x, int y);
+//bool browser_window_textarea_paste(struct browser_window *bw,
+
void browser_window_input_click(struct browser_window* bw,
struct box *input,
int box_x, int box_y,
int x, int y);
void browser_window_remove_caret(struct browser_window *bw);
+
+#endif
diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c
index e215a002d..4f9f385d7 100644
--- a/gtk/gtk_window.c
+++ b/gtk/gtk_window.c
@@ -380,6 +380,11 @@ void gui_start_selection(struct gui_window *g)
}
+void gui_paste_from_clipboard(struct browser_window *bw, int x, int y)
+{
+}
+
+
bool gui_copy_to_clipboard(struct selection *s)
{
return false;
diff --git a/render/box.c b/render/box.c
index 7e0df2483..f00b8aa1d 100644
--- a/render/box.c
+++ b/render/box.c
@@ -133,7 +133,35 @@ void box_insert_sibling(struct box *box, struct box *new_box)
/**
- * Free the a box tree recursively.
+ * Unlink a box from the box tree and then free it recursively.
+ *
+ * \param box box to unlink and free recursively.
+ */
+
+void box_unlink_and_free(struct box *box)
+{
+ struct box *parent = box->parent;
+ struct box *next = box->next;
+ struct box *prev = box->prev;
+
+ if (parent) {
+ if (parent->children == box)
+ parent->children = next;
+ if (parent->last == box)
+ parent->last = next ? next : prev;
+ }
+
+ if (prev)
+ prev->next = next;
+ if (next)
+ next->prev = prev;
+
+ box_free(box);
+}
+
+
+/**
+ * Free a box tree recursively.
*
* \param box box to free recursively
*
diff --git a/render/box.h b/render/box.h
index bcdf79005..60aba1ba5 100644
--- a/render/box.h
+++ b/render/box.h
@@ -234,6 +234,7 @@ struct box * box_create(struct css_style *style,
char *id, void *context);
void box_add_child(struct box *parent, struct box *child);
void box_insert_sibling(struct box *box, struct box *new_box);
+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);
diff --git a/riscos/gui.h b/riscos/gui.h
index 71eb73852..9293046bb 100644
--- a/riscos/gui.h
+++ b/riscos/gui.h
@@ -161,6 +161,7 @@ void ro_gui_scroll_request(wimp_scroll *scroll);
//#define window_y_units(y, state) (y - (state->visible.y1 - state->yscroll))
int window_x_units(int x, wimp_window_state *state);
int window_y_units(int y, wimp_window_state *state);
+bool window_screen_pos(struct gui_window *g, int x, int y, os_coord *pos);
bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message);
void ro_gui_window_process_reformats(void);
void ro_gui_window_default_options(struct browser_window *bw);
diff --git a/riscos/save.c b/riscos/save.c
index d4841bb56..9a4c11072 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -3,6 +3,7 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
*/
/** \file
diff --git a/riscos/textselection.c b/riscos/textselection.c
index 67779bf6e..c6e4be57f 100644
--- a/riscos/textselection.c
+++ b/riscos/textselection.c
@@ -259,6 +259,53 @@ bool gui_copy_to_clipboard(struct selection *s)
/**
+ * Request to paste the clipboard contents into a textarea/input field
+ * at a given position. Note that the actual operation may take place
+ * straight away (local clipboard) or in a number of chunks at some
+ * later time (clipboard owned by another app).
+ *
+ * \param g gui window
+ * \param x x ordinate at which to paste text
+ * \param y y ordinate at which to paste text
+ */
+
+void gui_paste_from_clipboard(struct gui_window *g, int x, int y)
+{
+ if (owns_clipboard) {
+ if (clip_length > 0)
+ browser_window_paste_text(g->bw, clipboard, clip_length, true);
+ }
+ else {
+ wimp_full_message_data_request msg;
+ os_error *error;
+ os_coord pos;
+
+ if (!window_screen_pos(g, x, y, &pos))
+ return;
+
+ msg.size = sizeof(msg);
+ msg.your_ref = 0;
+ msg.action = message_DATA_REQUEST;
+ msg.w = g->window;
+ msg.i = -1;
+ msg.pos.x = pos.x;
+ msg.pos.y = pos.y;
+ msg.flags = wimp_DATA_REQUEST_CLIPBOARD;
+ msg.file_types[0] = osfile_TYPE_TEXT;
+ msg.file_types[1] = ~0;
+
+ error = xwimp_send_message(wimp_USER_MESSAGE, (wimp_message*)&msg,
+ wimp_BROADCAST);
+ if (error) {
+ LOG(("xwimp_send_message: 0x%x : %s",
+ error->errnum, error->errmess));
+ warn_user("WimpError", error->errmess);
+ }
+ }
+}
+
+
+/**
* Discard the current contents of the clipboard, if any, releasing the
* memory it uses.
*/
@@ -306,8 +353,6 @@ void ro_gui_selection_claim_entity(wimp_full_message_claim_entity *claim)
void ro_gui_selection_data_request(wimp_full_message_data_request *req)
{
- LOG(("%x owns %d size %d", req->flags, owns_clipboard, req->size));
-
if (owns_clipboard && clip_length > 0 &&
(req->flags & wimp_DATA_REQUEST_CLIPBOARD)) {
wimp_full_message_data_xfer message;
diff --git a/riscos/window.c b/riscos/window.c
index 9c04494a1..5bf5a1edd 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -20,6 +20,7 @@
#include <string.h>
#include "oslib/colourtrans.h"
#include "oslib/osbyte.h"
+#include "oslib/osfile.h"
#include "oslib/osspriteop.h"
#include "oslib/serviceinternational.h"
#include "oslib/wimp.h"
@@ -28,7 +29,9 @@
#include "netsurf/content/content.h"
#include "netsurf/content/url_store.h"
#include "netsurf/css/css.h"
+#include "netsurf/desktop/browser.h"
#include "netsurf/desktop/plotters.h"
+#include "netsurf/desktop/textinput.h"
#include "netsurf/render/box.h"
#include "netsurf/render/form.h"
#include "netsurf/riscos/buffer.h"
@@ -48,6 +51,10 @@
#include "netsurf/utils/utils.h"
#include "netsurf/utils/messages.h"
+#ifndef wimp_KEY_END
+#define wimp_KEY_END wimp_KEY_COPY
+#endif
+
/** List of all browser windows. */
static struct gui_window *window_list = 0;
@@ -62,6 +69,7 @@ static float scale_snap_to[] = {0.10, 0.125, 0.25, 0.333, 0.5, 0.75,
static void ro_gui_window_clone_options(struct browser_window *new_bw,
struct browser_window *old_bw);
static browser_mouse_state ro_gui_mouse_drag_state(wimp_mouse_state buttons);
+static bool ro_gui_window_import_text(struct gui_window *g, const char *filename);
@@ -1616,14 +1624,29 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
/* We can't map onto 1->26 (reserved for ctrl+<qwerty>
That leaves 27->31 and 128->159 */
- if (c == 394) c = 9; /* Tab */
- else if (c == 410) c = 11; /* Shift+Tab */
- else if (c == 428) c = 128; /* Ctrl+Left */
- else if (c == 429) c = 129; /* Ctrl+Right*/
- else if (c == 396) c = 29; /* Left */
- else if (c == 397) c = 28; /* Right */
- else if (c == 398) c = 31; /* Down */
- else if (c == 399) c = 30; /* Up */
+ switch (key) {
+ case wimp_KEY_TAB: c = 9; break;
+ case wimp_KEY_SHIFT | wimp_KEY_TAB: c = 11; break;
+
+ /* cursor movement keys */
+ case wimp_KEY_CONTROL | wimp_KEY_LEFT: c = KEY_LINE_START; break;
+ case wimp_KEY_END:
+ case wimp_KEY_CONTROL | wimp_KEY_RIGHT: c = KEY_LINE_END; break;
+ case wimp_KEY_CONTROL | wimp_KEY_UP: c = KEY_TEXT_START; break;
+ case wimp_KEY_CONTROL | wimp_KEY_DOWN: c = KEY_TEXT_END; break;
+ case wimp_KEY_SHIFT | wimp_KEY_LEFT: c = KEY_WORD_LEFT ; break;
+ case wimp_KEY_SHIFT | wimp_KEY_RIGHT: c = KEY_WORD_RIGHT; break;
+ case wimp_KEY_SHIFT | wimp_KEY_UP: c = KEY_PAGE_UP; break;
+ case wimp_KEY_SHIFT | wimp_KEY_DOWN: c = KEY_PAGE_DOWN; break;
+ case wimp_KEY_LEFT: c = KEY_LEFT; break;
+ case wimp_KEY_RIGHT: c = KEY_RIGHT; break;
+ case wimp_KEY_UP: c = KEY_UP; break;
+ case wimp_KEY_DOWN: c = KEY_DOWN; break;
+
+ /* editing */
+ case wimp_KEY_CONTROL | wimp_KEY_END: c = 136; break;
+ }
+
if (c < 256) {
if ((wchar_t)key > 256)
/* do nothing */;
@@ -1685,7 +1708,7 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
"%x (ignoring)", c));
return true;
}
-
+
/* Continuation of UTF8 character */
wc |= ((c & 0x3F) << (6 * --shift));
if (shift > 0)
@@ -1993,6 +2016,35 @@ int window_y_units(int y, wimp_window_state *state) {
/**
+ * Convert x,y window co-ordinates into screen co-ordinates.
+ *
+ * \param g gui window
+ * \param x x ordinate
+ * \param y y ordinate
+ * \param pos receives position in screen co-ordinatates
+ * \return true iff conversion successful
+ */
+
+bool window_screen_pos(struct gui_window *g, int x, int y, os_coord *pos)
+{
+ wimp_window_state state;
+ os_error *error;
+
+ state.w = g->window;
+ 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;
+ }
+ pos->x = state.visible.x0 + ((x * 2 * g->option.scale) - state.xscroll);
+ pos->y = state.visible.y1 + ((-y * 2 * g->option.scale) - state.yscroll);
+ return true;
+}
+
+
+/**
* Handle Message_DataLoad (file dragged in) for a window.
*
* \param g window
@@ -2008,6 +2060,7 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
int x, y;
struct box *box;
struct box *file_box = 0;
+ struct box *text_box = 0;
struct browser_window *bw = g->bw;
struct content *content;
wimp_window_state state;
@@ -2021,7 +2074,7 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
if (0x1000 <= message->data.data_xfer.file_type)
return false;
- /* Search for a file input at the drop point. */
+ /* Search for a file input or text area at the drop point. */
state.w = message->data.data_xfer.w;
error = xwimp_get_window_state(&state);
if (error) {
@@ -2043,23 +2096,49 @@ bool ro_gui_window_dataload(struct gui_window *g, wimp_message *message)
box->style->visibility == CSS_VISIBILITY_HIDDEN)
continue;
- if (box->gadget && box->gadget->type == GADGET_FILE)
- file_box = box;
+ if (box->gadget) {
+ switch (box->gadget->type) {
+ case GADGET_FILE:
+ file_box = box;
+ break;
+
+ case GADGET_TEXTBOX:
+ case GADGET_TEXTAREA:
+ case GADGET_PASSWORD:
+ text_box = box;
+ break;
+
+ default: /* appease compiler */
+ break;
+ }
+ }
}
- if (!file_box)
+ if (!file_box && !text_box)
return false;
- /* Found: update form input. */
- free(file_box->gadget->value);
- file_box->gadget->value =
- strdup(message->data.data_xfer.file_name);
+ if (file_box) {
- /* Redraw box. */
- box_coords(file_box, &x, &y);
- gui_window_redraw(bw->window, x, y,
- x + file_box->width,
- y + file_box->height);
+ /* Found: update form input. */
+ free(file_box->gadget->value);
+ file_box->gadget->value =
+ strdup(message->data.data_xfer.file_name);
+
+ /* Redraw box. */
+ box_coords(file_box, &x, &y);
+ gui_window_redraw(bw->window, x, y,
+ x + file_box->width,
+ y + file_box->height);
+ }
+ else {
+
+ const char *filename = message->data.data_xfer.file_name;
+
+ browser_window_mouse_click(g->bw, BROWSER_MOUSE_CLICK_1, x, y);
+
+ if (!ro_gui_window_import_text(g, filename))
+ return true; /* it was for us, it just didn't work! */
+ }
/* send DataLoadAck */
message->action = message_DATA_LOAD_ACK;
@@ -2470,3 +2549,50 @@ void ro_gui_window_set_scale(struct gui_window *g, float scale)
browser_window_update(g->bw, false);
gui_reformat_pending = true;
}
+
+
+/**
+ * Import text file into textarea at caret position
+ *
+ * \param g gui window containing textarea
+ * \param filename pathname of file to be imported
+ * \return true iff successful
+ */
+
+bool ro_gui_window_import_text(struct gui_window *g, const char *filename)
+{
+ fileswitch_object_type obj_type;
+ os_error *error;
+ char *buf;
+ int size;
+
+ error = xosfile_read_stamped(filename, &obj_type, NULL, NULL,
+ &size, NULL, NULL);
+ if (error) {
+ LOG(("xosfile_read_stamped: 0x%x:%s",
+ error->errnum, error->errmess));
+ warn_user("FileError", error->errmess);
+ return true; /* was for us, but it didn't work! */
+ }
+
+ buf = malloc(size);
+ if (!buf) {
+ warn_user("NoMemory", NULL);
+ return true;
+ }
+
+ error = xosfile_load_stamped(filename, (byte*)buf,
+ NULL, NULL, NULL, NULL, NULL);
+ if (error) {
+ LOG(("xosfile_load_stamped: 0x%x:%s",
+ error->errnum, error->errmess));
+ warn_user("LoadError", error->errmess);
+ free(buf);
+ return true;
+ }
+
+ browser_window_paste_text(g->bw, buf, size, true);
+
+ free(buf);
+ return true;
+}