/* * Copyright 2008 Vincent Sanders * * Framebuffer windowing toolkit * * 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 . */ #include #include #include #include #include #include #include #include #include #include "utils/utils.h" #include "utils/log.h" #include "css/css.h" #include "desktop/browser.h" #include "desktop/plotters.h" #include "framebuffer/gui.h" #include "framebuffer/fbtk.h" #include "framebuffer/bitmap.h" #include "framebuffer/image_data.h" static plot_font_style_t root_style = { .family = PLOT_FONT_FAMILY_SANS_SERIF, .size = 11 * FONT_SIZE_SCALE, .weight = 400, .flags = FONTF_NONE, }; 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, }; typedef struct fbtk_widget_list_s fbtk_widget_list_t; /* wrapper struct for all widget types */ struct fbtk_widget_s { /* Generic properties */ int x; int y; int width; int height; colour bg; colour fg; /* handlers */ fbtk_mouseclick_t click; void *clickpw; /* private data for callback */ fbtk_input_t input; void *inputpw; /* private data for callback */ fbtk_move_t move; void *movepw; /* private data for callback */ fbtk_redraw_t redraw; void *redrawpw; /* private data for callback */ bool redraw_required; fbtk_widget_t *parent; /* parent widget */ /* Widget specific */ enum fbtk_widgettype_e type; union { /* toolkit base handle */ struct { nsfb_t *fb; fbtk_widget_t *rootw; fbtk_widget_t *input; } root; /* window */ struct { /* widgets associated with this window */ fbtk_widget_list_t *widgets; /* begining of list */ fbtk_widget_list_t *widgets_end; /* end of list */ } window; /* bitmap */ struct { struct bitmap *bitmap; } bitmap; /* text */ struct { char* text; bool outline; fbtk_enter_t enter; void *pw; int idx; } text; /* application driven widget */ struct { void *pw; /* private data for user widget */ } user; struct { int pos; int pct; } scroll; } u; }; /* widget list */ struct fbtk_widget_list_s { struct fbtk_widget_list_s *next; struct fbtk_widget_list_s *prev; fbtk_widget_t *widget; } ; enum { POINT_LEFTOF_REGION = 1, POINT_RIGHTOF_REGION = 2, POINT_ABOVE_REGION = 4, POINT_BELOW_REGION = 8, }; #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) ) #define SWAP(a, b) do { int t; t=(a); (a)=(b); (b)=t; } while(0) /* clip a rectangle to another rectangle */ bool fbtk_clip_rect(const bbox_t * restrict clip, bbox_t * restrict box) { uint8_t region1; uint8_t region2; 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; } /* clip a rectangle to a widgets area rectangle */ 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); } /* creates a new widget of a given type */ static fbtk_widget_t * new_widget(enum fbtk_widgettype_e type) { fbtk_widget_t *neww; neww = calloc(1, sizeof(fbtk_widget_t)); neww->type = type; return neww; } /* find the root widget from any widget in the toolkits hierarchy */ static fbtk_widget_t * 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; } /* set widget to be redrawn */ void fbtk_request_redraw(fbtk_widget_t *widget) { widget->redraw_required = 1; if (widget->type == FB_WIDGET_TYPE_WINDOW) { fbtk_widget_list_t *lent = widget->u.window.widgets; while (lent != NULL) { lent->widget->redraw_required = 1; lent = lent->next; } } while (widget->parent != NULL) { widget = widget->parent; widget->redraw_required = 1; } } static fbtk_widget_t * add_widget_to_window(fbtk_widget_t *window, fbtk_widget_t *widget) { fbtk_widget_list_t *newent; fbtk_widget_list_t **nextent; fbtk_widget_list_t *prevent; /* previous entry pointer */ if (window->type == FB_WIDGET_TYPE_WINDOW) { /* caller attached widget to a window */ nextent = &window->u.window.widgets; prevent = NULL; while (*nextent != NULL) { prevent = (*nextent); nextent = &(prevent->next); } newent = calloc(1, sizeof(struct fbtk_widget_list_s)); newent->widget = widget; newent->next = NULL; newent->prev = prevent; *nextent = newent; window->u.window.widgets_end = newent; } widget->parent = window; fbtk_request_redraw(widget); return widget; } static void remove_widget_from_window(fbtk_widget_t *window, fbtk_widget_t *widget) { fbtk_widget_list_t *lent = window->u.window.widgets; while ((lent != NULL) && (lent->widget != widget)) { lent = lent->next; } if (lent != NULL) { if (lent->prev == NULL) { window->u.window.widgets = lent->next; } else { lent->prev->next = lent->next; } if (lent->next == NULL) { window->u.window.widgets_end = lent->prev; } else { lent->next->prev = lent->prev; } free(lent); } } static void fbtk_redraw_widget(fbtk_widget_t *root, fbtk_widget_t *widget) { nsfb_bbox_t saved_plot_ctx; nsfb_bbox_t plot_ctx; //LOG(("widget %p type %d", widget, widget->type)); if (widget->redraw_required == false) return; widget->redraw_required = false; /* ensure there is a redraw handler */ if (widget->redraw == NULL) return; /* get the current clipping rectangle */ nsfb_plot_get_clip(root->u.root.fb, &saved_plot_ctx); plot_ctx.x0 = fbtk_get_x(widget); plot_ctx.y0 = fbtk_get_y(widget); plot_ctx.x1 = plot_ctx.x0 + widget->width; plot_ctx.y1 = plot_ctx.y0 + widget->height; /* clip widget to the current area and redraw if its exposed */ if (nsfb_plot_clip(&saved_plot_ctx, &plot_ctx )) { nsfb_plot_set_clip(root->u.root.fb, &plot_ctx); /* do our drawing according to type */ widget->redraw(root, widget, widget->redrawpw); /* restore clipping rectangle */ nsfb_plot_set_clip(root->u.root.fb, &saved_plot_ctx); //LOG(("OS redrawing %d,%d %d,%d", fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1)); } } /*************** redraw widgets **************/ static int fb_redraw_fill(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw) { nsfb_bbox_t bbox; fbtk_get_bbox(widget, &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); } nsfb_update(root->u.root.fb, &bbox); return 0; } static int fb_redraw_hscroll(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw) { int hscroll; int hpos; nsfb_bbox_t bbox; nsfb_bbox_t rect; 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); hscroll = ((widget->width - 4) * widget->u.scroll.pct) / 100 ; hpos = ((widget->width - 4) * widget->u.scroll.pos) / 100 ; 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 fb_redraw_vscroll(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw) { int vscroll; int vpos; nsfb_bbox_t bbox; nsfb_bbox_t rect; 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); 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); /* scroll well */ nsfb_plot_rectangle(root->u.root.fb, &rect, 1, 0xFF999999, false, false); /* scroll well outline */ vscroll = ((widget->height - 4) * widget->u.scroll.pct) / 100 ; vpos = ((widget->height - 4) * widget->u.scroll.pos) / 100 ; LOG(("scroll %d",vscroll)); 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 fb_redraw_bitmap(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw) { nsfb_bbox_t bbox; nsfb_bbox_t rect; 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); } /* plot the image */ nsfb_plot_bitmap(root->u.root.fb, &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(root->u.root.fb, &bbox); return 0; } static int fbtk_window_default_redraw(fbtk_widget_t *root, fbtk_widget_t *window, void *pw) { fbtk_widget_list_t *lent; int res = 0; if (!window->redraw) return res; /* get the list of widgets */ lent = window->u.window.widgets; while (lent != NULL) { fbtk_redraw_widget(root, lent->widget); lent = lent->next; } return res; } static int fbtk_window_default_move(fbtk_widget_t *window, int x, int y, void *pw) { fbtk_widget_list_t *lent; fbtk_widget_t *widget; int res = 0; /* get the list of widgets */ lent = window->u.window.widgets_end; while (lent != NULL) { widget = lent->widget; if ((x > widget->x) && (y > widget->y) && (x < widget->x + widget->width) && (y < widget->y + widget->height)) { if (widget->move != NULL) { res = widget->move(widget, x - widget->x, y - widget->y, widget->movepw); } break; } lent = lent->prev; } return res; } static int fbtk_window_default_click(fbtk_widget_t *window, nsfb_event_t *event, int x, int y, void *pw) { fbtk_widget_list_t *lent; fbtk_widget_t *widget; int res = 0; /* get the list of widgets */ lent = window->u.window.widgets; while (lent != NULL) { widget = lent->widget; if ((x > widget->x) && (y > widget->y) && (x < widget->x + widget->width) && (y < widget->y + widget->height)) { if (widget->input != NULL) { fbtk_widget_t *root = get_root_widget(widget); root->u.root.input = widget; } if (widget->click != NULL) { res = widget->click(widget, event, x - widget->x, y - widget->y, widget->clickpw); break; } } lent = lent->next; } return res; } static int fb_redraw_text(fbtk_widget_t *root, fbtk_widget_t *widget, void *pw) { nsfb_bbox_t bbox; nsfb_bbox_t rect; 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); } 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) { root_style.background = widget->bg; root_style.foreground = widget->fg; plot.text(bbox.x0 + 3, bbox.y0 + 17, widget->u.text.text, strlen(widget->u.text.text), &root_style); } nsfb_update(root->u.root.fb, &bbox); return 0; } static int text_input(fbtk_widget_t *widget, nsfb_event_t *event, void *pw) { int value; if (event == NULL) { /* gain focus */ if (widget->u.text.text == NULL) widget->u.text.text = calloc(1,1); widget->u.text.idx = strlen(widget->u.text.text); fbtk_request_redraw(widget); return 0; } if (event->type != NSFB_EVENT_KEY_DOWN) return 0; value = event->value.keycode; switch (value) { case NSFB_KEY_BACKSPACE: if (widget->u.text.idx <= 0) break; widget->u.text.idx--; widget->u.text.text[widget->u.text.idx] = 0; break; case NSFB_KEY_RETURN: widget->u.text.enter(widget->u.text.pw, widget->u.text.text); break; case NSFB_KEY_PAGEUP: case NSFB_KEY_PAGEDOWN: case NSFB_KEY_RIGHT: case NSFB_KEY_LEFT: case NSFB_KEY_UP: case NSFB_KEY_DOWN: case NSFB_KEY_RSHIFT: case NSFB_KEY_LSHIFT: /* Not handling any of these correctly yet, but avoid putting * charcters in the text widget when they're pressed. */ break; default: /* allow for new character and null */ { char *temp = realloc(widget->u.text.text, widget->u.text.idx + 2); if (temp != NULL) { widget->u.text.text = temp; widget->u.text.text[widget->u.text.idx] = value; widget->u.text.text[widget->u.text.idx + 1] = '\0'; widget->u.text.idx++; } } break; } fbtk_request_redraw(widget); return 0; } /* sets the enter action on a writable icon */ void fbtk_writable_text(fbtk_widget_t *widget, fbtk_enter_t enter, void *pw) { widget->u.text.enter = enter; widget->u.text.pw = pw; widget->input = text_input; widget->inputpw = widget; } /********** acessors ***********/ int fbtk_get_height(fbtk_widget_t *widget) { return widget->height; } int fbtk_get_width(fbtk_widget_t *widget) { return widget->width; } int fbtk_get_x(fbtk_widget_t *widget) { int x = widget->x; while (widget->parent != NULL) { widget = widget->parent; x += widget->x; } return x; } int fbtk_get_y(fbtk_widget_t *widget) { int y = widget->y; while (widget->parent != NULL) { widget = widget->parent; y += widget->y; } return y; } /* get widgets bounding box in screen co-ordinates */ 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; while (widget->parent != NULL) { widget = widget->parent; bbox->x0 += widget->x; bbox->y0 += widget->y; bbox->x1 += widget->x; bbox->y1 += widget->y; } return true; } void fbtk_set_handler_click(fbtk_widget_t *widget, fbtk_mouseclick_t click, void *pw) { widget->click = click; widget->clickpw = pw; } void fbtk_set_handler_input(fbtk_widget_t *widget, fbtk_input_t input, void *pw) { widget->input = input; widget->inputpw = pw; } void fbtk_set_handler_redraw(fbtk_widget_t *widget, fbtk_redraw_t redraw, void *pw) { widget->redraw = redraw; widget->redrawpw = pw; } void fbtk_set_handler_move(fbtk_widget_t *widget, fbtk_move_t move, void *pw) { widget->move = move; widget->movepw = pw; } void * fbtk_get_userpw(fbtk_widget_t *widget) { if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_USER)) return NULL; return widget->u.user.pw; } void fbtk_set_text(fbtk_widget_t *widget, const char *text) { 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.idx = strlen(text); fbtk_request_redraw(widget); } void fbtk_set_scroll(fbtk_widget_t *widget, int pct) { if (widget == NULL) return; if ((widget->type == FB_WIDGET_TYPE_HSCROLL) || (widget->type == FB_WIDGET_TYPE_VSCROLL)) { widget->u.scroll.pct = pct; fbtk_request_redraw(widget); } } void fbtk_set_scroll_pos(fbtk_widget_t *widget, int pos) { if (widget == NULL) return; if ((widget->type == FB_WIDGET_TYPE_HSCROLL) || (widget->type == FB_WIDGET_TYPE_VSCROLL)) { widget->u.scroll.pos = pos; fbtk_request_redraw(widget); } } void fbtk_set_bitmap(fbtk_widget_t *widget, struct bitmap *image) { if ((widget == NULL) || (widget->type != FB_WIDGET_TYPE_BITMAP)) return; widget->u.bitmap.bitmap = image; fbtk_request_redraw(widget); } void fbtk_set_pos_and_size(fbtk_widget_t *widget, int x, int y, int width, int height) { 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; fbtk_request_redraw(widget); LOG(("%d,%d %d,%d",x,y,width,height)); } } int fbtk_count_children(fbtk_widget_t *widget) { int count = 0; fbtk_widget_list_t *lent; if (widget->type != FB_WIDGET_TYPE_WINDOW) { if (widget->type != FB_WIDGET_TYPE_ROOT) return -1; widget = widget->u.root.rootw; } lent = widget->u.window.widgets; while (lent != NULL) { count++; lent = lent->next; } return count; } void fbtk_input(fbtk_widget_t *root, nsfb_event_t *event) { fbtk_widget_t *input; root = get_root_widget(root); /* obtain widget with input focus */ input = root->u.root.input; if (input == NULL) return; /* no widget with input */ if (input->input == NULL) return; /* call the widgets input method */ input->input(input, event, input->inputpw); } void fbtk_click(fbtk_widget_t *widget, nsfb_event_t *event) { fbtk_widget_t *root; fbtk_widget_t *window; nsfb_bbox_t cloc; /* ensure we have the root widget */ root = get_root_widget(widget); nsfb_cursor_loc_get(root->u.root.fb, &cloc); /* get the root window */ window = root->u.root.rootw; LOG(("click %d, %d",cloc.x0,cloc.y0)); if (window->click != NULL) window->click(window, event, cloc.x0, cloc.y0, window->clickpw); } void fbtk_move_pointer(fbtk_widget_t *widget, int x, int y, bool relative) { fbtk_widget_t *root; fbtk_widget_t *window; nsfb_bbox_t cloc; /* ensure we have the root widget */ root = 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; } root->redraw_required = true; nsfb_cursor_loc_set(root->u.root.fb, &cloc); /* get the root window */ window = root->u.root.rootw; if (window->move != NULL) window->move(window, cloc.x0, cloc.y0, window->movepw); } int fbtk_redraw(fbtk_widget_t *widget) { fbtk_widget_t *root; /* ensure we have the root widget */ root = get_root_widget(widget); if (!root->redraw_required) return 0; fbtk_redraw_widget(root, root->u.root.rootw); return 1; } /****** widget destruction ********/ int fbtk_destroy_widget(fbtk_widget_t *widget) { if (widget->type == FB_WIDGET_TYPE_WINDOW) { /* TODO: walk child widgets and destroy them */ } remove_widget_from_window(widget->parent, widget); free(widget); return 0; } /************** Widget creation *************/ fbtk_widget_t * fbtk_create_text(fbtk_widget_t *window, int x, int y, int width, int height, colour bg, colour fg, bool outline) { fbtk_widget_t *newt = new_widget(FB_WIDGET_TYPE_TEXT); newt->x = x; newt->y = y; newt->width = width; newt->height = height; newt->u.text.outline = outline; newt->fg = fg; newt->bg = bg; newt->redraw = fb_redraw_text; return add_widget_to_window(window, newt); } fbtk_widget_t * fbtk_create_bitmap(fbtk_widget_t *window, int x, int y, colour c, struct bitmap *image) { fbtk_widget_t *newb = new_widget(FB_WIDGET_TYPE_BITMAP); newb->x = x; newb->y = y; newb->width = image->width; newb->height = image->height; newb->bg = c; newb->u.bitmap.bitmap = image; newb->redraw = fb_redraw_bitmap; return add_widget_to_window(window, newb); } static void fbtk_width_height(fbtk_widget_t *parent, int x, int y, int *width, int *height) { /* make widget fit inside parent */ if (*width == 0) { *width = parent->width - x; } else if (*width < 0) { *width = parent->width + *width; } if ((*width + x) > parent->width) { *width = parent->width - x; } if (*height == 0) { *height = parent->height - y; } else if (*height < 0) { *height = parent->height + *height; } if ((*height + y) > parent->height) { *height = parent->height - y; } } fbtk_widget_t * fbtk_create_fill(fbtk_widget_t *window, int x, int y, int width, int height, colour c) { fbtk_widget_t *neww = new_widget(FB_WIDGET_TYPE_FILL); neww->x = x; neww->y = y; neww->width = width; neww->height = height; fbtk_width_height(window, x, y, &neww->width, &neww->height); neww->bg = c; neww->redraw = fb_redraw_fill; return add_widget_to_window(window, neww); } fbtk_widget_t * fbtk_create_hscroll(fbtk_widget_t *window, int x, int y, int width, int height, colour fg, colour bg) { fbtk_widget_t *neww = new_widget(FB_WIDGET_TYPE_HSCROLL); neww->x = x; neww->y = y; neww->width = width; neww->height = height; neww->fg = fg; neww->bg = bg; neww->redraw = fb_redraw_hscroll; return add_widget_to_window(window, neww); } fbtk_widget_t * fbtk_create_vscroll(fbtk_widget_t *window, int x, int y, int width, int height, colour fg, colour bg) { fbtk_widget_t *neww = new_widget(FB_WIDGET_TYPE_VSCROLL); neww->x = x; neww->y = y; neww->width = width; neww->height = height; neww->fg = fg; neww->bg = bg; neww->redraw = fb_redraw_vscroll; return add_widget_to_window(window, neww); } fbtk_widget_t * fbtk_create_button(fbtk_widget_t *window, int x, int y, colour c, struct bitmap *image, fbtk_mouseclick_t click, void *pw) { fbtk_widget_t *newb = fbtk_create_bitmap(window, x, y, c, image); newb->click = click; newb->clickpw = pw; return newb; } fbtk_widget_t * fbtk_create_writable_text(fbtk_widget_t *window, int x, int y, int width, int height, colour bg, colour fg, bool outline, fbtk_enter_t enter, void *pw) { fbtk_widget_t *newt = fbtk_create_text(window, x, y, width, height, bg,fg,outline); newt->u.text.enter = enter; newt->u.text.pw = pw; newt->input = text_input; newt->inputpw = newt; return newt; } /* create user widget * * @param x coord relative to parent */ fbtk_widget_t * fbtk_create_user(fbtk_widget_t *window, int x, int y, int width, int height, void *pw) { fbtk_widget_t *newu = new_widget(FB_WIDGET_TYPE_USER); /* make new window fit inside parent */ if (width == 0) { width = window->width - x; } else if (width < 0) { width = window->width + width; } if ((width + x) > window->width) { width = window->width - x; } if (height == 0) { height = window->height - y; } else if (height < 0) { height = window->height + height; } if ((height + y) > window->height) { height = window->height - y; } newu->x = x; newu->y = y; newu->width = width; newu->height = height; newu->u.user.pw = pw; return add_widget_to_window(window, newu); } /* create new window * * @param x coord relative to parent */ fbtk_widget_t * fbtk_create_window(fbtk_widget_t *parent, int x, int y, int width, int height) { fbtk_widget_t *newwin; LOG(("Creating window %p %d,%d %d,%d",parent,x,y,width,height)); if (parent == NULL) return NULL; if ((parent->type == FB_WIDGET_TYPE_ROOT) && (parent->u.root.rootw != NULL)) { LOG(("Using root window")); parent = parent->u.root.rootw; } newwin = new_widget(FB_WIDGET_TYPE_WINDOW); /* make new window fit inside parent */ if (width == 0) { width = parent->width - x; } else if (width < 0) { width = parent->width + width; } if ((width + x) > parent->width) { width = parent->width - x; } if (height == 0) { height = parent->height - y; } else if (height < 0) { height = parent->height + height; } if ((height + y) > parent->height) { height = parent->height - y; } newwin->x = x; newwin->y = y; newwin->width = width; newwin->height = height; newwin->redraw = fbtk_window_default_redraw; newwin->move = fbtk_window_default_move; newwin->click = fbtk_window_default_click; LOG(("Created window %p %d,%d %d,%d",newwin,x,y,width,height)); return add_widget_to_window(parent, newwin); } bool fbtk_event(fbtk_widget_t *root, nsfb_event_t *event, int timeout) { bool unused = false; /* is the event available */ /* ensure we have the root widget */ root = get_root_widget(root); //LOG(("Reading event with timeout %d",timeout)); if (nsfb_event(root->u.root.fb, event, timeout) == false) return false; switch (event->type) { case NSFB_EVENT_KEY_DOWN: case NSFB_EVENT_KEY_UP: if ((event->value.controlcode >= NSFB_KEY_MOUSE_1) && (event->value.controlcode <= 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: fbtk_move_pointer(root, event->value.vector.x, event->value.vector.y, true); break; case NSFB_EVENT_MOVE_ABSOLUTE: fbtk_move_pointer(root, event->value.vector.x, event->value.vector.y, false); break; default: break; } return unused; } nsfb_t * fbtk_get_nsfb(fbtk_widget_t *widget) { fbtk_widget_t *root; /* ensure we have the root widget */ root = get_root_widget(widget); return root->u.root.fb; } /* Initialise toolkit for use */ fbtk_widget_t * fbtk_init(nsfb_t *fb) { fbtk_widget_t *root = new_widget(FB_WIDGET_TYPE_ROOT); nsfb_get_geometry(fb, &root->width, &root->height, NULL); LOG(("width %d height %d",root->width, root->height)); root->u.root.fb = fb; root->x = 0; root->y = 0; root->u.root.rootw = fbtk_create_window(root, 0, 0, 0, 0); return root; } 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 */ }; /* performs character mapping */ int fbtk_keycode_to_ucs4(int code, uint8_t mods) { int ucs4 = -1; if (mods) { if ((code >= 0) && (code < (int) NOF_ELEMENTS(sh_keymap))) ucs4 = sh_keymap[code]; } else { if ((code >= 0) && (code < (int) NOF_ELEMENTS(keymap))) ucs4 = keymap[code]; } return ucs4; } /* * Local Variables: * c-basic-offset:8 * End: */