show workspace name when changing workspace
[wmaker-crm.git] / WINGs / wslider.c
blob7910dab2e5dcf9e326d32934da6c1e4a2775138c
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 resizeSlider();
43 W_ViewProcedureTable _SliderViewProcedures = {
44 NULL,
45 resizeSlider,
46 NULL
51 static void destroySlider(Slider *sPtr);
52 static void paintSlider(Slider *sPtr);
53 static void realizeSlider(Slider *sPtr);
55 static void handleEvents(XEvent *event, void *data);
56 static void handleActionEvents(XEvent *event, void *data);
58 static void makeKnobPixmap(Slider *sPtr);
60 static void
61 realizeObserver(void *self, WMNotification *not)
63 realizeSlider(self);
68 WMSlider*
69 WMCreateSlider(WMWidget *parent)
71 Slider *sPtr;
73 sPtr = wmalloc(sizeof(Slider));
74 memset(sPtr, 0, sizeof(Slider));
76 sPtr->widgetClass = WC_Slider;
78 sPtr->view = W_CreateView(W_VIEW(parent));
79 if (!sPtr->view) {
80 free(sPtr);
81 return NULL;
83 sPtr->view->self = sPtr;
85 WMCreateEventHandler(sPtr->view, ExposureMask|StructureNotifyMask,
86 handleEvents, sPtr);
89 WMCreateEventHandler(sPtr->view, ButtonPressMask|ButtonReleaseMask
90 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
91 handleActionEvents, sPtr);
93 W_ResizeView(sPtr->view, 100, 16);
94 sPtr->flags.vertical = 0;
95 sPtr->minValue = 0;
96 sPtr->maxValue = 100;
97 sPtr->value = 50;
99 sPtr->knobThickness = 20;
101 sPtr->flags.continuous = 1;
103 WMAddNotificationObserver(realizeObserver, sPtr,
104 WMViewRealizedNotification, sPtr->view);
106 return sPtr;
110 void
111 WMSetSliderImage(WMSlider *sPtr, WMPixmap *pixmap)
113 if (sPtr->backPixmap)
114 WMReleasePixmap(sPtr->backPixmap);
116 sPtr->backPixmap = WMRetainPixmap(pixmap);
118 if (sPtr->view->flags.mapped) {
119 paintSlider(sPtr);
124 void
125 WMSetSliderKnobThickness(WMSlider *sPtr, int thickness)
127 assert(thickness > 0);
129 sPtr->knobThickness = thickness;
131 if (sPtr->knobPixmap) {
132 makeKnobPixmap(sPtr);
135 if (sPtr->view->flags.mapped) {
136 paintSlider(sPtr);
142 WMGetSliderMinValue(WMSlider *slider)
144 CHECK_CLASS(slider, WC_Slider);
146 return slider->minValue;
151 WMGetSliderMaxValue(WMSlider *slider)
153 CHECK_CLASS(slider, WC_Slider);
155 return slider->maxValue;
160 WMGetSliderValue(WMSlider *slider)
162 CHECK_CLASS(slider, WC_Slider);
164 return slider->value;
168 void
169 WMSetSliderMinValue(WMSlider *slider, int value)
171 CHECK_CLASS(slider, WC_Slider);
173 slider->minValue = value;
174 if (slider->value < value) {
175 slider->value = value;
176 if (slider->view->flags.mapped)
177 paintSlider(slider);
182 void
183 WMSetSliderMaxValue(WMSlider *slider, int value)
185 CHECK_CLASS(slider, WC_Slider);
187 slider->maxValue = value;
188 if (slider->value > value) {
189 slider->value = value;
190 if (slider->view->flags.mapped)
191 paintSlider(slider);
196 void
197 WMSetSliderValue(WMSlider *slider, int value)
199 CHECK_CLASS(slider, WC_Slider);
201 if (value < slider->minValue)
202 slider->value = slider->minValue;
203 else if (value > slider->maxValue)
204 slider->value = slider->maxValue;
205 else
206 slider->value = value;
208 if (slider->view->flags.mapped)
209 paintSlider(slider);
213 void
214 WMSetSliderContinuous(WMSlider *slider, Bool flag)
216 CHECK_CLASS(slider, WC_Slider);
218 slider->flags.continuous = flag;
222 void
223 WMSetSliderAction(WMSlider *slider, WMAction *action, void *data)
225 CHECK_CLASS(slider, WC_Slider);
227 slider->action = action;
228 slider->clientData = data;
232 static void
233 makeKnobPixmap(Slider *sPtr)
235 Pixmap pix;
236 WMScreen *scr = sPtr->view->screen;
237 int w, h;
239 if (sPtr->flags.vertical) {
240 w = sPtr->view->size.width-2;
241 h = sPtr->knobThickness;
242 } else {
243 w = sPtr->knobThickness;
244 h = sPtr->view->size.height-2;
247 pix = XCreatePixmap(scr->display, sPtr->view->window, w, h, scr->depth);
248 XFillRectangle(scr->display, pix, WMColorGC(scr->gray), 0, 0, w, h);
250 if (sPtr->knobThickness < 10) {
251 W_DrawRelief(scr, pix, 0, 0, w, h, WRRaised);
252 } else if (sPtr->flags.vertical) {
253 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-3);
254 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
255 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, 1, w-2, h/2-2);
256 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-2, h/2, w-2, h-2);
258 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-2, 0);
259 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h/2-2, w-3, h/2-2);
260 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, h/2-1, w-3, h/2-1);
262 XDrawLine(scr->display, pix, WMColorGC(scr->black), w-1, 0, w-1, h-2);
264 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-3, w-2, h-3);
265 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-2, w-1, h-2);
266 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h-1, w-1,h-1);
267 } else {
268 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w-3, 0);
270 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h-2);
272 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h-3);
273 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2-2, 1, w/2-2, h-3);
274 XDrawLine(scr->display, pix, WMColorGC(scr->white), w/2-1, 0, w/2-1, h-3);
276 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-3, 0, w-3, h-2);
277 XDrawLine(scr->display, pix, WMColorGC(scr->black), w-2, 0, w-2, h-2);
278 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w-1, 0, w-1, h-1);
280 XDrawLine(scr->display, pix, WMColorGC(scr->black), 1, h-1, w/2+1, h-1);
281 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h-2, w/2-2, h-2);
282 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w/2, h-2, w-3,h-2);
284 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h-1, w-2, h-1);
287 if (sPtr->knobPixmap)
288 XFreePixmap(scr->display, sPtr->knobPixmap);
289 sPtr->knobPixmap = pix;
293 static void
294 realizeSlider(Slider *sPtr)
296 W_RealizeView(sPtr->view);
298 makeKnobPixmap(sPtr);
302 static void
303 resizeSlider(Slider *sPtr, unsigned int width, unsigned int height)
305 assert(width > 0);
306 assert(height > 0);
308 W_ResizeView(sPtr->view, width, height);
310 if (width > height) {
311 if (sPtr->flags.vertical) {
312 sPtr->flags.vertical = 0;
313 if (sPtr->view->flags.realized)
314 makeKnobPixmap(sPtr);
316 } else {
317 if (!sPtr->flags.vertical) {
318 sPtr->flags.vertical = 1;
319 if (sPtr->view->flags.realized)
320 makeKnobPixmap(sPtr);
327 static void
328 paintSlider(Slider *sPtr)
330 W_Screen *scr = sPtr->view->screen;
331 GC bgc;
332 GC wgc;
333 GC lgc;
334 WMSize size = sPtr->view->size;
335 int pos;
336 Pixmap buffer;
338 #define MINV sPtr->minValue
339 #define MAXV sPtr->maxValue
340 #define POSV sPtr->value
342 bgc = WMColorGC(scr->black);
343 wgc = WMColorGC(scr->white);
344 lgc = WMColorGC(scr->gray);
346 buffer = XCreatePixmap(scr->display, sPtr->view->window,
347 size.width, size.height, scr->depth);
349 if (sPtr->backPixmap) {
350 WMSize size = WMGetPixmapSize(sPtr->backPixmap);
352 XCopyArea(scr->display, WMGetPixmapXID(sPtr->backPixmap),
353 buffer, scr->copyGC, 0, 0, size.width, size.height, 1, 1);
354 } else {
355 XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width,
356 size.height);
357 XFillRectangle(scr->display, buffer, scr->stippleGC, 0, 0, size.width,
358 size.height);
361 if (sPtr->flags.vertical) {
362 pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
363 /* draw knob */
364 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
365 scr->copyGC, 0, 0, size.width-2, sPtr->knobThickness,
366 1, pos);
367 } else {
368 pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV)+1;
369 /* draw knob */
370 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
371 scr->copyGC, 0, 0, sPtr->knobThickness, size.height, pos, 1);
374 XDrawLine(scr->display, buffer, bgc, 0, 0, 0, size.height-1);
375 XDrawLine(scr->display, buffer, bgc, 0, 0, size.width, 0);
377 XDrawLine(scr->display, buffer, wgc, size.width-1, 0,
378 size.width-1, size.height-1);
379 XDrawLine(scr->display, buffer, wgc, 0, size.height-1,
380 size.width-1, size.height-1);
382 XCopyArea(scr->display, buffer, sPtr->view->window, scr->copyGC, 0, 0,
383 size.width, size.height, 0, 0);
384 XFreePixmap(scr->display, buffer);
389 static void
390 handleEvents(XEvent *event, void *data)
392 Slider *sPtr = (Slider*)data;
394 CHECK_CLASS(data, WC_Slider);
397 switch (event->type) {
398 case Expose:
399 if (event->xexpose.count!=0)
400 break;
401 paintSlider(sPtr);
402 break;
404 case DestroyNotify:
405 destroySlider(sPtr);
406 break;
412 #define DECR_PART 1
413 #define KNOB_PART 2
414 #define INCR_PART 3
416 static int
417 getSliderPart(Slider *sPtr, int x, int y)
419 int p;
420 int pos;
421 WMSize size = sPtr->view->size;
424 if (sPtr->flags.vertical) {
425 p = y;
426 pos = (size.height-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
427 if (p < pos)
428 return INCR_PART;
429 if (p > pos + sPtr->knobThickness)
430 return DECR_PART;
431 return KNOB_PART;
432 } else {
433 p = x;
434 pos = (size.width-2-sPtr->knobThickness)*(POSV-MINV)/(MAXV-MINV);
435 if (p < pos)
436 return DECR_PART;
437 if (p > pos + sPtr->knobThickness)
438 return INCR_PART;
439 return KNOB_PART;
444 static int
445 valueForMousePoint(Slider *sPtr, int x, int y)
447 WMSize size = sPtr->view->size;
448 int f;
450 if (sPtr->flags.vertical) {
451 f = (y-sPtr->knobThickness/2)*(MAXV-MINV)
452 / ((int)size.height-2-sPtr->knobThickness);
453 } else {
454 f = (x-sPtr->knobThickness/2)*(MAXV-MINV)
455 / ((int)size.width-2-sPtr->knobThickness);
458 f += sPtr->minValue;
459 if (f < sPtr->minValue)
460 f = sPtr->minValue;
461 else if (f > sPtr->maxValue)
462 f = sPtr->maxValue;
464 return f;
468 static void
469 handleActionEvents(XEvent *event, void *data)
471 WMSlider *sPtr = (Slider*)data;
472 int ovalue = sPtr->value;
474 CHECK_CLASS(data, WC_Slider);
477 switch (event->type) {
478 case ButtonPress:
479 if (getSliderPart(sPtr, event->xbutton.x, event->xbutton.y)==KNOB_PART)
480 sPtr->flags.dragging = 1;
481 else {
482 #ifdef STRICT_NEXT_BEHAVIOUR
483 sPtr->flags.dragging = 1;
485 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
486 event->xmotion.y);
487 paintSlider(sPtr);
488 #else
489 int tmp;
491 if (event->xbutton.button == Button2) {
492 sPtr->flags.dragging = 1;
494 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
495 event->xmotion.y);
496 paintSlider(sPtr);
497 } else {
498 tmp = valueForMousePoint(sPtr, event->xmotion.x,
499 event->xmotion.y);
500 if (tmp < sPtr->value)
501 tmp = sPtr->value-1;
502 else
503 tmp = sPtr->value+1;
504 WMSetSliderValue(sPtr, tmp);
506 #endif
508 if (sPtr->flags.continuous && sPtr->action) {
509 (*sPtr->action)(sPtr, sPtr->clientData);
512 break;
514 case ButtonRelease:
515 if (!sPtr->flags.continuous && ovalue != sPtr->value && sPtr->action) {
516 (*sPtr->action)(sPtr, sPtr->clientData);
518 sPtr->flags.dragging = 0;
519 break;
521 case MotionNotify:
522 if (sPtr->flags.dragging) {
523 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x,
524 event->xmotion.y);
525 paintSlider(sPtr);
527 if (sPtr->flags.continuous && sPtr->action) {
528 (*sPtr->action)(sPtr, sPtr->clientData);
531 break;
537 static void
538 destroySlider(Slider *sPtr)
540 if (sPtr->knobPixmap)
541 XFreePixmap(sPtr->view->screen->display, sPtr->knobPixmap);
543 if (sPtr->backPixmap)
544 WMReleasePixmap(sPtr->backPixmap);
546 WMRemoveNotificationObserver(sPtr);
548 free(sPtr);