summaryrefslogtreecommitdiff
path: root/frontends/framebuffer/fbtk
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2016-05-05 22:28:51 +0100
committerVincent Sanders <vince@kyllikki.org>2016-05-15 13:44:34 +0100
commitd21447d096a320a08b3efb2b8768fad0dcdcfd64 (patch)
tree1a83814b7c9e94b2f13c473261f23dd3a17dee64 /frontends/framebuffer/fbtk
parent2cbb337756d9af5bda4d594964d446439f602551 (diff)
downloadnetsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.gz
netsurf-d21447d096a320a08b3efb2b8768fad0dcdcfd64.tar.bz2
move frontends into sub directory
Diffstat (limited to 'frontends/framebuffer/fbtk')
-rw-r--r--frontends/framebuffer/fbtk/bitmap.c136
-rw-r--r--frontends/framebuffer/fbtk/event.c349
-rw-r--r--frontends/framebuffer/fbtk/fbtk.c830
-rw-r--r--frontends/framebuffer/fbtk/fill.c81
-rw-r--r--frontends/framebuffer/fbtk/osk.c199
-rw-r--r--frontends/framebuffer/fbtk/scroll.c589
-rw-r--r--frontends/framebuffer/fbtk/text.c640
-rw-r--r--frontends/framebuffer/fbtk/user.c64
-rw-r--r--frontends/framebuffer/fbtk/widget.h259
-rw-r--r--frontends/framebuffer/fbtk/window.c91
10 files changed, 3238 insertions, 0 deletions
diff --git a/frontends/framebuffer/fbtk/bitmap.c b/frontends/framebuffer/fbtk/bitmap.c
new file mode 100644
index 000000000..1f147be00
--- /dev/null
+++ b/frontends/framebuffer/fbtk/bitmap.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit bitmaped image widget
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+
+#include "desktop/browser.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+static int
+fb_redraw_bitmap(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ nsfb_bbox_t bbox;
+ nsfb_bbox_t rect;
+ nsfb_t *nsfb;
+
+ nsfb = fbtk_get_nsfb(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ rect = bbox;
+
+ nsfb_claim(nsfb, &bbox);
+
+ /* clear background */
+ if ((widget->bg & 0xFF000000) != 0) {
+ /* transparent polygon filling isnt working so fake it */
+ nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
+ }
+
+ /* plot the image */
+ nsfb_plot_bitmap(nsfb,
+ &rect,
+ (nsfb_colour_t *)widget->u.bitmap.bitmap->pixdata,
+ widget->u.bitmap.bitmap->width,
+ widget->u.bitmap.bitmap->height,
+ widget->u.bitmap.bitmap->width,
+ !widget->u.bitmap.bitmap->opaque);
+
+ nsfb_update(nsfb, &bbox);
+
+ return 0;
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_set_bitmap(fbtk_widget_t *widget, struct fbtk_bitmap *image)
+{
+ if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_BITMAP))
+ return;
+
+ widget->u.bitmap.bitmap = image;
+
+ fbtk_request_redraw(widget);
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_bitmap(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour c,
+ struct fbtk_bitmap *image)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_BITMAP, x, y, width, height);
+
+ neww->bg = c;
+ neww->mapped = true;
+ neww->u.bitmap.bitmap = image;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_bitmap, NULL);
+
+ return neww;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_button(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour c,
+ struct fbtk_bitmap *image,
+ fbtk_callback click,
+ void *pw)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_BITMAP, x, y, width, height);
+
+ neww->bg = c;
+ neww->mapped = true;
+ neww->u.bitmap.bitmap = image;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_bitmap, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_CLICK, click, pw);
+ fbtk_set_handler(neww, FBTK_CBT_POINTERENTER, fbtk_set_ptr, &hand_image);
+
+ return neww;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/event.c b/frontends/framebuffer/fbtk/event.c
new file mode 100644
index 000000000..c0894921e
--- /dev/null
+++ b/frontends/framebuffer/fbtk/event.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit event processing.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_plot_util.h>
+#include <libnsfb_event.h>
+#include <libnsfb_cursor.h>
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "desktop/browser.h"
+#include "desktop/textinput.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+/* exported function documented in fbtk.h */
+void
+fbtk_input(fbtk_widget_t *root, nsfb_event_t *event)
+{
+ fbtk_widget_t *input;
+
+ root = fbtk_get_root_widget(root);
+
+ /* obtain widget with input focus */
+ input = root->u.root.input;
+ if (input == NULL) {
+ LOG("No widget has input focus.");
+ return; /* no widget with input */
+ }
+
+ fbtk_post_callback(input, FBTK_CBT_INPUT, event);
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_click(fbtk_widget_t *widget, nsfb_event_t *event)
+{
+ fbtk_widget_t *root;
+ fbtk_widget_t *clicked;
+ nsfb_bbox_t cloc;
+ int x, y;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ nsfb_cursor_loc_get(root->u.root.fb, &cloc);
+
+ clicked = fbtk_get_widget_at(root, cloc.x0, cloc.y0);
+
+ if (clicked == NULL)
+ return;
+
+ if (fbtk_get_handler(clicked, FBTK_CBT_INPUT) != NULL) {
+ fbtk_set_focus(clicked);
+ }
+
+ x = fbtk_get_absx(clicked);
+ y = fbtk_get_absy(clicked);
+
+ LOG("clicked %p at %d,%d", clicked, x, y);
+
+ /* post the click */
+ fbtk_post_callback(clicked, FBTK_CBT_CLICK, event, cloc.x0 - x, cloc.y0 - y);
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_tgrab_pointer(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *root;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ if (root->u.root.grabbed == widget) {
+ /* release pointer grab */
+ root->u.root.grabbed = NULL;
+ return true;
+ } else if (root->u.root.grabbed == NULL) {
+ /* set pointer grab */
+ root->u.root.grabbed = widget;
+ return true;
+ }
+ /* pointer was already grabbed */
+ return false;
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_warp_pointer(fbtk_widget_t *widget, int x, int y, bool relative)
+{
+ fbtk_widget_t *root;
+ fbtk_widget_t *moved;
+ nsfb_bbox_t cloc;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ if (relative) {
+ nsfb_cursor_loc_get(root->u.root.fb, &cloc);
+ cloc.x0 += x;
+ cloc.y0 += y;
+ } else {
+ cloc.x0 = x;
+ cloc.y0 = y;
+ }
+
+ /* ensure cursor location lies within the root widget */
+ if (cloc.x0 < root->x)
+ cloc.x0 = root->x;
+ if (cloc.x0 >= (root->x + root->width))
+ cloc.x0 = (root->x + root->width) - 1;
+ if (cloc.y0 < root->y)
+ cloc.y0 = root->y;
+ if (cloc.y0 >= (root->y + root->height))
+ cloc.y0 = (root->y + root->height) - 1;
+
+ if (root->u.root.grabbed == NULL) {
+ /* update the pointer cursor */
+ nsfb_cursor_loc_set(root->u.root.fb, &cloc);
+
+ moved = fbtk_get_widget_at(root, cloc.x0, cloc.y0);
+
+ x = fbtk_get_absx(moved);
+ y = fbtk_get_absy(moved);
+
+ /* post enter and leaving messages */
+ if (moved != root->u.root.prev) {
+ fbtk_post_callback(root->u.root.prev, FBTK_CBT_POINTERLEAVE);
+ root->u.root.prev = moved;
+ fbtk_post_callback(root->u.root.prev, FBTK_CBT_POINTERENTER);
+ }
+ } else {
+ /* pointer movement has been grabbed by a widget */
+ moved = root->u.root.grabbed;
+
+ /* ensure pointer remains within widget boundary */
+ x = fbtk_get_absx(moved);
+ y = fbtk_get_absy(moved);
+
+ if (cloc.x0 < x)
+ cloc.x0 = x;
+ if (cloc.y0 < y)
+ cloc.y0 = y;
+ if (cloc.x0 > (x + moved->width))
+ cloc.x0 = (x + moved->width);
+ if (cloc.y0 > (y + moved->height))
+ cloc.y0 = (y + moved->height);
+
+ /* update the pointer cursor */
+ nsfb_cursor_loc_set(root->u.root.fb, &cloc);
+ }
+
+ /* post the movement */
+ fbtk_post_callback(moved, FBTK_CBT_POINTERMOVE, cloc.x0 - x, cloc.y0 - y);
+
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_event(fbtk_widget_t *root, nsfb_event_t *event, int timeout)
+{
+ nsfb_bbox_t cloc;
+ bool unused = false; /* is the event available */
+ bool move_pointer = false; /* whether pointer move events occured */
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(root);
+
+ do {
+ if (nsfb_event(root->u.root.fb, event, timeout) == false) {
+ if (move_pointer)
+ fbtk_warp_pointer(root, cloc.x0, cloc.y0,
+ false);
+ return false;
+ }
+
+ if (move_pointer && event->type != NSFB_EVENT_MOVE_RELATIVE &&
+ event->type != NSFB_EVENT_MOVE_ABSOLUTE) {
+ /* Flush the movements */
+ fbtk_warp_pointer(root, cloc.x0, cloc.y0, false);
+
+ } else if (!move_pointer &&
+ event->type == NSFB_EVENT_MOVE_RELATIVE) {
+ /* Get current pointer coords */
+ nsfb_cursor_loc_get(root->u.root.fb, &cloc);
+ }
+
+ switch (event->type) {
+ case NSFB_EVENT_KEY_DOWN:
+ case NSFB_EVENT_KEY_UP:
+ if ((event->value.keycode >= NSFB_KEY_MOUSE_1) &&
+ (event->value.keycode <= NSFB_KEY_MOUSE_5)) {
+ fbtk_click(root, event);
+ } else {
+ fbtk_input(root, event);
+ }
+ break;
+
+ case NSFB_EVENT_CONTROL:
+ unused = true;
+ break;
+
+ case NSFB_EVENT_MOVE_RELATIVE:
+ /* Consecutive move events are consolidated into a
+ * single pointer warp */
+ move_pointer = true;
+ cloc.x0 += event->value.vector.x;
+ cloc.y0 += event->value.vector.y;
+ timeout = 0;
+ break;
+
+ case NSFB_EVENT_MOVE_ABSOLUTE:
+ /* Consecutive move events are consolidated into a
+ * single pointer warp */
+ move_pointer = true;
+ cloc.x0 = event->value.vector.x;
+ cloc.y0 = event->value.vector.y;
+ timeout = 0;
+ break;
+
+ case NSFB_EVENT_RESIZE:
+ /* Try to resize framebuffer */
+ gui_resize(root,
+ event->value.resize.w,
+ event->value.resize.h);
+ break;
+
+ default:
+ break;
+ }
+ } while (event->type == NSFB_EVENT_MOVE_RELATIVE ||
+ event->type == NSFB_EVENT_MOVE_ABSOLUTE);
+ return unused;
+}
+
+static int keymap[] = {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ -1, -1, -1, -1, -1, -1, -1, -1, 8, 9, /* 0 - 9 */
+ -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, /* 10 - 19 */
+ -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, /* 20 - 29 */
+ -1, -1, ' ', '!', '"', '#', '$', -1, '&','\'', /* 30 - 39 */
+ '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', /* 40 - 49 */
+ '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', /* 50 - 59 */
+ '<', '=', '>', '?', '@', -1, -1, -1, -1, -1, /* 60 - 69 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */
+ -1, '[','\\', ']', '~', '_', '`', 'a', 'b', 'c', /* 90 - 99 */
+ 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', /* 100 - 109 */
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 110 - 119 */
+ 'x', 'y', 'z', -1, -1, -1, -1, -1, -1, -1, /* 120 - 129 */
+};
+
+static int sh_keymap[] = {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ -1, -1, -1, -1, -1, -1, -1, -1, 8, 9, /* 0 - 9 */
+ -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, /* 10 - 19 */
+ -1, -1, -1, -1, -1, -1, -1, 27, -1, -1, /* 20 - 29 */
+ -1, -1, ' ', '!', '"', '~', '$', -1, '&', '@', /* 30 - 39 */
+ '(', ')', '*', '+', '<', '_', '>', '?', ')', '!', /* 40 - 49 */
+ '"', 243, '$', '%', '^', '&', '*', '(', ';', ':', /* 50 - 59 */
+ '<', '+', '>', '?', '@', -1, -1, -1, -1, -1, /* 60 - 69 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */
+ -1, '{', '|', '}', '~', '_', 254, 'A', 'B', 'C', /* 90 - 99 */
+ 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', /* 100 - 109 */
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 110 - 119 */
+ 'X', 'Y', 'Z', -1, -1, -1, -1, -1, -1, -1, /* 120 - 129 */
+};
+
+
+/* exported function documented in fbtk.h */
+int
+fbtk_keycode_to_ucs4(int code, fbtk_modifier_type mods)
+{
+ int ucs4 = -1;
+
+ if (mods & FBTK_MOD_LSHIFT || mods & FBTK_MOD_RSHIFT) {
+ if ((code >= 0) && (code < (int) NOF_ELEMENTS(sh_keymap)))
+ ucs4 = sh_keymap[code];
+
+ } else if (mods == FBTK_MOD_CLEAR) {
+ if ((code >= 0) && (code < (int) NOF_ELEMENTS(keymap)))
+ ucs4 = keymap[code];
+
+ } else if (mods & FBTK_MOD_LCTRL || mods & FBTK_MOD_RCTRL) {
+ switch (code) {
+ case NSFB_KEY_a:
+ ucs4 = NS_KEY_SELECT_ALL;
+ break;
+
+ case NSFB_KEY_c:
+ ucs4 = NS_KEY_COPY_SELECTION;
+ break;
+
+ case NSFB_KEY_u:
+ ucs4 = NS_KEY_DELETE_LINE;
+ break;
+
+ case NSFB_KEY_v:
+ ucs4 = NS_KEY_PASTE;
+ break;
+
+ case NSFB_KEY_x:
+ ucs4 = NS_KEY_CUT_SELECTION;
+ break;
+
+ case NSFB_KEY_z:
+ ucs4 = NS_KEY_CLEAR_SELECTION;
+ break;
+ default:
+ break;
+ }
+ }
+ return ucs4;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/fbtk.c b/frontends/framebuffer/fbtk/fbtk.c
new file mode 100644
index 000000000..db1c1f1a9
--- /dev/null
+++ b/frontends/framebuffer/fbtk/fbtk.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright 2008,2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit core.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_plot_util.h>
+#include <libnsfb_event.h>
+#include <libnsfb_cursor.h>
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "desktop/browser.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+#ifdef FBTK_LOGGING
+
+/* tree dump debug, also example of depth first tree walk */
+static void
+dump_tk_tree(fbtk_widget_t *widget)
+{
+ widget = fbtk_get_root_widget(widget);
+ int indent = 0;
+
+ while (widget != NULL) {
+ LOG("%*s%p", indent, "", widget);
+ if (widget->first_child != NULL) {
+ widget = widget->first_child;
+ indent += 6;
+ } else if (widget->next != NULL) {
+ widget = widget->next;
+ } else {
+ while ((widget->parent != NULL) &&
+ (widget->parent->next == NULL)) {
+ widget = widget->parent;
+ indent -= 6;
+ }
+ if (widget->parent != NULL) {
+ indent -= 6;
+ widget = widget->parent->next;
+ } else {
+ widget = NULL;
+ }
+ }
+ }
+}
+
+#endif
+
+/* exported function documented in fbtk.h */
+void
+fbtk_request_redraw(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *cwidget;
+ fbtk_widget_t *pwidget;
+
+ assert(widget != NULL);
+
+ /* if widget not mapped do not try to redraw it */
+ pwidget = widget;
+ while (pwidget != NULL) {
+ if (pwidget->mapped == false)
+ return;
+ pwidget = pwidget->parent;
+ }
+
+ widget->redraw.needed = true;
+ widget->redraw.x = 0;
+ widget->redraw.y = 0;
+ widget->redraw.width = widget->width;
+ widget->redraw.height = widget->height;
+
+#ifdef FBTK_LOGGING
+ LOG("redrawing %p %d,%d %d,%d", widget, widget->redraw.x, widget->redraw.y, widget->redraw.width, widget->redraw.height);
+#endif
+
+ cwidget = widget->last_child;
+ while (cwidget != NULL) {
+ fbtk_request_redraw(cwidget);
+ cwidget = cwidget->prev;
+ }
+
+ while (widget->parent != NULL) {
+ widget = widget->parent;
+ widget->redraw.child = true;
+ }
+}
+
+
+
+/* exported function documented in fbtk.h */
+int
+fbtk_set_mapping(fbtk_widget_t *widget, bool map)
+{
+ LOG("setting mapping on %p to %d", widget, map);
+ widget->mapped = map;
+ if (map) {
+ fbtk_request_redraw(widget);
+ } else {
+ fbtk_request_redraw(widget->parent);
+ }
+ return 0;
+}
+
+/** swap the widget given with the next sibling.
+ *
+ * Swap a sibling widget with the next deepest in the hierachy
+ */
+static void
+swap_siblings(fbtk_widget_t *lw)
+{
+ fbtk_widget_t *rw = lw->next; /* the widget to swap lw with */
+ fbtk_widget_t *before;
+ fbtk_widget_t *after;
+
+ assert(rw != NULL);
+
+ LOG("Swapping %p with %p", lw, rw);
+ before = lw->prev;
+ after = rw->next;
+
+ if (before == NULL) {
+ /* left widget is currently the first child */
+ lw->parent->first_child = rw;
+ } else {
+ before->next = rw;
+ }
+ rw->prev = before;
+ rw->next = lw;
+
+ if (after == NULL) {
+ /* right widget is currently the last child */
+ rw->parent->last_child = lw;
+ } else {
+ after->prev = lw;
+ }
+ lw->next = after;
+ lw->prev = rw;
+}
+
+
+
+/* exported function documented in fbtk.h */
+int
+fbtk_set_zorder(fbtk_widget_t *widget, int z)
+{
+ while (z != 0) {
+ if (z < 0) {
+ if (widget->prev == NULL)
+ break; /* cannot go any shallower */
+
+ /* swap with previous entry */
+ swap_siblings(widget->prev);
+
+ z++;
+ } else {
+ if (widget->next == NULL)
+ break; /* cannot go any deeper */
+
+ /* swap with subsequent entry */
+ swap_siblings(widget);
+
+ z--;
+ }
+ }
+
+ return z;
+}
+
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_set_pos_and_size(fbtk_widget_t *widget,
+ int x, int y,
+ int width, int height)
+{
+ if (widget->parent != NULL) {
+ fbtk_widget_t *parent = widget->parent;
+
+ /* make new window fit inside parent */
+ if (width == 0) {
+ width = parent->width - x;
+ } else if (width < 0) {
+ width = parent->width + width - x;
+ }
+ if ((width + x) > parent->width) {
+ width = parent->width - x;
+ }
+
+ if (height == 0) {
+ height = parent->height - y;
+ } else if (height < 0) {
+ height = parent->height + height - y;
+ }
+ if ((height + y) > parent->height) {
+ height = parent->height - y;
+ }
+ }
+
+ if ((widget->x != x) ||
+ (widget->y != y) ||
+ (widget->width != width) ||
+ (widget->height != height)) {
+ widget->x = x;
+ widget->y = y;
+ widget->width = width;
+ widget->height = height;
+ return true;
+ }
+ return false;
+}
+
+
+/* exported function docuemnted in fbtk.h */
+void
+fbtk_set_caret(fbtk_widget_t *widget, bool set,
+ int x, int y, int height,
+ void (*remove_caret)(fbtk_widget_t *widget))
+{
+ fbtk_widget_t *root;
+
+ assert(widget != NULL);
+ root = fbtk_get_root_widget(widget);
+
+ if (root->u.root.caret.owner != NULL &&
+ root->u.root.caret.remove_cb != NULL)
+ root->u.root.caret.remove_cb(widget);
+
+ if (set) {
+ assert(remove_caret != NULL);
+
+ root->u.root.caret.owner = widget;
+ root->u.root.caret.x = x;
+ root->u.root.caret.y = y;
+ root->u.root.caret.height = height;
+ root->u.root.caret.remove_cb = remove_caret;
+
+ } else {
+ root->u.root.caret.owner = NULL;
+ root->u.root.caret.remove_cb = NULL;
+ }
+}
+
+/* exported function documented in fbtk.h */
+int
+fbtk_destroy_widget(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *parent;
+ int ret = 0;
+
+ ret = fbtk_post_callback(widget, FBTK_CBT_DESTROY);
+
+ while (widget->first_child != NULL) {
+ fbtk_destroy_widget(widget->first_child);
+ }
+
+ parent = widget->parent;
+ if (parent != NULL) {
+
+ /* unlink from siblings */
+ if (widget->prev != NULL) {
+ widget->prev->next = widget->next;
+ } else {
+ /* must be the first widget, unlink from parent */
+ parent->first_child = widget->next;
+ }
+ if (widget->next != NULL) {
+ widget->next->prev = widget->prev;
+ } else {
+ /* must be the last widget, unlink from parent */
+ parent->last_child = widget->prev;
+ }
+
+ free(widget);
+ }
+
+ return ret;
+}
+
+/* region coverage flags. */
+enum {
+ POINT_LEFTOF_REGION = 1,
+ POINT_RIGHTOF_REGION = 2,
+ POINT_ABOVE_REGION = 4,
+ POINT_BELOW_REGION = 8,
+};
+
+/* Computes where a point lies in respect to an area. */
+#define REGION(x,y,cx1,cx2,cy1,cy2) \
+ (( (y) > (cy2) ? POINT_BELOW_REGION : 0) | \
+ ( (y) < (cy1) ? POINT_ABOVE_REGION : 0) | \
+ ( (x) > (cx2) ? POINT_RIGHTOF_REGION : 0) | \
+ ( (x) < (cx1) ? POINT_LEFTOF_REGION : 0) )
+
+/* swap two integers */
+#define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t; } while(0)
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_clip_rect(const bbox_t * restrict clip, bbox_t * restrict box)
+{
+ uint8_t region1;
+ uint8_t region2;
+
+ /* ensure co-ordinates are in ascending order */
+ if (box->x1 < box->x0)
+ SWAP(box->x0, box->x1);
+ if (box->y1 < box->y0)
+ SWAP(box->y0, box->y1);
+
+ region1 = REGION(box->x0, box->y0, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+ region2 = REGION(box->x1, box->y1, clip->x0, clip->x1 - 1, clip->y0, clip->y1 - 1);
+
+ /* area lies entirely outside the clipping rectangle */
+ if ((region1 | region2) && (region1 & region2))
+ return false;
+
+ if (box->x0 < clip->x0)
+ box->x0 = clip->x0;
+ if (box->x0 > clip->x1)
+ box->x0 = clip->x1;
+
+ if (box->x1 < clip->x0)
+ box->x1 = clip->x0;
+ if (box->x1 > clip->x1)
+ box->x1 = clip->x1;
+
+ if (box->y0 < clip->y0)
+ box->y0 = clip->y0;
+ if (box->y0 > clip->y1)
+ box->y0 = clip->y1;
+
+ if (box->y1 < clip->y0)
+ box->y1 = clip->y0;
+ if (box->y1 > clip->y1)
+ box->y1 = clip->y1;
+
+ return true;
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_clip_to_widget(fbtk_widget_t *widget, bbox_t * restrict box)
+{
+ bbox_t wbox;
+ wbox.x0 = 0;
+ wbox.y0 = 0;
+ wbox.x1 = widget->width;
+ wbox.y1 = widget->height;
+ return fbtk_clip_rect(&wbox, box);
+}
+
+
+
+/* internally exported function documented in widget.h */
+int
+fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ fbtk_widget_t *root = fbtk_get_root_widget(widget);
+ struct fbtk_bitmap *bm = cbi->context;
+
+ nsfb_cursor_set(root->u.root.fb,
+ (nsfb_colour_t *)bm->pixdata,
+ bm->width,
+ bm->height,
+ bm->width,
+ bm->hot_x,
+ bm->hot_y);
+
+ return 0;
+}
+
+
+
+/* internally exported function documented in widget.h */
+fbtk_widget_t *
+fbtk_get_root_widget(fbtk_widget_t *widget)
+{
+ while (widget->parent != NULL)
+ widget = widget->parent;
+
+ /* check root widget was found */
+ if (widget->type != FB_WIDGET_TYPE_ROOT) {
+ LOG("Widget with null parent that is not the root widget!");
+ return NULL;
+ }
+
+ return widget;
+}
+
+
+/* exported function documented in fbtk.h */
+int
+fbtk_get_absx(fbtk_widget_t *widget)
+{
+ int x = widget->x;
+
+ while (widget->parent != NULL) {
+ widget = widget->parent;
+ x += widget->x;
+ }
+
+ return x;
+}
+
+/* exported function documented in fbtk.h */
+int
+fbtk_get_absy(fbtk_widget_t *widget)
+{
+ int y = widget->y;
+
+ while (widget->parent != NULL) {
+ widget = widget->parent;
+ y += widget->y;
+ }
+
+ return y;
+}
+
+/* exported function documented in fbtk.h */
+int
+fbtk_get_height(fbtk_widget_t *widget)
+{
+ return widget->height;
+}
+
+/* exported function documented in fbtk.h */
+int
+fbtk_get_width(fbtk_widget_t *widget)
+{
+ return widget->width;
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_get_bbox(fbtk_widget_t *widget, nsfb_bbox_t *bbox)
+{
+ bbox->x0 = widget->x;
+ bbox->y0 = widget->y;
+ bbox->x1 = widget->x + widget->width;
+ bbox->y1 = widget->y + widget->height;
+
+ widget = widget->parent;
+ while (widget != NULL) {
+ bbox->x0 += widget->x;
+ bbox->y0 += widget->y;
+ bbox->x1 += widget->x;
+ bbox->y1 += widget->y;
+ widget = widget->parent;
+ }
+
+ return true;
+}
+
+bool
+fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height)
+{
+ fbtk_widget_t *root = fbtk_get_root_widget(widget);
+
+ if (root->u.root.caret.owner == widget) {
+ *x = root->u.root.caret.x;
+ *y = root->u.root.caret.y;
+ *height = root->u.root.caret.height;
+
+ return true;
+
+ } else {
+ *x = 0;
+ *y = 0;
+ *height = 0;
+
+ return false;
+ }
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_get_widget_at(fbtk_widget_t *nwid, int x, int y)
+{
+ fbtk_widget_t *widget = NULL; /* found widget */
+
+ /* require the root widget to start */
+ nwid = fbtk_get_root_widget(nwid);
+
+ while (nwid != NULL) {
+ if ((nwid->mapped) &&
+ (x >= nwid->x) &&
+ (y >= nwid->y) &&
+ (x < (nwid->x + nwid->width)) &&
+ (y < (nwid->y + nwid->height))) {
+ widget = nwid;
+ x -= nwid->x;
+ y -= nwid->y;
+ nwid = nwid->first_child;
+ } else {
+ nwid = nwid->next;
+ }
+ }
+
+ return widget;
+}
+
+
+
+
+/* internally exported function documented in widget.h */
+fbtk_widget_t *
+fbtk_widget_new(fbtk_widget_t *parent,
+ enum fbtk_widgettype_e type,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ fbtk_widget_t *neww; /* new widget */
+
+ if (parent == NULL)
+ return NULL;
+
+ neww = calloc(1, sizeof(fbtk_widget_t));
+ if (neww == NULL)
+ return NULL;
+
+#ifdef FBTK_LOGGING
+ LOG("creating %p %d,%d %d,%d", neww, x, y, width, height);
+#endif
+
+ /* make new window fit inside parent */
+ if (width == 0) {
+ width = parent->width - x;
+ } else if (width < 0) {
+ width = parent->width + width - x;
+ }
+ if ((width + x) > parent->width) {
+ width = parent->width - x;
+ }
+
+ if (height == 0) {
+ height = parent->height - y;
+ } else if (height < 0) {
+ height = parent->height + height - y;
+ }
+ if ((height + y) > parent->height) {
+ height = parent->height - y;
+ }
+
+#ifdef FBTK_LOGGING
+ LOG("using %p %d,%d %d,%d", neww, x, y, width, height);
+#endif
+ /* set values */
+ neww->type = type;
+ neww->x = x;
+ neww->y = y;
+ neww->width = width;
+ neww->height = height;
+
+ /* insert into widget heiarchy */
+
+ neww->parent = parent;
+
+ if (parent->first_child == NULL) {
+ /* no child widgets yet */
+ parent->last_child = neww;
+ } else {
+ /* add new widget to front of sibling chain */
+ neww->next = parent->first_child;
+ neww->next->prev = neww;
+ }
+ parent->first_child = neww;
+
+ return neww;
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_get_redraw_pending(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *root;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ return root->redraw.needed | root->redraw.child;
+}
+
+/** Perform a depth-first tree-walk, calling the redraw callback of the widgets in turn.
+ *
+ * This function makes no decisions of its own and simply walks the
+ * widget tree depth first calling widgets redraw callbacks if flagged
+ * to do so.
+ * The tree search is optimised with a flag to indicate wether the
+ * children of a node should be considered.
+ */
+static int
+do_redraw(nsfb_t *nsfb, fbtk_widget_t *widget)
+{
+ nsfb_bbox_t plot_ctx;
+ fbtk_widget_t *cwidget; /* child widget */
+
+ /* check if the widget requires redrawing */
+ if (widget->redraw.needed == true) {
+ plot_ctx.x0 = fbtk_get_absx(widget) + widget->redraw.x;
+ plot_ctx.y0 = fbtk_get_absy(widget) + widget->redraw.y;
+ plot_ctx.x1 = plot_ctx.x0 + widget->redraw.width;
+ plot_ctx.y1 = plot_ctx.y0 + widget->redraw.height;
+
+#ifdef FBTK_LOGGING
+ LOG("clipping %p %d,%d %d,%d", widget, plot_ctx.x0, plot_ctx.y0, plot_ctx.x1, plot_ctx.y1);
+#endif
+ if (nsfb_plot_set_clip(nsfb, &plot_ctx) == true) {
+ fbtk_post_callback(widget, FBTK_CBT_REDRAW);
+ }
+ widget->redraw.needed = false;
+ }
+
+ /* walk the widgets children if child flag is set */
+ if (widget->redraw.child) {
+ cwidget = widget->last_child;
+ while (cwidget != NULL) {
+ do_redraw(nsfb, cwidget);
+ cwidget = cwidget->prev;
+ }
+ widget->redraw.child = false;
+ }
+
+ return 1;
+}
+
+/* exported function documented in fbtk.h */
+int
+fbtk_redraw(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *root;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ return do_redraw(root->u.root.fb, root);
+}
+
+/* exported function documented in fbtk.h */
+fbtk_callback
+fbtk_get_handler(fbtk_widget_t *widget, fbtk_callback_type cbt)
+{
+ if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
+ /* type out of range, no way to report error so return NULL */
+ return NULL;
+ }
+
+ return widget->callback[cbt];
+}
+
+/* exported function documented in fbtk.h */
+fbtk_callback
+fbtk_set_handler(fbtk_widget_t *widget,
+ fbtk_callback_type cbt,
+ fbtk_callback cb,
+ void *context)
+{
+ fbtk_callback prevcb;
+
+ if ((cbt <= FBTK_CBT_START) || (cbt >= FBTK_CBT_END)) {
+ /* type out of range, no way to report error so return NULL */
+ return NULL;
+ }
+
+ prevcb = widget->callback[cbt];
+
+ widget->callback[cbt] = cb;
+ widget->callback_context[cbt] = context;
+
+ return prevcb;
+}
+
+/* exported function docuemnted in fbtk.h */
+int
+fbtk_post_callback(fbtk_widget_t *widget, fbtk_callback_type cbt, ...)
+{
+ fbtk_callback_info cbi;
+ int ret = 0;
+ va_list ap;
+
+ if (widget == NULL)
+ return -1;
+ /* if the widget is not mapped do not attempt to post any
+ * events to it
+ */
+ if (widget->mapped == false)
+ return ret;
+
+ if (widget->callback[cbt] != NULL) {
+ cbi.type = cbt;
+ cbi.context = widget->callback_context[cbt];
+
+ va_start(ap, cbt);
+
+ switch (cbt) {
+ case FBTK_CBT_SCROLLX:
+ cbi.x = va_arg(ap,int);
+ break;
+
+ case FBTK_CBT_SCROLLY:
+ cbi.y = va_arg(ap,int);
+ break;
+
+ case FBTK_CBT_CLICK:
+ cbi.event = va_arg(ap, void *);
+ cbi.x = va_arg(ap, int);
+ cbi.y = va_arg(ap, int);
+ break;
+
+ case FBTK_CBT_INPUT:
+ cbi.event = va_arg(ap, void *);
+ break;
+
+ case FBTK_CBT_POINTERMOVE:
+ cbi.x = va_arg(ap, int);
+ cbi.y = va_arg(ap, int);
+ break;
+
+ case FBTK_CBT_REDRAW:
+ break;
+
+ case FBTK_CBT_USER:
+ break;
+
+ case FBTK_CBT_STRIP_FOCUS:
+ break;
+
+ default:
+ break;
+ }
+ va_end(ap);
+
+ ret = (widget->callback[cbt])(widget, &cbi);
+ }
+
+ return ret;
+}
+
+/* exported function docuemnted in fbtk.h */
+void
+fbtk_set_focus(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *root;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ if (root->u.root.input != NULL &&
+ root->u.root.input != widget) {
+ /* inform previous holder of focus that it's being stripped
+ * of focus */
+ fbtk_post_callback(root->u.root.input, FBTK_CBT_STRIP_FOCUS);
+ }
+
+ root->u.root.input = widget;
+}
+
+
+
+/* exported function docuemnted in fbtk.h */
+nsfb_t *
+fbtk_get_nsfb(fbtk_widget_t *widget)
+{
+ fbtk_widget_t *root;
+
+ /* ensure we have the root widget */
+ root = fbtk_get_root_widget(widget);
+
+ return root->u.root.fb;
+}
+
+/* exported function docuemnted in fbtk.h */
+fbtk_widget_t *
+fbtk_init(nsfb_t *fb)
+{
+ fbtk_widget_t *root;
+
+ /* create and configure root widget */
+ root = calloc(1, sizeof(fbtk_widget_t));
+ if (root == NULL)
+ return NULL;
+
+ root->type = FB_WIDGET_TYPE_ROOT;
+ root->u.root.fb = fb;
+ root->u.root.caret.owner = NULL;
+
+ nsfb_get_geometry(fb, &root->width, &root->height, NULL);
+
+ root->mapped = true;
+
+ return root;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/fill.c b/frontends/framebuffer/fbtk/fill.c
new file mode 100644
index 000000000..07397b2df
--- /dev/null
+++ b/frontends/framebuffer/fbtk/fill.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit filled area widget
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+
+#include "desktop/browser.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+
+#include "widget.h"
+
+static int
+fb_redraw_fill(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ nsfb_bbox_t bbox;
+ nsfb_t *nsfb;
+
+ nsfb = fbtk_get_nsfb(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ nsfb_claim(nsfb, &bbox);
+
+ /* clear background */
+ if ((widget->bg & 0xFF000000) != 0) {
+ /* transparent polygon filling isnt working so fake it */
+ nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
+ }
+
+ nsfb_update(nsfb, &bbox);
+
+ return 0;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_fill(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour c)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_FILL, x, y, width, height);
+ neww->bg = c;
+ neww->mapped = true;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_fill, NULL);
+
+ return neww;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/osk.c b/frontends/framebuffer/fbtk/osk.c
new file mode 100644
index 000000000..1d57f157f
--- /dev/null
+++ b/frontends/framebuffer/fbtk/osk.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit on screen keyboard.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <limits.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_event.h>
+#include <libnsfb_cursor.h>
+
+#include "utils/log.h"
+#include "desktop/browser.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+struct kbd_button_s {
+ int x;
+ int y;
+ int w;
+ int h;
+ const char *t;
+ enum nsfb_key_code_e keycode;
+};
+
+#define KEYCOUNT 58
+
+static struct kbd_button_s kbdbase[KEYCOUNT] = {
+ { 0, 0, 20, 15, "`", NSFB_KEY_BACKQUOTE},
+ { 20, 0, 20, 15, "1", NSFB_KEY_1},
+ { 40, 0, 20, 15, "2", NSFB_KEY_2},
+ { 60, 0, 20, 15, "3", NSFB_KEY_3},
+ { 80, 0, 20, 15, "4", NSFB_KEY_4},
+ { 100, 0, 20, 15, "5", NSFB_KEY_5},
+ { 120, 0, 20, 15, "6", NSFB_KEY_6},
+ { 140, 0, 20, 15, "7", NSFB_KEY_7},
+ { 160, 0, 20, 15, "8", NSFB_KEY_8},
+ { 180, 0, 20, 15, "9", NSFB_KEY_9},
+ { 200, 0, 20, 15, "0", NSFB_KEY_0},
+ { 220, 0, 20, 15, "-", NSFB_KEY_MINUS},
+ { 240, 0, 20, 15, "=", NSFB_KEY_EQUALS},
+ { 260, 0, 40, 15, "\xe2\x8c\xab", NSFB_KEY_BACKSPACE},
+ { 0, 15, 30, 15, "\xe2\x86\xb9", NSFB_KEY_TAB},
+ { 30, 15, 20, 15, "q", NSFB_KEY_q},
+ { 50, 15, 20, 15, "w", NSFB_KEY_w},
+ { 70, 15, 20, 15, "e", NSFB_KEY_e},
+ { 90, 15, 20, 15, "r", NSFB_KEY_r},
+ { 110, 15, 20, 15, "t", NSFB_KEY_t},
+ { 130, 15, 20, 15, "y", NSFB_KEY_y},
+ { 150, 15, 20, 15, "u", NSFB_KEY_u},
+ { 170, 15, 20, 15, "i", NSFB_KEY_i},
+ { 190, 15, 20, 15, "o", NSFB_KEY_o},
+ { 210, 15, 20, 15, "p", NSFB_KEY_p},
+ { 230, 15, 20, 15, "[", NSFB_KEY_LEFTBRACKET},
+ { 250, 15, 20, 15, "]", NSFB_KEY_RIGHTBRACKET},
+ { 275, 15, 25, 30, "\xe2\x8f\x8e", NSFB_KEY_RETURN},
+ { 35, 30, 20, 15, "a", NSFB_KEY_a},
+ { 55, 30, 20, 15, "s", NSFB_KEY_s},
+ { 75, 30, 20, 15, "d", NSFB_KEY_d},
+ { 95, 30, 20, 15, "f", NSFB_KEY_f},
+ { 115, 30, 20, 15, "g", NSFB_KEY_g},
+ { 135, 30, 20, 15, "h", NSFB_KEY_h},
+ { 155, 30, 20, 15, "j", NSFB_KEY_j},
+ { 175, 30, 20, 15, "k", NSFB_KEY_k},
+ { 195, 30, 20, 15, "l", NSFB_KEY_l},
+ { 215, 30, 20, 15, ";", NSFB_KEY_SEMICOLON},
+ { 235, 30, 20, 15, "'", NSFB_KEY_l},
+ { 255, 30, 20, 15, "#", NSFB_KEY_HASH},
+ { 0, 45, 25, 15, "\xe2\x87\xa7", NSFB_KEY_LSHIFT},
+ { 25, 45, 20, 15, "\\", NSFB_KEY_SLASH},
+ { 45, 45, 20, 15, "z", NSFB_KEY_z},
+ { 65, 45, 20, 15, "x", NSFB_KEY_x},
+ { 85, 45, 20, 15, "c", NSFB_KEY_c},
+ { 105, 45, 20, 15, "v", NSFB_KEY_v},
+ { 125, 45, 20, 15, "b", NSFB_KEY_b},
+ { 145, 45, 20, 15, "n", NSFB_KEY_n},
+ { 165, 45, 20, 15, "m", NSFB_KEY_m},
+ { 185, 45, 20, 15, ",", NSFB_KEY_COMMA},
+ { 205, 45, 20, 15, ".", NSFB_KEY_PERIOD},
+ { 225, 45, 20, 15, "/", NSFB_KEY_BACKSLASH},
+ { 245, 45, 55, 15, "\xe2\x87\xa7", NSFB_KEY_RSHIFT},
+ { 40, 67, 185, 15, "", NSFB_KEY_SPACE},
+ { 250, 60, 20, 15, "\xe2\x96\xb2", NSFB_KEY_UP},
+ { 230, 67, 20, 15, "\xe2\x97\x80", NSFB_KEY_LEFT},
+ { 270, 67, 20, 15, "\xe2\x96\xb6", NSFB_KEY_RIGHT},
+ { 250, 75, 20, 15, "\xe2\x96\xbc", NSFB_KEY_DOWN},
+};
+
+static fbtk_widget_t *osk;
+
+static int
+osk_close(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ if (cbi->event->type != NSFB_EVENT_KEY_UP)
+ return 0;
+
+ fbtk_set_mapping(osk, false);
+
+ return 0;
+}
+
+static int
+osk_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ nsfb_event_t event;
+ struct kbd_button_s *kbd_button = cbi->context;
+
+ event.type = cbi->event->type;
+ event.value.keycode = kbd_button->keycode;
+ fbtk_input(widget, &event);
+
+ return 0;
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_enable_oskb(fbtk_widget_t *fbtk)
+{
+ fbtk_widget_t *widget;
+ int kloop;
+ int maxx = 0;
+ int maxy = 0;
+ int ww;
+ int wh;
+ fbtk_widget_t *root = fbtk_get_root_widget(fbtk);
+ int furniture_width = 18;
+
+ for (kloop=0; kloop < KEYCOUNT; kloop++) {
+ if ((kbdbase[kloop].x + kbdbase[kloop].w) > maxx)
+ maxx=kbdbase[kloop].x + kbdbase[kloop].w;
+ if ((kbdbase[kloop].y + kbdbase[kloop].h) > maxy)
+ maxy=kbdbase[kloop].y + kbdbase[kloop].h;
+ }
+
+ ww = fbtk_get_width(root);
+
+ /* scale window height apropriately */
+ wh = (maxy * ww) / maxx;
+
+ osk = fbtk_create_window(root, 0, fbtk_get_height(root) - wh, 0, wh, 0xff202020);
+
+ for (kloop=0; kloop < KEYCOUNT; kloop++) {
+ widget = fbtk_create_text_button(osk,
+ (kbdbase[kloop].x * ww) / maxx,
+ (kbdbase[kloop].y * ww) / maxx,
+ (kbdbase[kloop].w * ww) / maxx,
+ (kbdbase[kloop].h *ww) / maxx,
+ FB_FRAME_COLOUR,
+ FB_COLOUR_BLACK,
+ osk_click,
+ &kbdbase[kloop]);
+ fbtk_set_text(widget, kbdbase[kloop].t);
+ }
+
+ widget = fbtk_create_button(osk,
+ fbtk_get_width(osk) - furniture_width,
+ fbtk_get_height(osk) - furniture_width,
+ furniture_width,
+ furniture_width,
+ FB_FRAME_COLOUR,
+ &osk_image,
+ osk_close,
+ NULL);
+}
+
+/* exported function documented in fbtk.h */
+void
+map_osk(void)
+{
+ fbtk_set_zorder(osk, INT_MIN);
+ fbtk_set_mapping(osk, true);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/scroll.c b/frontends/framebuffer/fbtk/scroll.c
new file mode 100644
index 000000000..c86c8a6de
--- /dev/null
+++ b/frontends/framebuffer/fbtk/scroll.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit scrollbar widgets
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include <stdbool.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_event.h>
+#include <libnsfb_cursor.h>
+
+#include "utils/log.h"
+#include "desktop/browser.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+/* Vertical scroll widget */
+
+static int
+vscroll_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int vscroll;
+ int vpos;
+
+ nsfb_bbox_t bbox;
+ nsfb_bbox_t rect;
+ fbtk_widget_t *root = fbtk_get_root_widget(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ nsfb_claim(root->u.root.fb, &bbox);
+
+ rect = bbox;
+
+ /* background */
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
+
+ /* scroll well */
+ rect.x0 = bbox.x0 + 2;
+ rect.y0 = bbox.y0 + 1;
+ rect.x1 = bbox.x1 - 3;
+ rect.y1 = bbox.y1 - 2;
+
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->fg);
+ nsfb_plot_rectangle(root->u.root.fb, &rect, 1, 0xFF999999, false, false);
+
+ /* scroll bar */
+ if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
+ vscroll = ((widget->height - 4) * widget->u.scroll.thumb) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ vpos = ((widget->height - 4) * widget->u.scroll.position) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ } else {
+ vscroll = (widget->height - 4);
+ vpos = 0;
+ }
+
+ rect.x0 = bbox.x0 + 5;
+ rect.y0 = bbox.y0 + 3 + vpos;
+ rect.x1 = bbox.x0 + widget->width - 5;
+ rect.y1 = bbox.y0 + vscroll + vpos;
+
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
+
+ nsfb_update(root->u.root.fb, &bbox);
+
+ return 0;
+}
+
+static int
+vscroll_drag(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ newpos = ((widget->u.scroll.drag_position +
+ (cbi->y - widget->u.scroll.drag)) *
+ (widget->u.scroll.maximum - widget->u.scroll.minimum)) /
+ (widget->height - 4);
+
+ if (newpos < scrollw->u.scroll.minimum)
+ newpos = scrollw->u.scroll.minimum;
+
+ if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
+ newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
+
+ if (newpos == scrollw->u.scroll.position)
+ return 0;
+
+ return fbtk_post_callback(widget, FBTK_CBT_SCROLLY, newpos);
+}
+
+static int
+vscrollu_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
+ return 0;
+
+ newpos = scrollw->u.scroll.position - scrollw->u.scroll.page;
+ if (newpos < scrollw->u.scroll.minimum)
+ newpos = scrollw->u.scroll.minimum;
+
+ if (newpos == scrollw->u.scroll.position)
+ return 0;
+
+ return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLY, newpos);
+}
+
+static int
+vscrolld_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
+ return 0;
+
+ newpos = scrollw->u.scroll.position + scrollw->u.scroll.page;
+ if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
+ newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
+
+ if (newpos == scrollw->u.scroll.position)
+ return 0;
+
+ return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLY, newpos);
+}
+
+static int
+vscrollarea_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int vscroll;
+ int vpos;
+ int newpos;
+ int ret = 0;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
+ /* end all drags, just in case */
+ if (fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, NULL, NULL) != NULL)
+ fbtk_tgrab_pointer(widget);
+ return 0;
+ }
+
+ switch (cbi->event->value.keycode) {
+
+ case NSFB_KEY_MOUSE_4:
+ /* scroll up */
+ newpos = widget->u.scroll.position - widget->u.scroll.page;
+ if (newpos < widget->u.scroll.minimum)
+ newpos = widget->u.scroll.minimum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
+ break;
+
+ case NSFB_KEY_MOUSE_5:
+ /* scroll down */
+ newpos = widget->u.scroll.position + widget->u.scroll.page;
+ if (newpos > widget->u.scroll.maximum)
+ newpos = widget->u.scroll.maximum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
+ break;
+
+ default:
+
+ if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
+ vscroll = ((widget->height - 4) * widget->u.scroll.thumb) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ vpos = ((widget->height - 4) * widget->u.scroll.position) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ } else {
+ vscroll = (widget->height - 4);
+ vpos = 0;
+ }
+
+ if (cbi->y < vpos) {
+ /* above bar */
+ newpos = widget->u.scroll.position - widget->u.scroll.thumb;
+ if (newpos < widget->u.scroll.minimum)
+ newpos = widget->u.scroll.minimum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
+ } else if (cbi->y > (vpos + vscroll)) {
+ /* below bar */
+ newpos = widget->u.scroll.position + widget->u.scroll.thumb;
+ if (newpos > widget->u.scroll.maximum)
+ newpos = widget->u.scroll.maximum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLY, newpos);
+ } else {
+ /* on bar - start drag */
+ widget->u.scroll.drag = cbi->y;
+ widget->u.scroll.drag_position = vpos;
+ fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, vscroll_drag, widget);
+ fbtk_tgrab_pointer(widget);
+ }
+ }
+ return ret;
+}
+
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_vscroll(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour fg,
+ colour bg,
+ fbtk_callback callback,
+ void *context)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent,
+ FB_WIDGET_TYPE_VSCROLL,
+ x,
+ y + scrollu.height,
+ width,
+ height - scrollu.height - scrolld.height);
+
+ neww->fg = fg;
+ neww->bg = bg;
+ neww->mapped = true;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, vscroll_redraw, NULL);
+
+ fbtk_set_handler(neww, FBTK_CBT_CLICK, vscrollarea_click, neww);
+
+ fbtk_set_handler(neww, FBTK_CBT_SCROLLY, callback, context);
+
+ neww->u.scroll.btnul = fbtk_create_button(parent,
+ x,
+ y,
+ width,
+ scrollu.height,
+ fg,
+ &scrollu,
+ vscrollu_click,
+ neww);
+
+ neww->u.scroll.btndr = fbtk_create_button(parent,
+ x,
+ y + height - scrolld.height,
+ width,
+ scrolld.height,
+ fg,
+ &scrolld,
+ vscrolld_click,
+ neww);
+
+
+ return neww;
+}
+
+
+/* exported function documented in fbtk.h */
+void
+fbtk_reposition_vscroll(fbtk_widget_t *vscroll,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ assert(vscroll->type == FB_WIDGET_TYPE_VSCROLL);
+
+ fbtk_set_pos_and_size(vscroll, x, y + scrollu.height,
+ width, height - scrollu.height - scrolld.height);
+ fbtk_set_pos_and_size(vscroll->u.scroll.btnul,
+ x, y, width, scrollu.height);
+ fbtk_set_pos_and_size(vscroll->u.scroll.btndr,
+ x, y + height - scrolld.height,
+ width, scrolld.height);
+}
+
+/* Horizontal scroll widget */
+
+static int
+hscroll_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int hscroll;
+ int hpos;
+ nsfb_bbox_t bbox;
+ nsfb_bbox_t rect;
+ fbtk_widget_t *root = fbtk_get_root_widget(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ nsfb_claim(root->u.root.fb, &bbox);
+
+ rect = bbox;
+
+ /* background */
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
+
+ /* scroll well */
+ rect.x0 = bbox.x0 + 1;
+ rect.y0 = bbox.y0 + 2;
+ rect.x1 = bbox.x1 - 2;
+ rect.y1 = bbox.y1 - 3;
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->fg);
+
+ /* scroll well outline */
+ nsfb_plot_rectangle(root->u.root.fb, &rect, 1, 0xFF999999, false, false);
+
+ if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
+ hscroll = ((widget->width - 4) * widget->u.scroll.thumb) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ hpos = ((widget->width - 4) * widget->u.scroll.position) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ } else {
+ hscroll = (widget->width - 4);
+ hpos = 0;
+ }
+
+ LOG("hscroll %d", hscroll);
+
+ rect.x0 = bbox.x0 + 3 + hpos;
+ rect.y0 = bbox.y0 + 5;
+ rect.x1 = bbox.x0 + hscroll + hpos;
+ rect.y1 = bbox.y0 + widget->height - 5;
+
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
+
+ nsfb_update(root->u.root.fb, &bbox);
+
+ return 0;
+}
+
+static int
+hscrolll_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
+ return 0;
+
+ newpos = scrollw->u.scroll.position - scrollw->u.scroll.page;
+ if (newpos < scrollw->u.scroll.minimum)
+ newpos = scrollw->u.scroll.minimum;
+
+ if (newpos == scrollw->u.scroll.position) {
+ LOG("horiz scroll was the same %d", newpos);
+ return 0;
+ }
+
+ return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLX, newpos);
+}
+
+static int
+hscrollr_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN)
+ return 0;
+
+ newpos = scrollw->u.scroll.position + scrollw->u.scroll.page;
+ if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
+ newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
+
+ if (newpos == scrollw->u.scroll.position)
+ return 0;
+
+ return fbtk_post_callback(scrollw, FBTK_CBT_SCROLLX, newpos);
+}
+
+static int
+hscroll_drag(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int newpos;
+ fbtk_widget_t *scrollw = cbi->context;
+
+ newpos = ((widget->u.scroll.drag_position +
+ (cbi->x - widget->u.scroll.drag)) *
+ (widget->u.scroll.maximum - widget->u.scroll.minimum)) /
+ (widget->width - 4);
+
+ if (newpos < scrollw->u.scroll.minimum)
+ newpos = scrollw->u.scroll.minimum;
+
+ if (newpos > (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb ))
+ newpos = (scrollw->u.scroll.maximum - scrollw->u.scroll.thumb);
+
+ if (newpos == scrollw->u.scroll.position)
+ return 0;
+
+ return fbtk_post_callback(widget, FBTK_CBT_SCROLLX, newpos);
+}
+
+static int
+hscrollarea_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int hscroll;
+ int hpos;
+ int newpos;
+ int ret = 0;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
+ /* end all drags, just in case */
+ if (fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, NULL, NULL) != NULL)
+ fbtk_tgrab_pointer(widget);
+ return 0;
+ }
+
+ if ((widget->u.scroll.maximum - widget->u.scroll.minimum) > 0) {
+ hscroll = ((widget->width - 4) * widget->u.scroll.thumb) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ hpos = ((widget->width - 4) * widget->u.scroll.position) /
+ (widget->u.scroll.maximum - widget->u.scroll.minimum) ;
+ } else {
+ hscroll = (widget->width - 4);
+ hpos = 0;
+ }
+
+ if (cbi->x < hpos) {
+ /* left of bar */
+ newpos = widget->u.scroll.position - widget->u.scroll.page;
+ if (newpos < widget->u.scroll.minimum)
+ newpos = widget->u.scroll.minimum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLX, newpos);
+ } else if (cbi->x > (hpos + hscroll)) {
+ /* right of bar */
+ newpos = widget->u.scroll.position + widget->u.scroll.page;
+ if (newpos > widget->u.scroll.maximum)
+ newpos = widget->u.scroll.maximum;
+ ret = fbtk_post_callback(cbi->context, FBTK_CBT_SCROLLX, newpos);
+ } else {
+ /* on bar - start drag */
+ widget->u.scroll.drag = cbi->x;
+ widget->u.scroll.drag_position = hpos;
+ fbtk_set_handler(widget, FBTK_CBT_POINTERMOVE, hscroll_drag, widget);
+ fbtk_tgrab_pointer(widget);
+ }
+ return ret;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_hscroll(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour fg,
+ colour bg,
+ fbtk_callback callback,
+ void *context)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent,
+ FB_WIDGET_TYPE_HSCROLL,
+ x + scrolll.width,
+ y,
+ width - scrolll.width - scrollr.width,
+ height);
+
+ neww->fg = fg;
+ neww->bg = bg;
+ neww->mapped = true;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, hscroll_redraw, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_CLICK, hscrollarea_click, neww);
+ fbtk_set_handler(neww, FBTK_CBT_SCROLLX, callback, context);
+
+ neww->u.scroll.btnul = fbtk_create_button(parent,
+ x,
+ y,
+ scrolll.width,
+ height,
+ fg,
+ &scrolll,
+ hscrolll_click,
+ neww);
+
+ neww->u.scroll.btndr = fbtk_create_button(parent,
+ x + width - scrollr.width,
+ y,
+ scrollr.width,
+ height,
+ fg,
+ &scrollr,
+ hscrollr_click,
+ neww);
+
+ return neww;
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_reposition_hscroll(fbtk_widget_t *scrollh,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ assert(scrollh->type == FB_WIDGET_TYPE_HSCROLL);
+
+ fbtk_set_pos_and_size(scrollh, x + scrolll.width, y,
+ width - scrolll.width - scrollr.width, height);
+ fbtk_set_pos_and_size(scrollh->u.scroll.btnul,
+ x, y, scrolll.width, height);
+ fbtk_set_pos_and_size(scrollh->u.scroll.btndr,
+ x + width - scrollr.width, y,
+ scrollr.width, height);
+}
+
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_set_scroll_parameters(fbtk_widget_t *widget,
+ int min,
+ int max,
+ int thumb,
+ int page)
+{
+ if (widget == NULL)
+ return false;
+
+ if ((widget->type != FB_WIDGET_TYPE_HSCROLL) &&
+ (widget->type != FB_WIDGET_TYPE_VSCROLL))
+ return false;
+
+ widget->u.scroll.minimum = min;
+ widget->u.scroll.maximum = max;
+ widget->u.scroll.thumb = thumb;
+ widget->u.scroll.page = page;
+
+ if (widget->u.scroll.position > max)
+ widget->u.scroll.position = max;
+ if (widget->u.scroll.position < min)
+ widget->u.scroll.position = min;
+
+ fbtk_request_redraw(widget);
+
+ return true;
+}
+
+/* exported function documented in fbtk.h */
+bool
+fbtk_set_scroll_position(fbtk_widget_t *widget, int position)
+{
+ if (widget == NULL)
+ return false;
+
+ if ((widget->type != FB_WIDGET_TYPE_HSCROLL) &&
+ (widget->type != FB_WIDGET_TYPE_VSCROLL))
+ return false;
+
+ if ((position < widget->u.scroll.minimum) ||
+ (position > widget->u.scroll.maximum))
+ return false;
+
+ widget->u.scroll.position = position;
+
+ fbtk_request_redraw(widget);
+
+ return true;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/text.c b/frontends/framebuffer/fbtk/text.c
new file mode 100644
index 000000000..258e9dff9
--- /dev/null
+++ b/frontends/framebuffer/fbtk/text.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit scrollbar widgets.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+#include <libnsfb_plot_util.h>
+#include <libnsfb_event.h>
+
+#include "utils/log.h"
+#include "desktop/browser.h"
+#include "desktop/plotters.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+#include "framebuffer/font.h"
+#include "framebuffer/framebuffer.h"
+#include "framebuffer/image_data.h"
+
+#include "widget.h"
+
+//#define TEXT_WIDGET_BORDER 3 /**< The pixel border round a text widget. */
+
+/* Lighten a colour by taking seven eights of each channel's intensity
+ * and adding a full eighth
+ */
+#define brighten_colour(c1) \
+ (((((7 * ((c1 >> 16) & 0xff)) >> 3) + 32) << 16) | \
+ ((((7 * ((c1 >> 8) & 0xff)) >> 3) + 32) << 8) | \
+ ((((7 * (c1 & 0xff)) >> 3) + 32) << 0))
+
+/* Convert pixels to points, assuming a DPI of 90 */
+#define px_to_pt(x) (((x) * 72) / FBTK_DPI)
+
+/* Get a font style for a text input */
+static inline void
+fb_text_font_style(fbtk_widget_t *widget, int *font_height, int *padding,
+ plot_font_style_t *font_style)
+{
+ if (widget->u.text.outline)
+ *padding = 1;
+ else
+ *padding = 0;
+
+#ifdef FB_USE_FREETYPE
+ *padding += widget->height / 6;
+ *font_height = widget->height - *padding - *padding;
+#else
+ *font_height = FB_FONT_HEIGHT;
+ *padding = (widget->height - *padding - *font_height) / 2;
+#endif
+
+ font_style->family = PLOT_FONT_FAMILY_SANS_SERIF;
+ font_style->size = px_to_pt(*font_height * FONT_SIZE_SCALE);
+ font_style->weight = 400;
+ font_style->flags = FONTF_NONE;
+ font_style->background = widget->bg;
+ font_style->foreground = widget->fg;
+}
+
+/** Text redraw callback.
+ *
+ * Called when a text widget requires redrawing.
+ *
+ * @param widget The widget to be redrawn.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi )
+{
+ nsfb_bbox_t bbox;
+ nsfb_bbox_t rect;
+ fbtk_widget_t *root;
+ plot_font_style_t font_style;
+ int caret_x, caret_y, caret_h;
+ int fh;
+ int padding;
+ int scroll = 0;
+ bool caret = false;
+
+ fb_text_font_style(widget, &fh, &padding, &font_style);
+
+ if (fbtk_get_caret(widget, &caret_x, &caret_y, &caret_h)) {
+ caret = true;
+ }
+
+ root = fbtk_get_root_widget(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ rect = bbox;
+
+ nsfb_claim(root->u.root.fb, &bbox);
+
+ /* clear background */
+ if ((widget->bg & 0xFF000000) != 0) {
+ /* transparent polygon filling isnt working so fake it */
+ nsfb_plot_rectangle_fill(root->u.root.fb, &bbox, widget->bg);
+ }
+
+ /* widget can have a single pixel outline border */
+ if (widget->u.text.outline) {
+ rect.x1--;
+ rect.y1--;
+ nsfb_plot_rectangle(root->u.root.fb, &rect, 1,
+ 0x00000000, false, false);
+ }
+
+ if (widget->u.text.text != NULL) {
+ int x = bbox.x0 + padding;
+ int y = bbox.y0 + ((fh * 3 + 2) / 4) + padding;
+
+#ifdef FB_USE_FREETYPE
+ /* Freetype renders text higher */
+ y += 1;
+#endif
+
+ if (caret && widget->width - padding - padding < caret_x) {
+ scroll = (widget->width - padding - padding) - caret_x;
+ x += scroll;
+ }
+
+ /* Call the fb text plotting, baseline is 3/4 down the font */
+ fb_plotters.text(x, y, widget->u.text.text,
+ widget->u.text.len, &font_style);
+ }
+
+ if (caret) {
+ /* This widget has caret, so render it */
+ nsfb_t *nsfb = fbtk_get_nsfb(widget);
+ nsfb_bbox_t line;
+ nsfb_plot_pen_t pen;
+
+ line.x0 = bbox.x0 + caret_x + scroll;
+ line.y0 = bbox.y0 + caret_y;
+ line.x1 = bbox.x0 + caret_x + scroll;
+ line.y1 = bbox.y0 + caret_y + caret_h;
+
+ pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
+ pen.stroke_width = 1;
+ pen.stroke_colour = 0xFF0000FF;
+
+ nsfb_plot_line(nsfb, &line, &pen);
+ }
+
+ nsfb_update(root->u.root.fb, &bbox);
+
+ return 0;
+}
+
+/** Text destroy callback.
+ *
+ * Called when a text widget is destroyed.
+ *
+ * @param widget The widget being destroyed.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int fb_destroy_text(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_TEXT)) {
+ return 0;
+ }
+
+ if (widget->u.text.text != NULL) {
+ free(widget->u.text.text);
+ }
+
+ return 0;
+}
+
+/** Text button redraw callback.
+ *
+ * Called when a text widget requires redrawing.
+ *
+ * @param widget The widget to be redrawn.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi )
+{
+ nsfb_bbox_t bbox;
+ nsfb_bbox_t rect;
+ nsfb_bbox_t line;
+ nsfb_plot_pen_t pen;
+ plot_font_style_t font_style;
+ int fh;
+ int border;
+ fbtk_widget_t *root = fbtk_get_root_widget(widget);
+
+ fb_text_font_style(widget, &fh, &border, &font_style);
+
+ pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID;
+ pen.stroke_width = 1;
+ pen.stroke_colour = brighten_colour(widget->bg);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ rect = bbox;
+ rect.x1--;
+ rect.y1--;
+
+ nsfb_claim(root->u.root.fb, &bbox);
+
+ /* clear background */
+ if ((widget->bg & 0xFF000000) != 0) {
+ /* transparent polygon filling isnt working so fake it */
+ nsfb_plot_rectangle_fill(root->u.root.fb, &rect, widget->bg);
+ }
+
+ if (widget->u.text.outline) {
+ line.x0 = rect.x0;
+ line.y0 = rect.y0;
+ line.x1 = rect.x0;
+ line.y1 = rect.y1;
+ nsfb_plot_line(root->u.root.fb, &line, &pen);
+ line.x0 = rect.x0;
+ line.y0 = rect.y0;
+ line.x1 = rect.x1;
+ line.y1 = rect.y0;
+ nsfb_plot_line(root->u.root.fb, &line, &pen);
+ pen.stroke_colour = darken_colour(widget->bg);
+ line.x0 = rect.x0;
+ line.y0 = rect.y1;
+ line.x1 = rect.x1;
+ line.y1 = rect.y1;
+ nsfb_plot_line(root->u.root.fb, &line, &pen);
+ line.x0 = rect.x1;
+ line.y0 = rect.y0;
+ line.x1 = rect.x1;
+ line.y1 = rect.y1;
+ nsfb_plot_line(root->u.root.fb, &line, &pen);
+ }
+
+ if (widget->u.text.text != NULL) {
+ /* Call the fb text plotting, baseline is 3/4 down the font */
+ fb_plotters.text(bbox.x0 + border,
+ bbox.y0 + ((fh * 3) / 4) + border,
+ widget->u.text.text,
+ widget->u.text.len,
+ &font_style);
+ }
+
+ nsfb_update(root->u.root.fb, &bbox);
+
+ return 0;
+}
+
+static void
+fb_text_input_remove_caret_cb(fbtk_widget_t *widget)
+{
+ int c_x, c_y, c_h;
+
+ if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
+ fbtk_request_redraw(widget);
+ }
+}
+
+/** Routine called when text events occour in writeable widget.
+ *
+ * @param widget The widget reciving input events.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+text_input(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ int value;
+ static fbtk_modifier_type modifier = FBTK_MOD_CLEAR;
+ char *temp;
+ plot_font_style_t font_style;
+ int fh;
+ int border;
+ bool caret_moved = false;
+
+ fb_text_font_style(widget, &fh, &border, &font_style);
+
+ if (cbi->event == NULL) {
+ /* gain focus */
+ if (widget->u.text.text == NULL)
+ widget->u.text.text = calloc(1,1);
+
+ return 0;
+ }
+
+ value = cbi->event->value.keycode;
+
+ if (cbi->event->type != NSFB_EVENT_KEY_DOWN) {
+ switch (value) {
+ case NSFB_KEY_RSHIFT:
+ modifier &= ~FBTK_MOD_RSHIFT;
+ break;
+
+ case NSFB_KEY_LSHIFT:
+ modifier &= ~FBTK_MOD_LSHIFT;
+ break;
+
+ case NSFB_KEY_RCTRL:
+ modifier &= ~FBTK_MOD_RCTRL;
+ break;
+
+ case NSFB_KEY_LCTRL:
+ modifier &= ~FBTK_MOD_LCTRL;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+ }
+
+ switch (value) {
+ case NSFB_KEY_BACKSPACE:
+ if (widget->u.text.idx <= 0)
+ break;
+ memmove(widget->u.text.text + widget->u.text.idx - 1,
+ widget->u.text.text + widget->u.text.idx,
+ widget->u.text.len - widget->u.text.idx);
+ widget->u.text.idx--;
+ widget->u.text.len--;
+ widget->u.text.text[widget->u.text.len] = 0;
+
+ fb_font_width(&font_style, widget->u.text.text,
+ widget->u.text.len, &widget->u.text.width);
+
+ caret_moved = true;
+ break;
+
+ case NSFB_KEY_RETURN:
+ widget->u.text.enter(widget->u.text.pw, widget->u.text.text);
+ break;
+
+ case NSFB_KEY_RIGHT:
+ if (widget->u.text.idx < widget->u.text.len) {
+ if (modifier == FBTK_MOD_CLEAR)
+ widget->u.text.idx++;
+ else
+ widget->u.text.idx = widget->u.text.len;
+
+ caret_moved = true;
+ }
+ break;
+
+ case NSFB_KEY_LEFT:
+ if (widget->u.text.idx > 0) {
+ if (modifier == FBTK_MOD_CLEAR)
+ widget->u.text.idx--;
+ else
+ widget->u.text.idx = 0;
+
+ caret_moved = true;
+ }
+ break;
+
+ case NSFB_KEY_PAGEUP:
+ case NSFB_KEY_PAGEDOWN:
+ case NSFB_KEY_UP:
+ case NSFB_KEY_DOWN:
+ /* Not handling any of these correctly yet, but avoid putting
+ * charcters in the text widget when they're pressed. */
+ break;
+
+ case NSFB_KEY_RSHIFT:
+ modifier |= FBTK_MOD_RSHIFT;
+ break;
+
+ case NSFB_KEY_LSHIFT:
+ modifier |= FBTK_MOD_LSHIFT;
+ break;
+
+ case NSFB_KEY_RCTRL:
+ modifier |= FBTK_MOD_RCTRL;
+ break;
+
+ case NSFB_KEY_LCTRL:
+ modifier |= FBTK_MOD_LCTRL;
+ break;
+
+ default:
+ if (modifier & FBTK_MOD_LCTRL || modifier & FBTK_MOD_RCTRL) {
+ /* CTRL pressed, don't enter any text */
+ if (value == NSFB_KEY_u) {
+ /* CTRL+U: clear writable */
+ widget->u.text.idx = 0;
+ widget->u.text.len = 0;
+ widget->u.text.text[widget->u.text.len] = '\0';
+ widget->u.text.width = 0;
+ caret_moved = true;
+ }
+ break;
+ }
+
+ /* allow for new character and null */
+ temp = realloc(widget->u.text.text, widget->u.text.len + 2);
+ if (temp == NULL) {
+ break;
+ }
+
+ widget->u.text.text = temp;
+ memmove(widget->u.text.text + widget->u.text.idx + 1,
+ widget->u.text.text + widget->u.text.idx,
+ widget->u.text.len - widget->u.text.idx);
+ widget->u.text.text[widget->u.text.idx] =
+ fbtk_keycode_to_ucs4(value, modifier);
+ widget->u.text.idx++;
+ widget->u.text.len++;
+ widget->u.text.text[widget->u.text.len] = '\0';
+
+ fb_font_width(&font_style, widget->u.text.text,
+ widget->u.text.len, &widget->u.text.width);
+ caret_moved = true;
+ break;
+ }
+
+ if (caret_moved) {
+ fb_font_width(&font_style, widget->u.text.text,
+ widget->u.text.idx, &widget->u.text.idx_offset);
+ fbtk_set_caret(widget, true,
+ widget->u.text.idx_offset + border,
+ border,
+ widget->height - border - border,
+ fb_text_input_remove_caret_cb);
+ }
+
+ fbtk_request_redraw(widget);
+
+ return 0;
+}
+
+/** Routine called when click events occour in writeable widget.
+ *
+ * @param widget The widget reciving click events.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+text_input_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ plot_font_style_t font_style;
+ int fh;
+ int border;
+ size_t idx;
+
+ fb_text_font_style(widget, &fh, &border, &font_style);
+
+ widget->u.text.idx = widget->u.text.len;
+
+ fb_font_position(&font_style, widget->u.text.text,
+ widget->u.text.len, cbi->x - border,
+ &idx,
+ &widget->u.text.idx_offset);
+ widget->u.text.idx = idx;
+ fbtk_set_caret(widget, true,
+ widget->u.text.idx_offset + border,
+ border,
+ widget->height - border - border,
+ fb_text_input_remove_caret_cb);
+
+ fbtk_request_redraw(widget);
+
+ return 0;
+}
+
+/** Routine called when "stripped of focus" event occours for writeable widget.
+ *
+ * @param widget The widget reciving "stripped of focus" event.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+text_input_strip_focus(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ fbtk_set_caret(widget, false, 0, 0, 0, NULL);
+
+ return 0;
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_writable_text(fbtk_widget_t *widget, fbtk_enter_t enter, void *pw)
+{
+ widget->u.text.enter = enter;
+ widget->u.text.pw = pw;
+
+ fbtk_set_handler(widget, FBTK_CBT_INPUT, text_input, widget);
+}
+
+/* exported function documented in fbtk.h */
+void
+fbtk_set_text(fbtk_widget_t *widget, const char *text)
+{
+ plot_font_style_t font_style;
+ int c_x, c_y, c_h;
+ int fh;
+ int border;
+
+ if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_TEXT))
+ return;
+ if (widget->u.text.text != NULL) {
+ if (strcmp(widget->u.text.text, text) == 0)
+ return; /* text is being set to the same thing */
+ free(widget->u.text.text);
+ }
+ widget->u.text.text = strdup(text);
+ widget->u.text.len = strlen(text);
+ widget->u.text.idx = widget->u.text.len;
+
+
+ fb_text_font_style(widget, &fh, &border, &font_style);
+ fb_font_width(&font_style, widget->u.text.text,
+ widget->u.text.len, &widget->u.text.width);
+ fb_font_width(&font_style, widget->u.text.text,
+ widget->u.text.idx, &widget->u.text.idx_offset);
+
+ if (fbtk_get_caret(widget, &c_x, &c_y, &c_h)) {
+ /* Widget has caret; move it to end of new string */
+ fbtk_set_caret(widget, true,
+ widget->u.text.idx_offset + border,
+ border,
+ widget->height - border - border,
+ fb_text_input_remove_caret_cb);
+ }
+
+ fbtk_request_redraw(widget);
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_text(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour bg,
+ colour fg,
+ bool outline)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
+ neww->fg = fg;
+ neww->bg = bg;
+ neww->mapped = true;
+ neww->u.text.outline = outline;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_DESTROY, fb_destroy_text, NULL);
+
+ return neww;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_writable_text(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour bg,
+ colour fg,
+ bool outline,
+ fbtk_enter_t enter,
+ void *pw)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
+ neww->fg = fg;
+ neww->bg = bg;
+ neww->mapped = true;
+
+ neww->u.text.outline = outline;
+ neww->u.text.enter = enter;
+ neww->u.text.pw = pw;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_DESTROY, fb_destroy_text, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_CLICK, text_input_click, pw);
+ fbtk_set_handler(neww, FBTK_CBT_STRIP_FOCUS, text_input_strip_focus, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_INPUT, text_input, neww);
+
+ return neww;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_text_button(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour bg,
+ colour fg,
+ fbtk_callback click,
+ void *pw)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_TEXT, x, y, width, height);
+ neww->fg = fg;
+ neww->bg = bg;
+ neww->mapped = true;
+
+ neww->u.text.outline = true;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_text_button, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_DESTROY, fb_destroy_text, NULL);
+ fbtk_set_handler(neww, FBTK_CBT_CLICK, click, pw);
+ fbtk_set_handler(neww, FBTK_CBT_POINTERENTER, fbtk_set_ptr, &hand_image);
+
+ return neww;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/user.c b/frontends/framebuffer/fbtk/user.c
new file mode 100644
index 000000000..2b9cc8768
--- /dev/null
+++ b/frontends/framebuffer/fbtk/user.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit user widget.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <libnsfb.h>
+
+#include "desktop/plot_style.h"
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+
+#include "widget.h"
+
+/* exported function documented in fbtk.h */
+void *
+fbtk_get_userpw(fbtk_widget_t *widget)
+{
+ if ((widget == NULL) ||
+ (widget->type != FB_WIDGET_TYPE_USER))
+ return NULL;
+
+ return widget->u.user.pw;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_user(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ void *pw)
+{
+ fbtk_widget_t *neww;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_USER, x, y, width, height);
+ neww->u.user.pw = pw;
+ neww->mapped = true;
+
+ return neww;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/widget.h b/frontends/framebuffer/fbtk/widget.h
new file mode 100644
index 000000000..5622723ee
--- /dev/null
+++ b/frontends/framebuffer/fbtk/widget.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_FB_FBTK_WIDGET_H
+#define NETSURF_FB_FBTK_WIDGET_H
+
+#include <stdbool.h>
+
+enum fbtk_widgettype_e {
+ FB_WIDGET_TYPE_ROOT = 0,
+ FB_WIDGET_TYPE_WINDOW,
+ FB_WIDGET_TYPE_BITMAP,
+ FB_WIDGET_TYPE_FILL,
+ FB_WIDGET_TYPE_TEXT,
+ FB_WIDGET_TYPE_HSCROLL,
+ FB_WIDGET_TYPE_VSCROLL,
+ FB_WIDGET_TYPE_USER,
+};
+
+
+/** Widget description.
+ *
+ * A widget is an entry in a tree structure which represents a
+ * rectangular area with co-ordinates relative to its parent widget.
+ * This area has a distinct set of callback operations for handling
+ * events which occour within its boundries. A widget may have an
+ * arbitrary number of child widgets. The order within the tree
+ * determines a widgets z order.
+ *
+ * ---
+ * A
+ * |
+ * +----------+
+ * +--->| Button 3 |
+ * | +----------+
+ * | | A
+ * | V |
+ * | +----------+
+ * | | Button 2 |
+ * | +----------+
+ * | | A
+ * | V |
+ * | +----------+
+ * | | Button 1 |
+ * | +----------+
+ * | | A
+ * | V |
+ * --- | +----------+
+ * A | +->| Filled |
+ * | | | +----------+
+ * +----------+ | | |
+ * +---->| |-+ | V
+ * | | Window 1 | | --- ---
+ * | | |---+ A
+ * | +----------+ |
+ * | | A +----------+ ---
+ * | | | +--->| Button 2 | A
+ * | | | | +----------+ |
+ * | | | | | A +-------------+
+ * | | | | | | +--->| Button Up |
+ * | | | | | | | +-------------+
+ * | | | | | | | | A
+ * | | | | | | | V |
+ * | | | | | | | +-------------+
+ * | | | | | | | | Button Down |
+ * | | | | | | | +-------------+
+ * | | | | | | | | A
+ * | | | | | | | V |
+ * | | | | | | | +-------------+
+ * | | | | | | | +->| Scroller |
+ * | | | | V | | | +-------------+
+ * | | | | +----------+ | | |
+ * | | | | | |-+ | V
+ * | | | | | V Scroll | | ---
+ * | | | | | |---+
+ * | | | | +----------+
+ * | | | | | A
+ * | | | | V |
+ * | | | | +----------+
+ * | | | | +->| Button 1 |
+ * | | | | | +----------+
+ * | +----------+ | | |
+ * | | |-+ | V
+ * | | Window 2 | | ---
+ * | | |---+
+ * | +----------+
+ * | | A
+ * | V |
+ * | +------------+
+ * --- | | Background |
+ * A | +->| Bitmap |
+ * | | | +------------+
+ * +------+ | | |
+ * | |-+ | V
+ * | Root | | ---
+ * | |---+
+ * +------+
+ * |
+ * V
+ * ---
+ *
+ * Every widget is contained within this generic wrapper. The
+ * integrated union provides for data specific to a widget type.
+ */
+struct fbtk_widget_s {
+ struct fbtk_widget_s *next; /* next lower z ordered widget in tree */
+ struct fbtk_widget_s *prev; /* next higher z ordered widget in tree */
+
+ struct fbtk_widget_s *parent; /* parent widget */
+
+ struct fbtk_widget_s *first_child; /* first child widget */
+ struct fbtk_widget_s *last_child; /* last child widget */
+
+ /* flags */
+ bool mapped; /**< The widget is mapped/visible . */
+
+ /* Generic properties */
+ int x;
+ int y;
+ int width;
+ int height;
+ colour bg;
+ colour fg;
+
+ /* event callback handlers */
+ fbtk_callback callback[FBTK_CBT_END];
+ void *callback_context[FBTK_CBT_END];
+
+ /* widget redraw */
+ struct {
+ bool child; /* A child of this widget requires redrawing */
+ bool needed; /* the widget requires redrawing */
+ int x;
+ int y;
+ int width;
+ int height;
+ } redraw;
+
+ enum fbtk_widgettype_e type; /**< The type of the widget */
+
+
+ union {
+ /* toolkit base handle */
+ struct {
+ nsfb_t *fb;
+ struct fbtk_widget_s *prev; /* previous widget pointer wasin */
+ struct fbtk_widget_s *grabbed; /* widget that has grabbed pointer movement. */
+ struct fbtk_widget_s *input;
+
+ /* caret */
+ struct {
+ struct fbtk_widget_s *owner; /* widget / NULL */
+ int x; /* relative to owner */
+ int y; /* relative to owner */
+ int height;
+ void (*remove_cb)(fbtk_widget_t *widget);
+ } caret;
+ } root;
+
+ /* bitmap */
+ struct {
+ struct fbtk_bitmap *bitmap;
+ } bitmap;
+
+ /* text */
+ struct {
+ char* text;
+ bool outline;
+ fbtk_enter_t enter;
+ void *pw;
+ int idx; /* caret pos in text */
+ int len; /* text length */
+ int width; /* text width in px */
+ int idx_offset; /* caret pos in pixels */
+ } text;
+
+ /* application driven widget */
+ struct {
+ void *pw; /* private data for user widget */
+ } user;
+
+ struct {
+ int minimum; /* lowest value of scrollbar */
+ int maximum; /* highest value of scrollbar */
+ int thumb; /* size of bar representing a page */
+ int page; /* amount to page document */
+ int position; /* position of bar */
+ int drag; /* offset to start of drag */
+ int drag_position; /* indicator bar pos at drag start */
+ struct fbtk_widget_s *btnul; /* scroll button up/left */
+ struct fbtk_widget_s *btndr; /* scroll button down/right*/
+ } scroll;
+
+ } u;
+};
+
+
+/* These functions are not considered part of the public API but are
+ * not static as they are used by the higher level widget provision
+ * routines
+ */
+
+
+/** creates a new widget and insert it into to hierachy.
+ *
+ * The widget is set to defaults of false, 0 or NULL.
+ *
+ * @param parent The parent widget. The new widget will be added with
+ * the shallowest z order relative to its siblings.
+ * @param type The type of the widget.
+ * @param x The x co-ordinate relative to the parent widget.
+ * @param y The y co-ordinate relative to the parent widget.
+ * @param width the widgets width. This will be clipped to the parent, if
+ * the value is 0 the largest extent which can fit within the parent
+ * is used, if the value is negative the largest value that will fit
+ * within the parent less the value given will be used.
+ * @param height the widgets width. This will be clipped to the parent, if
+ * the value is 0 the largest extent which can fit within the parent
+ * is used, if the value is negative the largest value that will fit
+ * within the parent less the value given will be used.
+ */
+fbtk_widget_t *fbtk_widget_new(fbtk_widget_t *parent, enum fbtk_widgettype_e type, int x, int y, int width, int height);
+
+/** find the root widget from any widget in the toolkit hierarchy.
+ *
+ * @param widget Any widget.
+ * @return The root widget or NULL if \a widget was not valid.
+ */
+fbtk_widget_t *fbtk_get_root_widget(fbtk_widget_t *widget);
+
+/** set pointer to bitmap in context.
+ *
+ * widget helper callback to set cursor image to the bitmap passed in
+ * the callbacks private data.
+ */
+int fbtk_set_ptr(fbtk_widget_t *widget, fbtk_callback_info *cbi);
+
+#endif
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */
diff --git a/frontends/framebuffer/fbtk/window.c b/frontends/framebuffer/fbtk/window.c
new file mode 100644
index 000000000..787dac720
--- /dev/null
+++ b/frontends/framebuffer/fbtk/window.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2010 Vincent Sanders <vince@simtec.co.uk>
+ *
+ * Framebuffer windowing toolkit window widget.
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <libnsfb.h>
+#include <libnsfb_plot.h>
+
+#include "desktop/browser.h"
+
+#include "framebuffer/gui.h"
+#include "framebuffer/fbtk.h"
+
+#include "widget.h"
+
+/** Window redraw callback.
+ *
+ * Called when a window requires redrawing.
+ *
+ * @param widget The widget to be redrawn.
+ * @param cbi The callback parameters.
+ * @return The callback result.
+ */
+static int
+fb_redraw_window(fbtk_widget_t *widget, fbtk_callback_info *cbi)
+{
+ nsfb_bbox_t bbox;
+ nsfb_t *nsfb;
+
+ if ((widget->bg & 0xFF000000) == 0)
+ return 0;
+
+ nsfb = fbtk_get_nsfb(widget);
+
+ fbtk_get_bbox(widget, &bbox);
+
+ nsfb_claim(nsfb, &bbox);
+
+ nsfb_plot_rectangle_fill(nsfb, &bbox, widget->bg);
+
+ nsfb_update(nsfb, &bbox);
+
+ return 0;
+}
+
+/* exported function documented in fbtk.h */
+fbtk_widget_t *
+fbtk_create_window(fbtk_widget_t *parent,
+ int x,
+ int y,
+ int width,
+ int height,
+ colour bg)
+{
+ fbtk_widget_t *neww;
+
+ if (parent == NULL)
+ return NULL;
+
+ neww = fbtk_widget_new(parent, FB_WIDGET_TYPE_WINDOW, x, y, width, height);
+
+ neww->bg = bg;
+
+ fbtk_set_handler(neww, FBTK_CBT_REDRAW, fb_redraw_window, NULL);
+
+ return neww;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:8
+ * End:
+ */