Icon creation in only one function
[wmaker-crm.git] / WINGs / wslider.c
blob1ee7dae727aeb2afea7032e39d77ecae0f9bd95c
2 #include "WINGsP.h"
4 #undef STRICT_NEXT_BEHAVIOUR
6 typedef struct W_Slider {
7 W_Class widgetClass;
8 WMView *view;
10 int minValue;
11 int maxValue;
13 int value;
15 Pixmap knobPixmap;
16 WMPixmap *backPixmap;
18 WMAction *action;
19 void *clientData;
21 int knobThickness;
23 struct {
24 unsigned int continuous:1;
26 unsigned int vertical:1;
27 unsigned int dragging:1;
28 } flags;
30 } Slider;
32 static void didResizeSlider();
34 W_ViewDelegate _SliderViewDelegate = {
35 NULL,
36 NULL,
37 didResizeSlider,
38 NULL,
39 NULL
42 static void destroySlider(Slider * sPtr);
43 static void paintSlider(Slider * sPtr);
45 static void handleEvents(XEvent * event, void *data);
46 static void handleActionEvents(XEvent * event, void *data);
48 static void makeKnobPixmap(Slider * sPtr);
50 static void realizeObserver(void *self, WMNotification * not)
52 makeKnobPixmap(self);
55 WMSlider *WMCreateSlider(WMWidget * parent)
57 Slider *sPtr;
59 sPtr = wmalloc(sizeof(Slider));
60 sPtr->widgetClass = WC_Slider;
62 sPtr->view = W_CreateView(W_VIEW(parent));
63 if (!sPtr->view) {
64 wfree(sPtr);
65 return NULL;
67 sPtr->view->self = sPtr;
69 sPtr->view->delegate = &_SliderViewDelegate;
71 WMCreateEventHandler(sPtr->view, ExposureMask | StructureNotifyMask, handleEvents, sPtr);
73 WMCreateEventHandler(sPtr->view, ButtonPressMask | ButtonReleaseMask
74 | EnterWindowMask | LeaveWindowMask | ButtonMotionMask, handleActionEvents, sPtr);
76 W_ResizeView(sPtr->view, 100, 16);
77 sPtr->flags.vertical = 0;
78 sPtr->minValue = 0;
79 sPtr->maxValue = 100;
80 sPtr->value = 50;
82 sPtr->knobThickness = 20;
84 sPtr->flags.continuous = 1;
86 WMAddNotificationObserver(realizeObserver, sPtr, WMViewRealizedNotification, sPtr->view);
88 return sPtr;
91 void WMSetSliderImage(WMSlider * sPtr, WMPixmap * pixmap)
93 if (sPtr->backPixmap)
94 WMReleasePixmap(sPtr->backPixmap);
96 sPtr->backPixmap = WMRetainPixmap(pixmap);
98 if (sPtr->view->flags.mapped) {
99 paintSlider(sPtr);
103 void WMSetSliderKnobThickness(WMSlider * sPtr, int thickness)
105 assert(thickness > 0);
107 sPtr->knobThickness = thickness;
109 if (sPtr->knobPixmap) {
110 makeKnobPixmap(sPtr);
113 if (sPtr->view->flags.mapped) {
114 paintSlider(sPtr);
118 int WMGetSliderMinValue(WMSlider * slider)
120 CHECK_CLASS(slider, WC_Slider);
122 return slider->minValue;
125 int WMGetSliderMaxValue(WMSlider * slider)
127 CHECK_CLASS(slider, WC_Slider);
129 return slider->maxValue;
132 int WMGetSliderValue(WMSlider * slider)
134 CHECK_CLASS(slider, WC_Slider);
136 return slider->value;
139 void WMSetSliderMinValue(WMSlider * slider, int value)
141 CHECK_CLASS(slider, WC_Slider);
143 slider->minValue = value;
144 if (slider->value < value) {
145 slider->value = value;
146 if (slider->view->flags.mapped)
147 paintSlider(slider);
151 void WMSetSliderMaxValue(WMSlider * slider, int value)
153 CHECK_CLASS(slider, WC_Slider);
155 slider->maxValue = value;
156 if (slider->value > value) {
157 slider->value = value;
158 if (slider->view->flags.mapped)
159 paintSlider(slider);
163 void 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);
178 void WMSetSliderContinuous(WMSlider * slider, Bool flag)
180 CHECK_CLASS(slider, WC_Slider);
182 slider->flags.continuous = ((flag == 0) ? 0 : 1);
185 void WMSetSliderAction(WMSlider * slider, WMAction * action, void *data)
187 CHECK_CLASS(slider, WC_Slider);
189 slider->action = action;
190 slider->clientData = data;
193 static void makeKnobPixmap(Slider * sPtr)
195 Pixmap pix;
196 WMScreen *scr = sPtr->view->screen;
197 int w, h;
199 if (sPtr->flags.vertical) {
200 w = sPtr->view->size.width - 2;
201 h = sPtr->knobThickness;
202 } else {
203 w = sPtr->knobThickness;
204 h = sPtr->view->size.height - 2;
207 pix = XCreatePixmap(scr->display, sPtr->view->window, w, h, scr->depth);
208 XFillRectangle(scr->display, pix, WMColorGC(scr->gray), 0, 0, w, h);
210 if (sPtr->knobThickness < 10) {
211 W_DrawRelief(scr, pix, 0, 0, w, h, WRRaised);
212 } else if (sPtr->flags.vertical) {
213 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h - 3);
214 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h - 3);
215 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w - 2, 1, w - 2, h / 2 - 2);
216 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w - 2, h / 2, w - 2, h - 2);
218 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w - 2, 0);
219 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h / 2 - 2, w - 3, h / 2 - 2);
220 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, h / 2 - 1, w - 3, h / 2 - 1);
222 XDrawLine(scr->display, pix, WMColorGC(scr->black), w - 1, 0, w - 1, h - 2);
224 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h - 3, w - 2, h - 3);
225 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h - 2, w - 1, h - 2);
226 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 0, h - 1, w - 1, h - 1);
227 } else {
228 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, w - 3, 0);
230 XDrawLine(scr->display, pix, WMColorGC(scr->white), 0, 0, 0, h - 2);
232 XDrawLine(scr->display, pix, WMColorGC(scr->white), 1, 0, 1, h - 3);
233 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w / 2 - 2, 1, w / 2 - 2, h - 3);
234 XDrawLine(scr->display, pix, WMColorGC(scr->white), w / 2 - 1, 0, w / 2 - 1, h - 3);
236 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w - 3, 0, w - 3, h - 2);
237 XDrawLine(scr->display, pix, WMColorGC(scr->black), w - 2, 0, w - 2, h - 2);
238 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w - 1, 0, w - 1, h - 1);
240 XDrawLine(scr->display, pix, WMColorGC(scr->black), 1, h - 1, w / 2 + 1, h - 1);
241 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), 1, h - 2, w / 2 - 2, h - 2);
242 XDrawLine(scr->display, pix, WMColorGC(scr->darkGray), w / 2, h - 2, w - 3, h - 2);
244 XDrawLine(scr->display, pix, WMColorGC(scr->black), 0, h - 1, w - 2, h - 1);
247 if (sPtr->knobPixmap)
248 XFreePixmap(scr->display, sPtr->knobPixmap);
249 sPtr->knobPixmap = pix;
252 static void didResizeSlider(W_ViewDelegate * self, WMView * view)
254 Slider *sPtr = (Slider *) view->self;
255 int width = sPtr->view->size.width;
256 int height = sPtr->view->size.height;
258 assert(width > 0);
259 assert(height > 0);
261 if (width > height) {
262 if (sPtr->flags.vertical) {
263 sPtr->flags.vertical = 0;
264 if (sPtr->view->flags.realized)
265 makeKnobPixmap(sPtr);
267 } else {
268 if (!sPtr->flags.vertical) {
269 sPtr->flags.vertical = 1;
270 if (sPtr->view->flags.realized)
271 makeKnobPixmap(sPtr);
276 static void paintSlider(Slider * sPtr)
278 W_Screen *scr = sPtr->view->screen;
279 GC bgc;
280 GC wgc;
281 GC lgc;
282 WMSize size = sPtr->view->size;
283 int pos;
284 Pixmap buffer;
286 #define MINV sPtr->minValue
287 #define MAXV sPtr->maxValue
288 #define POSV sPtr->value
290 bgc = WMColorGC(scr->black);
291 wgc = WMColorGC(scr->white);
292 lgc = WMColorGC(scr->gray);
294 buffer = XCreatePixmap(scr->display, sPtr->view->window, size.width, size.height, scr->depth);
296 if (sPtr->backPixmap) {
297 WMSize size = WMGetPixmapSize(sPtr->backPixmap);
299 XCopyArea(scr->display, WMGetPixmapXID(sPtr->backPixmap),
300 buffer, scr->copyGC, 0, 0, size.width, size.height, 1, 1);
301 } else {
302 XFillRectangle(scr->display, buffer, lgc, 0, 0, size.width, size.height);
303 XFillRectangle(scr->display, buffer, scr->stippleGC, 0, 0, size.width, size.height);
306 if (sPtr->flags.vertical) {
307 pos = (size.height - 2 - sPtr->knobThickness) * (POSV - MINV) / (MAXV - MINV) + 1;
308 /* draw knob */
309 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
310 scr->copyGC, 0, 0, size.width - 2, sPtr->knobThickness, 1, pos);
311 } else {
312 pos = (size.width - 2 - sPtr->knobThickness) * (POSV - MINV) / (MAXV - MINV) + 1;
313 /* draw knob */
314 XCopyArea(scr->display, sPtr->knobPixmap, buffer,
315 scr->copyGC, 0, 0, sPtr->knobThickness, size.height, pos, 1);
318 XDrawLine(scr->display, buffer, bgc, 0, 0, 0, size.height - 1);
319 XDrawLine(scr->display, buffer, bgc, 0, 0, size.width, 0);
321 XDrawLine(scr->display, buffer, wgc, size.width - 1, 0, size.width - 1, size.height - 1);
322 XDrawLine(scr->display, buffer, wgc, 0, size.height - 1, size.width - 1, size.height - 1);
324 XCopyArea(scr->display, buffer, sPtr->view->window, scr->copyGC, 0, 0, size.width, size.height, 0, 0);
325 XFreePixmap(scr->display, buffer);
328 static void handleEvents(XEvent * event, void *data)
330 Slider *sPtr = (Slider *) data;
332 CHECK_CLASS(data, WC_Slider);
334 switch (event->type) {
335 case Expose:
336 if (event->xexpose.count != 0)
337 break;
338 paintSlider(sPtr);
339 break;
341 case DestroyNotify:
342 destroySlider(sPtr);
343 break;
348 #define DECR_PART 1
349 #define KNOB_PART 2
350 #define INCR_PART 3
352 static int getSliderPart(Slider * sPtr, int x, int y)
354 int p;
355 int pos;
356 WMSize size = sPtr->view->size;
358 if (sPtr->flags.vertical) {
359 p = y;
360 pos = (size.height - 2 - sPtr->knobThickness) * (POSV - MINV) / (MAXV - MINV);
361 if (p < pos)
362 return INCR_PART;
363 if (p > pos + sPtr->knobThickness)
364 return DECR_PART;
365 return KNOB_PART;
366 } else {
367 p = x;
368 pos = (size.width - 2 - sPtr->knobThickness) * (POSV - MINV) / (MAXV - MINV);
369 if (p < pos)
370 return DECR_PART;
371 if (p > pos + sPtr->knobThickness)
372 return INCR_PART;
373 return KNOB_PART;
377 static int valueForMousePoint(Slider * sPtr, int x, int y)
379 WMSize size = sPtr->view->size;
380 int f;
382 if (sPtr->flags.vertical) {
383 f = (y - sPtr->knobThickness / 2) * (MAXV - MINV)
384 / ((int)size.height - 2 - sPtr->knobThickness);
385 } else {
386 f = (x - sPtr->knobThickness / 2) * (MAXV - MINV)
387 / ((int)size.width - 2 - sPtr->knobThickness);
390 f += sPtr->minValue;
391 if (f < sPtr->minValue)
392 f = sPtr->minValue;
393 else if (f > sPtr->maxValue)
394 f = sPtr->maxValue;
396 return f;
399 static void handleActionEvents(XEvent * event, void *data)
401 WMSlider *sPtr = (Slider *) data;
403 CHECK_CLASS(data, WC_Slider);
405 switch (event->type) {
406 case ButtonPress:
407 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp && !sPtr->flags.dragging) {
408 /* Wheel up */
409 if (sPtr->value + 1 <= sPtr->maxValue) {
410 WMSetSliderValue(sPtr, sPtr->value + 1);
411 if (sPtr->flags.continuous && sPtr->action) {
412 (*sPtr->action) (sPtr, sPtr->clientData);
415 } else if (event->xbutton.button == WINGsConfiguration.mouseWheelDown && !sPtr->flags.dragging) {
416 /* Wheel down */
417 if (sPtr->value - 1 >= sPtr->minValue) {
418 WMSetSliderValue(sPtr, sPtr->value - 1);
419 if (sPtr->flags.continuous && sPtr->action) {
420 (*sPtr->action) (sPtr, sPtr->clientData);
423 } else if (getSliderPart(sPtr, event->xbutton.x, event->xbutton.y)
424 == KNOB_PART)
425 sPtr->flags.dragging = 1;
426 else {
427 #ifdef STRICT_NEXT_BEHAVIOUR
428 sPtr->flags.dragging = 1;
430 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x, event->xmotion.y);
431 paintSlider(sPtr);
432 #else
433 int tmp;
435 if (event->xbutton.button == Button2) {
436 sPtr->flags.dragging = 1;
438 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x, event->xmotion.y);
439 paintSlider(sPtr);
440 } else {
441 tmp = valueForMousePoint(sPtr, event->xmotion.x, event->xmotion.y);
442 if (tmp < sPtr->value)
443 tmp = sPtr->value - 1;
444 else
445 tmp = sPtr->value + 1;
446 WMSetSliderValue(sPtr, tmp);
448 #endif
450 if (sPtr->flags.continuous && sPtr->action) {
451 (*sPtr->action) (sPtr, sPtr->clientData);
454 break;
456 case ButtonRelease:
457 if (!sPtr->flags.continuous && sPtr->action) {
458 (*sPtr->action) (sPtr, sPtr->clientData);
460 sPtr->flags.dragging = 0;
461 break;
463 case MotionNotify:
464 if (sPtr->flags.dragging) {
465 sPtr->value = valueForMousePoint(sPtr, event->xmotion.x, event->xmotion.y);
466 paintSlider(sPtr);
468 if (sPtr->flags.continuous && sPtr->action) {
469 (*sPtr->action) (sPtr, sPtr->clientData);
472 break;
476 static void destroySlider(Slider * sPtr)
478 if (sPtr->knobPixmap)
479 XFreePixmap(sPtr->view->screen->display, sPtr->knobPixmap);
481 if (sPtr->backPixmap)
482 WMReleasePixmap(sPtr->backPixmap);
484 WMRemoveNotificationObserver(sPtr);
486 wfree(sPtr);