Beispiel #1
0
/* 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, &null_image);

    return neww;
}
Beispiel #2
0
/* 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_INPUT, text_input, neww);

	return neww;
}
Beispiel #3
0
/* 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_CLICK, click, pw);
	fbtk_set_handler(neww, FBTK_CBT_POINTERENTER, fbtk_set_ptr, &hand_image);

	return neww;
}
Beispiel #4
0
/* 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,
						  load_bitmap("PROGDIR:Resources/Icons/scrollu.png"),
						  vscrollu_click,
						  neww);

	neww->u.scroll.btndr = fbtk_create_button(parent,
						  x,
						  y + height - scrolld.height,
						  width,
						  scrolld.height,
						  fg,
						  load_bitmap("PROGDIR:Resources/Icons/scrolld.png"),
						  vscrolld_click,
						  neww);


	return neww;
}
Beispiel #5
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);
}
Beispiel #6
0
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;
}
Beispiel #7
0
static void
create_browser_widget(struct gui_window *gw, int toolbar_height, int furniture_width)
{
	struct browser_widget_s *browser_widget;
	browser_widget = calloc(1, sizeof(struct browser_widget_s));

	gw->browser = fbtk_create_user(gw->window,
				       0,
				       toolbar_height,
				       -furniture_width,
				       -furniture_width,
				       browser_widget);

	fbtk_set_handler(gw->browser, FBTK_CBT_REDRAW, fb_browser_window_redraw, gw);
	fbtk_set_handler(gw->browser, FBTK_CBT_INPUT, fb_browser_window_input, gw);
	fbtk_set_handler(gw->browser, FBTK_CBT_CLICK, fb_browser_window_click, gw);
	fbtk_set_handler(gw->browser, FBTK_CBT_STRIP_FOCUS, fb_browser_window_strip_focus, gw);
	fbtk_set_handler(gw->browser, FBTK_CBT_POINTERMOVE, fb_browser_window_move, gw);
}
Beispiel #8
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;
}
Beispiel #9
0
/* 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;
}
Beispiel #10
0
/* 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);

	return neww;
}
Beispiel #11
0
static int
localhistory_redraw(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
	struct gui_localhistory *glh = cbi->context;
	nsfb_bbox_t rbox;

	struct redraw_context ctx = {
		.interactive = true,
		.background_images = true,
		.plot = &fb_plotters
	};

	rbox.x0 = fbtk_get_absx(widget);
	rbox.y0 = fbtk_get_absy(widget);

	rbox.x1 = rbox.x0 + fbtk_get_width(widget);
	rbox.y1 = rbox.y0 + fbtk_get_height(widget);

	nsfb_claim(fbtk_get_nsfb(widget), &rbox);

	nsfb_plot_rectangle_fill(fbtk_get_nsfb(widget), &rbox, 0xffffffff);

	history_redraw_rectangle(glh->bw->history,
				 glh->scrollx,
				 glh->scrolly,
				 fbtk_get_width(widget) + glh->scrollx,
				 fbtk_get_height(widget) + glh->scrolly,
				 0, 0, &ctx);

	nsfb_update(fbtk_get_nsfb(widget), &rbox);

	return 0;
}

static int
localhistory_click(fbtk_widget_t *widget, fbtk_callback_info *cbi)
{
	struct gui_localhistory *glh = cbi->context;

	if (cbi->event->type != NSFB_EVENT_KEY_UP)
		return 0;

	history_click(glh->bw, glh->bw->history, cbi->x, cbi->y, false);

	fbtk_set_mapping(glh->window, false);

	return 1;
}

struct gui_localhistory *
fb_create_localhistory(struct browser_window *bw,
		       fbtk_widget_t *parent,
		       int furniture_width)
{
	struct gui_localhistory *glh;
	glh = calloc(1, sizeof(struct gui_localhistory));

	if (glh == NULL)
		return NULL;

	glh->bw = bw;

	/* container window */
	glh->window = fbtk_create_window(parent, 0, 0, 0, 0, 0);

	glh->history = fbtk_create_user(glh->window, 0, 0, -furniture_width, -furniture_width, glh);

	fbtk_set_handler(glh->history, FBTK_CBT_REDRAW, localhistory_redraw, glh);
	fbtk_set_handler(glh->history, FBTK_CBT_CLICK, localhistory_click, glh);
	/*
	  fbtk_set_handler(gw->localhistory, FBTK_CBT_INPUT, fb_browser_window_input, gw);
	  fbtk_set_handler(gw->localhistory, FBTK_CBT_POINTERMOVE, fb_browser_window_move, bw);
	*/

	/* create horizontal scrollbar */
	glh->hscroll = fbtk_create_hscroll(glh->window,
					   0,
					   fbtk_get_height(glh->window) - furniture_width,
					   fbtk_get_width(glh->window) - furniture_width,
					   furniture_width,
					   FB_SCROLL_COLOUR,
					   FB_FRAME_COLOUR,
					   NULL,
					   NULL);

	glh->vscroll = fbtk_create_vscroll(glh->window,
					   fbtk_get_width(glh->window) - furniture_width,
					   0,
					   furniture_width,
					   fbtk_get_height(glh->window) - furniture_width,
					   FB_SCROLL_COLOUR,
					   FB_FRAME_COLOUR,
					   NULL,
					   NULL);

	fbtk_create_fill(glh->window,
			 fbtk_get_width(glh->window) - furniture_width,
			 fbtk_get_height(glh->window) - furniture_width,
			 furniture_width,
			 furniture_width,
			 FB_FRAME_COLOUR);

	return glh;
}

void
fb_localhistory_map(struct gui_localhistory * glh)
{
	fbtk_set_zorder(glh->window, INT_MIN);
	fbtk_set_mapping(glh->window, true);
}
Beispiel #12
0
/* exported function documented fb/corewindow.h */
nserror fb_corewindow_init(fbtk_widget_t *parent, struct fb_corewindow *fb_cw)
{
	int furniture_width;

	furniture_width = nsoption_int(fb_furniture_size);

	/* setup the core window callback table */
	fb_cw->cb_table = &fb_cw_cb_table;
	fb_cw->drag_status = CORE_WINDOW_DRAG_NONE;

	/* container window */
	fb_cw->wnd = fbtk_create_window(parent, 0, 0, 0, 0, 0);

	fb_cw->drawable = fbtk_create_user(fb_cw->wnd,
					   0, 0,
					   -furniture_width, -furniture_width,
					   fb_cw);

	fbtk_set_handler(fb_cw->drawable,
			 FBTK_CBT_REDRAW,
			 fb_cw_draw_event,
			 fb_cw);

	fbtk_set_handler(fb_cw->drawable,
			 FBTK_CBT_CLICK,
			 fb_cw_mouse_press_event,
			 fb_cw);
/*
	fbtk_set_handler(fb_cw->drawable,
			 FBTK_CBT_INPUT,
			 fb_cw_input_event,
			 fb_cw);

	fbtk_set_handler(fb_cw->drawable,
			 FBTK_CBT_POINTERMOVE,
			 fb_cw_move_event,
			 fb_cw);
*/

	/* create horizontal scrollbar */
	fb_cw->hscroll = fbtk_create_hscroll(fb_cw->wnd,
					   0,
					   fbtk_get_height(fb_cw->wnd) - furniture_width,
					   fbtk_get_width(fb_cw->wnd) - furniture_width,
					   furniture_width,
					   FB_SCROLL_COLOUR,
					   FB_FRAME_COLOUR,
					   NULL,
					   NULL);

	fb_cw->vscroll = fbtk_create_vscroll(fb_cw->wnd,
					   fbtk_get_width(fb_cw->wnd) - furniture_width,
					   0,
					   furniture_width,
					   fbtk_get_height(fb_cw->wnd) - furniture_width,
					   FB_SCROLL_COLOUR,
					   FB_FRAME_COLOUR,
					   NULL,
					   NULL);

	fbtk_create_fill(fb_cw->wnd,
			 fbtk_get_width(fb_cw->wnd) - furniture_width,
			 fbtk_get_height(fb_cw->wnd) - furniture_width,
			 furniture_width,
			 furniture_width,
			 FB_FRAME_COLOUR);


	return NSERROR_OK;
}
Beispiel #13
0
static void
create_normal_browser_window(struct gui_window *gw, int furniture_width)
{
	fbtk_widget_t *widget;
	fbtk_widget_t *toolbar;
	int statusbar_width = 0;
	int toolbar_height = nsoption_int(fb_toolbar_size);

	LOG(("Normal window"));

	gw->window = fbtk_create_window(fbtk, 0, 0, 0, 0, 0);

	statusbar_width = nsoption_int(toolbar_status_size) *
		fbtk_get_width(gw->window) / 10000;

	/* toolbar */
	toolbar = create_toolbar(gw, 
				 toolbar_height, 
				 2, 
				 FB_FRAME_COLOUR, 
				 nsoption_charp(fb_toolbar_layout));

	/* set the actually created toolbar height */
	if (toolbar != NULL) {
		toolbar_height = fbtk_get_height(toolbar);
	} else {
		toolbar_height = 0;
	}

	/* status bar */
	gw->status = fbtk_create_text(gw->window,
				      0,
				      fbtk_get_height(gw->window) - furniture_width,
				      statusbar_width, furniture_width,
				      FB_FRAME_COLOUR, FB_COLOUR_BLACK,
				      false);
	fbtk_set_handler(gw->status, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);

	LOG(("status bar %p at %d,%d", gw->status, fbtk_get_absx(gw->status), fbtk_get_absy(gw->status)));

	/* create horizontal scrollbar */
	gw->hscroll = fbtk_create_hscroll(gw->window,
					  statusbar_width,
					  fbtk_get_height(gw->window) - furniture_width,
					  fbtk_get_width(gw->window) - statusbar_width - furniture_width,
					  furniture_width,
					  FB_SCROLL_COLOUR,
					  FB_FRAME_COLOUR,
					  fb_scroll_callback,
					  gw);

	/* fill bottom right area */

	if (nsoption_bool(fb_osk) == true) {
		widget = fbtk_create_text_button(gw->window,
						 fbtk_get_width(gw->window) - furniture_width,
						 fbtk_get_height(gw->window) - furniture_width,
						 furniture_width,
						 furniture_width,
						 FB_FRAME_COLOUR, FB_COLOUR_BLACK,
						 fb_osk_click,
						 NULL);
		widget = fbtk_create_button(gw->window,
				fbtk_get_width(gw->window) - furniture_width,
				fbtk_get_height(gw->window) - furniture_width,
				furniture_width,
				furniture_width,
				FB_FRAME_COLOUR,
				&osk_image,
				fb_osk_click,
				NULL);
	} else {
		widget = fbtk_create_fill(gw->window,
					  fbtk_get_width(gw->window) - furniture_width,
					  fbtk_get_height(gw->window) - furniture_width,
					  furniture_width,
					  furniture_width,
					  FB_FRAME_COLOUR);

		fbtk_set_handler(widget, FBTK_CBT_POINTERENTER, set_ptr_default_move, NULL);
	}

	/* create vertical scrollbar */
	gw->vscroll = fbtk_create_vscroll(gw->window,
					  fbtk_get_width(gw->window) - furniture_width,
					  toolbar_height,
					  furniture_width,
					  fbtk_get_height(gw->window) - toolbar_height - furniture_width,
					  FB_SCROLL_COLOUR,
					  FB_FRAME_COLOUR,
					  fb_scroll_callback,
					  gw);

	/* browser widget */
	create_browser_widget(gw, toolbar_height, nsoption_int(fb_furniture_size));

	/* Give browser_window's user widget input focus */
	fbtk_set_focus(gw->browser);
}
Beispiel #14
0
/** Create a toolbar window and populate it with buttons. 
 *
 * The toolbar layout uses a character to define buttons type and position:
 * b - back
 * l - local history
 * f - forward
 * s - stop 
 * r - refresh
 * u - url bar expands to fit remaining space
 * t - throbber/activity indicator
 * c - close the current window
 *
 * The default layout is "blfsrut" there should be no more than a
 * single url bar entry or behaviour will be undefined.
 *
 * @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 frame_col Frame colour.
 * @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 fbtk_widget_t *
create_toolbar(struct gui_window *gw, 
	       int toolbar_height, 
	       int padding, 
	       colour frame_col,
	       const char *toolbar_layout)
{
	fbtk_widget_t *toolbar;
	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 */

	if (toolbar_layout == NULL) {
		toolbar_layout = NSFB_TOOLBAR_DEFAULT_LAYOUT;
	}

	LOG(("Using toolbar layout %s", toolbar_layout));

	itmtype = toolbar_layout;

	if (*itmtype == 0) {
		return NULL;
	}

	toolbar = fbtk_create_window(gw->window, 0, 0, 0, 
				     toolbar_height, 
				     frame_col);

	if (toolbar == NULL) {
		return NULL;
	}

	fbtk_set_handler(toolbar, 
			 FBTK_CBT_POINTERENTER, 
			 set_ptr_default_move, 
			 NULL);


	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) && 
	       (*itmtype != 0) && 
	       (xdir !=0)) {

		LOG(("toolbar adding %c", *itmtype));


		switch (*itmtype) {

		case 'b': /* back */
			widget = fbtk_create_button(toolbar, 
						    (xdir == 1) ? xpos : 
						     xpos - left_arrow.width, 
						    padding, 
						    left_arrow.width, 
						    -padding, 
						    frame_col, 
						    &left_arrow, 
						    fb_leftarrow_click, 
						    gw);
			gw->back = widget; /* keep reference */
			break;

		case 'l': /* local history */
			widget = fbtk_create_button(toolbar,
						    (xdir == 1) ? xpos : 
						     xpos - history_image.width,
						    padding,
						    history_image.width,
						    -padding,
						    frame_col,
						    &history_image,
						    fb_localhistory_btn_clik,
						    gw);
			break;

		case 'f': /* forward */
			widget = fbtk_create_button(toolbar,
						    (xdir == 1)?xpos : 
						     xpos - right_arrow.width,
						    padding,
						    right_arrow.width,
						    -padding,
						    frame_col,
						    &right_arrow,
						    fb_rightarrow_click,
						    gw);
			gw->forward = widget;
			break;

		case 'c': /* close the current window */
			widget = fbtk_create_button(toolbar,
						    (xdir == 1)?xpos : 
						     xpos - stop_image_g.width,
						    padding,
						    stop_image_g.width,
						    -padding,
						    frame_col,
						    &stop_image_g,
						    fb_close_click,
						    gw->bw);
			break;

		case 's': /* stop  */
			widget = fbtk_create_button(toolbar,
						    (xdir == 1)?xpos : 
						     xpos - stop_image.width,
						    padding,
						    stop_image.width,
						    -padding,
						    frame_col,
						    &stop_image,
						    fb_stop_click,
						    gw->bw);
			break;

		case 'r': /* reload */
			widget = fbtk_create_button(toolbar,
						    (xdir == 1)?xpos : 
						     xpos - reload.width,
						    padding,
						    reload.width,
						    -padding,
						    frame_col,
						    &reload,
						    fb_reload_click,
						    gw->bw);
			break;

		case 't': /* throbber/activity indicator */
			widget = fbtk_create_bitmap(toolbar,
						    (xdir == 1)?xpos : 
						     xpos - throbber0.width,
						    padding,
						    throbber0.width,
						    -padding,
						    frame_col, 
						    &throbber0);
			gw->throbber = widget;
			break;


		case 'u': /* url bar*/
			if (xdir == -1) {
				/* met the u going backwards add url
				 * now we know available extent 
				 */ 

				widget = fbtk_create_writable_text(toolbar,
						   xlhs,
						   padding,
						   xpos - xlhs,
						   -padding,
						   FB_COLOUR_WHITE,
						   FB_COLOUR_BLACK,
						   true,
						   fb_url_enter,
						   gw->bw);

				fbtk_set_handler(widget, 
						 FBTK_CBT_POINTERENTER, 
						 fb_url_move, gw->bw);

				gw->url = widget; /* keep reference */

				/* 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;
			xpos = (2 * fbtk_get_width(toolbar));
			widget = toolbar;
			break;

		default:
			widget = NULL;
			xdir = 0;
			LOG(("Unknown element %c in toolbar layout", *itmtype));
		        break;

		}

		if (widget != NULL) {
			xpos += (xdir * (fbtk_get_width(widget) + padding));
		}

		LOG(("xpos is %d",xpos));

		itmtype += xdir;
	}

	fbtk_set_mapping(toolbar, true);

	return toolbar;
}
Beispiel #15
0
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;
}