5 typedef struct W_Button
{
15 WMColorSpec textColor
;
16 WMColorSpec altTextColor
;
17 WMColorSpec disTextColor
;
30 float periodicInterval
;
32 WMHandlerID
*timer
; /* for continuous mode */
36 WMImagePosition imagePosition
:4;
37 WMAlignment alignment
:2;
39 unsigned int selected
:1;
41 unsigned int enabled
:1;
43 unsigned int dimsWhenDisabled
:1;
45 unsigned int bordered
:1;
47 unsigned int springLoaded
:1;
49 unsigned int pushIn
:1; /* change relief while pushed */
51 unsigned int pushLight
:1; /* highlight while pushed */
53 unsigned int pushChange
:1; /* change caption while pushed */
55 unsigned int stateLight
:1; /* state indicated by highlight */
57 unsigned int stateChange
:1; /* state indicated by caption change */
59 unsigned int statePush
:1; /* state indicated by relief */
61 unsigned int continuous
:1; /* continually perform action */
63 unsigned int prevSelected
:1;
65 unsigned int pushed
:1;
67 unsigned int wasPushed
:1;
69 unsigned int redrawPending
:1;
71 unsigned int addedObserver
:1;
75 #define DEFAULT_BUTTON_WIDTH 60
76 #define DEFAULT_BUTTON_HEIGHT 24
77 #define DEFAULT_BUTTON_ALIGNMENT WACenter
78 #define DEFAULT_BUTTON_IS_BORDERED True
80 #define DEFAULT_RADIO_WIDTH 100
81 #define DEFAULT_RADIO_HEIGHT 20
82 #define DEFAULT_RADIO_ALIGNMENT WALeft
83 #define DEFAULT_RADIO_IMAGE_POSITION WIPLeft
84 #define DEFAULT_RADIO_TEXT "Radio"
86 #define DEFAULT_SWITCH_WIDTH 100
87 #define DEFAULT_SWITCH_HEIGHT 20
88 #define DEFAULT_SWITCH_ALIGNMENT WALeft
89 #define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft
90 #define DEFAULT_SWITCH_TEXT "Switch"
92 static void destroyButton(Button
* bPtr
);
93 static void paintButton(Button
* bPtr
);
95 static void handleEvents(XEvent
* event
, void *data
);
96 static void handleActionEvents(XEvent
* event
, void *data
);
98 static char *WMPushedRadioNotification
= "WMPushedRadioNotification";
100 #define NFONT(b) (b)->view->screen->normalFont
102 WMButton
*WMCreateCustomButton(WMWidget
* parent
, int behaviourMask
)
106 bPtr
= wmalloc(sizeof(Button
));
107 memset(bPtr
, 0, sizeof(Button
));
109 bPtr
->widgetClass
= WC_Button
;
111 bPtr
->view
= W_CreateView(W_VIEW(parent
));
116 bPtr
->view
->self
= bPtr
;
118 bPtr
->flags
.type
= 0;
120 bPtr
->flags
.springLoaded
= (behaviourMask
& WBBSpringLoadedMask
) != 0;
121 bPtr
->flags
.pushIn
= (behaviourMask
& WBBPushInMask
) != 0;
122 bPtr
->flags
.pushChange
= (behaviourMask
& WBBPushChangeMask
) != 0;
123 bPtr
->flags
.pushLight
= (behaviourMask
& WBBPushLightMask
) != 0;
124 bPtr
->flags
.stateLight
= (behaviourMask
& WBBStateLightMask
) != 0;
125 bPtr
->flags
.stateChange
= (behaviourMask
& WBBStateChangeMask
) != 0;
126 bPtr
->flags
.statePush
= (behaviourMask
& WBBStatePushMask
) != 0;
128 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
129 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
130 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
132 bPtr
->flags
.enabled
= 1;
133 bPtr
->flags
.dimsWhenDisabled
= 1;
135 bPtr
->textColor
= WMBlackColorSpec();
136 bPtr
->altTextColor
= WMBlackColorSpec();
137 bPtr
->disTextColor
= WMDarkGrayColorSpec();
139 WMCreateEventHandler(bPtr
->view
, ExposureMask
| StructureNotifyMask
, handleEvents
, bPtr
);
141 WMCreateEventHandler(bPtr
->view
, ButtonPressMask
| ButtonReleaseMask
142 | EnterWindowMask
| LeaveWindowMask
, handleActionEvents
, bPtr
);
144 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
145 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
146 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
151 WMButton
*WMCreateButton(WMWidget
* parent
, WMButtonType type
)
153 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
157 case WBTMomentaryPush
:
158 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
| WBBPushInMask
| WBBPushLightMask
);
161 case WBTMomentaryChange
:
162 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
| WBBPushChangeMask
);
165 case WBTPushOnPushOff
:
166 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
| WBBStatePushMask
| WBBStateLightMask
);
170 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
| WBBStateChangeMask
| WBBStatePushMask
);
174 bPtr
= WMCreateCustomButton(parent
, WBBStateLightMask
);
178 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
179 bPtr
->flags
.bordered
= 0;
180 bPtr
->image
= WMRetainImage(scrPtr
->checkButtonImageOff
);
181 bPtr
->altImage
= WMRetainImage(scrPtr
->checkButtonImageOn
);
185 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
186 bPtr
->flags
.bordered
= 0;
187 bPtr
->image
= WMRetainImage(scrPtr
->radioButtonImageOff
);
188 bPtr
->altImage
= WMRetainImage(scrPtr
->radioButtonImageOn
);
192 case WBTMomentaryLight
:
193 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
| WBBPushLightMask
);
194 bPtr
->flags
.bordered
= 1;
198 bPtr
->flags
.type
= type
;
200 if (type
== WBTRadio
) {
201 W_ResizeView(bPtr
->view
, DEFAULT_RADIO_WIDTH
, DEFAULT_RADIO_HEIGHT
);
202 WMSetButtonText(bPtr
, DEFAULT_RADIO_TEXT
);
203 bPtr
->flags
.alignment
= DEFAULT_RADIO_ALIGNMENT
;
204 bPtr
->flags
.imagePosition
= DEFAULT_RADIO_IMAGE_POSITION
;
205 } else if (type
== WBTSwitch
) {
206 W_ResizeView(bPtr
->view
, DEFAULT_SWITCH_WIDTH
, DEFAULT_SWITCH_HEIGHT
);
207 WMSetButtonText(bPtr
, DEFAULT_SWITCH_TEXT
);
208 bPtr
->flags
.alignment
= DEFAULT_SWITCH_ALIGNMENT
;
209 bPtr
->flags
.imagePosition
= DEFAULT_SWITCH_IMAGE_POSITION
;
215 void WMSetButtonImageDefault(WMButton
* bPtr
)
217 WMSetButtonImage(bPtr
, WMWidgetScreen(bPtr
)->buttonArrow
);
218 WMSetButtonAltImage(bPtr
, WMWidgetScreen(bPtr
)->pushedButtonArrow
);
221 void WMSetButtonImage(WMButton
*bPtr
, WMImage
*image
)
223 if (bPtr
->image
!= NULL
)
224 WMDestroyImage(bPtr
->image
);
225 bPtr
->image
= WMRetainImage(image
);
227 if (bPtr
->view
->flags
.realized
) {
232 void WMSetButtonAltImage(WMButton
* bPtr
, WMImage
* image
)
234 if (bPtr
->altImage
!= NULL
)
235 WMDestroyImage(bPtr
->altImage
);
236 bPtr
->altImage
= WMRetainImage(image
);
238 if (bPtr
->view
->flags
.realized
) {
243 void WMSetButtonImagePosition(WMButton
* bPtr
, WMImagePosition position
)
245 bPtr
->flags
.imagePosition
= position
;
247 if (bPtr
->view
->flags
.realized
) {
252 void WMSetButtonTextAlignment(WMButton
* bPtr
, WMAlignment alignment
)
254 bPtr
->flags
.alignment
= alignment
;
256 if (bPtr
->view
->flags
.realized
) {
261 void WMSetButtonText(WMButton
* bPtr
, char *text
)
264 wfree(bPtr
->caption
);
267 bPtr
->caption
= wstrdup(text
);
269 bPtr
->caption
= NULL
;
272 if (bPtr
->view
->flags
.realized
) {
277 void WMSetButtonAltText(WMButton
* bPtr
, char *text
)
279 if (bPtr
->altCaption
)
280 wfree(bPtr
->altCaption
);
283 bPtr
->altCaption
= wstrdup(text
);
285 bPtr
->altCaption
= NULL
;
288 if (bPtr
->view
->flags
.realized
) {
293 void WMSetButtonTextColor(WMButton
*bPtr
, WMColorSpec
*color
)
295 bPtr
->textColor
= *color
;
298 void WMSetButtonAltTextColor(WMButton
*bPtr
, WMColorSpec
*color
)
300 bPtr
->altTextColor
= *color
;
303 void WMSetButtonDisabledTextColor(WMButton
*bPtr
, WMColorSpec
*color
)
305 bPtr
->disTextColor
= *color
;
308 void WMSetButtonSelected(WMButton
* bPtr
, int isSelected
)
310 bPtr
->flags
.selected
= isSelected
? 1 : 0;
312 if (bPtr
->view
->flags
.realized
) {
315 if (bPtr
->groupIndex
> 0)
316 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
319 int WMGetButtonSelected(WMButton
* bPtr
)
321 CHECK_CLASS(bPtr
, WC_Button
);
323 return bPtr
->flags
.selected
;
326 void WMSetButtonBordered(WMButton
* bPtr
, int isBordered
)
328 bPtr
->flags
.bordered
= isBordered
;
330 if (bPtr
->view
->flags
.realized
) {
335 void WMSetButtonFont(WMButton
* bPtr
, WMFont
* font
)
338 WMReleaseFont(bPtr
->font
);
340 bPtr
->font
= WMRetainFont(font
);
343 void WMSetButtonEnabled(WMButton
* bPtr
, Bool flag
)
345 bPtr
->flags
.enabled
= ((flag
== 0) ? 0 : 1);
347 if (bPtr
->view
->flags
.mapped
) {
352 int WMGetButtonEnabled(WMButton
* bPtr
)
354 CHECK_CLASS(bPtr
, WC_Button
);
356 return bPtr
->flags
.enabled
;
359 void WMSetButtonImageDimsWhenDisabled(WMButton
* bPtr
, Bool flag
)
361 bPtr
->flags
.dimsWhenDisabled
= ((flag
== 0) ? 0 : 1);
364 void WMSetButtonTag(WMButton
* bPtr
, int tag
)
369 void WMPerformButtonClick(WMButton
* bPtr
)
371 CHECK_CLASS(bPtr
, WC_Button
);
373 if (!bPtr
->flags
.enabled
)
376 bPtr
->flags
.pushed
= 1;
377 bPtr
->flags
.selected
= 1;
379 if (bPtr
->view
->flags
.mapped
) {
381 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr
)));
385 bPtr
->flags
.pushed
= 0;
387 if (bPtr
->groupIndex
> 0) {
388 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
392 (*bPtr
->action
) (bPtr
, bPtr
->clientData
);
394 if (bPtr
->view
->flags
.mapped
)
398 void WMSetButtonAction(WMButton
* bPtr
, WMAction
* action
, void *clientData
)
400 CHECK_CLASS(bPtr
, WC_Button
);
402 bPtr
->action
= action
;
404 bPtr
->clientData
= clientData
;
407 static void radioPushObserver(void *observerData
, WMNotification
* notification
)
409 WMButton
*bPtr
= (WMButton
*) observerData
;
410 WMButton
*pushedButton
= (WMButton
*) WMGetNotificationObject(notification
);
412 if (bPtr
!= pushedButton
&& pushedButton
->groupIndex
== bPtr
->groupIndex
&& bPtr
->groupIndex
!= 0) {
413 if (bPtr
->flags
.selected
) {
414 bPtr
->flags
.selected
= 0;
420 void WMGroupButtons(WMButton
* bPtr
, WMButton
* newMember
)
422 static int tagIndex
= 0;
424 CHECK_CLASS(bPtr
, WC_Button
);
425 CHECK_CLASS(newMember
, WC_Button
);
427 if (!bPtr
->flags
.addedObserver
) {
428 WMAddNotificationObserver(radioPushObserver
, bPtr
, WMPushedRadioNotification
, NULL
);
429 bPtr
->flags
.addedObserver
= 1;
431 if (!newMember
->flags
.addedObserver
) {
432 WMAddNotificationObserver(radioPushObserver
, newMember
, WMPushedRadioNotification
, NULL
);
433 newMember
->flags
.addedObserver
= 1;
436 if (bPtr
->groupIndex
== 0) {
437 bPtr
->groupIndex
= ++tagIndex
;
439 newMember
->groupIndex
= bPtr
->groupIndex
;
442 void WMSetButtonContinuous(WMButton
* bPtr
, Bool flag
)
444 bPtr
->flags
.continuous
= ((flag
== 0) ? 0 : 1);
446 WMDeleteTimerHandler(bPtr
->timer
);
451 void WMSetButtonPeriodicDelay(WMButton
* bPtr
, float delay
, float interval
)
453 bPtr
->periodicInterval
= interval
;
454 bPtr
->periodicDelay
= delay
;
457 static void paintButton(WMButton
* bPtr
)
459 cairo_t
*cr
= W_CreateCairoForView(W_VIEW(bPtr
));
460 W_Screen
*scrPtr
= bPtr
->view
->screen
;
465 unsigned int lightbg
= 0;
467 WMColorSpec textColor
;
468 WMColorSpec backColor
;
470 backColor
= bPtr
->view
->backColor
;
471 caption
= bPtr
->caption
;
473 if (bPtr
->flags
.enabled
) {
474 textColor
= bPtr
->textColor
;
476 textColor
= bPtr
->disTextColor
;
479 if (bPtr
->flags
.enabled
|| !bPtr
->flags
.dimsWhenDisabled
) {
480 image
= WMRetainImage(bPtr
->image
);
482 //XXX make dimmited image
483 image
= WMRetainImage(bPtr
->image
);
486 if (bPtr
->flags
.bordered
)
491 if (bPtr
->flags
.selected
) {
492 if (bPtr
->flags
.stateLight
) {
496 if (bPtr
->flags
.stateChange
) {
497 if (bPtr
->altCaption
)
498 caption
= bPtr
->altCaption
;
499 if (bPtr
->altImage
) {
500 WMDestroyImage(image
);
501 image
= WMRetainImage(bPtr
->altImage
);
502 textColor
= bPtr
->altTextColor
;
506 if (bPtr
->flags
.statePush
&& bPtr
->flags
.bordered
) {
512 if (bPtr
->flags
.pushed
) {
513 if (bPtr
->flags
.pushIn
) {
517 if (bPtr
->flags
.pushLight
) {
521 if (bPtr
->flags
.pushChange
) {
522 if (bPtr
->altCaption
)
523 caption
= bPtr
->altCaption
;
524 if (bPtr
->altImage
) {
525 WMDestroyImage(image
);
526 image
= WMRetainImage(bPtr
->altImage
);
527 textColor
= bPtr
->altTextColor
;
533 W_DrawButtonLightBack(cr
, bPtr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
,relief
);
535 W_DrawButtonDarkBack(cr
, bPtr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
,relief
);
538 W_DrawButtonRelief(cr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
, relief
);
540 W_PaintTextAndImage(scrPtr
, cr
, bPtr
->view
, True
, &textColor
,
541 (bPtr
->font
!=NULL
? bPtr
->font
: scrPtr
->normalFont
),
542 relief
, caption
, bPtr
->flags
.alignment
, image
,
543 bPtr
->flags
.imagePosition
, &backColor
, offset
);
546 WMDestroyImage(image
);
553 static void handleEvents(XEvent
* event
, void *data
)
555 Button
*bPtr
= (Button
*) data
;
557 CHECK_CLASS(data
, WC_Button
);
559 switch (event
->type
) {
561 if (event
->xexpose
.count
!= 0)
572 static void autoRepeat(void *data
)
574 Button
*bPtr
= (Button
*) data
;
576 if (bPtr
->action
&& bPtr
->flags
.pushed
)
577 (*bPtr
->action
) (bPtr
, bPtr
->clientData
);
579 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicInterval
* 1000), autoRepeat
, bPtr
);
582 static void handleActionEvents(XEvent
* event
, void *data
)
584 Button
*bPtr
= (Button
*) data
;
585 int doclick
= 0, dopaint
= 0;
587 CHECK_CLASS(data
, WC_Button
);
589 if (!bPtr
->flags
.enabled
)
592 switch (event
->type
) {
594 if (bPtr
->groupIndex
== 0) {
595 bPtr
->flags
.pushed
= bPtr
->flags
.wasPushed
;
596 if (bPtr
->flags
.pushed
) {
597 bPtr
->flags
.selected
= !bPtr
->flags
.prevSelected
;
604 if (bPtr
->groupIndex
== 0) {
605 bPtr
->flags
.wasPushed
= bPtr
->flags
.pushed
;
606 if (bPtr
->flags
.pushed
) {
607 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
610 bPtr
->flags
.pushed
= 0;
615 if (event
->xbutton
.button
== Button1
) {
616 bPtr
->flags
.prevSelected
= bPtr
->flags
.selected
;
617 bPtr
->flags
.wasPushed
= 0;
618 bPtr
->flags
.pushed
= 1;
619 if (bPtr
->groupIndex
> 0) {
620 bPtr
->flags
.selected
= 1;
624 bPtr
->flags
.selected
= !bPtr
->flags
.selected
;
627 if (bPtr
->flags
.continuous
&& !bPtr
->timer
) {
628 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicDelay
* 1000),
635 if (event
->xbutton
.button
== Button1
) {
636 if (bPtr
->flags
.pushed
) {
637 if (bPtr
->groupIndex
== 0 || (bPtr
->flags
.selected
&& bPtr
->groupIndex
> 0))
640 if (bPtr
->flags
.springLoaded
) {
641 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
644 bPtr
->flags
.pushed
= 0;
647 WMDeleteTimerHandler(bPtr
->timer
);
657 if (bPtr
->flags
.selected
&& bPtr
->groupIndex
> 0) {
658 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
662 (*bPtr
->action
) (bPtr
, bPtr
->clientData
);
666 static void destroyButton(Button
* bPtr
)
668 if (bPtr
->flags
.addedObserver
) {
669 WMRemoveNotificationObserver(bPtr
);
673 WMDeleteTimerHandler(bPtr
->timer
);
676 WMReleaseFont(bPtr
->font
);
679 wfree(bPtr
->caption
);
681 if (bPtr
->altCaption
)
682 wfree(bPtr
->altCaption
);
685 WMDestroyImage(bPtr
->image
);
688 WMDestroyImage(bPtr
->altImage
);