4 #undef STRICT_NEXT_BEHAVIOUR
6 typedef struct W_Slider
{
24 unsigned int continuous
:1;
26 unsigned int vertical
:1;
27 unsigned int dragging
:1;
32 static void didResizeSlider();
34 W_ViewDelegate _SliderViewDelegate
= {
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)
55 WMSlider
*WMCreateSlider(WMWidget
* parent
)
59 sPtr
= wmalloc(sizeof(Slider
));
60 memset(sPtr
, 0, sizeof(Slider
));
62 sPtr
->widgetClass
= WC_Slider
;
64 sPtr
->view
= W_CreateView(W_VIEW(parent
));
69 sPtr
->view
->self
= sPtr
;
71 sPtr
->view
->delegate
= &_SliderViewDelegate
;
73 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
, handleEvents
, sPtr
);
75 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
76 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
78 W_ResizeView(sPtr
->view
, 100, 16);
79 sPtr
->flags
.vertical
= 0;
84 sPtr
->knobThickness
= 20;
86 sPtr
->flags
.continuous
= 1;
88 WMAddNotificationObserver(realizeObserver
, sPtr
, WMViewRealizedNotification
, sPtr
->view
);
93 void WMSetSliderImage(WMSlider
* sPtr
, WMPixmap
* pixmap
)
96 WMReleasePixmap(sPtr
->backPixmap
);
98 sPtr
->backPixmap
= WMRetainPixmap(pixmap
);
100 if (sPtr
->view
->flags
.mapped
) {
105 void WMSetSliderKnobThickness(WMSlider
* sPtr
, int thickness
)
107 assert(thickness
> 0);
109 sPtr
->knobThickness
= thickness
;
111 if (sPtr
->knobPixmap
) {
112 makeKnobPixmap(sPtr
);
115 if (sPtr
->view
->flags
.mapped
) {
120 int WMGetSliderMinValue(WMSlider
* slider
)
122 CHECK_CLASS(slider
, WC_Slider
);
124 return slider
->minValue
;
127 int WMGetSliderMaxValue(WMSlider
* slider
)
129 CHECK_CLASS(slider
, WC_Slider
);
131 return slider
->maxValue
;
134 int WMGetSliderValue(WMSlider
* slider
)
136 CHECK_CLASS(slider
, WC_Slider
);
138 return slider
->value
;
141 void WMSetSliderMinValue(WMSlider
* slider
, int value
)
143 CHECK_CLASS(slider
, WC_Slider
);
145 slider
->minValue
= value
;
146 if (slider
->value
< value
) {
147 slider
->value
= value
;
148 if (slider
->view
->flags
.mapped
)
153 void WMSetSliderMaxValue(WMSlider
* slider
, int value
)
155 CHECK_CLASS(slider
, WC_Slider
);
157 slider
->maxValue
= value
;
158 if (slider
->value
> value
) {
159 slider
->value
= value
;
160 if (slider
->view
->flags
.mapped
)
165 void WMSetSliderValue(WMSlider
* slider
, int value
)
167 CHECK_CLASS(slider
, WC_Slider
);
169 if (value
< slider
->minValue
)
170 slider
->value
= slider
->minValue
;
171 else if (value
> slider
->maxValue
)
172 slider
->value
= slider
->maxValue
;
174 slider
->value
= value
;
176 if (slider
->view
->flags
.mapped
)
180 void WMSetSliderContinuous(WMSlider
* slider
, Bool flag
)
182 CHECK_CLASS(slider
, WC_Slider
);
184 slider
->flags
.continuous
= ((flag
== 0) ? 0 : 1);
187 void WMSetSliderAction(WMSlider
* slider
, WMAction
* action
, void *data
)
189 CHECK_CLASS(slider
, WC_Slider
);
191 slider
->action
= action
;
192 slider
->clientData
= data
;
195 static void makeKnobPixmap(Slider
* sPtr
)
198 WMScreen
*scr
= sPtr
->view
->screen
;
201 if (sPtr
->flags
.vertical
) {
202 w
= sPtr
->view
->size
.width
- 2;
203 h
= sPtr
->knobThickness
;
205 w
= sPtr
->knobThickness
;
206 h
= sPtr
->view
->size
.height
- 2;
209 pix
= XCreatePixmap(scr
->display
, sPtr
->view
->window
, w
, h
, scr
->depth
);
210 XFillRectangle(scr
->display
, pix
, WMColorGC(scr
->gray
), 0, 0, w
, h
);
212 if (sPtr
->knobThickness
< 10) {
213 W_DrawRelief(scr
, pix
, 0, 0, w
, h
, WRRaised
);
214 } else if (sPtr
->flags
.vertical
) {
215 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
- 3);
216 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
- 3);
217 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 2, 1, w
- 2, h
/ 2 - 2);
218 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 2, h
/ 2, w
- 2, h
- 2);
220 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
- 2, 0);
221 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
/ 2 - 2, w
- 3, h
/ 2 - 2);
222 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, h
/ 2 - 1, w
- 3, h
/ 2 - 1);
224 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
- 1, 0, w
- 1, h
- 2);
226 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
- 3, w
- 2, h
- 3);
227 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
- 2, w
- 1, h
- 2);
228 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
- 1, w
- 1, h
- 1);
230 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
- 3, 0);
232 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
- 2);
234 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
- 3);
235 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/ 2 - 2, 1, w
/ 2 - 2, h
- 3);
236 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), w
/ 2 - 1, 0, w
/ 2 - 1, h
- 3);
238 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 3, 0, w
- 3, h
- 2);
239 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
- 2, 0, w
- 2, h
- 2);
240 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 1, 0, w
- 1, h
- 1);
242 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 1, h
- 1, w
/ 2 + 1, h
- 1);
243 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
- 2, w
/ 2 - 2, h
- 2);
244 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/ 2, h
- 2, w
- 3, h
- 2);
246 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
- 1, w
- 2, h
- 1);
249 if (sPtr
->knobPixmap
)
250 XFreePixmap(scr
->display
, sPtr
->knobPixmap
);
251 sPtr
->knobPixmap
= pix
;
254 static void didResizeSlider(W_ViewDelegate
* self
, WMView
* view
)
256 Slider
*sPtr
= (Slider
*) view
->self
;
257 int width
= sPtr
->view
->size
.width
;
258 int height
= sPtr
->view
->size
.height
;
263 if (width
> height
) {
264 if (sPtr
->flags
.vertical
) {
265 sPtr
->flags
.vertical
= 0;
266 if (sPtr
->view
->flags
.realized
)
267 makeKnobPixmap(sPtr
);
270 if (!sPtr
->flags
.vertical
) {
271 sPtr
->flags
.vertical
= 1;
272 if (sPtr
->view
->flags
.realized
)
273 makeKnobPixmap(sPtr
);
278 static void paintSlider(Slider
* sPtr
)
280 W_Screen
*scr
= sPtr
->view
->screen
;
284 WMSize size
= sPtr
->view
->size
;
288 #define MINV sPtr->minValue
289 #define MAXV sPtr->maxValue
290 #define POSV sPtr->value
292 bgc
= WMColorGC(scr
->black
);
293 wgc
= WMColorGC(scr
->white
);
294 lgc
= WMColorGC(scr
->gray
);
296 buffer
= XCreatePixmap(scr
->display
, sPtr
->view
->window
, size
.width
, size
.height
, scr
->depth
);
298 if (sPtr
->backPixmap
) {
299 WMSize size
= WMGetPixmapSize(sPtr
->backPixmap
);
301 XCopyArea(scr
->display
, WMGetPixmapXID(sPtr
->backPixmap
),
302 buffer
, scr
->copyGC
, 0, 0, size
.width
, size
.height
, 1, 1);
304 XFillRectangle(scr
->display
, buffer
, lgc
, 0, 0, size
.width
, size
.height
);
305 XFillRectangle(scr
->display
, buffer
, scr
->stippleGC
, 0, 0, size
.width
, size
.height
);
308 if (sPtr
->flags
.vertical
) {
309 pos
= (size
.height
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
) + 1;
311 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
312 scr
->copyGC
, 0, 0, size
.width
- 2, sPtr
->knobThickness
, 1, pos
);
314 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
) + 1;
316 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
317 scr
->copyGC
, 0, 0, sPtr
->knobThickness
, size
.height
, pos
, 1);
320 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, 0, size
.height
- 1);
321 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, size
.width
, 0);
323 XDrawLine(scr
->display
, buffer
, wgc
, size
.width
- 1, 0, size
.width
- 1, size
.height
- 1);
324 XDrawLine(scr
->display
, buffer
, wgc
, 0, size
.height
- 1, size
.width
- 1, size
.height
- 1);
326 XCopyArea(scr
->display
, buffer
, sPtr
->view
->window
, scr
->copyGC
, 0, 0, size
.width
, size
.height
, 0, 0);
327 XFreePixmap(scr
->display
, buffer
);
330 static void handleEvents(XEvent
* event
, void *data
)
332 Slider
*sPtr
= (Slider
*) data
;
334 CHECK_CLASS(data
, WC_Slider
);
336 switch (event
->type
) {
338 if (event
->xexpose
.count
!= 0)
354 static int getSliderPart(Slider
* sPtr
, int x
, int y
)
358 WMSize size
= sPtr
->view
->size
;
360 if (sPtr
->flags
.vertical
) {
362 pos
= (size
.height
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
365 if (p
> pos
+ sPtr
->knobThickness
)
370 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
373 if (p
> pos
+ sPtr
->knobThickness
)
379 static int valueForMousePoint(Slider
* sPtr
, int x
, int y
)
381 WMSize size
= sPtr
->view
->size
;
384 if (sPtr
->flags
.vertical
) {
385 f
= (y
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
386 / ((int)size
.height
- 2 - sPtr
->knobThickness
);
388 f
= (x
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
389 / ((int)size
.width
- 2 - sPtr
->knobThickness
);
393 if (f
< sPtr
->minValue
)
395 else if (f
> sPtr
->maxValue
)
401 static void handleActionEvents(XEvent
* event
, void *data
)
403 WMSlider
*sPtr
= (Slider
*) data
;
405 CHECK_CLASS(data
, WC_Slider
);
407 switch (event
->type
) {
409 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
&& !sPtr
->flags
.dragging
) {
411 if (sPtr
->value
+ 1 <= sPtr
->maxValue
) {
412 WMSetSliderValue(sPtr
, sPtr
->value
+ 1);
413 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
414 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
417 } else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
&& !sPtr
->flags
.dragging
) {
419 if (sPtr
->value
- 1 >= sPtr
->minValue
) {
420 WMSetSliderValue(sPtr
, sPtr
->value
- 1);
421 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
422 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
425 } else if (getSliderPart(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
)
427 sPtr
->flags
.dragging
= 1;
429 #ifdef STRICT_NEXT_BEHAVIOUR
430 sPtr
->flags
.dragging
= 1;
432 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
437 if (event
->xbutton
.button
== Button2
) {
438 sPtr
->flags
.dragging
= 1;
440 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
443 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
444 if (tmp
< sPtr
->value
)
445 tmp
= sPtr
->value
- 1;
447 tmp
= sPtr
->value
+ 1;
448 WMSetSliderValue(sPtr
, tmp
);
452 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
453 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
459 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
460 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
462 sPtr
->flags
.dragging
= 0;
466 if (sPtr
->flags
.dragging
) {
467 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
470 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
471 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
478 static void destroySlider(Slider
* sPtr
)
480 if (sPtr
->knobPixmap
)
481 XFreePixmap(sPtr
->view
->screen
->display
, sPtr
->knobPixmap
);
483 if (sPtr
->backPixmap
)
484 WMReleasePixmap(sPtr
->backPixmap
);
486 WMRemoveNotificationObserver(sPtr
);