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
);
55 static void realizeSlider(Slider
*sPtr
);
57 static void handleEvents(XEvent
*event
, void *data
);
58 static void handleActionEvents(XEvent
*event
, void *data
);
60 static void makeKnobPixmap(Slider
*sPtr
);
63 realizeObserver(void *self
, WMNotification
*not)
71 WMCreateSlider(WMWidget
*parent
)
75 sPtr
= wmalloc(sizeof(Slider
));
76 memset(sPtr
, 0, sizeof(Slider
));
78 sPtr
->widgetClass
= WC_Slider
;
80 sPtr
->view
= W_CreateView(W_VIEW(parent
));
85 sPtr
->view
->self
= sPtr
;
87 sPtr
->view
->delegate
= &_SliderViewDelegate
;
89 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
,
93 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
|ButtonReleaseMask
94 |EnterWindowMask
|LeaveWindowMask
|ButtonMotionMask
,
95 handleActionEvents
, sPtr
);
97 W_ResizeView(sPtr
->view
, 100, 16);
98 sPtr
->flags
.vertical
= 0;
100 sPtr
->maxValue
= 100;
103 sPtr
->knobThickness
= 20;
105 sPtr
->flags
.continuous
= 1;
107 WMAddNotificationObserver(realizeObserver
, sPtr
,
108 WMViewRealizedNotification
, sPtr
->view
);
115 WMSetSliderImage(WMSlider
*sPtr
, WMPixmap
*pixmap
)
117 if (sPtr
->backPixmap
)
118 WMReleasePixmap(sPtr
->backPixmap
);
120 sPtr
->backPixmap
= WMRetainPixmap(pixmap
);
122 if (sPtr
->view
->flags
.mapped
) {
129 WMSetSliderKnobThickness(WMSlider
*sPtr
, int thickness
)
131 assert(thickness
> 0);
133 sPtr
->knobThickness
= thickness
;
135 if (sPtr
->knobPixmap
) {
136 makeKnobPixmap(sPtr
);
139 if (sPtr
->view
->flags
.mapped
) {
146 WMGetSliderMinValue(WMSlider
*slider
)
148 CHECK_CLASS(slider
, WC_Slider
);
150 return slider
->minValue
;
155 WMGetSliderMaxValue(WMSlider
*slider
)
157 CHECK_CLASS(slider
, WC_Slider
);
159 return slider
->maxValue
;
164 WMGetSliderValue(WMSlider
*slider
)
166 CHECK_CLASS(slider
, WC_Slider
);
168 return slider
->value
;
173 WMSetSliderMinValue(WMSlider
*slider
, int value
)
175 CHECK_CLASS(slider
, WC_Slider
);
177 slider
->minValue
= value
;
178 if (slider
->value
< value
) {
179 slider
->value
= value
;
180 if (slider
->view
->flags
.mapped
)
187 WMSetSliderMaxValue(WMSlider
*slider
, int value
)
189 CHECK_CLASS(slider
, WC_Slider
);
191 slider
->maxValue
= value
;
192 if (slider
->value
> value
) {
193 slider
->value
= value
;
194 if (slider
->view
->flags
.mapped
)
201 WMSetSliderValue(WMSlider
*slider
, int value
)
203 CHECK_CLASS(slider
, WC_Slider
);
205 if (value
< slider
->minValue
)
206 slider
->value
= slider
->minValue
;
207 else if (value
> slider
->maxValue
)
208 slider
->value
= slider
->maxValue
;
210 slider
->value
= value
;
212 if (slider
->view
->flags
.mapped
)
218 WMSetSliderContinuous(WMSlider
*slider
, Bool flag
)
220 CHECK_CLASS(slider
, WC_Slider
);
222 slider
->flags
.continuous
= flag
;
227 WMSetSliderAction(WMSlider
*slider
, WMAction
*action
, void *data
)
229 CHECK_CLASS(slider
, WC_Slider
);
231 slider
->action
= action
;
232 slider
->clientData
= data
;
237 makeKnobPixmap(Slider
*sPtr
)
240 WMScreen
*scr
= sPtr
->view
->screen
;
243 if (sPtr
->flags
.vertical
) {
244 w
= sPtr
->view
->size
.width
-2;
245 h
= sPtr
->knobThickness
;
247 w
= sPtr
->knobThickness
;
248 h
= sPtr
->view
->size
.height
-2;
251 pix
= XCreatePixmap(scr
->display
, sPtr
->view
->window
, w
, h
, scr
->depth
);
252 XFillRectangle(scr
->display
, pix
, WMColorGC(scr
->gray
), 0, 0, w
, h
);
254 if (sPtr
->knobThickness
< 10) {
255 W_DrawRelief(scr
, pix
, 0, 0, w
, h
, WRRaised
);
256 } else if (sPtr
->flags
.vertical
) {
257 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
-3);
258 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
-3);
259 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
-2, 1, w
-2, h
/2-2);
260 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
-2, h
/2, w
-2, h
-2);
262 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
-2, 0);
263 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
/2-2, w
-3, h
/2-2);
264 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, h
/2-1, w
-3, h
/2-1);
266 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
-1, 0, w
-1, h
-2);
268 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
-3, w
-2, h
-3);
269 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
-2, w
-1, h
-2);
270 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
-1, w
-1,h
-1);
272 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
-3, 0);
274 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
-2);
276 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
-3);
277 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/2-2, 1, w
/2-2, h
-3);
278 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), w
/2-1, 0, w
/2-1, h
-3);
280 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
-3, 0, w
-3, h
-2);
281 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
-2, 0, w
-2, h
-2);
282 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
-1, 0, w
-1, h
-1);
284 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 1, h
-1, w
/2+1, h
-1);
285 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
-2, w
/2-2, h
-2);
286 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/2, h
-2, w
-3,h
-2);
288 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
-1, w
-2, h
-1);
291 if (sPtr
->knobPixmap
)
292 XFreePixmap(scr
->display
, sPtr
->knobPixmap
);
293 sPtr
->knobPixmap
= pix
;
298 realizeSlider(Slider
*sPtr
)
300 W_RealizeView(sPtr
->view
);
302 makeKnobPixmap(sPtr
);
307 didResizeSlider(W_ViewDelegate
*self
, WMView
*view
)
309 Slider
*sPtr
= (Slider
*)view
->self
;
310 int width
= sPtr
->view
->size
.width
;
311 int height
= sPtr
->view
->size
.height
;
316 if (width
> height
) {
317 if (sPtr
->flags
.vertical
) {
318 sPtr
->flags
.vertical
= 0;
319 if (sPtr
->view
->flags
.realized
)
320 makeKnobPixmap(sPtr
);
323 if (!sPtr
->flags
.vertical
) {
324 sPtr
->flags
.vertical
= 1;
325 if (sPtr
->view
->flags
.realized
)
326 makeKnobPixmap(sPtr
);
334 paintSlider(Slider
*sPtr
)
336 W_Screen
*scr
= sPtr
->view
->screen
;
340 WMSize size
= sPtr
->view
->size
;
344 #define MINV sPtr->minValue
345 #define MAXV sPtr->maxValue
346 #define POSV sPtr->value
348 bgc
= WMColorGC(scr
->black
);
349 wgc
= WMColorGC(scr
->white
);
350 lgc
= WMColorGC(scr
->gray
);
352 buffer
= XCreatePixmap(scr
->display
, sPtr
->view
->window
,
353 size
.width
, size
.height
, scr
->depth
);
355 if (sPtr
->backPixmap
) {
356 WMSize size
= WMGetPixmapSize(sPtr
->backPixmap
);
358 XCopyArea(scr
->display
, WMGetPixmapXID(sPtr
->backPixmap
),
359 buffer
, scr
->copyGC
, 0, 0, size
.width
, size
.height
, 1, 1);
361 XFillRectangle(scr
->display
, buffer
, lgc
, 0, 0, size
.width
,
363 XFillRectangle(scr
->display
, buffer
, scr
->stippleGC
, 0, 0, size
.width
,
367 if (sPtr
->flags
.vertical
) {
368 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
370 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
371 scr
->copyGC
, 0, 0, size
.width
-2, sPtr
->knobThickness
,
374 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
376 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
377 scr
->copyGC
, 0, 0, sPtr
->knobThickness
, size
.height
, pos
, 1);
380 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, 0, size
.height
-1);
381 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, size
.width
, 0);
383 XDrawLine(scr
->display
, buffer
, wgc
, size
.width
-1, 0,
384 size
.width
-1, size
.height
-1);
385 XDrawLine(scr
->display
, buffer
, wgc
, 0, size
.height
-1,
386 size
.width
-1, size
.height
-1);
388 XCopyArea(scr
->display
, buffer
, sPtr
->view
->window
, scr
->copyGC
, 0, 0,
389 size
.width
, size
.height
, 0, 0);
390 XFreePixmap(scr
->display
, buffer
);
396 handleEvents(XEvent
*event
, void *data
)
398 Slider
*sPtr
= (Slider
*)data
;
400 CHECK_CLASS(data
, WC_Slider
);
403 switch (event
->type
) {
405 if (event
->xexpose
.count
!=0)
423 getSliderPart(Slider
*sPtr
, int x
, int y
)
427 WMSize size
= sPtr
->view
->size
;
430 if (sPtr
->flags
.vertical
) {
432 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
435 if (p
> pos
+ sPtr
->knobThickness
)
440 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
443 if (p
> pos
+ sPtr
->knobThickness
)
451 valueForMousePoint(Slider
*sPtr
, int x
, int y
)
453 WMSize size
= sPtr
->view
->size
;
456 if (sPtr
->flags
.vertical
) {
457 f
= (y
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
458 / ((int)size
.height
-2-sPtr
->knobThickness
);
460 f
= (x
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
461 / ((int)size
.width
-2-sPtr
->knobThickness
);
465 if (f
< sPtr
->minValue
)
467 else if (f
> sPtr
->maxValue
)
475 handleActionEvents(XEvent
*event
, void *data
)
477 WMSlider
*sPtr
= (Slider
*)data
;
479 CHECK_CLASS(data
, WC_Slider
);
482 switch (event
->type
) {
484 if (getSliderPart(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
)==KNOB_PART
)
485 sPtr
->flags
.dragging
= 1;
487 #ifdef STRICT_NEXT_BEHAVIOUR
488 sPtr
->flags
.dragging
= 1;
490 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
496 if (event
->xbutton
.button
== Button2
) {
497 sPtr
->flags
.dragging
= 1;
499 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
503 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
505 if (tmp
< sPtr
->value
)
509 WMSetSliderValue(sPtr
, tmp
);
513 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
514 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
520 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
521 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
523 sPtr
->flags
.dragging
= 0;
527 if (sPtr
->flags
.dragging
) {
528 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
532 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
533 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
543 destroySlider(Slider
*sPtr
)
545 if (sPtr
->knobPixmap
)
546 XFreePixmap(sPtr
->view
->screen
->display
, sPtr
->knobPixmap
);
548 if (sPtr
->backPixmap
)
549 WMReleasePixmap(sPtr
->backPixmap
);
551 WMRemoveNotificationObserver(sPtr
);