/* scrollbar.c */
/*
* Scrollbar widget
*/
#include <stdio.h>
#include <stdlib.h>
#include "lui.h"
#include "scrollbar.h"
static void compute_knob( LUI_SCROLLBAR *sb, int *x, int *y,
int *width, int *height )
{
/* compute knob position */
if (sb->orientation==1) {
/* vertical */
*x = sb->border + 1;
*width = sb->width - 2*sb->border - 2;
*height = (sb->height - 2*sb->border - 2) * sb->size / 100.0;
if (*height<10) {
*height = 10;
}
*y = sb->border + 1 + (sb->height - 2*sb->border - 2 - *height)
* sb->position / 100.0;
}
else {
/* horizontal */
*y = sb->border + 1;
*height = sb->height - 2*sb->border - 2;
*width = (sb->width - 2*sb->border - 2) * sb->size / 100.0;
if (*width<10) {
*width = 10;
}
*x = sb->border + 1 + (sb->width - 2*sb->border - 2 - *width)
* sb->position / 100.0;
}
}
static void draw( LUI_SCROLLBAR *sb )
{
int x, y, width, height;
compute_knob( sb, &x, &y, &width, &height );
/* draw background */
XFillRectangle( LUI_Display, sb->window, LUI_GC_gray,
sb->border, sb->border, sb->width-2*sb->border,
sb->height-2*sb->border );
/* draw knob */
/*
XFillRectangle( LUI_Display, sb->window, LUI_GC_black,
x, y, width, height );
*/
LUI_DrawFrame( sb->window, x, y, width, height, 3, 1 );
XDrawRectangle( LUI_Display, sb->window, LUI_GC_black,
x, y, width-1, height-1 );
#ifdef EXPERIMENTAL
if (sb->orientation==1) {
int w = sb->width - 2*sb->border;
int y2 = y + height;
XFillRectangle( LUI_Display, sb->window, LUI_GC_gray,
sb->border, sb->border, w, y-sb->border );
XFillRectangle( LUI_Display, sb->window, LUI_GC_black,
x, y, w, height );
XFillRectangle( LUI_Display, sb->window, LUI_GC_gray,
sb->border, y2, w, sb->height-y2-sb->border );
}
#endif
/* draw frame */
LUI_DrawFrame( sb->window, 0, 0, sb->width, sb->height,
sb->border, 0 );
}
/* called when button is pressed */
static void press( LUI_SCROLLBAR *sb, int newx, int newy )
{
int x, y, width, height;
float jump;
sb->dragging = 0;
jump = 100.0 / ((100.0 / sb->size) - 1);
/* jump = 100.0 / ((99.0 / sb->size) - 0);*/
compute_knob( sb, &x, &y, &width, &height );
if (sb->orientation==1) {
/* vertical */
if (newy < y) {
/* jump up */
sb->position -= jump;
if (sb->position<0.0) {
sb->position = 0.0;
}
draw( sb );
if (sb->callback) {
(*sb->callback)( sb, sb->position );
}
}
else if (newy>=y+height) {
/* jump down */
sb->position += jump;
if (sb->position>100.0) {
sb->position = 100.0;
}
draw( sb );
if (sb->callback) {
(*sb->callback)( sb, sb->position );
}
}
else if (sb->size<100.0) {
sb->startx = newx;
sb->starty = newy;
sb->startpos = sb->position;
sb->delta = newy - y;
sb->dragging = 1;
}
}
else {
/* horizontal */
if (newx < x) {
/* jump left */
sb->position -= jump;
if (sb->position<0.0) {
sb->position = 0.0;
}
draw( sb );
if (sb->callback) {
(*sb->callback)( sb, sb->position );
}
}
else if (newx>=x+width) {
/* jump right */
sb->position += jump;
if (sb->position>100.0) {
sb->position = 100.0;
}
draw( sb );
if (sb->callback) {
(*sb->callback)( sb, sb->position );
}
}
else if (sb->size<100.0) {
sb->startx = newx;
sb->starty = newy;
sb->startpos = sb->position;
sb->delta = newx - x;
sb->dragging = 1;
}
}
}
/* called when mouse is dragged */
static void drag( LUI_SCROLLBAR *sb, int newx, int newy )
{
float newpos;
int x, y, width, height;
if (sb->dragging) {
compute_knob( sb, &x, &y, &width, &height );
if (sb->orientation==1) {
/* vertical */
newy = newy - sb->border - 2 - sb->delta;
newpos = (float) newy / (sb->height - 2*sb->border - 2 - height) * 100.0;
/*
newpos = 100.0 * (float) (newy - sb->border-2)
/ (float) (sb->height - 2*sb->border - 4);
*/
if (newpos<0.0) {
sb->position = 0.0;
}
else if (newpos>100.0) {
sb->position = 100.0;
}
else {
sb->position = newpos;
}
}
else {
/* horizontal */
newx = newx - sb->border - 2 - sb->delta;
newpos = (float) newx / (sb->width - 2*sb->border - 2 - width) * 100.0;
if (newpos<0.0) {
sb->position = 0.0;
}
else if (newpos>100.0) {
sb->position = 100.0;
}
else {
sb->position = newpos;
}
}
draw( sb );
if (sb->callback) {
(*sb->callback)( sb, sb->position );
}
}
}
/*
* When an X event occurs in the scrollbar window, this function will
* be called.
* Input: scrollbar - which scrollbar widget
* event - the X event
*/
static int process( LUI_SCROLLBAR *scrollbar, XEvent *event )
{
int x, y;
switch (event->type) {
case Expose:
draw( scrollbar );
break;
case ButtonPress:
press( scrollbar, event->xbutton.x, event->xbutton.y );
break;
case MotionNotify:
/* dragging slider */
{
Display *dpy = event->xany.display;
XEvent next;
x = event->xmotion.x;
y = event->xmotion.y;
while (XPending(dpy)) {
XPeekEvent(dpy,&next);
if (next.type==MotionNotify) {
x = next.xmotion.x;
y = next.xmotion.y;
XNextEvent(dpy,&next); /* discard the event */
}
else {
break;
}
}
}
drag( scrollbar, x, y );
break;
case ButtonRelease:
scrollbar->dragging = 0;
break;
default:
printf("Error in scrollbar process: unexpected event (%d)\n",
(int) event->type );
}
return 1;
}
/*
* Create a new scroll bar widget.
* Input: parent - parent window ID
* x, y - position of scroll bar w.r.t. parent
* width, height - outside dimensions of scrollbar
* orientation - 1 = vertical, 0 = horizontal
*/
LUI_SCROLLBAR * LUI_ScrollBarCreate( Window parent, int x, int y,
int width, int height,
int orientation )
{
LUI_SCROLLBAR *scrollbar;
LUI_LayoutCheck( &x, &y, &width, &height );
scrollbar = (LUI_SCROLLBAR *) malloc( sizeof(LUI_SCROLLBAR) );
if (!scrollbar) {
return NULL;
}
scrollbar->x = x;
scrollbar->y = y;
scrollbar->width = width /*- 2*/;
scrollbar->height = height /*- 2*/;
scrollbar->border = LUI_Border;
scrollbar->window = XCreateSimpleWindow( LUI_Display, parent,
x, y, width/*-2*/, height/*-2*/,
1, LUI_Color_black, LUI_Color_gray );
LUI_EventAdd2( scrollbar->window,
ExposureMask | ButtonPressMask | ButtonReleaseMask
| ButtonMotionMask,
(LUI_FNCP) process, scrollbar );
XMapWindow( LUI_Display, scrollbar->window );
scrollbar->orientation = orientation;
scrollbar->size = 100.0;
scrollbar->position = 0.0;
scrollbar->callback = NULL;
scrollbar->userdata = NULL;
return scrollbar;
}
/*
* Change the size and position of the scrollbar and redraw it.
* Input: scrollbar - the scrollbar
* size - size of knob as a percent in [0,100]
* position - position of knob as percent in [0,100]
*/
void LUI_ScrollBarSet( LUI_SCROLLBAR *scrollbar, float size, float position )
{
scrollbar->size = size;
scrollbar->position = position;
draw( scrollbar );
}
/*
* Change the position of the scrollbar and redraw it.
* Input: scrollbar - the scrollbar
* position - position of knob as percent in [0,100]
*/
void LUI_ScrollBarSetPos( LUI_SCROLLBAR *scrollbar, float position )
{
scrollbar->position = position;
draw( scrollbar );
}
/*
* Return the current position of the named scrollbar.
*/
float LUI_ScrollBarGetPos( LUI_SCROLLBAR *scrollbar )
{
return scrollbar->position;
}
/*
* Register the function to call when the scrollbar is moved.
* Input: scrollbar - which scrollbar
* callback - the callback function. It should be declared as:
* int callback( LUI_SCROLLBAR *sb, float position )
* The position will be in [0,100]
*/
void LUI_ScrollBarCallback( LUI_SCROLLBAR *scrollbar,
int (* callback)( LUI_SCROLLBAR *, float ) )
{
scrollbar->callback = callback;
scrollbar->context_index = context_index;
}
/*
* Attach a pointer to userdata to the scrollbar.
*/
void LUI_ScrollBarData( LUI_SCROLLBAR *scrollbar, void *data )
{
scrollbar->userdata = data;
}
/*
* Destroy a scrollbar.
*/
void LUI_ScrollBarDestroy( LUI_SCROLLBAR *sb )
{
LUI_EventRemove( sb->window );
XDestroyWindow( LUI_Display, sb->window );
free( sb );
}
void LUI_ScrollBarResize( LUI_SCROLLBAR *sb, int width, int height )
{
XResizeWindow( LUI_Display, sb->window, width, height );
sb->width = width;
sb->height = height;
}
syntax highlighted by Code2HTML, v. 0.9.1