8 #undef STRICT_NEXT_BEHAVIOUR
11 typedef struct W_Slider
{
29 unsigned int continuous
:1;
31 unsigned int vertical
:1;
32 unsigned int dragging
:1;
40 static void didResizeSlider();
43 W_ViewDelegate _SliderViewDelegate
= {
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
);
62 realizeObserver(void *self
, WMNotification
*not)
70 WMCreateSlider(WMWidget
*parent
)
74 sPtr
= wmalloc(sizeof(Slider
));
75 memset(sPtr
, 0, sizeof(Slider
));
77 sPtr
->widgetClass
= WC_Slider
;
79 sPtr
->view
= W_CreateView(W_VIEW(parent
));
84 sPtr
->view
->self
= sPtr
;
86 sPtr
->view
->delegate
= &_SliderViewDelegate
;
88 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
,
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;
102 sPtr
->knobThickness
= 20;
104 sPtr
->flags
.continuous
= 1;
106 WMAddNotificationObserver(realizeObserver
, sPtr
,
107 WMViewRealizedNotification
, sPtr
->view
);
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
) {
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
) {
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
;
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
)
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
)
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
;
209 slider
->value
= value
;
211 if (slider
->view
->flags
.mapped
)
217 WMSetSliderContinuous(WMSlider
*slider
, Bool flag
)
219 CHECK_CLASS(slider
, WC_Slider
);
221 slider
->flags
.continuous
= ((flag
==0) ? 0 : 1);
226 WMSetSliderAction(WMSlider
*slider
, WMAction
*action
, void *data
)
228 CHECK_CLASS(slider
, WC_Slider
);
230 slider
->action
= action
;
231 slider
->clientData
= data
;
236 makeKnobPixmap(Slider
*sPtr
)
239 WMScreen
*scr
= sPtr
->view
->screen
;
242 if (sPtr
->flags
.vertical
) {
243 w
= sPtr
->view
->size
.width
-2;
244 h
= sPtr
->knobThickness
;
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);
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
;
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
;
306 if (width
> height
) {
307 if (sPtr
->flags
.vertical
) {
308 sPtr
->flags
.vertical
= 0;
309 if (sPtr
->view
->flags
.realized
)
310 makeKnobPixmap(sPtr
);
313 if (!sPtr
->flags
.vertical
) {
314 sPtr
->flags
.vertical
= 1;
315 if (sPtr
->view
->flags
.realized
)
316 makeKnobPixmap(sPtr
);
324 paintSlider(Slider
*sPtr
)
326 W_Screen
*scr
= sPtr
->view
->screen
;
330 WMSize size
= sPtr
->view
->size
;
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);
351 XFillRectangle(scr
->display
, buffer
, lgc
, 0, 0, size
.width
,
353 XFillRectangle(scr
->display
, buffer
, scr
->stippleGC
, 0, 0, size
.width
,
357 if (sPtr
->flags
.vertical
) {
358 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
360 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
361 scr
->copyGC
, 0, 0, size
.width
-2, sPtr
->knobThickness
,
364 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
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
);
386 handleEvents(XEvent
*event
, void *data
)
388 Slider
*sPtr
= (Slider
*)data
;
390 CHECK_CLASS(data
, WC_Slider
);
393 switch (event
->type
) {
395 if (event
->xexpose
.count
!=0)
413 getSliderPart(Slider
*sPtr
, int x
, int y
)
417 WMSize size
= sPtr
->view
->size
;
420 if (sPtr
->flags
.vertical
) {
422 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
425 if (p
> pos
+ sPtr
->knobThickness
)
430 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
433 if (p
> pos
+ sPtr
->knobThickness
)
441 valueForMousePoint(Slider
*sPtr
, int x
, int y
)
443 WMSize size
= sPtr
->view
->size
;
446 if (sPtr
->flags
.vertical
) {
447 f
= (y
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
448 / ((int)size
.height
-2-sPtr
->knobThickness
);
450 f
= (x
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
451 / ((int)size
.width
-2-sPtr
->knobThickness
);
455 if (f
< sPtr
->minValue
)
457 else if (f
> sPtr
->maxValue
)
465 handleActionEvents(XEvent
*event
, void *data
)
467 WMSlider
*sPtr
= (Slider
*)data
;
469 CHECK_CLASS(data
, WC_Slider
);
472 switch (event
->type
) {
474 if (event
->xbutton
.button
==WINGsConfiguration
.mouseWheelUp
475 &&!sPtr
->flags
.dragging
) {
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
) {
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
)
496 sPtr
->flags
.dragging
= 1;
498 #ifdef STRICT_NEXT_BEHAVIOUR
499 sPtr
->flags
.dragging
= 1;
501 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
507 if (event
->xbutton
.button
== Button2
) {
508 sPtr
->flags
.dragging
= 1;
510 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
514 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
516 if (tmp
< sPtr
->value
)
520 WMSetSliderValue(sPtr
, tmp
);
524 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
525 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
531 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
532 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
534 sPtr
->flags
.dragging
= 0;
538 if (sPtr
->flags
.dragging
) {
539 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
543 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
544 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
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
);