Update German translation
[wmaker-crm.git] / WINGs / wscroller.c
blob33afa4eb6212eecce18a4f89a2d95128b403be7f
2 #include "WINGsP.h"
4 #include <math.h>
6 /* undefine will disable the autoadjusting of the knob dimple to be
7 * directly below the cursor
8 * DOES NOT WORK */
9 #undef STRICT_NEXT_BEHAVIOUR
11 #define AUTOSCROLL_INITIAL_DELAY 200
13 #define AUTOSCROLL_DELAY 40
15 char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
17 typedef struct W_Scroller {
18 W_Class widgetClass;
19 W_View *view;
21 void *clientData;
22 WMAction *action;
24 float knobProportion;
25 float floatValue;
27 WMHandlerID timerID; /* for continuous scrolling mode */
29 #ifndef STRICT_NEXT_BEHAVIOUR
30 int dragPoint; /* point where the knob is being
31 * dragged */
32 #endif
33 struct {
34 WMScrollArrowPosition arrowsPosition:4;
36 unsigned int horizontal:1;
38 WMScrollerPart hitPart:4;
40 /* */
41 unsigned int documentFullyVisible:1; /* document is fully visible */
43 unsigned int prevSelected:1;
45 unsigned int pushed:1;
47 unsigned int incrDown:1; /* whether increment button is down */
49 unsigned int decrDown:1;
51 unsigned int draggingKnob:1;
53 unsigned int configured:1;
55 unsigned int redrawPending:1;
56 } flags;
57 } Scroller;
59 #define DEFAULT_HEIGHT 60
60 #define DEFAULT_WIDTH SCROLLER_WIDTH
61 #define DEFAULT_ARROWS_POSITION WSAMinEnd
63 #define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
65 static void destroyScroller(Scroller * sPtr);
66 static void paintScroller(Scroller * sPtr);
68 static void willResizeScroller();
69 static void handleEvents(XEvent * event, void *data);
70 static void handleActionEvents(XEvent * event, void *data);
72 static void handleMotion(Scroller * sPtr, int mouseX, int mouseY);
74 W_ViewDelegate _ScrollerViewDelegate = {
75 NULL,
76 NULL,
77 NULL,
78 NULL,
79 willResizeScroller
82 WMScroller *WMCreateScroller(WMWidget * parent)
84 Scroller *sPtr;
86 sPtr = wmalloc(sizeof(Scroller));
87 memset(sPtr, 0, sizeof(Scroller));
89 sPtr->widgetClass = WC_Scroller;
91 sPtr->view = W_CreateView(W_VIEW(parent));
92 if (!sPtr->view) {
93 wfree(sPtr);
94 return NULL;
96 sPtr->view->self = sPtr;
98 sPtr->view->delegate = &_ScrollerViewDelegate;
100 sPtr->flags.documentFullyVisible = 1;
102 WMCreateEventHandler(sPtr->view, ExposureMask | StructureNotifyMask
103 | ClientMessageMask, handleEvents, sPtr);
105 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
106 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
108 WMCreateEventHandler(sPtr->view, ButtonPressMask | ButtonReleaseMask
109 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, sPtr);
111 sPtr->flags.hitPart = WSNoPart;
113 sPtr->floatValue = 0.0;
114 sPtr->knobProportion = 1.0;
116 return sPtr;
119 void WMSetScrollerArrowsPosition(WMScroller * sPtr, WMScrollArrowPosition position)
121 sPtr->flags.arrowsPosition = position;
122 if (sPtr->view->flags.realized) {
123 paintScroller(sPtr);
127 static void willResizeScroller(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
129 WMScroller *sPtr = (WMScroller *) view->self;
131 if (*width > *height) {
132 sPtr->flags.horizontal = 1;
133 *height = SCROLLER_WIDTH;
134 } else {
135 sPtr->flags.horizontal = 0;
136 *width = SCROLLER_WIDTH;
140 void WMSetScrollerAction(WMScroller * sPtr, WMAction * action, void *clientData)
142 CHECK_CLASS(sPtr, WC_Scroller);
144 sPtr->action = action;
146 sPtr->clientData = clientData;
149 void WMSetScrollerParameters(WMScroller * sPtr, float floatValue, float knobProportion)
151 CHECK_CLASS(sPtr, WC_Scroller);
153 assert(!isnan(floatValue));
155 if (floatValue < 0.0)
156 sPtr->floatValue = 0.0;
157 else if (floatValue > 1.0)
158 sPtr->floatValue = 1.0;
159 else
160 sPtr->floatValue = floatValue;
162 if (knobProportion <= 0.0) {
164 sPtr->knobProportion = 0.0;
165 sPtr->flags.documentFullyVisible = 0;
167 } else if (knobProportion >= 1.0) {
169 sPtr->knobProportion = 1.0;
170 sPtr->flags.documentFullyVisible = 1;
172 } else {
173 sPtr->knobProportion = knobProportion;
174 sPtr->flags.documentFullyVisible = 0;
177 if (sPtr->view->flags.realized)
178 paintScroller(sPtr);
180 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
183 float WMGetScrollerKnobProportion(WMScroller * sPtr)
185 CHECK_CLASS(sPtr, WC_Scroller);
187 return sPtr->knobProportion;
190 float WMGetScrollerValue(WMScroller * sPtr)
192 CHECK_CLASS(sPtr, WC_Scroller);
194 return sPtr->floatValue;
197 WMScrollerPart WMGetScrollerHitPart(WMScroller * sPtr)
199 CHECK_CLASS(sPtr, WC_Scroller);
201 return sPtr->flags.hitPart;
204 static void paintArrow(WMScroller * sPtr, Drawable d, int part)
206 * part- 0 paints the decrement arrow, 1 the increment arrow
209 WMView *view = sPtr->view;
210 WMScreen *scr = view->screen;
211 int ofs;
212 W_Pixmap *arrow;
214 #ifndef DOUBLE_BUFFER
215 GC gc = scr->lightGC;
216 #endif
218 if (part == 0) { /* decrement button */
219 if (sPtr->flags.horizontal) {
220 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
221 ofs = view->size.width - 2 * (BUTTON_SIZE + 1) - 1;
222 } else {
223 ofs = 2;
225 if (sPtr->flags.decrDown)
226 arrow = scr->hiLeftArrow;
227 else
228 arrow = scr->leftArrow;
230 } else {
231 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
232 ofs = view->size.height - 2 * (BUTTON_SIZE + 1) - 1;
233 } else {
234 ofs = 2;
236 if (sPtr->flags.decrDown)
237 arrow = scr->hiUpArrow;
238 else
239 arrow = scr->upArrow;
242 #ifndef DOUBLE_BUFFER
243 if (sPtr->flags.decrDown)
244 gc = WMColorGC(scr->white);
245 #endif
246 } else { /* increment button */
247 if (sPtr->flags.horizontal) {
248 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
249 ofs = view->size.width - BUTTON_SIZE + 1 - 3;
250 } else {
251 ofs = 2 + BUTTON_SIZE + 1;
253 if (sPtr->flags.incrDown)
254 arrow = scr->hiRightArrow;
255 else
256 arrow = scr->rightArrow;
257 } else {
258 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
259 ofs = view->size.height - BUTTON_SIZE + 1 - 3;
260 } else {
261 ofs = 2 + BUTTON_SIZE + 1;
263 if (sPtr->flags.incrDown)
264 arrow = scr->hiDownArrow;
265 else
266 arrow = scr->downArrow;
269 #ifndef DOUBLE_BUFFER
270 if (sPtr->flags.incrDown)
271 gc = scr->whiteGC;
272 #endif
275 if (sPtr->flags.horizontal) {
276 /* paint button */
277 #ifndef DOUBLE_BUFFER
278 XFillRectangle(scr->display, d, gc, ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
279 #else
280 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
281 XFillRectangle(scr->display, d, WMColorGC(scr->white),
282 ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
283 #endif /* DOUBLE_BUFFER */
284 W_DrawRelief(scr, d, ofs, 2, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
286 /* paint arrow */
287 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
288 XSetClipOrigin(scr->display, scr->clipGC,
289 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
291 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
292 0, 0, arrow->width, arrow->height,
293 ofs + (BUTTON_SIZE - arrow->width) / 2, 2 + (BUTTON_SIZE - arrow->height) / 2);
295 } else { /* vertical */
297 /* paint button */
298 #ifndef DOUBLE_BUFFER
299 XFillRectangle(scr->display, d, gc, 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
300 #else
301 if ((!part && sPtr->flags.decrDown) || (part && sPtr->flags.incrDown))
302 XFillRectangle(scr->display, d, WMColorGC(scr->white),
303 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
304 #endif /* DOUBLE_BUFFER */
305 W_DrawRelief(scr, d, 2, ofs, BUTTON_SIZE, BUTTON_SIZE, WRRaised);
307 /* paint arrow */
309 XSetClipMask(scr->display, scr->clipGC, arrow->mask);
310 XSetClipOrigin(scr->display, scr->clipGC,
311 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
312 XCopyArea(scr->display, arrow->pixmap, d, scr->clipGC,
313 0, 0, arrow->width, arrow->height,
314 2 + (BUTTON_SIZE - arrow->width) / 2, ofs + (BUTTON_SIZE - arrow->height) / 2);
318 static int knobLength(Scroller * sPtr)
320 int tmp, length;
322 if (sPtr->flags.horizontal)
323 length = sPtr->view->size.width - 4;
324 else
325 length = sPtr->view->size.height - 4;
327 if (sPtr->flags.arrowsPosition != WSANone) {
328 length -= 2 * (BUTTON_SIZE + 1);
331 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
332 /* keep minimum size */
333 if (tmp < BUTTON_SIZE)
334 tmp = BUTTON_SIZE;
336 return tmp;
339 static void paintScroller(Scroller * sPtr)
341 WMView *view = sPtr->view;
342 WMScreen *scr = view->screen;
343 #ifdef DOUBLE_BUFFER
344 Pixmap d;
345 #else
346 Drawable d = view->window;
347 #endif
348 int length, ofs;
349 float knobP, knobL;
351 #ifdef DOUBLE_BUFFER
352 d = XCreatePixmap(scr->display, view->window, view->size.width, view->size.height, scr->depth);
353 XFillRectangle(scr->display, d, WMColorGC(scr->gray), 0, 0, view->size.width, view->size.height);
354 #endif
356 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0, view->size.width - 1, view->size.height - 1);
357 #ifndef DOUBLE_BUFFER
358 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1, view->size.width - 3, view->size.height - 3);
359 #endif
361 if (sPtr->flags.horizontal)
362 length = view->size.width - 4;
363 else
364 length = view->size.height - 4;
366 if (sPtr->flags.documentFullyVisible) {
367 XFillRectangle(scr->display, d, scr->stippleGC, 2, 2, view->size.width - 4, view->size.height - 4);
368 } else {
369 ofs = 2;
370 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
371 length -= (BUTTON_SIZE + 1) * 2;
372 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
373 ofs += (BUTTON_SIZE + 1) * 2;
374 length -= (BUTTON_SIZE + 1) * 2;
377 knobL = (float)knobLength(sPtr);
379 knobP = sPtr->floatValue * ((float)length - knobL);
381 if (sPtr->flags.horizontal) {
382 /* before */
383 XFillRectangle(scr->display, d, scr->stippleGC, ofs, 2, (int)knobP, view->size.height - 4);
385 /* knob */
386 #ifndef DOUBLE_BUFFER
387 XFillRectangle(scr->display, d, scr->lightGC,
388 ofs + (int)knobP + 2, 2 + 2, (int)knobL - 4, view->size.height - 4 - 4);
389 #endif
390 W_DrawRelief(scr, d, ofs + (int)knobP, 2, (int)knobL, view->size.height - 4, WRRaised);
392 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
393 scr->copyGC, 0, 0,
394 scr->scrollerDimple->width, scr->scrollerDimple->height,
395 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->width - 1) / 2,
396 (view->size.height - scr->scrollerDimple->height - 1) / 2);
398 /* after */
399 if ((int)(knobP + knobL) < length)
400 XFillRectangle(scr->display, d, scr->stippleGC,
401 ofs + (int)(knobP + knobL), 2,
402 length - (int)(knobP + knobL), view->size.height - 4);
403 } else {
404 /* before */
405 if (knobP > 0.0)
406 XFillRectangle(scr->display, d, scr->stippleGC,
407 2, ofs, view->size.width - 4, (int)knobP);
409 /* knob */
410 #ifndef DOUBLE_BUFFER
411 XFillRectangle(scr->display, d, scr->lightGC,
412 2 + 2, ofs + (int)knobP + 2, view->size.width - 4 - 4, (int)knobL - 4);
413 #endif
414 XCopyArea(scr->display, scr->scrollerDimple->pixmap, d,
415 scr->copyGC, 0, 0,
416 scr->scrollerDimple->width, scr->scrollerDimple->height,
417 (view->size.width - scr->scrollerDimple->width - 1) / 2,
418 ofs + (int)knobP + ((int)knobL - scr->scrollerDimple->height - 1) / 2);
420 W_DrawRelief(scr, d, 2, ofs + (int)knobP, view->size.width - 4, (int)knobL, WRRaised);
422 /* after */
423 if ((int)(knobP + knobL) < length)
424 XFillRectangle(scr->display, d, scr->stippleGC,
425 2, ofs + (int)(knobP + knobL),
426 view->size.width - 4, length - (int)(knobP + knobL));
429 if (sPtr->flags.arrowsPosition != WSANone) {
430 paintArrow(sPtr, d, 0);
431 paintArrow(sPtr, d, 1);
435 #ifdef DOUBLE_BUFFER
436 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0, view->size.width, view->size.height, 0, 0);
437 XFreePixmap(scr->display, d);
438 #endif
441 static void handleEvents(XEvent * event, void *data)
443 Scroller *sPtr = (Scroller *) data;
445 CHECK_CLASS(data, WC_Scroller);
447 switch (event->type) {
448 case Expose:
449 if (event->xexpose.count == 0)
450 paintScroller(sPtr);
451 break;
453 case DestroyNotify:
454 destroyScroller(sPtr);
455 break;
460 * locatePointInScroller-
461 * Return the part of the scroller where the point is located.
463 static WMScrollerPart locatePointInScroller(Scroller * sPtr, int x, int y, int alternate)
465 int width = sPtr->view->size.width;
466 int height = sPtr->view->size.height;
467 int c, p1, p2, p3, p4, p5, p6;
468 int knobL, slotL;
470 /* if there is no knob... */
471 if (sPtr->flags.documentFullyVisible)
472 return WSKnobSlot;
474 if (sPtr->flags.horizontal)
475 c = x;
476 else
477 c = y;
479 /* p1 p2 p3 p4 p5 p6
480 * | | |###########| |#####| | |
481 * | < | > |###########| O |#####| < | > |
482 * | | |###########| |#####| | |
485 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
486 p1 = 18;
487 p2 = 36;
489 if (sPtr->flags.horizontal) {
490 slotL = width - 36;
491 p5 = width;
492 } else {
493 slotL = height - 36;
494 p5 = height;
496 p6 = p5;
497 } else if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
498 if (sPtr->flags.horizontal) {
499 slotL = width - 36;
500 p6 = width - 18;
501 } else {
502 slotL = height - 36;
503 p6 = height - 18;
505 p5 = p6 - 18;
507 p1 = p2 = 0;
508 } else {
509 /* no arrows */
510 p1 = p2 = 0;
512 if (sPtr->flags.horizontal) {
513 slotL = p5 = p6 = width;
514 } else {
515 slotL = p5 = p6 = height;
519 knobL = knobLength(sPtr);
520 p3 = p2 + (int)((float)(slotL - knobL) * sPtr->floatValue);
521 p4 = p3 + knobL;
523 /* uses a mix of the NS and Win ways of doing scroll page */
524 if (c <= p1)
525 return alternate ? WSDecrementPage : WSDecrementLine;
526 else if (c <= p2)
527 return alternate ? WSIncrementPage : WSIncrementLine;
528 else if (c <= p3)
529 return WSDecrementPage;
530 else if (c <= p4)
531 return WSKnob;
532 else if (c <= p5)
533 return WSIncrementPage;
534 else if (c <= p6)
535 return alternate ? WSDecrementPage : WSDecrementLine;
536 else
537 return alternate ? WSIncrementPage : WSIncrementLine;
540 static void handlePush(Scroller * sPtr, int pushX, int pushY, int alternate)
542 WMScrollerPart part;
543 int doAction = 0;
545 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
547 sPtr->flags.hitPart = part;
549 switch (part) {
550 case WSIncrementLine:
551 sPtr->flags.incrDown = 1;
552 doAction = 1;
553 break;
555 case WSIncrementPage:
556 doAction = 1;
557 break;
559 case WSDecrementLine:
560 sPtr->flags.decrDown = 1;
561 doAction = 1;
562 break;
564 case WSDecrementPage:
565 doAction = 1;
566 break;
568 case WSKnob:
569 sPtr->flags.draggingKnob = 1;
570 #ifndef STRICT_NEXT_BEHAVIOUR
571 if (sPtr->flags.horizontal)
572 sPtr->dragPoint = pushX;
573 else
574 sPtr->dragPoint = pushY;
577 int length, knobP;
578 int buttonsLen;
580 if (sPtr->flags.arrowsPosition != WSANone)
581 buttonsLen = 2 * (BUTTON_SIZE + 1);
582 else
583 buttonsLen = 0;
585 if (sPtr->flags.horizontal)
586 length = sPtr->view->size.width - 4 - buttonsLen;
587 else
588 length = sPtr->view->size.height - 4 - buttonsLen;
590 knobP = (int)(sPtr->floatValue * (float)(length - knobLength(sPtr)));
592 if (sPtr->flags.arrowsPosition == WSAMinEnd)
593 sPtr->dragPoint -= 2 + buttonsLen + knobP;
594 else
595 sPtr->dragPoint -= 2 + knobP;
597 #endif /* STRICT_NEXT_BEHAVIOUR */
598 /* This does not seem necesary here since we don't know yet if the
599 * knob will be dragged later. -Dan
600 handleMotion(sPtr, pushX, pushY); */
601 break;
603 case WSDecrementWheel:
604 case WSIncrementWheel:
605 case WSKnobSlot:
606 case WSNoPart:
607 /* dummy */
608 break;
611 if (doAction && sPtr->action) {
612 (*sPtr->action) (sPtr, sPtr->clientData);
614 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
618 static float floatValueForPoint(Scroller * sPtr, int point)
620 float floatValue = 0;
621 float position;
622 int slotOfs, slotLength, knobL;
624 if (sPtr->flags.horizontal)
625 slotLength = sPtr->view->size.width - 4;
626 else
627 slotLength = sPtr->view->size.height - 4;
629 slotOfs = 2;
630 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
631 slotLength -= (BUTTON_SIZE + 1) * 2;
632 } else if (sPtr->flags.arrowsPosition == WSAMinEnd) {
633 slotOfs += (BUTTON_SIZE + 1) * 2;
634 slotLength -= (BUTTON_SIZE + 1) * 2;
637 knobL = (float)knobLength(sPtr);
638 #ifdef STRICT_NEXT_BEHAVIOUR
639 if (point < slotOfs + knobL / 2)
640 position = (float)(slotOfs + knobL / 2);
641 else if (point > slotOfs + slotLength - knobL / 2)
642 position = (float)(slotOfs + slotLength - knobL / 2);
643 else
644 position = (float)point;
646 floatValue = (position - (float)(slotOfs + slotLength / 2))
647 / (float)(slotLength - knobL);
648 #else
649 /* Adjust the last point to lie inside the knob slot */
650 if (point < slotOfs)
651 position = (float)slotOfs;
652 else if (point > slotOfs + slotLength)
653 position = (float)(slotOfs + slotLength);
654 else
655 position = (float)point;
657 /* Compute the float value */
658 floatValue = (position - (float)slotOfs) / (float)(slotLength - knobL);
659 #endif
661 assert(!isnan(floatValue));
662 return floatValue;
665 static void handleMotion(Scroller * sPtr, int mouseX, int mouseY)
667 if (sPtr->flags.draggingKnob) {
668 float newFloatValue;
669 int point;
671 if (sPtr->flags.horizontal) {
672 point = mouseX;
673 } else {
674 point = mouseY;
677 #ifndef STRICT_NEXT_BEHAVIOUR
678 point -= sPtr->dragPoint;
679 #endif
681 newFloatValue = floatValueForPoint(sPtr, point);
682 WMSetScrollerParameters(sPtr, newFloatValue, sPtr->knobProportion);
683 if (sPtr->action) {
684 (*sPtr->action) (sPtr, sPtr->clientData);
685 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
687 } else {
688 int part;
690 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
692 sPtr->flags.hitPart = part;
694 if (part == WSIncrementLine && sPtr->flags.decrDown) {
695 sPtr->flags.decrDown = 0;
696 sPtr->flags.incrDown = 1;
697 } else if (part == WSDecrementLine && sPtr->flags.incrDown) {
698 sPtr->flags.incrDown = 0;
699 sPtr->flags.decrDown = 1;
700 } else if (part != WSIncrementLine && part != WSDecrementLine) {
701 sPtr->flags.incrDown = 0;
702 sPtr->flags.decrDown = 0;
707 static void autoScroll(void *clientData)
709 Scroller *sPtr = (Scroller *) clientData;
711 if (sPtr->action) {
712 (*sPtr->action) (sPtr, sPtr->clientData);
713 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
715 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
718 static void handleActionEvents(XEvent * event, void *data)
720 Scroller *sPtr = (Scroller *) data;
721 int wheelDecrement, wheelIncrement;
722 int id, dd;
724 /* check if we're really dealing with a scroller, as something
725 * might have gone wrong in the event dispatching stuff */
726 CHECK_CLASS(sPtr, WC_Scroller);
728 id = sPtr->flags.incrDown;
729 dd = sPtr->flags.decrDown;
731 switch (event->type) {
732 case EnterNotify:
733 break;
735 case LeaveNotify:
736 if (sPtr->timerID) {
737 WMDeleteTimerHandler(sPtr->timerID);
738 sPtr->timerID = NULL;
740 sPtr->flags.incrDown = 0;
741 sPtr->flags.decrDown = 0;
742 break;
744 case ButtonPress:
745 /* FIXME: change Mod1Mask with something else */
746 if (sPtr->flags.documentFullyVisible)
747 break;
749 if (sPtr->flags.horizontal) {
750 wheelDecrement = WINGsConfiguration.mouseWheelDown;
751 wheelIncrement = WINGsConfiguration.mouseWheelUp;
752 } else {
753 wheelDecrement = WINGsConfiguration.mouseWheelUp;
754 wheelIncrement = WINGsConfiguration.mouseWheelDown;
757 if (event->xbutton.button == wheelDecrement) {
758 if (event->xbutton.state & ControlMask) {
759 sPtr->flags.hitPart = WSDecrementPage;
760 } else if (event->xbutton.state & ShiftMask) {
761 sPtr->flags.hitPart = WSDecrementLine;
762 } else {
763 sPtr->flags.hitPart = WSDecrementWheel;
765 if (sPtr->action) {
766 (*sPtr->action) (sPtr, sPtr->clientData);
767 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
769 } else if (event->xbutton.button == wheelIncrement) {
770 if (event->xbutton.state & ControlMask) {
771 sPtr->flags.hitPart = WSIncrementPage;
772 } else if (event->xbutton.state & ShiftMask) {
773 sPtr->flags.hitPart = WSIncrementLine;
774 } else {
775 sPtr->flags.hitPart = WSIncrementWheel;
777 if (sPtr->action) {
778 (*sPtr->action) (sPtr, sPtr->clientData);
779 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
781 } else {
782 handlePush(sPtr, event->xbutton.x, event->xbutton.y, (event->xbutton.state & Mod1Mask)
783 || event->xbutton.button == Button2);
784 /* continue scrolling if pushed on the buttons */
785 if (sPtr->flags.hitPart == WSIncrementLine || sPtr->flags.hitPart == WSDecrementLine) {
786 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_INITIAL_DELAY, autoScroll, sPtr);
789 break;
791 case ButtonRelease:
792 if (sPtr->flags.draggingKnob) {
793 if (sPtr->action) {
794 (*sPtr->action) (sPtr, sPtr->clientData);
795 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
798 if (sPtr->timerID) {
799 WMDeleteTimerHandler(sPtr->timerID);
800 sPtr->timerID = NULL;
802 sPtr->flags.incrDown = 0;
803 sPtr->flags.decrDown = 0;
804 sPtr->flags.draggingKnob = 0;
805 break;
807 case MotionNotify:
808 handleMotion(sPtr, event->xbutton.x, event->xbutton.y);
809 if (sPtr->timerID && sPtr->flags.hitPart != WSIncrementLine
810 && sPtr->flags.hitPart != WSDecrementLine) {
811 WMDeleteTimerHandler(sPtr->timerID);
812 sPtr->timerID = NULL;
814 break;
816 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
817 paintScroller(sPtr);
820 static void destroyScroller(Scroller * sPtr)
822 /* we don't want autoscroll try to scroll a freed widget */
823 if (sPtr->timerID) {
824 WMDeleteTimerHandler(sPtr->timerID);
827 wfree(sPtr);