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.
This commit is contained in:
Michael Drake 2014-07-26 22:12:55 +01:00
parent 989e82544e
commit 31def6a338
8 changed files with 435 additions and 33 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -18,6 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdbool.h>
#include <libnsfb.h>
@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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:

View File

@ -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 */