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(W_ViewDelegate
* self
, WMView
* view
);
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 sPtr
->widgetClass
= WC_Slider
;
62 sPtr
->view
= W_CreateView(W_VIEW(parent
));
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;
82 sPtr
->knobThickness
= 20;
84 sPtr
->flags
.continuous
= 1;
86 WMAddNotificationObserver(realizeObserver
, sPtr
, WMViewRealizedNotification
, sPtr
->view
);
91 void WMSetSliderImage(WMSlider
* sPtr
, WMPixmap
* pixmap
)
94 WMReleasePixmap(sPtr
->backPixmap
);
96 sPtr
->backPixmap
= WMRetainPixmap(pixmap
);
98 if (sPtr
->view
->flags
.mapped
) {
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
) {
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
)
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
)
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
;
172 slider
->value
= value
;
174 if (slider
->view
->flags
.mapped
)
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
)
196 WMScreen
*scr
= sPtr
->view
->screen
;
199 if (sPtr
->flags
.vertical
) {
200 w
= sPtr
->view
->size
.width
- 2;
201 h
= sPtr
->knobThickness
;
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);
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
;
261 if (width
> height
) {
262 if (sPtr
->flags
.vertical
) {
263 sPtr
->flags
.vertical
= 0;
264 if (sPtr
->view
->flags
.realized
)
265 makeKnobPixmap(sPtr
);
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
;
282 WMSize size
= sPtr
->view
->size
;
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);
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;
309 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
310 scr
->copyGC
, 0, 0, size
.width
- 2, sPtr
->knobThickness
, 1, pos
);
312 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
) + 1;
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
) {
336 if (event
->xexpose
.count
!= 0)
352 static int getSliderPart(Slider
* sPtr
, int x
, int y
)
356 WMSize size
= sPtr
->view
->size
;
358 if (sPtr
->flags
.vertical
) {
360 pos
= (size
.height
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
363 if (p
> pos
+ sPtr
->knobThickness
)
368 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
371 if (p
> pos
+ sPtr
->knobThickness
)
377 static int valueForMousePoint(Slider
* sPtr
, int x
, int y
)
379 WMSize size
= sPtr
->view
->size
;
382 if (sPtr
->flags
.vertical
) {
383 f
= (y
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
384 / ((int)size
.height
- 2 - sPtr
->knobThickness
);
386 f
= (x
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
387 / ((int)size
.width
- 2 - sPtr
->knobThickness
);
391 if (f
< sPtr
->minValue
)
393 else if (f
> sPtr
->maxValue
)
399 static void handleActionEvents(XEvent
* event
, void *data
)
401 WMSlider
*sPtr
= (Slider
*) data
;
403 CHECK_CLASS(data
, WC_Slider
);
405 switch (event
->type
) {
407 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
&& !sPtr
->flags
.dragging
) {
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
) {
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
)
425 sPtr
->flags
.dragging
= 1;
427 #ifdef STRICT_NEXT_BEHAVIOUR
428 sPtr
->flags
.dragging
= 1;
430 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
435 if (event
->xbutton
.button
== Button2
) {
436 sPtr
->flags
.dragging
= 1;
438 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
441 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
442 if (tmp
< sPtr
->value
)
443 tmp
= sPtr
->value
- 1;
445 tmp
= sPtr
->value
+ 1;
446 WMSetSliderValue(sPtr
, tmp
);
450 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
451 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
457 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
458 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
460 sPtr
->flags
.dragging
= 0;
464 if (sPtr
->flags
.dragging
) {
465 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
468 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
469 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
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
);