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)
52 /* Parameter not used, but tell the compiler that it is ok */
58 WMSlider
*WMCreateSlider(WMWidget
* parent
)
62 sPtr
= wmalloc(sizeof(Slider
));
63 sPtr
->widgetClass
= WC_Slider
;
65 sPtr
->view
= W_CreateView(W_VIEW(parent
));
70 sPtr
->view
->self
= sPtr
;
72 sPtr
->view
->delegate
= &_SliderViewDelegate
;
74 WMCreateEventHandler(sPtr
->view
, ExposureMask
| StructureNotifyMask
, handleEvents
, sPtr
);
76 WMCreateEventHandler(sPtr
->view
, ButtonPressMask
| ButtonReleaseMask
77 | EnterWindowMask
| LeaveWindowMask
| ButtonMotionMask
, handleActionEvents
, sPtr
);
79 W_ResizeView(sPtr
->view
, 100, 16);
80 sPtr
->flags
.vertical
= 0;
85 sPtr
->knobThickness
= 20;
87 sPtr
->flags
.continuous
= 1;
89 WMAddNotificationObserver(realizeObserver
, sPtr
, WMViewRealizedNotification
, sPtr
->view
);
94 void WMSetSliderImage(WMSlider
* sPtr
, WMPixmap
* pixmap
)
97 WMReleasePixmap(sPtr
->backPixmap
);
99 sPtr
->backPixmap
= WMRetainPixmap(pixmap
);
101 if (sPtr
->view
->flags
.mapped
) {
106 void WMSetSliderKnobThickness(WMSlider
* sPtr
, int thickness
)
108 assert(thickness
> 0);
110 sPtr
->knobThickness
= thickness
;
112 if (sPtr
->knobPixmap
) {
113 makeKnobPixmap(sPtr
);
116 if (sPtr
->view
->flags
.mapped
) {
121 int WMGetSliderMinValue(WMSlider
* slider
)
123 CHECK_CLASS(slider
, WC_Slider
);
125 return slider
->minValue
;
128 int WMGetSliderMaxValue(WMSlider
* slider
)
130 CHECK_CLASS(slider
, WC_Slider
);
132 return slider
->maxValue
;
135 int WMGetSliderValue(WMSlider
* slider
)
137 CHECK_CLASS(slider
, WC_Slider
);
139 return slider
->value
;
142 void WMSetSliderMinValue(WMSlider
* slider
, int value
)
144 CHECK_CLASS(slider
, WC_Slider
);
146 slider
->minValue
= value
;
147 if (slider
->value
< value
) {
148 slider
->value
= value
;
149 if (slider
->view
->flags
.mapped
)
154 void WMSetSliderMaxValue(WMSlider
* slider
, int value
)
156 CHECK_CLASS(slider
, WC_Slider
);
158 slider
->maxValue
= value
;
159 if (slider
->value
> value
) {
160 slider
->value
= value
;
161 if (slider
->view
->flags
.mapped
)
166 void WMSetSliderValue(WMSlider
* slider
, int value
)
168 CHECK_CLASS(slider
, WC_Slider
);
170 if (value
< slider
->minValue
)
171 slider
->value
= slider
->minValue
;
172 else if (value
> slider
->maxValue
)
173 slider
->value
= slider
->maxValue
;
175 slider
->value
= value
;
177 if (slider
->view
->flags
.mapped
)
181 void WMSetSliderContinuous(WMSlider
* slider
, Bool flag
)
183 CHECK_CLASS(slider
, WC_Slider
);
185 slider
->flags
.continuous
= ((flag
== 0) ? 0 : 1);
188 void WMSetSliderAction(WMSlider
* slider
, WMAction
* action
, void *data
)
190 CHECK_CLASS(slider
, WC_Slider
);
192 slider
->action
= action
;
193 slider
->clientData
= data
;
196 static void makeKnobPixmap(Slider
* sPtr
)
199 WMScreen
*scr
= sPtr
->view
->screen
;
202 if (sPtr
->flags
.vertical
) {
203 w
= sPtr
->view
->size
.width
- 2;
204 h
= sPtr
->knobThickness
;
206 w
= sPtr
->knobThickness
;
207 h
= sPtr
->view
->size
.height
- 2;
210 pix
= XCreatePixmap(scr
->display
, sPtr
->view
->window
, w
, h
, scr
->depth
);
211 XFillRectangle(scr
->display
, pix
, WMColorGC(scr
->gray
), 0, 0, w
, h
);
213 if (sPtr
->knobThickness
< 10) {
214 W_DrawRelief(scr
, pix
, 0, 0, w
, h
, WRRaised
);
215 } else if (sPtr
->flags
.vertical
) {
216 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
- 3);
217 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
- 3);
218 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 2, 1, w
- 2, h
/ 2 - 2);
219 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 2, h
/ 2, w
- 2, h
- 2);
221 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
- 2, 0);
222 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
/ 2 - 2, w
- 3, h
/ 2 - 2);
223 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, h
/ 2 - 1, w
- 3, h
/ 2 - 1);
225 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
- 1, 0, w
- 1, h
- 2);
227 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
- 3, w
- 2, h
- 3);
228 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
- 2, w
- 1, h
- 2);
229 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 0, h
- 1, w
- 1, h
- 1);
231 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, w
- 3, 0);
233 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 0, 0, 0, h
- 2);
235 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), 1, 0, 1, h
- 3);
236 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/ 2 - 2, 1, w
/ 2 - 2, h
- 3);
237 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->white
), w
/ 2 - 1, 0, w
/ 2 - 1, h
- 3);
239 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 3, 0, w
- 3, h
- 2);
240 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), w
- 2, 0, w
- 2, h
- 2);
241 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
- 1, 0, w
- 1, h
- 1);
243 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 1, h
- 1, w
/ 2 + 1, h
- 1);
244 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), 1, h
- 2, w
/ 2 - 2, h
- 2);
245 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->darkGray
), w
/ 2, h
- 2, w
- 3, h
- 2);
247 XDrawLine(scr
->display
, pix
, WMColorGC(scr
->black
), 0, h
- 1, w
- 2, h
- 1);
250 if (sPtr
->knobPixmap
)
251 XFreePixmap(scr
->display
, sPtr
->knobPixmap
);
252 sPtr
->knobPixmap
= pix
;
255 static void didResizeSlider(W_ViewDelegate
* self
, WMView
* view
)
257 Slider
*sPtr
= (Slider
*) view
->self
;
258 int width
= sPtr
->view
->size
.width
;
259 int height
= sPtr
->view
->size
.height
;
261 /* Parameter not used, but tell the compiler that it is ok */
267 if (width
> height
) {
268 if (sPtr
->flags
.vertical
) {
269 sPtr
->flags
.vertical
= 0;
270 if (sPtr
->view
->flags
.realized
)
271 makeKnobPixmap(sPtr
);
274 if (!sPtr
->flags
.vertical
) {
275 sPtr
->flags
.vertical
= 1;
276 if (sPtr
->view
->flags
.realized
)
277 makeKnobPixmap(sPtr
);
282 static void paintSlider(Slider
* sPtr
)
284 W_Screen
*scr
= sPtr
->view
->screen
;
288 WMSize size
= sPtr
->view
->size
;
292 #define MINV sPtr->minValue
293 #define MAXV sPtr->maxValue
294 #define POSV sPtr->value
296 bgc
= WMColorGC(scr
->black
);
297 wgc
= WMColorGC(scr
->white
);
298 lgc
= WMColorGC(scr
->gray
);
300 buffer
= XCreatePixmap(scr
->display
, sPtr
->view
->window
, size
.width
, size
.height
, scr
->depth
);
302 if (sPtr
->backPixmap
) {
303 WMSize size
= WMGetPixmapSize(sPtr
->backPixmap
);
305 XCopyArea(scr
->display
, WMGetPixmapXID(sPtr
->backPixmap
),
306 buffer
, scr
->copyGC
, 0, 0, size
.width
, size
.height
, 1, 1);
308 XFillRectangle(scr
->display
, buffer
, lgc
, 0, 0, size
.width
, size
.height
);
309 XFillRectangle(scr
->display
, buffer
, scr
->stippleGC
, 0, 0, size
.width
, size
.height
);
312 if (sPtr
->flags
.vertical
) {
313 pos
= (size
.height
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
) + 1;
315 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
316 scr
->copyGC
, 0, 0, size
.width
- 2, sPtr
->knobThickness
, 1, pos
);
318 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
) + 1;
320 XCopyArea(scr
->display
, sPtr
->knobPixmap
, buffer
,
321 scr
->copyGC
, 0, 0, sPtr
->knobThickness
, size
.height
, pos
, 1);
324 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, 0, size
.height
- 1);
325 XDrawLine(scr
->display
, buffer
, bgc
, 0, 0, size
.width
, 0);
327 XDrawLine(scr
->display
, buffer
, wgc
, size
.width
- 1, 0, size
.width
- 1, size
.height
- 1);
328 XDrawLine(scr
->display
, buffer
, wgc
, 0, size
.height
- 1, size
.width
- 1, size
.height
- 1);
330 XCopyArea(scr
->display
, buffer
, sPtr
->view
->window
, scr
->copyGC
, 0, 0, size
.width
, size
.height
, 0, 0);
331 XFreePixmap(scr
->display
, buffer
);
334 static void handleEvents(XEvent
* event
, void *data
)
336 Slider
*sPtr
= (Slider
*) data
;
338 CHECK_CLASS(data
, WC_Slider
);
340 switch (event
->type
) {
342 if (event
->xexpose
.count
!= 0)
358 static int getSliderPart(Slider
* sPtr
, int x
, int y
)
362 WMSize size
= sPtr
->view
->size
;
364 if (sPtr
->flags
.vertical
) {
366 pos
= (size
.height
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
369 if (p
> pos
+ sPtr
->knobThickness
)
374 pos
= (size
.width
- 2 - sPtr
->knobThickness
) * (POSV
- MINV
) / (MAXV
- MINV
);
377 if (p
> pos
+ sPtr
->knobThickness
)
383 static int valueForMousePoint(Slider
* sPtr
, int x
, int y
)
385 WMSize size
= sPtr
->view
->size
;
388 if (sPtr
->flags
.vertical
) {
389 f
= (y
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
390 / ((int)size
.height
- 2 - sPtr
->knobThickness
);
392 f
= (x
- sPtr
->knobThickness
/ 2) * (MAXV
- MINV
)
393 / ((int)size
.width
- 2 - sPtr
->knobThickness
);
397 if (f
< sPtr
->minValue
)
399 else if (f
> sPtr
->maxValue
)
405 static void handleActionEvents(XEvent
* event
, void *data
)
407 WMSlider
*sPtr
= (Slider
*) data
;
409 CHECK_CLASS(data
, WC_Slider
);
411 switch (event
->type
) {
413 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
&& !sPtr
->flags
.dragging
) {
415 if (sPtr
->value
+ 1 <= sPtr
->maxValue
) {
416 WMSetSliderValue(sPtr
, sPtr
->value
+ 1);
417 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
418 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
421 } else if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
&& !sPtr
->flags
.dragging
) {
423 if (sPtr
->value
- 1 >= sPtr
->minValue
) {
424 WMSetSliderValue(sPtr
, sPtr
->value
- 1);
425 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
426 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
429 } else if (getSliderPart(sPtr
, event
->xbutton
.x
, event
->xbutton
.y
)
431 sPtr
->flags
.dragging
= 1;
433 #ifdef STRICT_NEXT_BEHAVIOUR
434 sPtr
->flags
.dragging
= 1;
436 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
441 if (event
->xbutton
.button
== Button2
) {
442 sPtr
->flags
.dragging
= 1;
444 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
447 tmp
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
448 if (tmp
< sPtr
->value
)
449 tmp
= sPtr
->value
- 1;
451 tmp
= sPtr
->value
+ 1;
452 WMSetSliderValue(sPtr
, tmp
);
456 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
457 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
463 if (!sPtr
->flags
.continuous
&& sPtr
->action
) {
464 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
466 sPtr
->flags
.dragging
= 0;
470 if (sPtr
->flags
.dragging
) {
471 sPtr
->value
= valueForMousePoint(sPtr
, event
->xmotion
.x
, event
->xmotion
.y
);
474 if (sPtr
->flags
.continuous
&& sPtr
->action
) {
475 (*sPtr
->action
) (sPtr
, sPtr
->clientData
);
482 static void destroySlider(Slider
* sPtr
)
484 if (sPtr
->knobPixmap
)
485 XFreePixmap(sPtr
->view
->screen
->display
, sPtr
->knobPixmap
);
487 if (sPtr
->backPixmap
)
488 WMReleasePixmap(sPtr
->backPixmap
);
490 WMRemoveNotificationObserver(sPtr
);