Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wscroller.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002#include "WINGsP.h"
3
64defd4d kojima2001-02-25 20:47:04 +00004#include <math.h>
5
9d2e6ef9 scottc1998-09-29 22:36:29 +00006/* undefine will disable the autoadjusting of the knob dimple to be
6830b057 dan2004-10-12 21:28:27 +00007 * directly below the cursor
9d2e6ef9 scottc1998-09-29 22:36:29 +00008 * DOES NOT WORK */
9#undef STRICT_NEXT_BEHAVIOUR
10
11#define AUTOSCROLL_INITIAL_DELAY 200
12
13#define AUTOSCROLL_DELAY 40
14
275a2a37 kojima2000-10-11 16:21:50 +000015char *WMScrollerDidScrollNotification = "WMScrollerDidScrollNotification";
16
9d2e6ef9 scottc1998-09-29 22:36:29 +000017typedef struct W_Scroller {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020018 W_Class widgetClass;
19 W_View *view;
9d2e6ef9 scottc1998-09-29 22:36:29 +000020
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020021 void *clientData;
22 WMAction *action;
9d2e6ef9 scottc1998-09-29 22:36:29 +000023
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020024 float knobProportion;
25 float floatValue;
9d2e6ef9 scottc1998-09-29 22:36:29 +000026
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020027 WMHandlerID timerID; /* for continuous scrolling mode */
9d2e6ef9 scottc1998-09-29 22:36:29 +000028
29#ifndef STRICT_NEXT_BEHAVIOUR
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020030 int dragPoint; /* point where the knob is being
31 * dragged */
9d2e6ef9 scottc1998-09-29 22:36:29 +000032#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020033 struct {
34 WMScrollArrowPosition arrowsPosition:4;
9d2e6ef9 scottc1998-09-29 22:36:29 +000035
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020036 unsigned int horizontal:1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000037
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020038 WMScrollerPart hitPart:4;
9d2e6ef9 scottc1998-09-29 22:36:29 +000039
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020040 /* */
41 unsigned int documentFullyVisible:1; /* document is fully visible */
9d2e6ef9 scottc1998-09-29 22:36:29 +000042
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020043 unsigned int prevSelected:1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000044
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020045 unsigned int pushed:1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000046
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020047 unsigned int incrDown:1; /* whether increment button is down */
6830b057 dan2004-10-12 21:28:27 +000048
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020049 unsigned int decrDown:1;
6830b057 dan2004-10-12 21:28:27 +000050
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020051 unsigned int draggingKnob:1;
6830b057 dan2004-10-12 21:28:27 +000052
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020053 unsigned int configured:1;
6830b057 dan2004-10-12 21:28:27 +000054
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020055 unsigned int redrawPending:1;
56 } flags;
9d2e6ef9 scottc1998-09-29 22:36:29 +000057} Scroller;
58
9d2e6ef9 scottc1998-09-29 22:36:29 +000059#define DEFAULT_HEIGHT 60
60#define DEFAULT_WIDTH SCROLLER_WIDTH
61#define DEFAULT_ARROWS_POSITION WSAMinEnd
62
0616167b dan2001-04-29 03:24:17 +000063#define BUTTON_SIZE ((SCROLLER_WIDTH) - 4)
64
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020065static void destroyScroller(Scroller * sPtr);
66static void paintScroller(Scroller * sPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000067
5e4625da kojima1999-05-29 21:41:25 +000068static void willResizeScroller();
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020069static void handleEvents(XEvent * event, void *data);
70static void handleActionEvents(XEvent * event, void *data);
9d2e6ef9 scottc1998-09-29 22:36:29 +000071
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020072static void handleMotion(Scroller * sPtr, int mouseX, int mouseY);
9d2e6ef9 scottc1998-09-29 22:36:29 +000073
5e4625da kojima1999-05-29 21:41:25 +000074W_ViewDelegate _ScrollerViewDelegate = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020075 NULL,
76 NULL,
77 NULL,
78 NULL,
79 willResizeScroller
9d2e6ef9 scottc1998-09-29 22:36:29 +000080};
81
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020082WMScroller *WMCreateScroller(WMWidget * parent)
9d2e6ef9 scottc1998-09-29 22:36:29 +000083{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020084 Scroller *sPtr;
6830b057 dan2004-10-12 21:28:27 +000085
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020086 sPtr = wmalloc(sizeof(Scroller));
87 memset(sPtr, 0, sizeof(Scroller));
6830b057 dan2004-10-12 21:28:27 +000088
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020089 sPtr->widgetClass = WC_Scroller;
9d2e6ef9 scottc1998-09-29 22:36:29 +000090
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020091 sPtr->view = W_CreateView(W_VIEW(parent));
92 if (!sPtr->view) {
93 wfree(sPtr);
94 return NULL;
95 }
96 sPtr->view->self = sPtr;
5e4625da kojima1999-05-29 21:41:25 +000097
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020098 sPtr->view->delegate = &_ScrollerViewDelegate;
6830b057 dan2004-10-12 21:28:27 +000099
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200100 sPtr->flags.documentFullyVisible = 1;
6830b057 dan2004-10-12 21:28:27 +0000101
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200102 WMCreateEventHandler(sPtr->view, ExposureMask | StructureNotifyMask
103 | ClientMessageMask, handleEvents, sPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000104
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200105 W_ResizeView(sPtr->view, DEFAULT_WIDTH, DEFAULT_WIDTH);
106 sPtr->flags.arrowsPosition = DEFAULT_ARROWS_POSITION;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000107
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200108 WMCreateEventHandler(sPtr->view, ButtonPressMask | ButtonReleaseMask
109 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, sPtr);
6830b057 dan2004-10-12 21:28:27 +0000110
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200111 sPtr->flags.hitPart = WSNoPart;
6830b057 dan2004-10-12 21:28:27 +0000112
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200113 sPtr->floatValue = 0.0;
114 sPtr->knobProportion = 1.0;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000115
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200116 return sPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000117}
118
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200119void WMSetScrollerArrowsPosition(WMScroller * sPtr, WMScrollArrowPosition position)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000120{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200121 sPtr->flags.arrowsPosition = position;
122 if (sPtr->view->flags.realized) {
123 paintScroller(sPtr);
124 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000125}
126
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200127static void willResizeScroller(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000128{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200129 WMScroller *sPtr = (WMScroller *) view->self;
130
131 if (*width > *height) {
132 sPtr->flags.horizontal = 1;
133 *height = SCROLLER_WIDTH;
134 } else {
135 sPtr->flags.horizontal = 0;
136 *width = SCROLLER_WIDTH;
137 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000138}
139
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200140void WMSetScrollerAction(WMScroller * sPtr, WMAction * action, void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000141{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200142 CHECK_CLASS(sPtr, WC_Scroller);
6830b057 dan2004-10-12 21:28:27 +0000143
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200144 sPtr->action = action;
6830b057 dan2004-10-12 21:28:27 +0000145
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200146 sPtr->clientData = clientData;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000147}
148
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200149void WMSetScrollerParameters(WMScroller * sPtr, float floatValue, float knobProportion)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000150{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200151 CHECK_CLASS(sPtr, WC_Scroller);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000152
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200153 assert(!isnan(floatValue));
6830b057 dan2004-10-12 21:28:27 +0000154
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200155 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;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000161
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200162 if (knobProportion <= 0.0) {
6830b057 dan2004-10-12 21:28:27 +0000163
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200164 sPtr->knobProportion = 0.0;
165 sPtr->flags.documentFullyVisible = 0;
6830b057 dan2004-10-12 21:28:27 +0000166
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200167 } else if (knobProportion >= 1.0) {
6830b057 dan2004-10-12 21:28:27 +0000168
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200169 sPtr->knobProportion = 1.0;
170 sPtr->flags.documentFullyVisible = 1;
6830b057 dan2004-10-12 21:28:27 +0000171
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200172 } else {
173 sPtr->knobProportion = knobProportion;
174 sPtr->flags.documentFullyVisible = 0;
175 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000176
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200177 if (sPtr->view->flags.realized)
178 paintScroller(sPtr);
6830b057 dan2004-10-12 21:28:27 +0000179
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200180 /* WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL); */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000181}
182
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200183float WMGetScrollerKnobProportion(WMScroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000184{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200185 CHECK_CLASS(sPtr, WC_Scroller);
6830b057 dan2004-10-12 21:28:27 +0000186
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200187 return sPtr->knobProportion;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000188}
189
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200190float WMGetScrollerValue(WMScroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000191{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200192 CHECK_CLASS(sPtr, WC_Scroller);
6830b057 dan2004-10-12 21:28:27 +0000193
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200194 return sPtr->floatValue;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000195}
196
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200197WMScrollerPart WMGetScrollerHitPart(WMScroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000198{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200199 CHECK_CLASS(sPtr, WC_Scroller);
6830b057 dan2004-10-12 21:28:27 +0000200
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200201 return sPtr->flags.hitPart;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000202}
203
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200204static void paintArrow(WMScroller * sPtr, Drawable d, int part)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000205/*
206 * part- 0 paints the decrement arrow, 1 the increment arrow
207 */
208{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200209 WMView *view = sPtr->view;
210 WMScreen *scr = view->screen;
211 int ofs;
212 W_Pixmap *arrow;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000213
214#ifndef DOUBLE_BUFFER
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200215 GC gc = scr->lightGC;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000216#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +0000217
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200218 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;
224 }
225 if (sPtr->flags.decrDown)
226 arrow = scr->hiLeftArrow;
227 else
228 arrow = scr->leftArrow;
229
230 } else {
231 if (sPtr->flags.arrowsPosition == WSAMaxEnd) {
232 ofs = view->size.height - 2 * (BUTTON_SIZE + 1) - 1;
233 } else {
234 ofs = 2;
235 }
236 if (sPtr->flags.decrDown)
237 arrow = scr->hiUpArrow;
238 else
239 arrow = scr->upArrow;
240 }
6830b057 dan2004-10-12 21:28:27 +0000241
9d2e6ef9 scottc1998-09-29 22:36:29 +0000242#ifndef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200243 if (sPtr->flags.decrDown)
244 gc = WMColorGC(scr->white);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000245#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200246 } 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;
252 }
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;
262 }
263 if (sPtr->flags.incrDown)
264 arrow = scr->hiDownArrow;
265 else
266 arrow = scr->downArrow;
267 }
6830b057 dan2004-10-12 21:28:27 +0000268
9d2e6ef9 scottc1998-09-29 22:36:29 +0000269#ifndef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200270 if (sPtr->flags.incrDown)
271 gc = scr->whiteGC;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000272#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200273 }
9aca0d5f dan2004-10-12 01:34:32 +0000274
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200275 if (sPtr->flags.horizontal) {
276 /* paint button */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000277#ifndef DOUBLE_BUFFER
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200278 XFillRectangle(scr->display, d, gc, ofs + 1, 2 + 1, BUTTON_SIZE + 1 - 3, BUTTON_SIZE - 3);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000279#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200280 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);
285
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);
290
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);
294
295 } else { /* vertical */
296
297 /* paint button */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000298#ifndef DOUBLE_BUFFER
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200299 XFillRectangle(scr->display, d, gc, 2 + 1, ofs + 1, BUTTON_SIZE - 3, BUTTON_SIZE + 1 - 3);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000300#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200301 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);
306
307 /* paint arrow */
308
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);
315 }
6830b057 dan2004-10-12 21:28:27 +0000316}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000317
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200318static int knobLength(Scroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000319{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200320 int tmp, length;
6830b057 dan2004-10-12 21:28:27 +0000321
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200322 if (sPtr->flags.horizontal)
323 length = sPtr->view->size.width - 4;
324 else
325 length = sPtr->view->size.height - 4;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000326
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200327 if (sPtr->flags.arrowsPosition != WSANone) {
328 length -= 2 * (BUTTON_SIZE + 1);
329 }
6830b057 dan2004-10-12 21:28:27 +0000330
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200331 tmp = (int)((float)length * sPtr->knobProportion + 0.5);
332 /* keep minimum size */
333 if (tmp < BUTTON_SIZE)
334 tmp = BUTTON_SIZE;
6830b057 dan2004-10-12 21:28:27 +0000335
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200336 return tmp;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000337}
338
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200339static void paintScroller(Scroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000340{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200341 WMView *view = sPtr->view;
342 WMScreen *scr = view->screen;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000343#ifdef DOUBLE_BUFFER
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200344 Pixmap d;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345#else
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200346 Drawable d = view->window;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000347#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200348 int length, ofs;
349 float knobP, knobL;
6830b057 dan2004-10-12 21:28:27 +0000350
9d2e6ef9 scottc1998-09-29 22:36:29 +0000351#ifdef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200352 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);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000354#endif
6830b057 dan2004-10-12 21:28:27 +0000355
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200356 XDrawRectangle(scr->display, d, WMColorGC(scr->black), 0, 0, view->size.width - 1, view->size.height - 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000357#ifndef DOUBLE_BUFFER
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200358 XDrawRectangle(scr->display, d, WMColorGC(scr->gray), 1, 1, view->size.width - 3, view->size.height - 3);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000359#endif
360
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200361 if (sPtr->flags.horizontal)
362 length = view->size.width - 4;
363 else
364 length = view->size.height - 4;
365
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;
375 }
376
377 knobL = (float)knobLength(sPtr);
378
379 knobP = sPtr->floatValue * ((float)length - knobL);
380
381 if (sPtr->flags.horizontal) {
382 /* before */
383 XFillRectangle(scr->display, d, scr->stippleGC, ofs, 2, (int)knobP, view->size.height - 4);
384
385 /* knob */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000386#ifndef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200387 XFillRectangle(scr->display, d, scr->lightGC,
388 ofs + (int)knobP + 2, 2 + 2, (int)knobL - 4, view->size.height - 4 - 4);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000389#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200390 W_DrawRelief(scr, d, ofs + (int)knobP, 2, (int)knobL, view->size.height - 4, WRRaised);
391
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);
397
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);
408
409 /* knob */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000410#ifndef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200411 XFillRectangle(scr->display, d, scr->lightGC,
412 2 + 2, ofs + (int)knobP + 2, view->size.width - 4 - 4, (int)knobL - 4);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000413#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200414 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);
419
420 W_DrawRelief(scr, d, 2, ofs + (int)knobP, view->size.width - 4, (int)knobL, WRRaised);
421
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));
427 }
428
429 if (sPtr->flags.arrowsPosition != WSANone) {
430 paintArrow(sPtr, d, 0);
431 paintArrow(sPtr, d, 1);
432 }
433 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000434
435#ifdef DOUBLE_BUFFER
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200436 XCopyArea(scr->display, d, view->window, scr->copyGC, 0, 0, view->size.width, view->size.height, 0, 0);
437 XFreePixmap(scr->display, d);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000438#endif
439}
440
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200441static void handleEvents(XEvent * event, void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000442{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200443 Scroller *sPtr = (Scroller *) data;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000444
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200445 CHECK_CLASS(data, WC_Scroller);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000446
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200447 switch (event->type) {
448 case Expose:
449 if (event->xexpose.count == 0)
450 paintScroller(sPtr);
451 break;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000452
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200453 case DestroyNotify:
454 destroyScroller(sPtr);
455 break;
456 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000457}
458
9d2e6ef9 scottc1998-09-29 22:36:29 +0000459/*
460 * locatePointInScroller-
461 * Return the part of the scroller where the point is located.
462 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200463static WMScrollerPart locatePointInScroller(Scroller * sPtr, int x, int y, int alternate)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000464{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200465 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;
469
470 /* if there is no knob... */
471 if (sPtr->flags.documentFullyVisible)
472 return WSKnobSlot;
473
474 if (sPtr->flags.horizontal)
475 c = x;
476 else
477 c = y;
478
479 /* p1 p2 p3 p4 p5 p6
480 * | | |###########| |#####| | |
481 * | < | > |###########| O |#####| < | > |
482 * | | |###########| |#####| | |
483 */
484
485 if (sPtr->flags.arrowsPosition == WSAMinEnd) {
486 p1 = 18;
487 p2 = 36;
488
489 if (sPtr->flags.horizontal) {
490 slotL = width - 36;
491 p5 = width;
492 } else {
493 slotL = height - 36;
494 p5 = height;
495 }
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;
504 }
505 p5 = p6 - 18;
506
507 p1 = p2 = 0;
508 } else {
509 /* no arrows */
510 p1 = p2 = 0;
511
512 if (sPtr->flags.horizontal) {
513 slotL = p5 = p6 = width;
514 } else {
515 slotL = p5 = p6 = height;
516 }
517 }
518
519 knobL = knobLength(sPtr);
520 p3 = p2 + (int)((float)(slotL - knobL) * sPtr->floatValue);
521 p4 = p3 + knobL;
522
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;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000538}
539
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200540static void handlePush(Scroller * sPtr, int pushX, int pushY, int alternate)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000541{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200542 WMScrollerPart part;
543 int doAction = 0;
6830b057 dan2004-10-12 21:28:27 +0000544
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200545 part = locatePointInScroller(sPtr, pushX, pushY, alternate);
6830b057 dan2004-10-12 21:28:27 +0000546
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200547 sPtr->flags.hitPart = part;
6830b057 dan2004-10-12 21:28:27 +0000548
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200549 switch (part) {
550 case WSIncrementLine:
551 sPtr->flags.incrDown = 1;
552 doAction = 1;
553 break;
6830b057 dan2004-10-12 21:28:27 +0000554
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200555 case WSIncrementPage:
556 doAction = 1;
557 break;
6830b057 dan2004-10-12 21:28:27 +0000558
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200559 case WSDecrementLine:
560 sPtr->flags.decrDown = 1;
561 doAction = 1;
562 break;
6830b057 dan2004-10-12 21:28:27 +0000563
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200564 case WSDecrementPage:
565 doAction = 1;
566 break;
6830b057 dan2004-10-12 21:28:27 +0000567
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200568 case WSKnob:
569 sPtr->flags.draggingKnob = 1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000570#ifndef STRICT_NEXT_BEHAVIOUR
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200571 if (sPtr->flags.horizontal)
572 sPtr->dragPoint = pushX;
573 else
574 sPtr->dragPoint = pushY;
575
576 {
577 int length, knobP;
578 int buttonsLen;
579
580 if (sPtr->flags.arrowsPosition != WSANone)
581 buttonsLen = 2 * (BUTTON_SIZE + 1);
582 else
583 buttonsLen = 0;
584
585 if (sPtr->flags.horizontal)
586 length = sPtr->view->size.width - 4 - buttonsLen;
587 else
588 length = sPtr->view->size.height - 4 - buttonsLen;
589
590 knobP = (int)(sPtr->floatValue * (float)(length - knobLength(sPtr)));
591
592 if (sPtr->flags.arrowsPosition == WSAMinEnd)
593 sPtr->dragPoint -= 2 + buttonsLen + knobP;
594 else
595 sPtr->dragPoint -= 2 + knobP;
596 }
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;
602
603 case WSDecrementWheel:
604 case WSIncrementWheel:
605 case WSKnobSlot:
606 case WSNoPart:
607 /* dummy */
608 break;
609 }
610
611 if (doAction && sPtr->action) {
612 (*sPtr->action) (sPtr, sPtr->clientData);
613
614 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
615 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000616}
617
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200618static float floatValueForPoint(Scroller * sPtr, int point)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000619{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200620 float floatValue = 0;
621 float position;
622 int slotOfs, slotLength, knobL;
623
624 if (sPtr->flags.horizontal)
625 slotLength = sPtr->view->size.width - 4;
626 else
627 slotLength = sPtr->view->size.height - 4;
628
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;
635 }
636
637 knobL = (float)knobLength(sPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000638#ifdef STRICT_NEXT_BEHAVIOUR
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200639 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;
645
646 floatValue = (position - (float)(slotOfs + slotLength / 2))
647 / (float)(slotLength - knobL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000648#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200649 /* 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;
656
657 /* Compute the float value */
658 floatValue = (position - (float)slotOfs) / (float)(slotLength - knobL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000659#endif
64defd4d kojima2001-02-25 20:47:04 +0000660
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200661 assert(!isnan(floatValue));
662 return floatValue;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000663}
664
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200665static void handleMotion(Scroller * sPtr, int mouseX, int mouseY)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000666{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200667 if (sPtr->flags.draggingKnob) {
668 float newFloatValue;
669 int point;
0616167b dan2001-04-29 03:24:17 +0000670
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200671 if (sPtr->flags.horizontal) {
672 point = mouseX;
673 } else {
674 point = mouseY;
675 }
0616167b dan2001-04-29 03:24:17 +0000676
677#ifndef STRICT_NEXT_BEHAVIOUR
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200678 point -= sPtr->dragPoint;
0616167b dan2001-04-29 03:24:17 +0000679#endif
680
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200681 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);
686 }
687 } else {
688 int part;
689
690 part = locatePointInScroller(sPtr, mouseX, mouseY, False);
691
692 sPtr->flags.hitPart = part;
693
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;
703 }
704 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000705}
706
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200707static void autoScroll(void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000708{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200709 Scroller *sPtr = (Scroller *) clientData;
6830b057 dan2004-10-12 21:28:27 +0000710
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200711 if (sPtr->action) {
712 (*sPtr->action) (sPtr, sPtr->clientData);
713 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
714 }
715 sPtr->timerID = WMAddTimerHandler(AUTOSCROLL_DELAY, autoScroll, clientData);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000716}
717
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200718static void handleActionEvents(XEvent * event, void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000719{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200720 Scroller *sPtr = (Scroller *) data;
721 int wheelDecrement, wheelIncrement;
722 int id, dd;
723
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);
727
728 id = sPtr->flags.incrDown;
729 dd = sPtr->flags.decrDown;
730
731 switch (event->type) {
732 case EnterNotify:
733 break;
734
735 case LeaveNotify:
736 if (sPtr->timerID) {
737 WMDeleteTimerHandler(sPtr->timerID);
738 sPtr->timerID = NULL;
739 }
740 sPtr->flags.incrDown = 0;
741 sPtr->flags.decrDown = 0;
742 break;
743
744 case ButtonPress:
745 /* FIXME: change Mod1Mask with something else */
746 if (sPtr->flags.documentFullyVisible)
747 break;
748
749 if (sPtr->flags.horizontal) {
750 wheelDecrement = WINGsConfiguration.mouseWheelDown;
751 wheelIncrement = WINGsConfiguration.mouseWheelUp;
752 } else {
753 wheelDecrement = WINGsConfiguration.mouseWheelUp;
754 wheelIncrement = WINGsConfiguration.mouseWheelDown;
755 }
756
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;
764 }
765 if (sPtr->action) {
766 (*sPtr->action) (sPtr, sPtr->clientData);
767 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
768 }
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;
776 }
777 if (sPtr->action) {
778 (*sPtr->action) (sPtr, sPtr->clientData);
779 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
780 }
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);
787 }
788 }
789 break;
790
791 case ButtonRelease:
792 if (sPtr->flags.draggingKnob) {
793 if (sPtr->action) {
794 (*sPtr->action) (sPtr, sPtr->clientData);
795 WMPostNotificationName(WMScrollerDidScrollNotification, sPtr, NULL);
796 }
797 }
798 if (sPtr->timerID) {
799 WMDeleteTimerHandler(sPtr->timerID);
800 sPtr->timerID = NULL;
801 }
802 sPtr->flags.incrDown = 0;
803 sPtr->flags.decrDown = 0;
804 sPtr->flags.draggingKnob = 0;
805 break;
806
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;
813 }
814 break;
815 }
816 if (id != sPtr->flags.incrDown || dd != sPtr->flags.decrDown)
817 paintScroller(sPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000818}
819
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200820static void destroyScroller(Scroller * sPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000821{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200822 /* we don't want autoscroll try to scroll a freed widget */
823 if (sPtr->timerID) {
824 WMDeleteTimerHandler(sPtr->timerID);
825 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000826
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200827 wfree(sPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000828}