Initial revision
[wmaker-crm.git] / WINGs / wslider.c
blob90439b74a15e0050790ee21e3dfe3074793cbeb1
5 #include "WINGsP.h"
8 #undef STRICT_NEXT_BEHAVIOUR
11 typedef struct W_Slider {
12 W_Class widgetClass;
13 WMView *view;
15 int minValue;
16 int maxValue;
18 int value;
20 Pixmap knobPixmap;
22 WMAction *action;
23 void *clientData;
25 struct {
26 unsigned int continuous:1;
28 unsigned int vertical:1;
29 unsigned int dragging:1;
30 } flags;
32 } Slider;
36 #define SLIDER_LENGTH 20
39 static void resizeSlider();
42 W_ViewProcedureTable _SliderViewProcedures = {
43 NULL,
44 resizeSlider,
45 NULL
50 static void destroySlider(Slider *sPtr);
51 static void paintSlider(Slider *sPtr);
52 static void realizeSlider(Slider *sPtr);
54 static void handleEvents(XEvent *event, void *data);
55 static void handleActionEvents(XEvent *event, void *data);
58 static void
59 realizeObserver(void *self, WMNotification *not)
61 realizeSlider(self);
66 WMSlider*
67 WMCreateSlider(WMWidget *parent)
69 Slider *sPtr;
71 sPtr = wmalloc(sizeof(Slider));
72 memset(sPtr, 0, sizeof(Slider));
74 sPtr->widgetClass = WC_Slider;
76 sPtr->view = W_CreateView(W_VIEW(parent));
77 if (!sPtr->view) {
78 free(sPtr);
79 return NULL;
81 sPtr->view->self = sPtr;
83 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask,
84 handleEvents, sPtr);
87 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
88 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
89 handleActionEvents, sPtr);
91 W_ResizeView(sPtr->view, 100, 16);
92 sPtr->flags.vertical = 0;
93 sPtr->minValue = 0;
94 sPtr->maxValue = 100;
95 sPtr->value = 50;
97 sPtr->flags.continuous = 1;
99 WMAddNotificationObserver(realizeObserver, sPtr,
100 WMViewRealizedNotification, sPtr->view);
102 return sPtr;
108 WMGetSliderMinValue(WMSlider *slider)
110 CHECK_CLASS(slider, WC_Slider);
112 return slider->minValue;
117 WMGetSliderMaxValue(WMSlider *slider)
119 CHECK_CLASS(slider, WC_Slider);
121 return slider->maxValue;
126 WMGetSliderValue(WMSlider *slider)
128 CHECK_CLASS(slider, WC_Slider);
130 return slider->value;
134 void
135 WMSetSliderMinValue(WMSlider *slider, int value)
137 CHECK_CLASS(slider, WC_Slider);
139 slider->minValue = value;
140 if (slider->value < value) {
141 slider->value = value;
142 if (slider->view->flags.mapped)
143 paintSlider(slider);
148 void
149 WMSetSliderMaxValue(WMSlider *slider, int value)
151 CHECK_CLASS(slider, WC_Slider);
153 slider->maxValue = value;
154 if (slider->value > value) {
155 slider->value = value;
156 if (slider->view->flags.mapped)
157 paintSlider(slider);
162 void
163 WMSetSliderValue(WMSlider *slider, int value)
165 CHECK_CLASS(slider, WC_Slider);
167 if (value < slider->minValue)
168 slider->value = slider->minValue;
169 else if (value > slider->maxValue)
170 slider->value = slider->maxValue;
171 else
172 slider->value = value;
174 if (slider->view->flags.mapped)
175 paintSlider(slider);
179 void
180 WMSetSliderContinuous(WMSlider *slider, Bool flag)
182 CHECK_CLASS(slider, WC_Slider);
184 slider->flags.continuous = flag;
188 void
189 WMSetSliderAction(WMSlider *slider, WMAction *action, void *data)
191 CHECK_CLASS(slider, WC_Slider);
193 slider->action = action;
194 slider->clientData = data;
198 static void
199 makeKnobPixmap(Slider *sPtr)
201 Pixmap pix;
202 WMScreen *scr = sPtr->view->screen;
203 int w, h;
205 if (sPtr->flags.vertical) {
206 w = sPtr->view->size.width-2;
207 h = SLIDER_LENGTH;
208 } else {
209 w = SLIDER_LENGTH;
210 h = sPtr->view->size.height-2;
213 pix = XCreatePixmap(scr->display, sPtr->view->window, w, h, scr->depth);
214 XFillRectangle(scr->display, pix, W_GC(scr->gray), 0, 0, w, h);
216 if (sPtr->flags.vertical) {
217 XDrawLine(scr->display, pix, W_GC(scr->white), 0, 0, 0, h-3);
218 XDrawLine(scr->display, pix, W_GC(scr->white), 1, 0, 1, h-3);
219 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w-2, 1, w-2, h/2-2);
220 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w-2, h/2, w-2, h-2);
222 XDrawLine(scr->display, pix, W_GC(scr->white), 0, 0, w-2, 0);
223 XDrawLine(scr->display, pix, W_GC(scr->darkGray), 1, h/2-2, w-3, h/2-2);
224 XDrawLine(scr->display, pix, W_GC(scr->white), 0, h/2-1, w-3, h/2-1);
225 XDrawLine(scr->display, pix, W_GC(scr->black), w-1, 0, w-1, h-2);
227 XDrawLine(scr->display, pix, W_GC(scr->darkGray), 0, h-3, w-2, h-3);
228 XDrawLine(scr->display, pix, W_GC(scr->black), 0, h-2, w-1, h-2);
229 XDrawLine(scr->display, pix, W_GC(scr->darkGray), 0, h-1, w-1,h-1);
230 } else {
231 XDrawLine(scr->display, pix, W_GC(scr->white), 0, 0, w-3, 0);
233 XDrawLine(scr->display, pix, W_GC(scr->white), 0, 0, 0, h-2);
234 XDrawLine(scr->display, pix, W_GC(scr->white), 1, 0, 1, h-3);
235 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w/2-2, 1, w/2-2, h-3);
236 XDrawLine(scr->display, pix, W_GC(scr->white), w/2-1, 0, w/2-1, h-3);
237 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w-3, 0, w-3, h-2);
238 XDrawLine(scr->display, pix, W_GC(scr->black), w-2, 0, w-2, h-2);
239 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w-1, 0, w-1, h-1);
241 XDrawLine(scr->display, pix, W_GC(scr->black), 1, h-1, w/2+1, h-1);
242 XDrawLine(scr->display, pix, W_GC(scr->darkGray), 1, h-2, w/2-2, h-2);
243 XDrawLine(scr->display, pix, W_GC(scr->darkGray), w/2, h-2, w-3,h-2);
244 XDrawLine(scr->display, pix, W_GC(scr->black), 0, h-1, w-2, h-1);
247 if (sPtr->knobPixmap)
248 XFreePixmap(scr->display, sPtr->knobPixmap);
249 sPtr->knobPixmap = pix;
253 static void
254 realizeSlider(Slider *sPtr)
256 W_RealizeView(sPtr->view);
258 makeKnobPixmap(sPtr);
262 static void
263 resizeSlider(Slider *sPtr, unsigned int width, unsigned int height)
265 assert(width > 0);
266 assert(height > 0);
268 W_ResizeView(sPtr->view, width, height);
270 if (width > height) {
271 if (sPtr->flags.vertical) {
272 sPtr->flags.vertical = 0;
273 if (sPtr->view->flags.realized)
274 makeKnobPixmap(sPtr);
276 } else {
277 if (!sPtr->flags.vertical) {
278 sPtr->flags.vertical = 1;
279 if (sPtr->view->flags.realized)
280 makeKnobPixmap(sPtr);
287 static void
288 paintSlider(Slider *sPtr)
290 W_Screen *scr = sPtr->view->screen;
291 GC bgc;
292 GC wgc;
293 GC lgc;
294 WMSize size = sPtr->view->size;
295 int pos;
296 Pixmap buffer;
298 #define MINV sPtr->minValue
299 #define MAXV sPtr->maxValue
300 #define POSV sPtr->value
302 bgc = W_GC(scr->black);
303 wgc = W_GC(scr->white);
304 lgc = W_GC(scr->gray);
306 buffer = XCreatePixmap(scr->display, sPtr->view->window,
307 size.width, size.height, scr->depth);
308 XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width, size.height);
309 XFillRectangle(scr->display, buffer, scr->stippleGC, 0, 0, size.width,
310 size.height);
312 if (sPtr->flags.vertical) {
313 pos = (size.height-2-SLIDER_LENGTH)*(POSV-MINV)/(MAXV-MINV)+1;
314 /* draw knob */
315 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
316 scr->copyGC, 0, 0, size.width-2, SLIDER_LENGTH, 1, pos);
317 } else {
318 pos = (size.width-2-SLIDER_LENGTH)*(POSV-MINV)/(MAXV-MINV)+1;
319 /* draw knob */
320 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
321 scr->copyGC, 0, 0, SLIDER_LENGTH, size.height, pos, 1);
324 XDrawLine(scr->display, buffer, bgc, 0, 0, 0, size.height-1);
325 XDrawLine(scr->display, buffer, bgc, 0, 0, size.width, 0);
327 XDrawLine(scr->display, buffer, wgc, size.width-1, 0,
328 size.width-1, size.height-1);
329 XDrawLine(scr->display, buffer, wgc, 0, size.height-1,
330 size.width-1, size.height-1);
332 XCopyArea(scr->display, buffer, sPtr->view->window, scr->copyGC, 0, 0,
333 size.width, size.height, 0, 0);
334 XFreePixmap(scr->display, buffer);
339 static void
340 handleEvents(XEvent *event, void *data)
342 Slider *sPtr = (Slider*)data;
344 CHECK_CLASS(data, WC_Slider);
347 switch (event->type) {
348 case Expose:
349 if (event->xexpose.count!=0)
350 break;
351 paintSlider(sPtr);
352 break;
354 case DestroyNotify:
355 destroySlider(sPtr);
356 break;
362 #define DECR_PART 1
363 #define KNOB_PART 2
364 #define INCR_PART 3
366 static int
367 getSliderPart(Slider *sPtr, int x, int y)
369 int p;
370 int pos;
371 WMSize size = sPtr->view->size;
374 if (sPtr->flags.vertical) {
375 p = y;
376 pos = (size.height-2-SLIDER_LENGTH)*(POSV-MINV)/(MAXV-MINV);
377 if (p < pos)
378 return INCR_PART;
379 if (p > pos + SLIDER_LENGTH)
380 return DECR_PART;
381 return KNOB_PART;
382 } else {
383 p = x;
384 pos = (size.width-2-SLIDER_LENGTH)*(POSV-MINV)/(MAXV-MINV);
385 if (p < pos)
386 return DECR_PART;
387 if (p > pos + SLIDER_LENGTH)
388 return INCR_PART;
389 return KNOB_PART;
394 static int
395 valueForMousePoint(Slider *sPtr, int x, int y)
397 WMSize size = sPtr->view->size;
398 int f;
400 if (sPtr->flags.vertical) {
401 f = (y-SLIDER_LENGTH/2)*(MAXV-MINV)/((int)size.height-2-SLIDER_LENGTH);
402 } else {
403 f = (x-SLIDER_LENGTH/2)*(MAXV-MINV)/((int)size.width-2-SLIDER_LENGTH);
406 f += sPtr->minValue;
407 if (f < sPtr->minValue)
408 f = sPtr->minValue;
409 else if (f > sPtr->maxValue)
410 f = sPtr->maxValue;
411 return f;
415 static void
416 handleActionEvents(XEvent *event, void *data)
418 WMSlider *sPtr = (Slider*)data;
420 CHECK_CLASS(data, WC_Slider);
423 switch (event->type) {
424 case ButtonPress:
425 if (getSliderPart(sPtr, event->xbutton.x, event->xbutton.y)==KNOB_PART)
426 sPtr->flags.dragging = 1;
427 else {
428 #ifdef STRICT_NEXT_BEHAVIOUR
429 sPtr->flags.dragging = 1;
431 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
432 event->xmotion.y);
433 paintSlider(sPtr);
434 #else
435 int tmp;
437 tmp = valueForMousePoint(sPtr, event->xmotion.x, event->xmotion.y);
438 if (tmp < sPtr->value)
439 tmp = sPtr->value-1;
440 else
441 tmp = sPtr->value+1;
442 WMSetSliderValue(sPtr, tmp);
443 #endif
445 if (sPtr->flags.continuous && sPtr->action) {
446 (*sPtr->action)(sPtr, sPtr->clientData);
449 break;
451 case ButtonRelease:
452 if (!sPtr->flags.continuous && sPtr->flags.dragging && sPtr->action) {
453 (*sPtr->action)(sPtr, sPtr->clientData);
455 sPtr->flags.dragging = 0;
456 break;
458 case MotionNotify:
459 if (sPtr->flags.dragging) {
460 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
461 event->xmotion.y);
462 paintSlider(sPtr);
464 if (sPtr->flags.continuous && sPtr->action) {
465 (*sPtr->action)(sPtr, sPtr->clientData);
468 break;
474 static void
475 destroySlider(Slider *sPtr)
477 if (sPtr->knobPixmap)
478 XFreePixmap(sPtr->view->screen->display, sPtr->knobPixmap);
480 free(sPtr);