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 resizeSlider();
43 W_ViewProcedureTable _SliderViewProcedures
= {
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
);
61 realizeObserver(void *self
, WMNotification
*not)
69 WMCreateSlider(WMWidget
*parent
)
73 sPtr
= wmalloc(sizeof(Slider
));
74 memset(sPtr
, 0, sizeof(Slider
));
76 sPtr
->widgetClass
= WC_Slider
;
78 sPtr
->view
= W_CreateView(W_VIEW(parent
));
83 sPtr
->view
->self
= sPtr
;
85 WMCreateEventHandler(sPtr
->view
, ExposureMask
|StructureNotifyMask
,
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;
99 sPtr
->knobThickness
= 20;
101 sPtr
->flags
.continuous
= 1;
103 WMAddNotificationObserver(realizeObserver
, sPtr
,
104 WMViewRealizedNotification
, sPtr
->view
);
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
) {
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
) {
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
;
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
)
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
)
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
;
206 slider
->value
= value
;
208 if (slider
->view
->flags
.mapped
)
214 WMSetSliderContinuous(WMSlider
*slider
, Bool flag
)
216 CHECK_CLASS(slider
, WC_Slider
);
218 slider
->flags
.continuous
= flag
;
223 WMSetSliderAction(WMSlider
*slider
, WMAction
*action
, void *data
)
225 CHECK_CLASS(slider
, WC_Slider
);
227 slider
->action
= action
;
228 slider
->clientData
= data
;
233 makeKnobPixmap(Slider
*sPtr
)
236 WMScreen
*scr
= sPtr
->view
->screen
;
239 if (sPtr
->flags
.vertical
) {
240 w
= sPtr
->view
->size
.width
-2;
241 h
= sPtr
->knobThickness
;
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);
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
;
294 realizeSlider(Slider
*sPtr
)
296 W_RealizeView(sPtr
->view
);
298 makeKnobPixmap(sPtr
);
303 resizeSlider(Slider
*sPtr
, unsigned int width
, unsigned int height
)
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
);
317 if (!sPtr
->flags
.vertical
) {
318 sPtr
->flags
.vertical
= 1;
319 if (sPtr
->view
->flags
.realized
)
320 makeKnobPixmap(sPtr
);
328 paintSlider(Slider
*sPtr
)
330 W_Screen
*scr
= sPtr
->view
->screen
;
334 WMSize size
= sPtr
->view
->size
;
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);
355 XFillRectangle(scr
->display
, buffer
, lgc
, 0, 0, size
.width
,
357 XFillRectangle(scr
->display
, buffer
, scr
->stippleGC
, 0, 0, size
.width
,
361 if (sPtr
->flags
.vertical
) {
362 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
364 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
365 scr
->copyGC
, 0, 0, size
.width
-2, sPtr
->knobThickness
,
368 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
)+1;
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
);
390 handleEvents(XEvent
*event
, void *data
)
392 Slider
*sPtr
= (Slider
*)data
;
394 CHECK_CLASS(data
, WC_Slider
);
397 switch (event
->type
) {
399 if (event
->xexpose
.count
!=0)
417 getSliderPart(Slider
*sPtr
, int x
, int y
)
421 WMSize size
= sPtr
->view
->size
;
424 if (sPtr
->flags
.vertical
) {
426 pos
= (size
.height
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
429 if (p
> pos
+ sPtr
->knobThickness
)
434 pos
= (size
.width
-2-sPtr
->knobThickness
)*(POSV
-MINV
)/(MAXV
-MINV
);
437 if (p
> pos
+ sPtr
->knobThickness
)
445 valueForMousePoint(Slider
*sPtr
, int x
, int y
)
447 WMSize size
= sPtr
->view
->size
;
450 if (sPtr
->flags
.vertical
) {
451 f
= (y
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
452 / ((int)size
.height
-2-sPtr
->knobThickness
);
454 f
= (x
-sPtr
->knobThickness
/2)*(MAXV
-MINV
)
455 / ((int)size
.width
-2-sPtr
->knobThickness
);
459 if (f
< sPtr
->minValue
)
461 else if (f
> sPtr
->maxValue
)
469 handleActionEvents(XEvent
*event
, void *data
)
471 WMSlider
*sPtr
= (Slider
*)data
;
473 CHECK_CLASS(data
, WC_Slider
);
476 switch (event
->type
) {
478 if (getSliderPart(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
)==KNOB_PART
)
479 sPtr
->flags
.dragging
= 1;
481 #ifdef STRICT_NEXT_BEHAVIOUR
482 sPtr
->flags
.dragging
= 1;
484 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
490 if (event
->xbutton
.button
== Button2
) {
491 sPtr
->flags
.dragging
= 1;
493 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
497 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
499 if (tmp
< sPtr
->value
)
503 WMSetSliderValue(sPtr
, tmp
);
507 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
508 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
514 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
515 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
517 sPtr
->flags
.dragging
= 0;
521 if (sPtr
->flags
.dragging
) {
522 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
,
526 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
527 (*sPtr
->action
)(sPtr
, sPtr
->clientData
);
537 destroySlider(Slider
*sPtr
)
539 if (sPtr
->knobPixmap
)
540 XFreePixmap(sPtr
->view
->screen
->display
, sPtr
->knobPixmap
);
542 if (sPtr
->backPixmap
)
543 WMReleasePixmap(sPtr
->backPixmap
);
545 WMRemoveNotificationObserver(sPtr
);