/* * 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 "utils/log.h" #include "css/css.h" #include "desktop/browser.h" #include "desktop/plotters.h" #include "framebuffer/fb_gui.h" #include "framebuffer/fb_tk.h" #include "framebuffer/fb_plotters.h" #include "framebuffer/fb_bitmap.h" #include "framebuffer/fb_cursor.h" #include "framebuffer/fb_image_data.h" #include "framebuffer/fb_frontend.h" static struct css_style root_style; 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 { framebuffer_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; } /* 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 *widget) { bbox_t saved_plot_ctx; //LOG(("widget %p type %d", widget, widget->type)); /* set the clipping rectangle to the widget area */ saved_plot_ctx = fb_plot_ctx; fb_plot_ctx.x0 = fbtk_get_x(widget); fb_plot_ctx.y0 = fbtk_get_y(widget); fb_plot_ctx.x1 = fb_plot_ctx.x0 + widget->width; fb_plot_ctx.y1 = fb_plot_ctx.y0 + widget->height; if (fbtk_clip_rect(&saved_plot_ctx, &fb_plot_ctx )) { /* do our drawing according to type */ widget->redraw(widget, widget->redrawpw); widget->redraw_required = false; //LOG(("OS redrawing %d,%d %d,%d", fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1)); } /* restore clipping rectangle */ fb_plot_ctx = saved_plot_ctx; //LOG(("Redraw Complete")); } /*************** redraw widgets **************/ static int fb_redraw_fill(fbtk_widget_t *widget, void *pw) { /* clear background */ if ((widget->bg & 0xFF000000) != 0) { /* transparent polygon filling isnt working so fake it */ plot.fill(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1, widget->bg); } fb_os_redraw(&fb_plot_ctx); return 0; } static int fb_redraw_hscroll(fbtk_widget_t *widget, void *pw) { int hscroll; int hpos; plot.fill(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1, widget->bg); plot.fill(fb_plot_ctx.x0 + 1, fb_plot_ctx.y0 + 3, fb_plot_ctx.x1 - 1, fb_plot_ctx.y1 - 3, widget->fg); plot.rectangle(fb_plot_ctx.x0, fb_plot_ctx.y0 + 2, fb_plot_ctx.x1 - fb_plot_ctx.x0 - 1, fb_plot_ctx.y1 - fb_plot_ctx.y0 - 5, 1, 0xFF000000, false, false); hscroll = ((widget->width - 4) * widget->u.scroll.pct) / 100 ; hpos = ((widget->width - 4) * widget->u.scroll.pos) / 100 ; LOG(("hscroll %d",hscroll)); plot.fill(fb_plot_ctx.x0 + 3 + hpos, fb_plot_ctx.y0 + 5, fb_plot_ctx.x0 + hscroll + hpos, fb_plot_ctx.y0 + widget->height - 5, widget->bg); fb_os_redraw(&fb_plot_ctx); return 0; } static int fb_redraw_vscroll(fbtk_widget_t *widget, void *pw) { int vscroll; int vpos; plot.fill(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1, widget->bg); plot.fill(fb_plot_ctx.x0 + 1, fb_plot_ctx.y0 + 3, fb_plot_ctx.x1 - 1, fb_plot_ctx.y1 - 3, widget->fg); plot.rectangle(fb_plot_ctx.x0, fb_plot_ctx.y0 + 2, fb_plot_ctx.x1 - fb_plot_ctx.x0 - 1, fb_plot_ctx.y1 - fb_plot_ctx.y0 - 5, 1, 0xFF000000, false, false); vscroll = ((widget->height - 4) * widget->u.scroll.pct) / 100 ; vpos = ((widget->height - 4) * widget->u.scroll.pos) / 100 ; LOG(("scroll %d",vscroll)); plot.fill(fb_plot_ctx.x0 + 3, fb_plot_ctx.y0 + 5 + vpos, fb_plot_ctx.x0 + widget->width - 3, fb_plot_ctx.y0 + vscroll + vpos - 5, widget->bg); fb_os_redraw(&fb_plot_ctx); return 0; } static int fb_redraw_bitmap(fbtk_widget_t *widget, void *pw) { /* clear background */ if ((widget->bg & 0xFF000000) != 0) { /* transparent polygon filling isnt working so fake it */ plot.fill(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1, widget->bg); } /* plot the image */ plot.bitmap(fb_plot_ctx.x0, fb_plot_ctx.y0, widget->width, widget->height, widget->u.bitmap.bitmap, 0, NULL); fb_os_redraw(&fb_plot_ctx); return 0; } static int fbtk_window_default_redraw(fbtk_widget_t *window, void *pw) { fbtk_widget_list_t *lent; fbtk_widget_t *widget; int res = 0; if (!window->redraw) return res; /* get the list of widgets */ lent = window->u.window.widgets; while (lent != NULL) { widget = lent->widget; if ((widget->redraw != NULL) && (widget->redraw_required)) { fbtk_redraw_widget(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, browser_mouse_state st, 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, st, x - widget->x, y - widget->y, widget->clickpw); break; } } lent = lent->next; } return res; } static int fb_redraw_text(fbtk_widget_t *widget, void *pw) { /* clear background */ if ((widget->bg & 0xFF000000) != 0) { /* transparent polygon filling isnt working so fake it */ plot.fill(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1, fb_plot_ctx.y1, widget->bg); } if (widget->u.text.outline) { plot.rectangle(fb_plot_ctx.x0, fb_plot_ctx.y0, fb_plot_ctx.x1 - fb_plot_ctx.x0 - 1, fb_plot_ctx.y1 - fb_plot_ctx.y0 - 1, 1, 0x00000000, false, false); } if (widget->u.text.text != NULL) { plot.text(fb_plot_ctx.x0 + 3, fb_plot_ctx.y0 + 17, &root_style, widget->u.text.text, strlen(widget->u.text.text), widget->bg, widget->fg); } fb_os_redraw(&fb_plot_ctx); return 0; } static int text_input(fbtk_widget_t *widget, int value, void *pw) { switch (value) { case -1: /* gain focus */ if (widget->u.text.text == NULL) widget->u.text.text = calloc(1,1); widget->u.text.idx = strlen(widget->u.text.text); break; case '\b': if (widget->u.text.idx <= 0) break; widget->u.text.idx--; widget->u.text.text[widget->u.text.idx] = 0; break; case '\r': widget->u.text.enter(widget->u.text.pw, widget->u.text.text); break; default: /* allow for new character and null */ widget->u.text.text = realloc(widget->u.text.text, widget->u.text.idx + 2); 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; } 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 *widget, uint32_t ucs4) { fbtk_widget_t *input; widget = get_root_widget(widget); /* obtain widget with input focus */ input = widget->u.root.input; if (input == NULL) return; if (input->input == NULL) return; input->input(input, ucs4, input->inputpw); } void fbtk_click(fbtk_widget_t *widget, browser_mouse_state st) { fbtk_widget_t *root; fbtk_widget_t *window; int x; int y; /* ensure we have the root widget */ root = get_root_widget(widget); x = fb_cursor_x(root->u.root.fb); y = fb_cursor_y(root->u.root.fb); /* get the root window */ window = root->u.root.rootw; if (window->click != NULL) window->click(window, st, x, y, window->clickpw); } void fbtk_move_pointer(fbtk_widget_t *widget, int x, int y, bool relative) { fbtk_widget_t *root; fbtk_widget_t *window; /* ensure we have the root widget */ root = get_root_widget(widget); if (relative) { x += fb_cursor_x(root->u.root.fb); y += fb_cursor_y(root->u.root.fb); } root->redraw_required = true; fb_cursor_move(root->u.root.fb, x, y); /* get the root window */ window = root->u.root.rootw; if (window->move != NULL) window->move(window, x, y,window->movepw); } int fbtk_redraw(fbtk_widget_t *widget) { fbtk_widget_t *root; fbtk_widget_t *window; bbox_t saved_plot_ctx; /* ensure we have the root widget */ root = get_root_widget(widget); if (!root->redraw_required) return 0; /* set the clipping rectangle to the widget area */ saved_plot_ctx = fb_plot_ctx; /* get the root window */ window = root->u.root.rootw; fb_plot_ctx.x0 = window->x; fb_plot_ctx.y0 = window->y; fb_plot_ctx.x1 = window->x + window->width; fb_plot_ctx.y1 = window->y + window->height; fb_cursor_clear(root->u.root.fb); if (window->redraw != NULL) fbtk_redraw_widget(window); root->redraw_required = false; fb_plot_ctx = saved_plot_ctx; fb_cursor_plot(root->u.root.fb); 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); } /* Initialise toolkit for use */ fbtk_widget_t * fbtk_init(framebuffer_t *fb) { fbtk_widget_t *root = new_widget(FB_WIDGET_TYPE_ROOT); root->u.root.fb = fb; root->x = 0; root->y = 0; root->width = framebuffer->width; root->height = framebuffer->height; root->u.root.rootw = fbtk_create_window(root, 0, 0, 0, 0); root_style.font_size.value.length.unit = CSS_UNIT_PX; root_style.font_size.value.length.value = 14; return root; } /* * Local Variables: * c-basic-offset:8 * End: */