7 typedef struct W_Button
{
18 WMColor
*altTextColor
;
19 WMColor
*disTextColor
;
34 float periodicInterval
;
36 WMHandlerID
*timer
; /* for continuous mode */
40 WMImagePosition imagePosition
:4;
41 WMAlignment alignment
:2;
43 unsigned int selected
:1;
45 unsigned int enabled
:1;
47 unsigned int dimsWhenDisabled
:1;
49 unsigned int bordered
:1;
51 unsigned int springLoaded
:1;
53 unsigned int pushIn
:1; /* change relief while pushed */
55 unsigned int pushLight
:1; /* highlight while pushed */
57 unsigned int pushChange
:1; /* change caption while pushed */
59 unsigned int stateLight
:1; /* state indicated by highlight */
61 unsigned int stateChange
:1; /* state indicated by caption change */
63 unsigned int statePush
:1; /* state indicated by relief */
65 unsigned int continuous
:1; /* continually perform action */
67 unsigned int prevSelected
:1;
69 unsigned int pushed
:1;
71 unsigned int wasPushed
:1;
73 unsigned int redrawPending
:1;
75 unsigned int addedObserver
:1;
81 #define DEFAULT_BUTTON_WIDTH 60
82 #define DEFAULT_BUTTON_HEIGHT 24
83 #define DEFAULT_BUTTON_ALIGNMENT WACenter
84 #define DEFAULT_BUTTON_IS_BORDERED True
87 #define DEFAULT_RADIO_WIDTH 100
88 #define DEFAULT_RADIO_HEIGHT 20
89 #define DEFAULT_RADIO_ALIGNMENT WALeft
90 #define DEFAULT_RADIO_IMAGE_POSITION WIPLeft
91 #define DEFAULT_RADIO_TEXT "Radio"
94 #define DEFAULT_SWITCH_WIDTH 100
95 #define DEFAULT_SWITCH_HEIGHT 20
96 #define DEFAULT_SWITCH_ALIGNMENT WALeft
97 #define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft
98 #define DEFAULT_SWITCH_TEXT "Switch"
101 static void destroyButton(Button
*bPtr
);
102 static void paintButton(Button
*bPtr
);
104 static void handleEvents(XEvent
*event
, void *data
);
105 static void handleActionEvents(XEvent
*event
, void *data
);
108 static char *WMPushedRadioNotification
="WMPushedRadioNotification";
111 #define NFONT(b) (b)->view->screen->normalFont
115 WMCreateCustomButton(WMWidget
*parent
, int behaviourMask
)
119 bPtr
= wmalloc(sizeof(Button
));
120 memset(bPtr
, 0, sizeof(Button
));
122 bPtr
->widgetClass
= WC_Button
;
124 bPtr
->view
= W_CreateView(W_VIEW(parent
));
129 bPtr
->view
->self
= bPtr
;
131 bPtr
->flags
.type
= 0;
133 bPtr
->flags
.springLoaded
= (behaviourMask
& WBBSpringLoadedMask
)!=0;
134 bPtr
->flags
.pushIn
= (behaviourMask
& WBBPushInMask
)!=0;
135 bPtr
->flags
.pushChange
= (behaviourMask
& WBBPushChangeMask
)!=0;
136 bPtr
->flags
.pushLight
= (behaviourMask
& WBBPushLightMask
)!=0;
137 bPtr
->flags
.stateLight
= (behaviourMask
& WBBStateLightMask
)!=0;
138 bPtr
->flags
.stateChange
= (behaviourMask
& WBBStateChangeMask
)!=0;
139 bPtr
->flags
.statePush
= (behaviourMask
& WBBStatePushMask
)!=0;
141 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
142 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
143 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
145 bPtr
->flags
.enabled
= 1;
146 bPtr
->flags
.dimsWhenDisabled
= 1;
148 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
,
151 WMCreateEventHandler(bPtr
->view
, ButtonPressMask
|ButtonReleaseMask
152 |EnterWindowMask
|LeaveWindowMask
,
153 handleActionEvents
, bPtr
);
155 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
156 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
157 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
165 WMCreateButton(WMWidget
*parent
, WMButtonType type
)
167 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
171 case WBTMomentaryPush
:
172 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
173 |WBBPushInMask
|WBBPushLightMask
);
176 case WBTMomentaryChange
:
177 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
181 case WBTPushOnPushOff
:
182 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStatePushMask
187 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStateChangeMask
192 bPtr
= WMCreateCustomButton(parent
, WBBStateLightMask
);
196 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
197 bPtr
->flags
.bordered
= 0;
198 bPtr
->image
= WMRetainPixmap(scrPtr
->checkButtonImageOff
);
199 bPtr
->altImage
= WMRetainPixmap(scrPtr
->checkButtonImageOn
);
203 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
204 bPtr
->flags
.bordered
= 0;
205 bPtr
->image
= WMRetainPixmap(scrPtr
->radioButtonImageOff
);
206 bPtr
->altImage
= WMRetainPixmap(scrPtr
->radioButtonImageOn
);
210 case WBTMomentaryLight
:
211 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
213 bPtr
->flags
.bordered
= 1;
217 bPtr
->flags
.type
= type
;
219 if (type
==WBTRadio
) {
220 W_ResizeView(bPtr
->view
, DEFAULT_RADIO_WIDTH
, DEFAULT_RADIO_HEIGHT
);
221 WMSetButtonText(bPtr
, DEFAULT_RADIO_TEXT
);
222 bPtr
->flags
.alignment
= DEFAULT_RADIO_ALIGNMENT
;
223 bPtr
->flags
.imagePosition
= DEFAULT_RADIO_IMAGE_POSITION
;
224 } else if (type
==WBTSwitch
) {
225 W_ResizeView(bPtr
->view
, DEFAULT_SWITCH_WIDTH
, DEFAULT_SWITCH_HEIGHT
);
226 WMSetButtonText(bPtr
, DEFAULT_SWITCH_TEXT
);
227 bPtr
->flags
.alignment
= DEFAULT_SWITCH_ALIGNMENT
;
228 bPtr
->flags
.imagePosition
= DEFAULT_SWITCH_IMAGE_POSITION
;
236 updateDisabledMask(WMButton
*bPtr
)
238 WMScreen
*scr
= WMWidgetScreen(bPtr
);
239 Display
*dpy
= scr
->display
;
244 if (bPtr
->dimage
->mask
) {
245 XFreePixmap(dpy
, bPtr
->dimage
->mask
);
246 bPtr
->dimage
->mask
= None
;
249 if (bPtr
->flags
.dimsWhenDisabled
) {
250 bPtr
->dimage
->mask
= XCreatePixmap(dpy
, scr
->stipple
,
252 bPtr
->dimage
->height
, 1);
254 XSetForeground(dpy
, scr
->monoGC
, 0);
255 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
256 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
260 gcv
.stipple
= scr
->stipple
;
261 gcv
.fill_style
= FillStippled
;
262 gcv
.clip_mask
= bPtr
->image
->mask
;
263 gcv
.clip_x_origin
= 0;
264 gcv
.clip_y_origin
= 0;
266 XChangeGC(dpy
, scr
->monoGC
, GCForeground
|GCBackground
|GCStipple
267 |GCFillStyle
|GCClipMask
|GCClipXOrigin
|GCClipYOrigin
, &gcv
);
269 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
270 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
272 gcv
.fill_style
= FillSolid
;
273 gcv
.clip_mask
= None
;
274 XChangeGC(dpy
, scr
->monoGC
, GCFillStyle
|GCClipMask
, &gcv
);
280 WMSetButtonImageDefault(WMButton
*bPtr
)
282 WMSetButtonImage (bPtr
, WMWidgetScreen(bPtr
)->buttonArrow
);
283 WMSetButtonAltImage (bPtr
, WMWidgetScreen(bPtr
)->pushedButtonArrow
);
287 WMSetButtonImage(WMButton
*bPtr
, WMPixmap
*image
)
289 if (bPtr
->image
!=NULL
)
290 WMReleasePixmap(bPtr
->image
);
291 bPtr
->image
= WMRetainPixmap(image
);
294 bPtr
->dimage
->pixmap
= None
;
295 WMReleasePixmap(bPtr
->dimage
);
300 bPtr
->dimage
= WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr
),
302 image
->width
, image
->height
,
304 updateDisabledMask(bPtr
);
307 if (bPtr
->view
->flags
.realized
) {
314 WMSetButtonAltImage(WMButton
*bPtr
, WMPixmap
*image
)
316 if (bPtr
->altImage
!=NULL
)
317 WMReleasePixmap(bPtr
->altImage
);
318 bPtr
->altImage
= WMRetainPixmap(image
);
321 if (bPtr
->view
->flags
.realized
) {
328 WMSetButtonImagePosition(WMButton
*bPtr
, WMImagePosition position
)
330 bPtr
->flags
.imagePosition
= position
;
333 if (bPtr
->view
->flags
.realized
) {
342 WMSetButtonTextAlignment(WMButton
*bPtr
, WMAlignment alignment
)
344 bPtr
->flags
.alignment
= alignment
;
347 if (bPtr
->view
->flags
.realized
) {
353 WMSetButtonText(WMButton
*bPtr
, char *text
)
356 wfree(bPtr
->caption
);
359 bPtr
->caption
= wstrdup(text
);
361 bPtr
->caption
= NULL
;
365 if (bPtr
->view
->flags
.realized
) {
372 WMSetButtonAltText(WMButton
*bPtr
, char *text
)
374 if (bPtr
->altCaption
)
375 wfree(bPtr
->altCaption
);
378 bPtr
->altCaption
= wstrdup(text
);
380 bPtr
->altCaption
= NULL
;
383 if (bPtr
->view
->flags
.realized
) {
390 WMSetButtonTextColor(WMButton
*bPtr
, WMColor
*color
)
393 WMReleaseColor(bPtr
->textColor
);
395 bPtr
->textColor
= WMRetainColor(color
);
400 WMSetButtonAltTextColor(WMButton
*bPtr
, WMColor
*color
)
402 if (bPtr
->altTextColor
)
403 WMReleaseColor(bPtr
->altTextColor
);
405 bPtr
->altTextColor
= WMRetainColor(color
);
410 WMSetButtonDisabledTextColor(WMButton
*bPtr
, WMColor
*color
)
412 if (bPtr
->disTextColor
)
413 WMReleaseColor(bPtr
->disTextColor
);
415 bPtr
->disTextColor
= WMRetainColor(color
);
420 WMSetButtonSelected(WMButton
*bPtr
, int isSelected
)
422 bPtr
->flags
.selected
= isSelected
? 1 : 0;
424 if (bPtr
->view
->flags
.realized
) {
427 if (bPtr
->groupIndex
> 0)
428 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
433 WMGetButtonSelected(WMButton
*bPtr
)
435 CHECK_CLASS(bPtr
, WC_Button
);
437 return bPtr
->flags
.selected
;
442 WMSetButtonBordered(WMButton
*bPtr
, int isBordered
)
444 bPtr
->flags
.bordered
= isBordered
;
446 if (bPtr
->view
->flags
.realized
) {
453 WMSetButtonFont(WMButton
*bPtr
, WMFont
*font
)
456 WMReleaseFont(bPtr
->font
);
458 bPtr
->font
= WMRetainFont(font
);
463 WMSetButtonEnabled(WMButton
*bPtr
, Bool flag
)
465 bPtr
->flags
.enabled
= ((flag
==0) ? 0 : 1);
467 if (bPtr
->view
->flags
.mapped
) {
474 WMGetButtonEnabled(WMButton
*bPtr
)
476 CHECK_CLASS(bPtr
, WC_Button
);
478 return bPtr
->flags
.enabled
;
483 WMSetButtonImageDimsWhenDisabled(WMButton
*bPtr
, Bool flag
)
485 bPtr
->flags
.dimsWhenDisabled
= ((flag
==0) ? 0 : 1);
487 updateDisabledMask(bPtr
);
492 WMSetButtonTag(WMButton
*bPtr
, int tag
)
499 WMPerformButtonClick(WMButton
*bPtr
)
501 CHECK_CLASS(bPtr
, WC_Button
);
503 if (!bPtr
->flags
.enabled
)
506 bPtr
->flags
.pushed
= 1;
507 bPtr
->flags
.selected
= 1;
509 if (bPtr
->view
->flags
.mapped
) {
511 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr
)));
515 bPtr
->flags
.pushed
= 0;
517 if (bPtr
->groupIndex
> 0) {
518 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
522 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
524 if (bPtr
->view
->flags
.mapped
)
531 WMSetButtonAction(WMButton
*bPtr
, WMAction
*action
, void *clientData
)
533 CHECK_CLASS(bPtr
, WC_Button
);
535 bPtr
->action
= action
;
537 bPtr
->clientData
= clientData
;
544 radioPushObserver(void *observerData
, WMNotification
*notification
)
546 WMButton
*bPtr
= (WMButton
*)observerData
;
547 WMButton
*pushedButton
= (WMButton
*)WMGetNotificationObject(notification
);
549 if (bPtr
!=pushedButton
&& pushedButton
->groupIndex
== bPtr
->groupIndex
550 && bPtr
->groupIndex
!=0) {
551 if (bPtr
->flags
.selected
) {
552 bPtr
->flags
.selected
= 0;
561 WMGroupButtons(WMButton
*bPtr
, WMButton
*newMember
)
563 static int tagIndex
= 0;
565 CHECK_CLASS(bPtr
, WC_Button
);
566 CHECK_CLASS(newMember
, WC_Button
);
568 if (!bPtr
->flags
.addedObserver
) {
569 WMAddNotificationObserver(radioPushObserver
, bPtr
,
570 WMPushedRadioNotification
, NULL
);
571 bPtr
->flags
.addedObserver
= 1;
573 if (!newMember
->flags
.addedObserver
) {
574 WMAddNotificationObserver(radioPushObserver
, newMember
,
575 WMPushedRadioNotification
, NULL
);
576 newMember
->flags
.addedObserver
= 1;
579 if (bPtr
->groupIndex
==0) {
580 bPtr
->groupIndex
= ++tagIndex
;
582 newMember
->groupIndex
= bPtr
->groupIndex
;
587 WMSetButtonContinuous(WMButton
*bPtr
, Bool flag
)
589 bPtr
->flags
.continuous
= ((flag
==0) ? 0 : 1);
591 WMDeleteTimerHandler(bPtr
->timer
);
598 WMSetButtonPeriodicDelay(WMButton
*bPtr
, float delay
, float interval
)
600 bPtr
->periodicInterval
= interval
;
601 bPtr
->periodicDelay
= delay
;
607 paintButton(Button
*bPtr
)
609 W_Screen
*scrPtr
= bPtr
->view
->screen
;
618 caption
= bPtr
->caption
;
620 if (bPtr
->flags
.enabled
) {
621 textColor
= (bPtr
->textColor
!=NULL
622 ? bPtr
->textColor
: scrPtr
->black
);
624 textColor
= (bPtr
->disTextColor
!=NULL
625 ? bPtr
->disTextColor
: scrPtr
->darkGray
);
628 if (bPtr
->flags
.enabled
|| !bPtr
->dimage
)
631 image
= bPtr
->dimage
;
633 if (bPtr
->flags
.bordered
)
638 if (bPtr
->flags
.selected
) {
639 if (bPtr
->flags
.stateLight
) {
640 backColor
= scrPtr
->white
;
641 textColor
= scrPtr
->black
;
644 if (bPtr
->flags
.stateChange
) {
645 if (bPtr
->altCaption
)
646 caption
= bPtr
->altCaption
;
648 image
= bPtr
->altImage
;
649 if (bPtr
->altTextColor
)
650 textColor
= bPtr
->altTextColor
;
653 if (bPtr
->flags
.statePush
&& bPtr
->flags
.bordered
) {
659 if (bPtr
->flags
.pushed
) {
660 if (bPtr
->flags
.pushIn
) {
664 if (bPtr
->flags
.pushLight
) {
665 backColor
= scrPtr
->white
;
666 textColor
= scrPtr
->black
;
669 if (bPtr
->flags
.pushChange
) {
670 if (bPtr
->altCaption
)
671 caption
= bPtr
->altCaption
;
673 image
= bPtr
->altImage
;
674 if (bPtr
->altTextColor
)
675 textColor
= bPtr
->altTextColor
;
679 W_PaintTextAndImage(bPtr
->view
, True
, textColor
,
680 (bPtr
->font
!=NULL
? bPtr
->font
: scrPtr
->normalFont
),
681 relief
, caption
, bPtr
->flags
.alignment
, image
,
682 bPtr
->flags
.imagePosition
, backColor
, offset
);
688 handleEvents(XEvent
*event
, void *data
)
690 Button
*bPtr
= (Button
*)data
;
692 CHECK_CLASS(data
, WC_Button
);
695 switch (event
->type
) {
697 if (event
->xexpose
.count
!=0)
710 autoRepeat(void *data
)
712 Button
*bPtr
= (Button
*)data
;
714 if (bPtr
->action
&& bPtr
->flags
.pushed
)
715 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
717 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicInterval
*1000),
723 handleActionEvents(XEvent
*event
, void *data
)
725 Button
*bPtr
= (Button
*)data
;
726 int doclick
= 0, dopaint
=0;
728 CHECK_CLASS(data
, WC_Button
);
730 if (!bPtr
->flags
.enabled
)
733 switch (event
->type
) {
735 if (bPtr
->groupIndex
== 0) {
736 bPtr
->flags
.pushed
= bPtr
->flags
.wasPushed
;
737 if (bPtr
->flags
.pushed
) {
738 bPtr
->flags
.selected
= !bPtr
->flags
.prevSelected
;
745 if (bPtr
->groupIndex
== 0) {
746 bPtr
->flags
.wasPushed
= bPtr
->flags
.pushed
;
747 if (bPtr
->flags
.pushed
) {
748 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
751 bPtr
->flags
.pushed
= 0;
756 if (event
->xbutton
.button
== Button1
) {
757 bPtr
->flags
.prevSelected
= bPtr
->flags
.selected
;
758 bPtr
->flags
.wasPushed
= 0;
759 bPtr
->flags
.pushed
= 1;
760 if (bPtr
->groupIndex
>0) {
761 bPtr
->flags
.selected
= 1;
765 bPtr
->flags
.selected
= !bPtr
->flags
.selected
;
768 if (bPtr
->flags
.continuous
&& !bPtr
->timer
) {
769 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicDelay
*1000),
776 if (event
->xbutton
.button
== Button1
) {
777 if (bPtr
->flags
.pushed
) {
778 if (bPtr
->groupIndex
==0 ||
779 (bPtr
->flags
.selected
&& bPtr
->groupIndex
> 0))
782 if (bPtr
->flags
.springLoaded
) {
783 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
786 bPtr
->flags
.pushed
= 0;
789 WMDeleteTimerHandler(bPtr
->timer
);
799 if (bPtr
->flags
.selected
&& bPtr
->groupIndex
> 0) {
800 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
804 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
811 destroyButton(Button
*bPtr
)
813 if (bPtr
->flags
.addedObserver
) {
814 WMRemoveNotificationObserver(bPtr
);
818 WMDeleteTimerHandler(bPtr
->timer
);
821 WMReleaseFont(bPtr
->font
);
824 wfree(bPtr
->caption
);
826 if (bPtr
->altCaption
)
827 wfree(bPtr
->altCaption
);
830 WMReleaseColor(bPtr
->textColor
);
832 if (bPtr
->altTextColor
)
833 WMReleaseColor(bPtr
->altTextColor
);
835 if (bPtr
->disTextColor
)
836 WMReleaseColor(bPtr
->disTextColor
);
839 WMReleasePixmap(bPtr
->image
);
843 bPtr
->dimage
->pixmap
= None
;
845 WMReleasePixmap(bPtr
->dimage
);
848 WMReleasePixmap(bPtr
->altImage
);