Make scrollbar behave better

This commit is contained in:
Dave Davenport 2016-10-26 08:24:34 +02:00
parent 163934fa8c
commit fb459e1660
8 changed files with 64 additions and 51 deletions

View file

@ -36,7 +36,7 @@ struct _widget
void ( *update )( struct _widget * );
/** Handle mouse motion, used for dragging */
gboolean (*motion_notify)( struct _widget *, xcb_motion_notify_event_t * );
gboolean ( *motion_notify )( struct _widget *, xcb_motion_notify_event_t * );
/** widget clicked callback */
widget_clicked_cb clicked;

View file

@ -82,16 +82,29 @@ void scrollbar_set_handle_length ( scrollbar *sb, unsigned int pos_length )
}
}
/**
* The range is the height - handle length.
* r = h - handle;
* handle is the element length of the handle* length of one element.
* handle = r / ( num ) * hl
*
* r = h - r / ( num) *hl
* r*num = num*h - r*hl
* r*num+r*hl = num*h;
* r ( num+hl ) = num*h
* r = (num*h)/(num+hl)
*/
static void scrollbar_draw ( widget *wid, cairo_t *draw )
{
scrollbar *sb = (scrollbar *) wid;
// Calculate position and size.
const short bh = sb->widget.h;
float sec = ( ( bh ) / (float) ( sb->length + sb->pos_length - 2 ) );
short height = sb->pos_length * sec;
short y = sb->pos * sec;
unsigned int r = ( sb->length * wid->h ) / ( (double) ( sb->length + sb->pos_length ) );
unsigned int handle = wid->h - r;
double sec = ( ( r ) / (double) ( sb->length - 1 ) );
unsigned int height = handle;
unsigned int y = sb->pos * sec;
// Set max pos.
y = MIN ( y, bh );
y = MIN ( y, wid->h - handle );
// Never go out of bar.
height = MAX ( 2, height );
// Cap length;
@ -114,13 +127,14 @@ unsigned int scrollbar_clicked ( const scrollbar *sb, int y )
{
if ( sb != NULL ) {
if ( y >= sb->widget.y && y <= ( sb->widget.y + sb->widget.h ) ) {
const short bh = sb->widget.h;
float sec = ( ( bh ) / (float) ( sb->length + sb->pos_length ) );
unsigned int half_handle = MAX ( 1, sec * ( sb->pos_length / 2.0 ) );
unsigned int r = ( sb->length * sb->widget.h ) / ( (double) ( sb->length + sb->pos_length ) );
unsigned int handle = sb->widget.h - r;
double sec = ( ( r ) / (double) ( sb->length - 1 ) );
unsigned int half_handle = handle / 2;
y -= sb->widget.y + half_handle;
y = MIN ( MAX ( 0, y ), sb->widget.h - 2 * half_handle );
unsigned int sel = y / sec;
unsigned int sel = ( ( y ) / sec );
return MIN ( sel, sb->length - 1 );
}
}

View file

@ -47,7 +47,7 @@
#include <rofi.h>
/** Checks if the if x and y is inside rectangle. */
#define INTERSECT( x,y, x1, y1, w1, h1 ) ( ( ((x) >= (x1)) && ((x) < (x1+w1)) ) && ( ((y) >= (y1)) && ((y) < (y1+h1)) ) )
#define INTERSECT( x, y, x1, y1, w1, h1 ) ( ( ( ( x ) >= ( x1 ) ) && ( ( x ) < ( x1 + w1 ) ) ) && ( ( ( y ) >= ( y1 ) ) && ( ( y ) < ( y1 + h1 ) ) ) )
#include "x11-helper.h"
#include "xkb-internal.h"

View file

@ -51,25 +51,24 @@ int main ( G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv )
scrollbar_set_handle_length ( sb, 0);
TASSERTE ( sb->pos_length, 1 );
unsigned int cl = scrollbar_clicked ( sb, 10 );
TASSERTE ( cl, 900);
TASSERTE ( cl, 1010);
cl = scrollbar_clicked ( sb, 20 );
TASSERTE ( cl, 1900);
TASSERTE ( cl, 2020);
cl = scrollbar_clicked ( sb, 0 );
TASSERTE ( cl, 0);
cl = scrollbar_clicked ( sb, 99 );
TASSERTE ( cl, 9800);
TASSERTE ( cl, 9999);
scrollbar_set_handle_length ( sb, 1000);
cl = scrollbar_clicked ( sb, 10 );
TASSERTE ( cl, 555);
cl = scrollbar_clicked ( sb, 20 );
TASSERTE ( cl, 1666);
cl = scrollbar_clicked ( sb, 0 );
TASSERTE ( cl, 0);
cl = scrollbar_clicked ( sb, 99 );
TASSERTE ( cl, 9999);
scrollbar_set_max_value ( sb, 100 );
for ( unsigned int i = 1; i < 99; i++ ){
cl = scrollbar_clicked ( sb, i );
TASSERTE ( cl, i-1);
}
scrollbar_set_max_value ( sb, 200 );
for ( unsigned int i = 1; i < 100; i++ ){
cl = scrollbar_clicked ( sb, i );
TASSERTE ( cl, i*2-2);
}
widget_free( WIDGET (sb ) );
}