mirror of
https://github.com/gryf/wmaker.git
synced 2026-02-14 04:45:57 +01:00
Initial revision
This commit is contained in:
863
WINGs/wscroller.c
Normal file
863
WINGs/wscroller.c
Normal file
@@ -0,0 +1,863 @@
|
||||
|
||||
|
||||
|
||||
|
||||
#include "WINGsP.h"
|
||||
|
||||
/* undefine will disable the autoadjusting of the knob dimple to be
|
||||
* directly below the cursor
|
||||
* DOES NOT WORK */
|
||||
#undef STRICT_NEXT_BEHAVIOUR
|
||||
|
||||
#define AUTOSCROLL_INITIAL_DELAY 200
|
||||
|
||||
#define AUTOSCROLL_DELAY 40
|
||||
|
||||
|
||||
typedef struct W_Scroller {
|
||||
W_Class widgetClass;
|
||||
W_View *view;
|
||||
|
||||
void *clientData;
|
||||
WMAction *action;
|
||||
|
||||
float knobProportion;
|
||||
float floatValue;
|
||||
|
||||
WMHandlerID timerID; /* for continuous scrolling mode */
|
||||
|
||||
#ifndef STRICT_NEXT_BEHAVIOUR
|
||||
int dragPoint; /* point where the knob is being
|
||||
* dragged */
|
||||
#endif
|
||||
struct {
|
||||
WMScrollArrowPosition arrowsPosition:3;
|
||||
|
||||
unsigned int horizontal:1;
|
||||
|
||||
WMScrollerPart hitPart:3;
|
||||
|
||||
/* */
|
||||
unsigned int documentFullyVisible:1; /* document is fully visible */
|
||||
|
||||
unsigned int prevSelected:1;
|
||||
|
||||
unsigned int pushed:1;
|
||||
|
||||
unsigned int incrDown:1; /* whether increment button is down */
|
||||
|
||||
unsigned int decrDown:1;
|
||||
|
||||
unsigned int draggingKnob:1;
|
||||
|
||||
unsigned int configured:1;
|
||||
|
||||
unsigned int redrawPending:1;
|
||||
} flags;
|
||||
} Scroller;
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_HEIGHT 60
|
||||
#define DEFAULT_WIDTH SCROLLER_WIDTH
|
||||
#define DEFAULT_ARROWS_POSITION WSAMinEnd
|
||||
|
||||
|
||||
|
||||
static void destroyScroller(Scroller *sPtr);
|
||||
static void paintScroller(Scroller *sPtr);
|
||||
|
||||
static void resizeScroller();
|
||||
static void handleEvents(XEvent *event, void *data);
|
||||
static void handleActionEvents(XEvent *event, void *data);
|
||||
|
||||
static void handleMotion(Scroller *sPtr, int mouseX, int mouseY);
|
||||
|
||||
|
||||
W_ViewProcedureTable _ScrollerViewProcedures = {
|
||||
NULL,
|
||||
resizeScroller,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
WMScroller*
|
||||
WMCreateScroller(WMWidget *parent)
|
||||
{
|
||||
Scroller *sPtr;
|
||||
|
||||
sPtr = wmalloc(sizeof(Scroller));
|
||||
memset(sPtr, 0, sizeof(Scroller));
|
||||
|
||||
sPtr->widgetClass = WC_Scroller;
|
||||
|
||||
sPtr->view = W_CreateView(W_VIEW(parent));
|
||||
if (!sPtr->view) {
|
||||
free(sPtr);
|
||||
return NULL;
|
||||
}
|
||||
sPtr->view->self = sPtr;
|
||||
|
||||
sPtr->flags.documentFullyVisible = 1;
|
||||
|
||||
WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask
|
||||
|ClientMessageMask, handleEvents, sPtr);
|
||||
|
||||
resizeScroller(sPtr, DEFAULT_WIDTH, DEFAULT_WIDTH);
|
||||
sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
|
||||
|
||||
WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
|
||||
|EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
|
||||
handleActionEvents, sPtr);
|
||||
|
||||
sPtr->flags.hitPart = WSNoPart;
|
||||
|
||||
return sPtr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
WMSetScrollerArrowsPosition(WMScroller *sPtr, WMScrollArrowPosition position)
|
||||
{
|
||||
sPtr->flags.arrowsPosition = position;
|
||||
if (sPtr->view->flags.realized) {
|
||||
paintScroller(sPtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
resizeScroller(WMScroller *sPtr, unsigned int width, unsigned int height)
|
||||
{
|
||||
if (width > height) {
|
||||
sPtr->flags.horizontal = 1;
|
||||
W_ResizeView(sPtr->view, width, SCROLLER_WIDTH);
|
||||
} else {
|
||||
sPtr->flags.horizontal = 0;
|
||||
W_ResizeView(sPtr->view, SCROLLER_WIDTH, height);
|
||||
}
|
||||
if (sPtr->view->flags.realized) {
|
||||
paintScroller(sPtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WMSetScrollerAction(WMScroller *sPtr, WMAction *action, void *clientData)
|
||||
{
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
sPtr->action = action;
|
||||
|
||||
sPtr->clientData = clientData;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WMSetScrollerParameters(WMScroller *sPtr, float floatValue,
|
||||
float knobProportion)
|
||||
{
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
if (floatValue < 0.0)
|
||||
sPtr->floatValue = 0.0;
|
||||
else if (floatValue > 1.0)
|
||||
sPtr->floatValue = 1.0;
|
||||
else
|
||||
sPtr->floatValue = floatValue;
|
||||
|
||||
if (knobProportion <= 0.0) {
|
||||
|
||||
sPtr->knobProportion = 0.0;
|
||||
sPtr->flags.documentFullyVisible = 0;
|
||||
|
||||
} else if (knobProportion >= 1.0) {
|
||||
|
||||
sPtr->knobProportion = 1.0;
|
||||
sPtr->flags.documentFullyVisible = 1;
|
||||
|
||||
} else {
|
||||
sPtr->knobProportion = knobProportion;
|
||||
sPtr->flags.documentFullyVisible = 0;
|
||||
}
|
||||
|
||||
if (sPtr->view->flags.realized)
|
||||
paintScroller(sPtr);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
WMGetScrollerKnobProportion(WMScroller *sPtr)
|
||||
{
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
return sPtr->knobProportion;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
WMGetScrollerValue(WMScroller *sPtr)
|
||||
{
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
return sPtr->floatValue;
|
||||
}
|
||||
|
||||
|
||||
WMScrollerPart
|
||||
WMGetScrollerHitPart(WMScroller *sPtr)
|
||||
{
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
return sPtr->flags.hitPart;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
paintArrow(WMScroller *sPtr, Drawable d, int part)
|
||||
/*
|
||||
* part- 0 paints the decrement arrow, 1 the increment arrow
|
||||
*/
|
||||
{
|
||||
WMView *view = sPtr->view;
|
||||
WMScreen *scr = view->screen;
|
||||
int ofs, bsize;
|
||||
W_Pixmap *arrow;
|
||||
|
||||
#ifndef DOUBLE_BUFFER
|
||||
GC gc = scr->lightGC;
|
||||
#endif
|
||||
|
||||
bsize = SCROLLER_WIDTH - 4;
|
||||
|
||||
|
||||
if (part == 0) { /* decrement button */
|
||||
if (sPtr->flags.horizontal) {
|
||||
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
ofs = view->size.width - 2*(bsize+1) - 1;
|
||||
} else {
|
||||
ofs = 2;
|
||||
}
|
||||
if (sPtr->flags.decrDown)
|
||||
arrow = scr->hiLeftArrow;
|
||||
else
|
||||
arrow = scr->leftArrow;
|
||||
|
||||
} else {
|
||||
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
ofs = view->size.height - 2*(bsize+1) - 1;
|
||||
} else {
|
||||
ofs = 2;
|
||||
}
|
||||
if (sPtr->flags.decrDown)
|
||||
arrow = scr->hiUpArrow;
|
||||
else
|
||||
arrow = scr->upArrow;
|
||||
}
|
||||
|
||||
#ifndef DOUBLE_BUFFER
|
||||
if (sPtr->flags.decrDown)
|
||||
gc = W_GC(scr->white);
|
||||
#endif
|
||||
} else { /* increment button */
|
||||
if (sPtr->flags.horizontal) {
|
||||
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
ofs = view->size.width - bsize+1 - 3;
|
||||
} else {
|
||||
ofs = 2 + bsize+1;
|
||||
}
|
||||
if (sPtr->flags.incrDown)
|
||||
arrow = scr->hiRightArrow;
|
||||
else
|
||||
arrow = scr->rightArrow;
|
||||
} else {
|
||||
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
ofs = view->size.height - bsize+1 - 3;
|
||||
} else {
|
||||
ofs = 2 + bsize+1;
|
||||
}
|
||||
if (sPtr->flags.incrDown)
|
||||
arrow = scr->hiDownArrow;
|
||||
else
|
||||
arrow = scr->downArrow;
|
||||
}
|
||||
|
||||
#ifndef DOUBLE_BUFFER
|
||||
if (sPtr->flags.incrDown)
|
||||
gc = scr->whiteGC;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
if (sPtr->flags.horizontal) {
|
||||
|
||||
/* paint button */
|
||||
#ifndef DOUBLE_BUFFER
|
||||
XFillRectangle(scr->display, d, gc,
|
||||
ofs+1, 2+1, bsize+1-3, bsize-3);
|
||||
#else
|
||||
if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
|
||||
XFillRectangle(scr->display, d, W_GC(scr->white),
|
||||
ofs+1, 2+1, bsize+1-3, bsize-3);
|
||||
#endif /* DOUBLE_BUFFER */
|
||||
W_DrawRelief(scr, d, ofs, 2, bsize, bsize, WRRaised);
|
||||
|
||||
/* paint arrow */
|
||||
XSetClipMask(scr->display, scr->clipGC, arrow->mask);
|
||||
XSetClipOrigin(scr->display, scr->clipGC,
|
||||
ofs + (bsize - arrow->width) / 2,
|
||||
2 + (bsize - arrow->height) / 2);
|
||||
|
||||
XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
|
||||
0, 0, arrow->width, arrow->height,
|
||||
ofs + (bsize - arrow->width) / 2,
|
||||
2 + (bsize - arrow->height) / 2);
|
||||
|
||||
} else { /* vertical */
|
||||
|
||||
/* paint button */
|
||||
#ifndef DOUBLE_BUFFER
|
||||
XFillRectangle(scr->display, d, gc,
|
||||
2+1, ofs+1, bsize-3, bsize+1-3);
|
||||
#else
|
||||
if ((!part&&sPtr->flags.decrDown) || (part&&sPtr->flags.incrDown))
|
||||
XFillRectangle(scr->display, d, W_GC(scr->white),
|
||||
2+1, ofs+1, bsize-3, bsize+1-3);
|
||||
#endif /* DOUBLE_BUFFER */
|
||||
W_DrawRelief(scr, d, 2, ofs, bsize, bsize, WRRaised);
|
||||
|
||||
/* paint arrow */
|
||||
|
||||
XSetClipMask(scr->display, scr->clipGC, arrow->mask);
|
||||
XSetClipOrigin(scr->display, scr->clipGC,
|
||||
2 + (bsize - arrow->width) / 2,
|
||||
ofs + (bsize - arrow->height) / 2);
|
||||
XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
|
||||
0, 0, arrow->width, arrow->height,
|
||||
2 + (bsize - arrow->width) / 2,
|
||||
ofs + (bsize - arrow->height) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
knobLength(Scroller *sPtr)
|
||||
{
|
||||
int tmp, length;
|
||||
|
||||
|
||||
if (sPtr->flags.horizontal)
|
||||
length = sPtr->view->size.width - 4;
|
||||
else
|
||||
length = sPtr->view->size.height - 4;
|
||||
|
||||
if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
length -= (SCROLLER_WIDTH - 4 + 1)*2;
|
||||
} else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
|
||||
length -= (SCROLLER_WIDTH - 4 + 1)*2;
|
||||
}
|
||||
|
||||
tmp = (int)((float)length * sPtr->knobProportion + 0.5);
|
||||
/* keep minimum size */
|
||||
if (tmp < SCROLLER_WIDTH-4)
|
||||
tmp = SCROLLER_WIDTH-4;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
paintScroller(Scroller *sPtr)
|
||||
{
|
||||
WMView *view = sPtr->view;
|
||||
WMScreen *scr = view->screen;
|
||||
#ifdef DOUBLE_BUFFER
|
||||
Pixmap d;
|
||||
#else
|
||||
Drawable d = view->window;
|
||||
#endif
|
||||
int length, ofs;
|
||||
float knobP, knobL;
|
||||
|
||||
|
||||
#ifdef DOUBLE_BUFFER
|
||||
d = XCreatePixmap(scr->display, view->window, view->size.width,
|
||||
view->size.height, scr->depth);
|
||||
XFillRectangle(scr->display, d, W_GC(scr->gray), 0, 0,
|
||||
view->size.width, view->size.height);
|
||||
#endif
|
||||
|
||||
XDrawRectangle(scr->display, d, W_GC(scr->black), 0, 0,
|
||||
view->size.width-1, view->size.height-1);
|
||||
#ifndef DOUBLE_BUFFER
|
||||
XDrawRectangle(scr->display, d, W_GC(scr->gray), 1, 1,
|
||||
view->size.width-3, view->size.height-3);
|
||||
#endif
|
||||
|
||||
if (sPtr->flags.horizontal)
|
||||
length = view->size.width - 4;
|
||||
else
|
||||
length = view->size.height - 4;
|
||||
|
||||
if (sPtr->flags.documentFullyVisible) {
|
||||
XFillRectangle(scr->display, d, scr->stippleGC, 2, 2,
|
||||
view->size.width-4, view->size.height-4);
|
||||
} else {
|
||||
if (sPtr->flags.arrowsPosition==WSAMaxEnd) {
|
||||
ofs = 0;
|
||||
length -= (SCROLLER_WIDTH - 4 + 1)*2;
|
||||
} else if (sPtr->flags.arrowsPosition==WSAMinEnd) {
|
||||
ofs = (SCROLLER_WIDTH - 4 + 1)*2;
|
||||
length -= (SCROLLER_WIDTH - 4 + 1)*2;
|
||||
} else {
|
||||
ofs = 0;
|
||||
}
|
||||
|
||||
knobL = (float)knobLength(sPtr);
|
||||
|
||||
knobP = sPtr->floatValue * ((float)length - knobL);
|
||||
|
||||
|
||||
if (sPtr->flags.horizontal) {
|
||||
/* before */
|
||||
XFillRectangle(scr->display, d, scr->stippleGC,
|
||||
ofs+2, 2, (int)knobP, view->size.height-4);
|
||||
|
||||
/* knob */
|
||||
#ifndef DOUBLE_BUFFER
|
||||
XFillRectangle(scr->display, d, scr->lightGC,
|
||||
ofs+2+(int)knobP+2, 2+2, (int)knobL-4,
|
||||
view->size.height-4-4);
|
||||
#endif
|
||||
W_DrawRelief(scr, d, ofs+2+(int)knobP, 2, (int)knobL,
|
||||
view->size.height-4, WRRaised);
|
||||
|
||||
XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
|
||||
scr->copyGC, 0, 0,
|
||||
scr->scrollerDimple->width, scr->scrollerDimple->height,
|
||||
ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->width-1)/2,
|
||||
(view->size.height-scr->scrollerDimple->height-1)/2);
|
||||
|
||||
/* after */
|
||||
if ((int)(knobP+knobL) < length)
|
||||
XFillRectangle(scr->display, d, scr->stippleGC,
|
||||
ofs+2+(int)(knobP+knobL), 2,
|
||||
length-(int)(knobP+knobL),
|
||||
view->size.height-4);
|
||||
} else {
|
||||
/* before */
|
||||
if (knobP>0.0)
|
||||
XFillRectangle(scr->display, d, scr->stippleGC,
|
||||
2, ofs+2, view->size.width-4, (int)knobP);
|
||||
|
||||
/* knob */
|
||||
#ifndef DOUBLE_BUFFER
|
||||
XFillRectangle(scr->display, d, scr->lightGC,
|
||||
2+2, ofs+2+(int)knobP+2,
|
||||
view->size.width-4-4, (int)knobL-4);
|
||||
#endif
|
||||
XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
|
||||
scr->copyGC, 0, 0,
|
||||
scr->scrollerDimple->width, scr->scrollerDimple->height,
|
||||
(view->size.width-scr->scrollerDimple->width-1)/2,
|
||||
ofs+2+(int)knobP+((int)knobL-scr->scrollerDimple->height-1)/2);
|
||||
|
||||
W_DrawRelief(scr, d, 2, ofs+2+(int)knobP,
|
||||
view->size.width-4, (int)knobL, WRRaised);
|
||||
|
||||
/* after */
|
||||
if ((int)(knobP+knobL) < length)
|
||||
XFillRectangle(scr->display, d, scr->stippleGC,
|
||||
2, ofs+2+(int)(knobP+knobL),
|
||||
view->size.width-4,
|
||||
length-(int)(knobP+knobL));
|
||||
}
|
||||
|
||||
if (sPtr->flags.arrowsPosition != WSANone) {
|
||||
paintArrow(sPtr, d, 0);
|
||||
paintArrow(sPtr, d, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DOUBLE_BUFFER
|
||||
XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0,
|
||||
view->size.width, view->size.height, 0, 0);
|
||||
XFreePixmap(scr->display, d);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handleEvents(XEvent *event, void *data)
|
||||
{
|
||||
Scroller *sPtr = (Scroller*)data;
|
||||
|
||||
CHECK_CLASS(data, WC_Scroller);
|
||||
|
||||
|
||||
switch (event->type) {
|
||||
case Expose:
|
||||
if (event->xexpose.count==0)
|
||||
paintScroller(sPtr);
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
destroyScroller(sPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* locatePointInScroller-
|
||||
* Return the part of the scroller where the point is located.
|
||||
*/
|
||||
static WMScrollerPart
|
||||
locatePointInScroller(Scroller *sPtr, int x, int y, int alternate)
|
||||
{
|
||||
int width = sPtr->view->size.width;
|
||||
int height = sPtr->view->size.height;
|
||||
int c, p1, p2, p3, p4, p5, p6;
|
||||
int knobL, slotL;
|
||||
|
||||
|
||||
/* if there is no knob... */
|
||||
if (sPtr->flags.documentFullyVisible)
|
||||
return WSKnobSlot;
|
||||
|
||||
if (sPtr->flags.horizontal)
|
||||
c = x;
|
||||
else
|
||||
c = y;
|
||||
|
||||
/* p1 p2 p3 p4 p5 p6
|
||||
* | | |###########| |#####| | |
|
||||
* | < | > |###########| O |#####| < | > |
|
||||
* | | |###########| |#####| | |
|
||||
*/
|
||||
|
||||
if (sPtr->flags.arrowsPosition == WSAMinEnd) {
|
||||
p1 = 18;
|
||||
p2 = 36;
|
||||
|
||||
if (sPtr->flags.horizontal) {
|
||||
slotL = width - 36;
|
||||
p5 = width;
|
||||
} else {
|
||||
slotL = height - 36;
|
||||
p5 = height;
|
||||
}
|
||||
p6 = p5;
|
||||
} else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
|
||||
if (sPtr->flags.horizontal) {
|
||||
slotL = width - 36;
|
||||
p6 = width - 18;
|
||||
} else {
|
||||
slotL = height - 36;
|
||||
p6 = height - 18;
|
||||
}
|
||||
p5 = p6 - 18;
|
||||
|
||||
p1 = p2 = 0;
|
||||
} else {
|
||||
/* no arrows */
|
||||
p1 = p2 = 0;
|
||||
|
||||
if (sPtr->flags.horizontal) {
|
||||
slotL = p5 = p6 = width;
|
||||
} else {
|
||||
slotL = p5 = p6 = height;
|
||||
}
|
||||
}
|
||||
|
||||
knobL = knobLength(sPtr);
|
||||
p3 = p2 + (int)((float)(slotL-knobL) * sPtr->floatValue);
|
||||
p4 = p3 + knobL;
|
||||
|
||||
/* uses a mix of the NS and Win ways of doing scroll page */
|
||||
if (c <= p1)
|
||||
return alternate ? WSDecrementPage : WSDecrementLine;
|
||||
else if (c <= p2)
|
||||
return alternate ? WSIncrementPage : WSIncrementLine;
|
||||
else if (c <= p3)
|
||||
return WSDecrementPage;
|
||||
else if (c <= p4)
|
||||
return WSKnob;
|
||||
else if (c <= p5)
|
||||
return WSIncrementPage;
|
||||
else if (c <= p6)
|
||||
return alternate ? WSDecrementPage : WSDecrementLine;
|
||||
else
|
||||
return alternate ? WSIncrementPage : WSIncrementLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handlePush(Scroller *sPtr, int pushX, int pushY, int alternate)
|
||||
{
|
||||
WMScrollerPart part;
|
||||
int doAction = 0;
|
||||
|
||||
part = locatePointInScroller(sPtr, pushX, pushY, alternate);
|
||||
|
||||
sPtr->flags.hitPart = part;
|
||||
|
||||
switch (part) {
|
||||
case WSIncrementLine:
|
||||
sPtr->flags.incrDown = 1;
|
||||
doAction = 1;
|
||||
break;
|
||||
|
||||
case WSIncrementPage:
|
||||
doAction = 1;
|
||||
break;
|
||||
|
||||
case WSDecrementLine:
|
||||
sPtr->flags.decrDown = 1;
|
||||
doAction = 1;
|
||||
break;
|
||||
|
||||
case WSDecrementPage:
|
||||
doAction = 1;
|
||||
break;
|
||||
|
||||
case WSKnob:
|
||||
sPtr->flags.draggingKnob = 1;
|
||||
#ifndef STRICT_NEXT_BEHAVIOUR
|
||||
if (sPtr->flags.horizontal)
|
||||
sPtr->dragPoint = pushX;
|
||||
else
|
||||
sPtr->dragPoint = pushY;
|
||||
|
||||
{
|
||||
int noButtons = (sPtr->flags.arrowsPosition == WSANone);
|
||||
int length, knobP;
|
||||
|
||||
if (sPtr->flags.horizontal)
|
||||
length = sPtr->view->size.width - 4;
|
||||
else
|
||||
length = sPtr->view->size.height - 4;
|
||||
|
||||
if (!noButtons)
|
||||
length -= 36;
|
||||
|
||||
knobP = (int)(sPtr->floatValue * (float)(length-knobLength(sPtr)));
|
||||
|
||||
if (sPtr->flags.arrowsPosition == WSAMinEnd)
|
||||
sPtr->dragPoint -= 2 + (noButtons ? 0 : 36) + knobP;
|
||||
else
|
||||
sPtr->dragPoint -= 2 + knobP;
|
||||
}
|
||||
#endif /* STRICT_NEXT_BEHAVIOUR */
|
||||
handleMotion(sPtr, pushX, pushY);
|
||||
break;
|
||||
|
||||
case WSKnobSlot:
|
||||
case WSNoPart:
|
||||
/* dummy */
|
||||
break;
|
||||
}
|
||||
|
||||
if (doAction && sPtr->action) {
|
||||
(*sPtr->action)(sPtr, sPtr->clientData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static float
|
||||
floatValueForPoint(int slotOfs, int slotLength, int knobLength, int point)
|
||||
{
|
||||
float floatValue = 0;
|
||||
float position;
|
||||
|
||||
#ifdef STRICT_NEXT_BEHAVIOUR
|
||||
if (point < slotOfs + knobLength/2)
|
||||
position = (float)(slotOfs + knobLength/2);
|
||||
else if (point > slotOfs + slotLength - knobLength/2)
|
||||
position = (float)(slotOfs + slotLength - knobLength/2);
|
||||
else
|
||||
position = (float)point;
|
||||
|
||||
floatValue = (position-(float)(slotOfs+slotLength/2))
|
||||
/(float)(slotLength-knobLength);
|
||||
#else
|
||||
/* Adjust the last point to lie inside the knob slot */
|
||||
if (point < slotOfs)
|
||||
position = (float)slotOfs;
|
||||
else if (point > slotOfs + slotLength)
|
||||
position = (float)(slotOfs + slotLength);
|
||||
else
|
||||
position = (float)point;
|
||||
|
||||
/* Compute the float value */
|
||||
floatValue = (position-(float)slotOfs) / (float)(slotLength-knobLength);
|
||||
#endif
|
||||
|
||||
return floatValue;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handleMotion(Scroller *sPtr, int mouseX, int mouseY)
|
||||
{
|
||||
int slotOffset;
|
||||
int slotLength;
|
||||
int noButtons = (sPtr->flags.arrowsPosition == WSANone);
|
||||
|
||||
if (sPtr->flags.arrowsPosition == WSAMinEnd)
|
||||
slotOffset = 2 + (noButtons ? 0 : 36);
|
||||
else
|
||||
slotOffset = 2;
|
||||
|
||||
if (sPtr->flags.draggingKnob) {
|
||||
float newFloatValue;
|
||||
#ifdef STRICT_NEXT_BEHAVIOUR
|
||||
if (sPtr->flags.horizontal) {
|
||||
slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
|
||||
newFloatValue = floatValueForPoint(slotOffset, slotLength,
|
||||
(int)(slotLength*sPtr->knobProportion),
|
||||
mouseX);
|
||||
} else {
|
||||
slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
|
||||
newFloatValue = floatValueForPoint(slotOffset, slotLength,
|
||||
(int)(slotLength*sPtr->knobProportion),
|
||||
mouseY);
|
||||
}
|
||||
#else
|
||||
if (sPtr->flags.horizontal) {
|
||||
slotLength = sPtr->view->size.width-4-(noButtons ? 0 : 36);
|
||||
newFloatValue = floatValueForPoint(slotOffset, slotLength,
|
||||
(int)(slotLength*sPtr->knobProportion),
|
||||
mouseX-sPtr->dragPoint);
|
||||
} else {
|
||||
slotLength = sPtr->view->size.height-4-(noButtons ? 0 : 36);
|
||||
newFloatValue = floatValueForPoint(slotOffset, slotLength,
|
||||
(int)(slotLength*sPtr->knobProportion),
|
||||
mouseY-sPtr->dragPoint);
|
||||
}
|
||||
#endif /* !STRICT_NEXT_BEHAVIOUR */
|
||||
WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
|
||||
if (sPtr->action) {
|
||||
(*sPtr->action)(sPtr, sPtr->clientData);
|
||||
}
|
||||
} else {
|
||||
int part;
|
||||
|
||||
part = locatePointInScroller(sPtr, mouseX, mouseY, False);
|
||||
|
||||
sPtr->flags.hitPart = part;
|
||||
|
||||
if (part == WSIncrementLine && sPtr->flags.decrDown) {
|
||||
sPtr->flags.decrDown = 0;
|
||||
sPtr->flags.incrDown = 1;
|
||||
} else if (part == WSDecrementLine && sPtr->flags.incrDown) {
|
||||
sPtr->flags.incrDown = 0;
|
||||
sPtr->flags.decrDown = 1;
|
||||
} else if (part != WSIncrementLine && part != WSDecrementLine) {
|
||||
sPtr->flags.incrDown = 0;
|
||||
sPtr->flags.decrDown = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
autoScroll(void *clientData)
|
||||
{
|
||||
Scroller *sPtr = (Scroller*)clientData;
|
||||
|
||||
if (sPtr->action) {
|
||||
(*sPtr->action)(sPtr, sPtr->clientData);
|
||||
}
|
||||
sPtr->timerID= WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handleActionEvents(XEvent *event, void *data)
|
||||
{
|
||||
Scroller *sPtr = (Scroller*)data;
|
||||
int id, dd;
|
||||
|
||||
|
||||
/* check if we're really dealing with a scroller, as something
|
||||
* might have gone wrong in the event dispatching stuff */
|
||||
CHECK_CLASS(sPtr, WC_Scroller);
|
||||
|
||||
id = sPtr->flags.incrDown;
|
||||
dd = sPtr->flags.decrDown;
|
||||
|
||||
switch (event->type) {
|
||||
case EnterNotify:
|
||||
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
if (sPtr->timerID) {
|
||||
WMDeleteTimerHandler(sPtr->timerID);
|
||||
sPtr->timerID = NULL;
|
||||
}
|
||||
sPtr->flags.incrDown = 0;
|
||||
sPtr->flags.decrDown = 0;
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
/* FIXME: change Mod1Mask with something else */
|
||||
handlePush(sPtr, event->xbutton.x, event->xbutton.y,
|
||||
(event->xbutton.state & Mod1Mask)
|
||||
||event->xbutton.button==Button2);
|
||||
/* continue scrolling if pushed on the buttons */
|
||||
if (sPtr->flags.hitPart == WSIncrementLine
|
||||
|| sPtr->flags.hitPart == WSDecrementLine) {
|
||||
sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY,
|
||||
autoScroll, sPtr);
|
||||
}
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
if (sPtr->flags.draggingKnob) {
|
||||
if (sPtr->action) {
|
||||
(*sPtr->action)(sPtr, sPtr->clientData);
|
||||
}
|
||||
}
|
||||
if (sPtr->timerID) {
|
||||
WMDeleteTimerHandler(sPtr->timerID);
|
||||
sPtr->timerID = NULL;
|
||||
}
|
||||
sPtr->flags.incrDown = 0;
|
||||
sPtr->flags.decrDown = 0;
|
||||
sPtr->flags.draggingKnob = 0;
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
|
||||
if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
|
||||
&& sPtr->flags.hitPart != WSDecrementLine) {
|
||||
WMDeleteTimerHandler(sPtr->timerID);
|
||||
sPtr->timerID = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
|
||||
paintScroller(sPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
destroyScroller(Scroller *sPtr)
|
||||
{
|
||||
/* we don't want autoscroll try to scroll a freed widget */
|
||||
if (sPtr->timerID) {
|
||||
WMDeleteTimerHandler(sPtr->timerID);
|
||||
}
|
||||
|
||||
free(sPtr);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user