7 typedef struct W_Button
{
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 bordered
:1;
45 unsigned int springLoaded
:1;
47 unsigned int pushIn
:1; /* change relief while pushed */
49 unsigned int pushLight
:1; /* highlight while pushed */
51 unsigned int pushChange
:1; /* change caption while pushed */
53 unsigned int stateLight
:1; /* state indicated by highlight */
55 unsigned int stateChange
:1; /* state indicated by caption change */
57 unsigned int statePush
:1; /* state indicated by relief */
59 unsigned int continuous
:1; /* continually perform action */
61 unsigned int prevSelected
:1;
63 unsigned int pushed
:1;
65 unsigned int wasPushed
:1;
67 unsigned int redrawPending
:1;
69 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
81 #define DEFAULT_RADIO_WIDTH 100
82 #define DEFAULT_RADIO_HEIGHT 20
83 #define DEFAULT_RADIO_ALIGNMENT WALeft
84 #define DEFAULT_RADIO_IMAGE_POSITION WIPLeft
85 #define DEFAULT_RADIO_TEXT "Radio"
88 #define DEFAULT_SWITCH_WIDTH 100
89 #define DEFAULT_SWITCH_HEIGHT 20
90 #define DEFAULT_SWITCH_ALIGNMENT WALeft
91 #define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft
92 #define DEFAULT_SWITCH_TEXT "Switch"
95 static void destroyButton(Button
*bPtr
);
96 static void paintButton(Button
*bPtr
);
98 static void handleEvents(XEvent
*event
, void *data
);
99 static void handleActionEvents(XEvent
*event
, void *data
);
102 static char *WMPushedRadioNotification
="WMPushedRadioNotification";
105 #define NFONT(b) (b)->view->screen->normalFont
109 WMCreateCustomButton(WMWidget
*parent
, int behaviourMask
)
113 bPtr
= wmalloc(sizeof(Button
));
114 memset(bPtr
, 0, sizeof(Button
));
116 bPtr
->widgetClass
= WC_Button
;
118 bPtr
->view
= W_CreateView(W_VIEW(parent
));
123 bPtr
->view
->self
= bPtr
;
125 bPtr
->flags
.type
= 0;
127 bPtr
->flags
.springLoaded
= (behaviourMask
& WBBSpringLoadedMask
)!=0;
128 bPtr
->flags
.pushIn
= (behaviourMask
& WBBPushInMask
)!=0;
129 bPtr
->flags
.pushChange
= (behaviourMask
& WBBPushChangeMask
)!=0;
130 bPtr
->flags
.pushLight
= (behaviourMask
& WBBPushLightMask
)!=0;
131 bPtr
->flags
.stateLight
= (behaviourMask
& WBBStateLightMask
)!=0;
132 bPtr
->flags
.stateChange
= (behaviourMask
& WBBStateChangeMask
)!=0;
133 bPtr
->flags
.statePush
= (behaviourMask
& WBBStatePushMask
)!=0;
135 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
136 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
137 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
139 bPtr
->flags
.enabled
= 1;
142 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
,
145 WMCreateEventHandler(bPtr
->view
, ButtonPressMask
|ButtonReleaseMask
146 |EnterWindowMask
|LeaveWindowMask
,
147 handleActionEvents
, bPtr
);
149 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
150 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
151 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
159 WMCreateButton(WMWidget
*parent
, WMButtonType type
)
161 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
165 case WBTMomentaryPush
:
166 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
167 |WBBPushInMask
|WBBPushLightMask
);
170 case WBTMomentaryChange
:
171 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
175 case WBTPushOnPushOff
:
176 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStatePushMask
181 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStateChangeMask
186 bPtr
= WMCreateCustomButton(parent
, WBBStateLightMask
);
190 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
191 bPtr
->flags
.bordered
= 0;
192 bPtr
->image
= WMRetainPixmap(scrPtr
->checkButtonImageOff
);
193 bPtr
->altImage
= WMRetainPixmap(scrPtr
->checkButtonImageOn
);
197 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
198 bPtr
->flags
.bordered
= 0;
199 bPtr
->image
= WMRetainPixmap(scrPtr
->radioButtonImageOff
);
200 bPtr
->altImage
= WMRetainPixmap(scrPtr
->radioButtonImageOn
);
204 case WBTMomentaryLight
:
205 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
207 bPtr
->flags
.bordered
= 1;
211 bPtr
->flags
.type
= type
;
213 if (type
==WBTRadio
) {
214 W_ResizeView(bPtr
->view
, DEFAULT_RADIO_WIDTH
, DEFAULT_RADIO_HEIGHT
);
215 WMSetButtonText(bPtr
, DEFAULT_RADIO_TEXT
);
216 bPtr
->flags
.alignment
= DEFAULT_RADIO_ALIGNMENT
;
217 bPtr
->flags
.imagePosition
= DEFAULT_RADIO_IMAGE_POSITION
;
218 } else if (type
==WBTSwitch
) {
219 W_ResizeView(bPtr
->view
, DEFAULT_SWITCH_WIDTH
, DEFAULT_SWITCH_HEIGHT
);
220 WMSetButtonText(bPtr
, DEFAULT_SWITCH_TEXT
);
221 bPtr
->flags
.alignment
= DEFAULT_SWITCH_ALIGNMENT
;
222 bPtr
->flags
.imagePosition
= DEFAULT_SWITCH_IMAGE_POSITION
;
230 updateDisabledMask(WMButton
*bPtr
)
232 WMScreen
*scr
= WMWidgetScreen(bPtr
);
233 Display
*dpy
= scr
->display
;
238 bPtr
->dimage
->mask
= XCreatePixmap(dpy
, scr
->stipple
,
240 bPtr
->dimage
->height
, 1);
242 XSetForeground(dpy
, scr
->monoGC
, 0);
243 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
244 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
248 gcv
.stipple
= scr
->stipple
;
249 gcv
.fill_style
= FillStippled
;
250 gcv
.clip_mask
= bPtr
->image
->mask
;
251 gcv
.clip_x_origin
= 0;
252 gcv
.clip_y_origin
= 0;
254 XChangeGC(dpy
, scr
->monoGC
, GCForeground
|GCBackground
|GCStipple
255 |GCFillStyle
|GCClipMask
|GCClipXOrigin
|GCClipYOrigin
, &gcv
);
257 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
258 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
260 gcv
.fill_style
= FillSolid
;
261 gcv
.clip_mask
= None
;
262 XChangeGC(dpy
, scr
->monoGC
, GCFillStyle
|GCClipMask
, &gcv
);
267 WMSetButtonImageDefault(WMButton
*bPtr
)
269 WMSetButtonImage (bPtr
, WMWidgetScreen(bPtr
)->buttonArrow
);
270 WMSetButtonAltImage (bPtr
, WMWidgetScreen(bPtr
)->pushedButtonArrow
);
274 WMSetButtonImage(WMButton
*bPtr
, WMPixmap
*image
)
276 if (bPtr
->image
!=NULL
)
277 WMReleasePixmap(bPtr
->image
);
278 bPtr
->image
= WMRetainPixmap(image
);
281 bPtr
->dimage
->pixmap
= None
;
282 WMReleasePixmap(bPtr
->dimage
);
287 bPtr
->dimage
= WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr
),
289 image
->width
, image
->height
,
291 updateDisabledMask(bPtr
);
294 if (bPtr
->view
->flags
.realized
) {
301 WMSetButtonAltImage(WMButton
*bPtr
, WMPixmap
*image
)
303 if (bPtr
->altImage
!=NULL
)
304 WMReleasePixmap(bPtr
->altImage
);
305 bPtr
->altImage
= WMRetainPixmap(image
);
308 if (bPtr
->view
->flags
.realized
) {
315 WMSetButtonImagePosition(WMButton
*bPtr
, WMImagePosition position
)
317 bPtr
->flags
.imagePosition
= position
;
320 if (bPtr
->view
->flags
.realized
) {
329 WMSetButtonTextAlignment(WMButton
*bPtr
, WMAlignment alignment
)
331 bPtr
->flags
.alignment
= alignment
;
334 if (bPtr
->view
->flags
.realized
) {
340 WMSetButtonText(WMButton
*bPtr
, char *text
)
343 wfree(bPtr
->caption
);
346 bPtr
->caption
= wstrdup(text
);
348 bPtr
->caption
= NULL
;
352 if (bPtr
->view
->flags
.realized
) {
359 WMSetButtonAltText(WMButton
*bPtr
, char *text
)
361 if (bPtr
->altCaption
)
362 wfree(bPtr
->altCaption
);
365 bPtr
->altCaption
= wstrdup(text
);
367 bPtr
->altCaption
= NULL
;
370 if (bPtr
->view
->flags
.realized
) {
377 WMSetButtonSelected(WMButton
*bPtr
, int isSelected
)
379 bPtr
->flags
.selected
= isSelected
;
381 if (bPtr
->view
->flags
.realized
) {
388 WMGetButtonSelected(WMButton
*bPtr
)
390 CHECK_CLASS(bPtr
, WC_Button
);
392 return bPtr
->flags
.selected
;
397 WMSetButtonBordered(WMButton
*bPtr
, int isBordered
)
399 bPtr
->flags
.bordered
= isBordered
;
401 if (bPtr
->view
->flags
.realized
) {
408 WMSetButtonFont(WMButton
*bPtr
, WMFont
*font
)
411 WMReleaseFont(bPtr
->font
);
413 bPtr
->font
= WMRetainFont(font
);
418 WMSetButtonEnabled(WMButton
*bPtr
, Bool flag
)
420 bPtr
->flags
.enabled
= flag
;
422 if (bPtr
->view
->flags
.mapped
) {
429 WMSetButtonTag(WMButton
*bPtr
, int tag
)
437 WMPerformButtonClick(WMButton
*bPtr
)
439 CHECK_CLASS(bPtr
, WC_Button
);
441 if (!bPtr
->flags
.enabled
)
444 bPtr
->flags
.pushed
= 1;
445 bPtr
->flags
.selected
= 1;
447 if (bPtr
->view
->flags
.mapped
) {
449 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr
)));
453 if (bPtr
->groupIndex
>0) {
454 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
458 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
460 bPtr
->flags
.pushed
= 0;
462 if (bPtr
->view
->flags
.mapped
)
469 WMSetButtonAction(WMButton
*bPtr
, WMAction
*action
, void *clientData
)
471 CHECK_CLASS(bPtr
, WC_Button
);
473 bPtr
->action
= action
;
475 bPtr
->clientData
= clientData
;
482 radioPushObserver(void *observerData
, WMNotification
*notification
)
484 WMButton
*bPtr
= (WMButton
*)observerData
;
485 WMButton
*pushedButton
= (WMButton
*)WMGetNotificationObject(notification
);
487 if (bPtr
!=pushedButton
&& pushedButton
->groupIndex
== bPtr
->groupIndex
488 && bPtr
->groupIndex
!=0) {
489 if (bPtr
->flags
.selected
) {
490 bPtr
->flags
.selected
= 0;
499 WMGroupButtons(WMButton
*bPtr
, WMButton
*newMember
)
501 static int tagIndex
= 0;
503 CHECK_CLASS(bPtr
, WC_Button
);
504 CHECK_CLASS(newMember
, WC_Button
);
506 if (!bPtr
->flags
.addedObserver
) {
507 WMAddNotificationObserver(radioPushObserver
, bPtr
,
508 WMPushedRadioNotification
, NULL
);
509 bPtr
->flags
.addedObserver
= 1;
511 if (!newMember
->flags
.addedObserver
) {
512 WMAddNotificationObserver(radioPushObserver
, newMember
,
513 WMPushedRadioNotification
, NULL
);
514 newMember
->flags
.addedObserver
= 1;
517 if (bPtr
->groupIndex
==0) {
518 bPtr
->groupIndex
= ++tagIndex
;
520 newMember
->groupIndex
= bPtr
->groupIndex
;
525 WMSetButtonContinuous(WMButton
*bPtr
, Bool flag
)
527 bPtr
->flags
.continuous
= flag
;
529 WMDeleteTimerHandler(bPtr
->timer
);
536 WMSetButtonPeriodicDelay(WMButton
*bPtr
, float delay
, float interval
)
538 bPtr
->periodicInterval
= interval
;
539 bPtr
->periodicDelay
= delay
;
545 paintButton(Button
*bPtr
)
547 W_Screen
*scrPtr
= bPtr
->view
->screen
;
556 caption
= bPtr
->caption
;
557 if (bPtr
->flags
.enabled
|| !bPtr
->dimage
)
560 image
= bPtr
->dimage
;
562 if (bPtr
->flags
.bordered
)
567 if (bPtr
->flags
.selected
) {
568 if (bPtr
->flags
.stateLight
)
569 gc
= WMColorGC(scrPtr
->white
);
571 if (bPtr
->flags
.stateChange
) {
572 if (bPtr
->altCaption
) {
573 caption
= bPtr
->altCaption
;
576 image
= bPtr
->altImage
;
579 if (bPtr
->flags
.statePush
&& bPtr
->flags
.bordered
) {
585 if (bPtr
->flags
.pushed
) {
586 if (bPtr
->flags
.pushIn
) {
590 if (bPtr
->flags
.pushLight
)
591 gc
= WMColorGC(scrPtr
->white
);
593 if (bPtr
->flags
.pushChange
) {
594 if (bPtr
->altCaption
) {
595 caption
= bPtr
->altCaption
;
598 image
= bPtr
->altImage
;
603 if (bPtr
->flags
.enabled
)
604 textGC
= WMColorGC(scrPtr
->black
);
606 textGC
= WMColorGC(scrPtr
->darkGray
);
608 W_PaintTextAndImage(bPtr
->view
, True
, textGC
,
609 (bPtr
->font
!=NULL
? bPtr
->font
: scrPtr
->normalFont
),
610 relief
, caption
, bPtr
->flags
.alignment
, image
,
611 bPtr
->flags
.imagePosition
, gc
, offset
);
617 handleEvents(XEvent
*event
, void *data
)
619 Button
*bPtr
= (Button
*)data
;
621 CHECK_CLASS(data
, WC_Button
);
624 switch (event
->type
) {
626 if (event
->xexpose
.count
!=0)
639 autoRepeat(void *data
)
641 Button
*bPtr
= (Button
*)data
;
643 if (bPtr
->action
&& bPtr
->flags
.pushed
)
644 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
646 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicInterval
*1000),
652 handleActionEvents(XEvent
*event
, void *data
)
654 Button
*bPtr
= (Button
*)data
;
655 int doclick
= 0, dopaint
=0;
657 CHECK_CLASS(data
, WC_Button
);
659 if (!bPtr
->flags
.enabled
)
662 switch (event
->type
) {
664 if (bPtr
->groupIndex
== 0) {
665 bPtr
->flags
.pushed
= bPtr
->flags
.wasPushed
;
666 if (bPtr
->flags
.pushed
) {
667 bPtr
->flags
.selected
= !bPtr
->flags
.prevSelected
;
674 if (bPtr
->groupIndex
== 0) {
675 bPtr
->flags
.wasPushed
= bPtr
->flags
.pushed
;
676 if (bPtr
->flags
.pushed
) {
677 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
680 bPtr
->flags
.pushed
= 0;
685 if (event
->xbutton
.button
== Button1
) {
686 if (bPtr
->groupIndex
>0) {
687 if (!bPtr
->flags
.selected
)
689 bPtr
->flags
.pushed
= 1;
690 bPtr
->flags
.selected
= 1;
694 bPtr
->flags
.wasPushed
= 0;
695 bPtr
->flags
.pushed
= 1;
696 bPtr
->flags
.prevSelected
= bPtr
->flags
.selected
;
697 bPtr
->flags
.selected
= !bPtr
->flags
.selected
;
700 if (bPtr
->flags
.continuous
&& !bPtr
->timer
) {
701 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicDelay
*1000),
708 if (event
->xbutton
.button
== Button1
) {
709 if (bPtr
->flags
.pushed
) {
710 if (bPtr
->groupIndex
==0)
713 if (bPtr
->flags
.springLoaded
) {
714 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
717 bPtr
->flags
.pushed
= 0;
720 WMDeleteTimerHandler(bPtr
->timer
);
730 if (bPtr
->flags
.selected
&& bPtr
->groupIndex
>0) {
731 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
735 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
742 destroyButton(Button
*bPtr
)
744 if (bPtr
->flags
.addedObserver
) {
745 WMRemoveNotificationObserver(bPtr
);
749 WMDeleteTimerHandler(bPtr
->timer
);
752 WMReleaseFont(bPtr
->font
);
755 wfree(bPtr
->caption
);
757 if (bPtr
->altCaption
)
758 wfree(bPtr
->altCaption
);
761 WMReleasePixmap(bPtr
->image
);
765 bPtr
->dimage
->pixmap
= None
;
767 WMReleasePixmap(bPtr
->dimage
);
770 WMReleasePixmap(bPtr
->altImage
);