updated changelog
[wmaker-crm.git] / WINGs / wslider.c
blob7815bc7938ee90fe80a27c9fbf5f9392f70e596b
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;
21 WMPixmap *backPixmap;
23 WMAction *action;
24 void *clientData;
26 int knobThickness;
28 struct {
29 unsigned int continuous:1;
31 unsigned int vertical:1;
32 unsigned int dragging:1;
33 } flags;
35 } Slider;
40 static void didResizeSlider();
43 W_ViewDelegate _SliderViewDelegate = {
44 NULL,
45 NULL,
46 didResizeSlider,
47 NULL,
48 NULL
53 static void destroySlider(Slider *sPtr);
54 static void paintSlider(Slider *sPtr);
56 static void handleEvents(XEvent *event, void *data);
57 static void handleActionEvents(XEvent *event, void *data);
59 static void makeKnobPixmap(Slider *sPtr);
61 static void
62 realizeObserver(void *self, WMNotification *not)
64 makeKnobPixmap(self);
69 WMSlider*
70 WMCreateSlider(WMWidget *parent)
72 Slider *sPtr;
74 sPtr = wmalloc(sizeof(Slider));
75 memset(sPtr, 0, sizeof(Slider));
77 sPtr->widgetClass = WC_Slider;
79 sPtr->view = W_CreateView(W_VIEW(parent));
80 if (!sPtr->view) {
81 wfree(sPtr);
82 return NULL;
84 sPtr->view->self = sPtr;
86 sPtr->view->delegate = &_SliderViewDelegate;
88 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask,
89 handleEvents, sPtr);
92 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
93 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
94 handleActionEvents, sPtr);
96 W_ResizeView(sPtr->view, 100, 16);
97 sPtr->flags.vertical = 0;
98 sPtr->minValue = 0;
99 sPtr->maxValue = 100;
100 sPtr->value = 50;
102 sPtr->knobThickness = 20;
104 sPtr->flags.continuous = 1;
106 WMAddNotificationObserver(realizeObserver, sPtr,
107 WMViewRealizedNotification, sPtr->view);
109 return sPtr;
113 void
114 WMSetSliderImage(WMSlider *sPtr, WMPixmap *pixmap)
116 if (sPtr->backPixmap)
117 WMReleasePixmap(sPtr->backPixmap);
119 sPtr->backPixmap = WMRetainPixmap(pixmap);
121 if (sPtr->view->flags.mapped) {
122 paintSlider(sPtr);
127 void
128 WMSetSliderKnobThickness(WMSlider *sPtr, int thickness)
130 assert(thickness > 0);
132 sPtr->knobThickness = thickness;
134 if (sPtr->knobPixmap) {
135 makeKnobPixmap(sPtr);
138 if (sPtr->view->flags.mapped) {
139 paintSlider(sPtr);
145 WMGetSliderMinValue(WMSlider *slider)
147 CHECK_CLASS(slider, WC_Slider);
149 return slider->minValue;
154 WMGetSliderMaxValue(WMSlider *slider)
156 CHECK_CLASS(slider, WC_Slider);
158 return slider->maxValue;
163 WMGetSliderValue(WMSlider *slider)
165 CHECK_CLASS(slider, WC_Slider);
167 return slider->value;
171 void
172 WMSetSliderMinValue(WMSlider *slider, int value)
174 CHECK_CLASS(slider, WC_Slider);
176 slider->minValue = value;
177 if (slider->value < value) {
178 slider->value = value;
179 if (slider->view->flags.mapped)
180 paintSlider(slider);
185 void
186 WMSetSliderMaxValue(WMSlider *slider, int value)
188 CHECK_CLASS(slider, WC_Slider);
190 slider->maxValue = value;
191 if (slider->value > value) {
192 slider->value = value;
193 if (slider->view->flags.mapped)
194 paintSlider(slider);
199 void
200 WMSetSliderValue(WMSlider *slider, int value)
202 CHECK_CLASS(slider, WC_Slider);
204 if (value < slider->minValue)
205 slider->value = slider->minValue;
206 else if (value > slider->maxValue)
207 slider->value = slider->maxValue;
208 else
209 slider->value = value;
211 if (slider->view->flags.mapped)
212 paintSlider(slider);
216 void
217 WMSetSliderContinuous(WMSlider *slider, Bool flag)
219 CHECK_CLASS(slider, WC_Slider);
221 slider->flags.continuous = ((flag==0) ? 0 : 1);
225 void
226 WMSetSliderAction(WMSlider *slider, WMAction *action, void *data)
228 CHECK_CLASS(slider, WC_Slider);
230 slider->action = action;
231 slider->clientData = data;
235 static void
236 makeKnobPixmap(Slider *sPtr)
238 Pixmap pix;
239 WMScreen *scr = sPtr->view->screen;
240 int w, h;
242 if (sPtr->flags.vertical) {
243 w = sPtr->view->size.width-2;
244 h = sPtr->knobThickness;
245 } else {
246 w = sPtr->knobThickness;
247 h = sPtr->view->size.height-2;
250 pix = XCreatePixmap(scr->display, sPtr->view->window, w, h, scr->depth);
251 XFillRectangle(scr->display, pix, WMColorGC(scr->gray), 0, 0, w, h);
253 if (sPtr->knobThickness < 10) {
254 W_DrawRelief(scr, pix, 0, 0, w, h, WRRaised);
255 } else if (sPtr->flags.vertical) {
256 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-3);
257 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
258 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, 1, w-2, h/2-2);
259 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, h/2, w-2, h-2);
261 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-2, 0);
262 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h/2-2, w-3, h/2-2);
263 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, h/2-1, w-3, h/2-1);
265 XDrawLine(scr->display, pix, WMColorGC(scr->black), w-1, 0, w-1, h-2);
267 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-3, w-2, h-3);
268 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-2, w-1, h-2);
269 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-1, w-1,h-1);
270 } else {
271 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-3, 0);
273 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-2);
275 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
276 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2-2, 1, w/2-2, h-3);
277 XDrawLine(scr->display, pix, WMColorGC(scr->white), w/2-1, 0, w/2-1, h-3);
279 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-3, 0, w-3, h-2);
280 XDrawLine(scr->display, pix, WMColorGC(scr->black), w-2, 0, w-2, h-2);
281 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-1, 0, w-1, h-1);
283 XDrawLine(scr->display, pix, WMColorGC(scr->black), 1, h-1, w/2+1, h-1);
284 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h-2, w/2-2, h-2);
285 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2, h-2, w-3,h-2);
287 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-1, w-2, h-1);
290 if (sPtr->knobPixmap)
291 XFreePixmap(scr->display, sPtr->knobPixmap);
292 sPtr->knobPixmap = pix;
296 static void
297 didResizeSlider(W_ViewDelegate *self, WMView *view)
299 Slider *sPtr = (Slider*)view->self;
300 int width = sPtr->view->size.width;
301 int height = sPtr->view->size.height;
303 assert(width > 0);
304 assert(height > 0);
306 if (width > height) {
307 if (sPtr->flags.vertical) {
308 sPtr->flags.vertical = 0;
309 if (sPtr->view->flags.realized)
310 makeKnobPixmap(sPtr);
312 } else {
313 if (!sPtr->flags.vertical) {
314 sPtr->flags.vertical = 1;
315 if (sPtr->view->flags.realized)
316 makeKnobPixmap(sPtr);
323 static void
324 paintSlider(Slider *sPtr)
326 W_Screen *scr = sPtr->view->screen;
327 GC bgc;
328 GC wgc;
329 GC lgc;
330 WMSize size = sPtr->view->size;
331 int pos;
332 Pixmap buffer;
334 #define MINV sPtr->minValue
335 #define MAXV sPtr->maxValue
336 #define POSV sPtr->value
338 bgc = WMColorGC(scr->black);
339 wgc = WMColorGC(scr->white);
340 lgc = WMColorGC(scr->gray);
342 buffer = XCreatePixmap(scr->display, sPtr->view->window,
343 size.width, size.height, scr->depth);
345 if (sPtr->backPixmap) {
346 WMSize size = WMGetPixmapSize(sPtr->backPixmap);
348 XCopyArea(scr->display, WMGetPixmapXID(sPtr->backPixmap),
349 buffer, scr->copyGC, 0, 0, size.width, size.height, 1, 1);
350 } else {
351 XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width,
352 size.height);
353 XFillRectangle(scr->display, buffer, scr->stippleGC, 0, 0, size.width,
354 size.height);
357 if (sPtr->flags.vertical) {
358 pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
359 /* draw knob */
360 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
361 scr->copyGC, 0, 0, size.width-2, sPtr->knobThickness,
362 1, pos);
363 } else {
364 pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
365 /* draw knob */
366 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
367 scr->copyGC, 0, 0, sPtr->knobThickness, size.height, pos, 1);
370 XDrawLine(scr->display, buffer, bgc, 0, 0, 0, size.height-1);
371 XDrawLine(scr->display, buffer, bgc, 0, 0, size.width, 0);
373 XDrawLine(scr->display, buffer, wgc, size.width-1, 0,
374 size.width-1, size.height-1);
375 XDrawLine(scr->display, buffer, wgc, 0, size.height-1,
376 size.width-1, size.height-1);
378 XCopyArea(scr->display, buffer, sPtr->view->window, scr->copyGC, 0, 0,
379 size.width, size.height, 0, 0);
380 XFreePixmap(scr->display, buffer);
385 static void
386 handleEvents(XEvent *event, void *data)
388 Slider *sPtr = (Slider*)data;
390 CHECK_CLASS(data, WC_Slider);
393 switch (event->type) {
394 case Expose:
395 if (event->xexpose.count!=0)
396 break;
397 paintSlider(sPtr);
398 break;
400 case DestroyNotify:
401 destroySlider(sPtr);
402 break;
408 #define DECR_PART 1
409 #define KNOB_PART 2
410 #define INCR_PART 3
412 static int
413 getSliderPart(Slider *sPtr, int x, int y)
415 int p;
416 int pos;
417 WMSize size = sPtr->view->size;
420 if (sPtr->flags.vertical) {
421 p = y;
422 pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
423 if (p < pos)
424 return INCR_PART;
425 if (p > pos + sPtr->knobThickness)
426 return DECR_PART;
427 return KNOB_PART;
428 } else {
429 p = x;
430 pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
431 if (p < pos)
432 return DECR_PART;
433 if (p > pos + sPtr->knobThickness)
434 return INCR_PART;
435 return KNOB_PART;
440 static int
441 valueForMousePoint(Slider *sPtr, int x, int y)
443 WMSize size = sPtr->view->size;
444 int f;
446 if (sPtr->flags.vertical) {
447 f = (y-sPtr->knobThickness/2)*(MAXV-MINV)
448 / ((int)size.height-2-sPtr->knobThickness);
449 } else {
450 f = (x-sPtr->knobThickness/2)*(MAXV-MINV)
451 / ((int)size.width-2-sPtr->knobThickness);
454 f += sPtr->minValue;
455 if (f < sPtr->minValue)
456 f = sPtr->minValue;
457 else if (f > sPtr->maxValue)
458 f = sPtr->maxValue;
460 return f;
464 static void
465 handleActionEvents(XEvent *event, void *data)
467 WMSlider *sPtr = (Slider*)data;
469 CHECK_CLASS(data, WC_Slider);
472 switch (event->type) {
473 case ButtonPress:
474 if (event->xbutton.button==WINGsConfiguration.mouseWheelUp
475 &&!sPtr->flags.dragging) {
476 /* Wheel up */
477 if (sPtr->value+1<=sPtr->maxValue) {
478 WMSetSliderValue(sPtr, sPtr->value+1);
479 if (sPtr->flags.continuous && sPtr->action) {
480 (*sPtr->action)(sPtr, sPtr->clientData);
483 } else if (event->xbutton.button==WINGsConfiguration.mouseWheelDown
484 &&!sPtr->flags.dragging) {
485 /* Wheel down */
486 if (sPtr->value-1>=sPtr->minValue)
488 WMSetSliderValue(sPtr, sPtr->value-1);
489 if (sPtr->flags.continuous && sPtr->action) {
490 (*sPtr->action)(sPtr, sPtr->clientData);
494 else if (getSliderPart(sPtr, event->xbutton.x, event->xbutton.y)
495 ==KNOB_PART)
496 sPtr->flags.dragging = 1;
497 else {
498 #ifdef STRICT_NEXT_BEHAVIOUR
499 sPtr->flags.dragging = 1;
501 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
502 event->xmotion.y);
503 paintSlider(sPtr);
504 #else
505 int tmp;
507 if (event->xbutton.button == Button2) {
508 sPtr->flags.dragging = 1;
510 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
511 event->xmotion.y);
512 paintSlider(sPtr);
513 } else {
514 tmp = valueForMousePoint(sPtr, event->xmotion.x,
515 event->xmotion.y);
516 if (tmp < sPtr->value)
517 tmp = sPtr->value-1;
518 else
519 tmp = sPtr->value+1;
520 WMSetSliderValue(sPtr, tmp);
522 #endif
524 if (sPtr->flags.continuous && sPtr->action) {
525 (*sPtr->action)(sPtr, sPtr->clientData);
528 break;
530 case ButtonRelease:
531 if (!sPtr->flags.continuous && sPtr->action) {
532 (*sPtr->action)(sPtr, sPtr->clientData);
534 sPtr->flags.dragging = 0;
535 break;
537 case MotionNotify:
538 if (sPtr->flags.dragging) {
539 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
540 event->xmotion.y);
541 paintSlider(sPtr);
543 if (sPtr->flags.continuous && sPtr->action) {
544 (*sPtr->action)(sPtr, sPtr->clientData);
547 break;
553 static void
554 destroySlider(Slider *sPtr)
556 if (sPtr->knobPixmap)
557 XFreePixmap(sPtr->view->screen->display, sPtr->knobPixmap);
559 if (sPtr->backPixmap)
560 WMReleasePixmap(sPtr->backPixmap);
562 WMRemoveNotificationObserver(sPtr);
564 wfree(sPtr);