From 31def6a33878b1ca8f5340d30708c853cdafefa1 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Sat, 26 Jul 2014 22:12:55 +0100 Subject: Add rudimentary support for resizing. - Currently only libnsfb's SDL surface supports resizing. - Flickers like crazy while resizing. Possibly because the SDL surface is not set to use double buffering. - The internal widget library, fbtk, was never intended for this, as such it has no knowledge of how a widget should be positioned with respect to its parent. This means the top level window has to track everything and move them itself. --- framebuffer/fbtk.h | 23 +++- framebuffer/fbtk/event.c | 7 ++ framebuffer/fbtk/fbtk.c | 27 ++++- framebuffer/fbtk/scroll.c | 41 +++++++ framebuffer/framebuffer.c | 85 ++++++++++----- framebuffer/framebuffer.h | 1 + framebuffer/gui.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++ framebuffer/gui.h | 12 ++ 8 files changed, 435 insertions(+), 33 deletions(-) (limited to 'framebuffer') diff --git a/framebuffer/fbtk.h b/framebuffer/fbtk.h index 325db0e9b..aff281439 100644 --- a/framebuffer/fbtk.h +++ b/framebuffer/fbtk.h @@ -270,7 +270,7 @@ bool fbtk_get_caret(fbtk_widget_t *widget, int *x, int *y, int *height); /******************* Widget Manipulation **********************/ -/** Change the widget's position and size. +/** Change the widget's position and size. (Doesn't redraw) * */ bool fbtk_set_pos_and_size(fbtk_widget_t *widget, int x, int y, int width, int height); @@ -369,6 +369,27 @@ bool fbtk_set_scroll_parameters(fbtk_widget_t *widget, int min, int max, int thu bool fbtk_set_scroll_position(fbtk_widget_t *widget, int pos); +/** Move and/or resize a horizontal scroll widget + * + * @param vscroll the horizontal scroll widget + * @param x new x pos + * @param y new y pos + * @param width new width + * @param height new height + */ +void fbtk_reposition_hscroll(fbtk_widget_t *scrollh, + int x, int y, int width, int height); + +/** Move and/or resize a vertical scroll widget + * + * @param vscroll the vertical scroll widget + * @param x new x pos + * @param y new y pos + * @param width new width + * @param height new height + */ +void fbtk_reposition_vscroll(fbtk_widget_t *scrollv, + int x, int y, int width, int height); diff --git a/framebuffer/fbtk/event.c b/framebuffer/fbtk/event.c index bd018c52c..2ef36321e 100644 --- a/framebuffer/fbtk/event.c +++ b/framebuffer/fbtk/event.c @@ -248,6 +248,13 @@ fbtk_event(fbtk_widget_t *root, nsfb_event_t *event, int timeout) 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; } diff --git a/framebuffer/fbtk/fbtk.c b/framebuffer/fbtk/fbtk.c index 984748402..cb8aec57f 100644 --- a/framebuffer/fbtk/fbtk.c +++ b/framebuffer/fbtk/fbtk.c @@ -209,6 +209,29 @@ 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) || @@ -217,10 +240,6 @@ fbtk_set_pos_and_size(fbtk_widget_t *widget, widget->y = y; widget->width = width; widget->height = height; - /* @todo This should limit the redrawn area to the sum - * of the old and new widget dimensions, not redraw the lot. - */ - fbtk_request_redraw(widget->parent); return true; } return false; diff --git a/framebuffer/fbtk/scroll.c b/framebuffer/fbtk/scroll.c index 0ce56a6ee..e91c3ef6e 100644 --- a/framebuffer/fbtk/scroll.c +++ b/framebuffer/fbtk/scroll.c @@ -18,6 +18,8 @@ * along with this program. If not, see . */ +#include + #include #include @@ -272,6 +274,26 @@ fbtk_create_vscroll(fbtk_widget_t *parent, 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 @@ -488,6 +510,25 @@ fbtk_create_hscroll(fbtk_widget_t *parent, 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 diff --git a/framebuffer/framebuffer.c b/framebuffer/framebuffer.c index 4cd064c34..1b0c34b54 100644 --- a/framebuffer/framebuffer.c +++ b/framebuffer/framebuffer.c @@ -341,6 +341,42 @@ const struct plotter_table fb_plotters = { }; +static bool framebuffer_format_from_bpp(int bpp, enum nsfb_format_e *fmt) +{ + switch (bpp) { + case 32: + *fmt = NSFB_FMT_XRGB8888; + break; + + case 24: + *fmt = NSFB_FMT_RGB888; + break; + + case 16: + *fmt = NSFB_FMT_RGB565; + break; + + case 8: + *fmt = NSFB_FMT_I8; + break; + + case 4: + *fmt = NSFB_FMT_I4; + break; + + case 1: + *fmt = NSFB_FMT_I1; + break; + + default: + LOG(("Bad bits per pixel (%d)\n", bpp)); + return false; + } + + return true; +} + + nsfb_t * framebuffer_initialise(const char *fename, int width, int height, int bpp) @@ -349,34 +385,8 @@ framebuffer_initialise(const char *fename, int width, int height, int bpp) enum nsfb_format_e fbfmt; /* bpp is a proxy for the framebuffer format */ - switch (bpp) { - case 32: - fbfmt = NSFB_FMT_XRGB8888; - break; - - case 24: - fbfmt = NSFB_FMT_RGB888; - break; - - case 16: - fbfmt = NSFB_FMT_RGB565; - break; - - case 8: - fbfmt = NSFB_FMT_I8; - break; - - case 4: - fbfmt = NSFB_FMT_I4; - break; - - case 1: - fbfmt = NSFB_FMT_I1; - break; - - default: - LOG(("Bad bits per pixel (%d)\n", bpp)); - return NULL; + if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) { + return NULL; } fbtype = nsfb_type_from_name(fename); @@ -409,6 +419,25 @@ framebuffer_initialise(const char *fename, int width, int height, int bpp) } +bool +framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp) +{ + enum nsfb_format_e fbfmt; + + /* bpp is a proxy for the framebuffer format */ + if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) { + return false; + } + + if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) { + LOG(("Unable to change surface geometry\n")); + return false; + } + + return true; + +} + void framebuffer_finalise(void) { diff --git a/framebuffer/framebuffer.h b/framebuffer/framebuffer.h index 0e46cb1f5..5204dbd92 100644 --- a/framebuffer/framebuffer.h +++ b/framebuffer/framebuffer.h @@ -3,6 +3,7 @@ extern const struct plotter_table fb_plotters; nsfb_t *framebuffer_initialise(const char *fename, int width, int height, int bpp); +bool framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp); void framebuffer_finalise(void); bool framebuffer_set_cursor(struct fbtk_bitmap *bm); diff --git a/framebuffer/gui.c b/framebuffer/gui.c index f77edc46e..5590a66e9 100644 --- a/framebuffer/gui.c +++ b/framebuffer/gui.c @@ -1229,6 +1229,7 @@ create_toolbar(struct gui_window *gw, &history_image, fb_localhistory_btn_clik, gw); + gw->history = widget; break; case 'f': /* forward */ @@ -1256,6 +1257,7 @@ create_toolbar(struct gui_window *gw, &stop_image_g, fb_close_click, gw->bw); + gw->close = widget; break; case 's': /* stop */ @@ -1269,6 +1271,7 @@ create_toolbar(struct gui_window *gw, &stop_image, fb_stop_click, gw->bw); + gw->stop = widget; break; case 'r': /* reload */ @@ -1282,6 +1285,7 @@ create_toolbar(struct gui_window *gw, &reload, fb_reload_click, gw->bw); + gw->reload = widget; break; case 't': /* throbber/activity indicator */ @@ -1356,6 +1360,155 @@ create_toolbar(struct gui_window *gw, return toolbar; } + +/** Resize a toolbar. + * + * @param gw Parent window + * @param toolbar_height The height in pixels of the toolbar + * @param padding The padding in pixels round each element of the toolbar + * @param toolbar_layout A string defining which buttons and controls + * should be added to the toolbar. May be empty + * string to disable the bar. + */ +static void +resize_toolbar(struct gui_window *gw, + int toolbar_height, + int padding, + const char *toolbar_layout) +{ + fbtk_widget_t *widget; + + int xpos; /* The position of the next widget. */ + int xlhs = 0; /* extent of the left hand side widgets */ + int xdir = 1; /* the direction of movement + or - 1 */ + const char *itmtype; /* type of the next item */ + int x = 0, y = 0, w = 0, h = 0; + + if (gw->toolbar == NULL) { + return; + } + + if (toolbar_layout == NULL) { + toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT; + } + + itmtype = toolbar_layout; + + if (*itmtype == 0) { + return; + } + + fbtk_set_pos_and_size(gw->toolbar, 0, 0, 0, toolbar_height); + + xpos = padding; + + /* loop proceeds creating widget on the left hand side until + * it runs out of layout or encounters a url bar declaration + * wherupon it works backwards from the end of the layout + * untill the space left is for the url bar + */ + while (itmtype >= toolbar_layout && xdir != 0) { + + switch (*itmtype) { + case 'b': /* back */ + widget = gw->back; + x = (xdir == 1) ? xpos : xpos - left_arrow.width; + y = padding; + w = left_arrow.width; + h = -padding; + break; + + case 'l': /* local history */ + widget = gw->history; + x = (xdir == 1) ? xpos : xpos - history_image.width; + y = padding; + w = history_image.width; + h = -padding; + break; + + case 'f': /* forward */ + widget = gw->forward; + x = (xdir == 1) ? xpos : xpos - right_arrow.width; + y = padding; + w = right_arrow.width; + h = -padding; + break; + + case 'c': /* close the current window */ + widget = gw->close; + x = (xdir == 1) ? xpos : xpos - stop_image_g.width; + y = padding; + w = stop_image_g.width; + h = -padding; + break; + + case 's': /* stop */ + widget = gw->stop; + x = (xdir == 1) ? xpos : xpos - stop_image.width; + y = padding; + w = stop_image.width; + h = -padding; + break; + + case 'r': /* reload */ + widget = gw->reload; + x = (xdir == 1) ? xpos : xpos - reload.width; + y = padding; + w = reload.width; + h = -padding; + break; + + case 't': /* throbber/activity indicator */ + widget = gw->throbber; + x = (xdir == 1) ? xpos : xpos - throbber0.width; + y = padding; + w = throbber0.width; + h = -padding; + break; + + + case 'u': /* url bar*/ + if (xdir == -1) { + /* met the u going backwards add url + * now we know available extent + */ + widget = gw->url; + x = xlhs; + y = padding; + w = xpos - xlhs; + h = -padding; + + /* toolbar is complete */ + xdir = 0; + break; + } + /* met url going forwards, note position and + * reverse direction + */ + itmtype = toolbar_layout + strlen(toolbar_layout); + xdir = -1; + xlhs = xpos; + w = fbtk_get_width(gw->toolbar); + xpos = 2 * w; + widget = gw->toolbar; + break; + + default: + widget = NULL; + break; + + } + + if (widget != NULL) { + if (widget != gw->toolbar) + fbtk_set_pos_and_size(widget, x, y, w, h); + xpos += xdir * (w + padding); + } + + itmtype += xdir; + } +} + /** Routine called when "stripped of focus" event occours for browser widget. * * @param widget The widget reciving "stripped of focus" event. @@ -1391,6 +1544,14 @@ create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_w fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw); } +static void +resize_browser_widget(struct gui_window *gw, int x, int y, + int width, int height) +{ + fbtk_set_pos_and_size(gw->browser, x, y, width, height); + browser_window_reformat(gw->bw, false, width, height); +} + static void create_normal_browser_window(struct gui_window *gw, int furniture_width) { @@ -1412,6 +1573,7 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width) 2, FB_FRAME_COLOUR, nsoption_charp(fb_toolbar_layout)); + gw->toolbar = toolbar; /* set the actually created toolbar height */ if (toolbar != NULL) { @@ -1473,6 +1635,8 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width) fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL); } + gw->bottom_right = widget; + /* create vertical scrollbar */ gw->vscroll = fbtk_create_vscroll(gw->window, fbtk_get_width(gw->window) - furniture_width, @@ -1491,6 +1655,81 @@ create_normal_browser_window(struct gui_window *gw, int furniture_width) fbtk_set_focus(gw->browser); } +static void +resize_normal_browser_window(struct gui_window *gw, int furniture_width) +{ + bool resized; + int width, height; + int toolbar_height = fbtk_get_height(gw->toolbar); + int statusbar_width = nsoption_int(toolbar_status_size) * + width / 10000; + + /* Resize the main window widget */ + resized = fbtk_set_pos_and_size(gw->window, 0, 0, 0, 0); + if (!resized) + return; + + width = fbtk_get_width(gw->window); + height = fbtk_get_height(gw->window); + + resize_toolbar(gw, toolbar_height, 2, + nsoption_charp(fb_toolbar_layout)); + fbtk_set_pos_and_size(gw->status, + 0, height - furniture_width, + statusbar_width, furniture_width); + fbtk_reposition_hscroll(gw->hscroll, + statusbar_width, height - furniture_width, + width - statusbar_width - furniture_width, + furniture_width); + fbtk_set_pos_and_size(gw->bottom_right, + width - furniture_width, height - furniture_width, + furniture_width, furniture_width); + fbtk_reposition_vscroll(gw->vscroll, + width - furniture_width, + toolbar_height, furniture_width, + height - toolbar_height - furniture_width); + resize_browser_widget(gw, + 0, toolbar_height, + width - furniture_width, + height - furniture_width - toolbar_height); +} + +static void gui_window_add_to_window_list(struct gui_window *gw) +{ + gw->next = NULL; + gw->prev = NULL; + + if (window_list == NULL) { + window_list = gw; + } else { + window_list->prev = gw; + gw->next = window_list; + window_list = gw; + } +} + +static void gui_window_remove_from_window_list(struct gui_window *gw) +{ + struct gui_window *list; + + for (list = window_list; list != NULL; list = list->next) { + if (list != gw) + continue; + + if (list == window_list) { + window_list = list->next; + if (window_list != NULL) + window_list->prev = NULL; + } else { + list->prev->next = list->next; + if (list->next != NULL) { + list->next->prev = list->prev; + } + } + break; + } +} + static struct gui_window * gui_window_create(struct browser_window *bw, @@ -1514,12 +1753,17 @@ gui_window_create(struct browser_window *bw, /* map and request redraw of gui window */ fbtk_set_mapping(gw->window, true); + /* Add it to the window list */ + gui_window_add_to_window_list(gw); + return gw; } static void gui_window_destroy(struct gui_window *gw) { + gui_window_remove_from_window_list(gw); + fbtk_destroy_widget(gw->window); free(gw); @@ -1903,6 +2147,34 @@ main(int argc, char** argv) return 0; } +void gui_resize(fbtk_widget_t *root, int width, int height) +{ + struct gui_window *gw; + nsfb_t *nsfb = fbtk_get_nsfb(root); + + /* Enforce a minimum */ + if (width < 300) + width = 300; + if (height < 200) + height = 200; + + if (framebuffer_resize(nsfb, width, height, febpp) == false) { + return; + } + + fbtk_set_pos_and_size(root, 0, 0, width, height); + + fewidth = width; + feheight = height; + + for (gw = window_list; gw != NULL; gw = gw->next) { + resize_normal_browser_window(gw, + nsoption_int(fb_furniture_size)); + } + + fbtk_request_redraw(root); +} + /* * Local Variables: diff --git a/framebuffer/gui.h b/framebuffer/gui.h index c1fa3cc1d..e102b2551 100644 --- a/framebuffer/gui.h +++ b/framebuffer/gui.h @@ -20,6 +20,7 @@ #define NETSURF_FB_GUI_H typedef struct fb_cursor_s fb_cursor_t; +typedef struct fbtk_widget_s fbtk_widget_t; /* bounding box */ typedef struct nsfb_bbox_s bbox_t; @@ -41,16 +42,25 @@ struct gui_window { struct fbtk_widget_s *window; struct fbtk_widget_s *back; struct fbtk_widget_s *forward; + struct fbtk_widget_s *history; + struct fbtk_widget_s *stop; + struct fbtk_widget_s *reload; + struct fbtk_widget_s *close; struct fbtk_widget_s *url; struct fbtk_widget_s *status; struct fbtk_widget_s *throbber; struct fbtk_widget_s *hscroll; struct fbtk_widget_s *vscroll; struct fbtk_widget_s *browser; + struct fbtk_widget_s *toolbar; + struct fbtk_widget_s *bottom_right; int throbber_index; struct gui_localhistory *localhistory; + + struct gui_window *next; + struct gui_window *prev; }; @@ -59,6 +69,8 @@ extern struct gui_window *window_list; struct gui_localhistory *fb_create_localhistory(struct browser_window *bw, struct fbtk_widget_s *parent, int furniture_width); void fb_localhistory_map(struct gui_localhistory * glh); +void gui_resize(fbtk_widget_t *root, int width, int height); + #endif /* NETSURF_FB_GUI_H */ -- cgit v1.2.3