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 bordered
:1;
49 unsigned int springLoaded
:1;
51 unsigned int pushIn
:1; /* change relief while pushed */
53 unsigned int pushLight
:1; /* highlight while pushed */
55 unsigned int pushChange
:1; /* change caption while pushed */
57 unsigned int stateLight
:1; /* state indicated by highlight */
59 unsigned int stateChange
:1; /* state indicated by caption change */
61 unsigned int statePush
:1; /* state indicated by relief */
63 unsigned int continuous
:1; /* continually perform action */
65 unsigned int prevSelected
:1;
67 unsigned int pushed
:1;
69 unsigned int wasPushed
:1;
71 unsigned int redrawPending
:1;
73 unsigned int addedObserver
:1;
79 #define DEFAULT_BUTTON_WIDTH 60
80 #define DEFAULT_BUTTON_HEIGHT 24
81 #define DEFAULT_BUTTON_ALIGNMENT WACenter
82 #define DEFAULT_BUTTON_IS_BORDERED True
85 #define DEFAULT_RADIO_WIDTH 100
86 #define DEFAULT_RADIO_HEIGHT 20
87 #define DEFAULT_RADIO_ALIGNMENT WALeft
88 #define DEFAULT_RADIO_IMAGE_POSITION WIPLeft
89 #define DEFAULT_RADIO_TEXT "Radio"
92 #define DEFAULT_SWITCH_WIDTH 100
93 #define DEFAULT_SWITCH_HEIGHT 20
94 #define DEFAULT_SWITCH_ALIGNMENT WALeft
95 #define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft
96 #define DEFAULT_SWITCH_TEXT "Switch"
99 static void destroyButton(Button
*bPtr
);
100 static void paintButton(Button
*bPtr
);
102 static void handleEvents(XEvent
*event
, void *data
);
103 static void handleActionEvents(XEvent
*event
, void *data
);
106 static char *WMPushedRadioNotification
="WMPushedRadioNotification";
109 #define NFONT(b) (b)->view->screen->normalFont
113 WMCreateCustomButton(WMWidget
*parent
, int behaviourMask
)
117 bPtr
= wmalloc(sizeof(Button
));
118 memset(bPtr
, 0, sizeof(Button
));
120 bPtr
->widgetClass
= WC_Button
;
122 bPtr
->view
= W_CreateView(W_VIEW(parent
));
127 bPtr
->view
->self
= bPtr
;
129 bPtr
->flags
.type
= 0;
131 bPtr
->flags
.springLoaded
= (behaviourMask
& WBBSpringLoadedMask
)!=0;
132 bPtr
->flags
.pushIn
= (behaviourMask
& WBBPushInMask
)!=0;
133 bPtr
->flags
.pushChange
= (behaviourMask
& WBBPushChangeMask
)!=0;
134 bPtr
->flags
.pushLight
= (behaviourMask
& WBBPushLightMask
)!=0;
135 bPtr
->flags
.stateLight
= (behaviourMask
& WBBStateLightMask
)!=0;
136 bPtr
->flags
.stateChange
= (behaviourMask
& WBBStateChangeMask
)!=0;
137 bPtr
->flags
.statePush
= (behaviourMask
& WBBStatePushMask
)!=0;
139 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
140 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
141 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
143 bPtr
->flags
.enabled
= 1;
146 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
,
149 WMCreateEventHandler(bPtr
->view
, ButtonPressMask
|ButtonReleaseMask
150 |EnterWindowMask
|LeaveWindowMask
,
151 handleActionEvents
, bPtr
);
153 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
154 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
155 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
163 WMCreateButton(WMWidget
*parent
, WMButtonType type
)
165 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
169 case WBTMomentaryPush
:
170 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
171 |WBBPushInMask
|WBBPushLightMask
);
174 case WBTMomentaryChange
:
175 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
179 case WBTPushOnPushOff
:
180 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStatePushMask
185 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStateChangeMask
190 bPtr
= WMCreateCustomButton(parent
, WBBStateLightMask
);
194 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
195 bPtr
->flags
.bordered
= 0;
196 bPtr
->image
= WMRetainPixmap(scrPtr
->checkButtonImageOff
);
197 bPtr
->altImage
= WMRetainPixmap(scrPtr
->checkButtonImageOn
);
201 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
202 bPtr
->flags
.bordered
= 0;
203 bPtr
->image
= WMRetainPixmap(scrPtr
->radioButtonImageOff
);
204 bPtr
->altImage
= WMRetainPixmap(scrPtr
->radioButtonImageOn
);
208 case WBTMomentaryLight
:
209 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
211 bPtr
->flags
.bordered
= 1;
215 bPtr
->flags
.type
= type
;
217 if (type
==WBTRadio
) {
218 W_ResizeView(bPtr
->view
, DEFAULT_RADIO_WIDTH
, DEFAULT_RADIO_HEIGHT
);
219 WMSetButtonText(bPtr
, DEFAULT_RADIO_TEXT
);
220 bPtr
->flags
.alignment
= DEFAULT_RADIO_ALIGNMENT
;
221 bPtr
->flags
.imagePosition
= DEFAULT_RADIO_IMAGE_POSITION
;
222 } else if (type
==WBTSwitch
) {
223 W_ResizeView(bPtr
->view
, DEFAULT_SWITCH_WIDTH
, DEFAULT_SWITCH_HEIGHT
);
224 WMSetButtonText(bPtr
, DEFAULT_SWITCH_TEXT
);
225 bPtr
->flags
.alignment
= DEFAULT_SWITCH_ALIGNMENT
;
226 bPtr
->flags
.imagePosition
= DEFAULT_SWITCH_IMAGE_POSITION
;
234 updateDisabledMask(WMButton
*bPtr
)
236 WMScreen
*scr
= WMWidgetScreen(bPtr
);
237 Display
*dpy
= scr
->display
;
242 bPtr
->dimage
->mask
= XCreatePixmap(dpy
, scr
->stipple
,
244 bPtr
->dimage
->height
, 1);
246 XSetForeground(dpy
, scr
->monoGC
, 0);
247 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
248 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
252 gcv
.stipple
= scr
->stipple
;
253 gcv
.fill_style
= FillStippled
;
254 gcv
.clip_mask
= bPtr
->image
->mask
;
255 gcv
.clip_x_origin
= 0;
256 gcv
.clip_y_origin
= 0;
258 XChangeGC(dpy
, scr
->monoGC
, GCForeground
|GCBackground
|GCStipple
259 |GCFillStyle
|GCClipMask
|GCClipXOrigin
|GCClipYOrigin
, &gcv
);
261 XFillRectangle(dpy
, bPtr
->dimage
->mask
, scr
->monoGC
, 0, 0,
262 bPtr
->dimage
->width
, bPtr
->dimage
->height
);
264 gcv
.fill_style
= FillSolid
;
265 gcv
.clip_mask
= None
;
266 XChangeGC(dpy
, scr
->monoGC
, GCFillStyle
|GCClipMask
, &gcv
);
271 WMSetButtonImageDefault(WMButton
*bPtr
)
273 WMSetButtonImage (bPtr
, WMWidgetScreen(bPtr
)->buttonArrow
);
274 WMSetButtonAltImage (bPtr
, WMWidgetScreen(bPtr
)->pushedButtonArrow
);
278 WMSetButtonImage(WMButton
*bPtr
, WMPixmap
*image
)
280 if (bPtr
->image
!=NULL
)
281 WMReleasePixmap(bPtr
->image
);
282 bPtr
->image
= WMRetainPixmap(image
);
285 bPtr
->dimage
->pixmap
= None
;
286 WMReleasePixmap(bPtr
->dimage
);
291 bPtr
->dimage
= WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr
),
293 image
->width
, image
->height
,
295 updateDisabledMask(bPtr
);
298 if (bPtr
->view
->flags
.realized
) {
305 WMSetButtonAltImage(WMButton
*bPtr
, WMPixmap
*image
)
307 if (bPtr
->altImage
!=NULL
)
308 WMReleasePixmap(bPtr
->altImage
);
309 bPtr
->altImage
= WMRetainPixmap(image
);
312 if (bPtr
->view
->flags
.realized
) {
319 WMSetButtonImagePosition(WMButton
*bPtr
, WMImagePosition position
)
321 bPtr
->flags
.imagePosition
= position
;
324 if (bPtr
->view
->flags
.realized
) {
333 WMSetButtonTextAlignment(WMButton
*bPtr
, WMAlignment alignment
)
335 bPtr
->flags
.alignment
= alignment
;
338 if (bPtr
->view
->flags
.realized
) {
344 WMSetButtonText(WMButton
*bPtr
, char *text
)
347 wfree(bPtr
->caption
);
350 bPtr
->caption
= wstrdup(text
);
352 bPtr
->caption
= NULL
;
356 if (bPtr
->view
->flags
.realized
) {
363 WMSetButtonAltText(WMButton
*bPtr
, char *text
)
365 if (bPtr
->altCaption
)
366 wfree(bPtr
->altCaption
);
369 bPtr
->altCaption
= wstrdup(text
);
371 bPtr
->altCaption
= NULL
;
374 if (bPtr
->view
->flags
.realized
) {
381 WMSetButtonTextColor(WMButton
*bPtr
, WMColor
*color
)
384 WMReleaseColor(bPtr
->textColor
);
386 bPtr
->textColor
= WMRetainColor(color
);
391 WMSetButtonAltTextColor(WMButton
*bPtr
, WMColor
*color
)
393 if (bPtr
->altTextColor
)
394 WMReleaseColor(bPtr
->altTextColor
);
396 bPtr
->altTextColor
= WMRetainColor(color
);
401 WMSetButtonDisabledTextColor(WMButton
*bPtr
, WMColor
*color
)
403 if (bPtr
->disTextColor
)
404 WMReleaseColor(bPtr
->disTextColor
);
406 bPtr
->disTextColor
= WMRetainColor(color
);
411 WMSetButtonSelected(WMButton
*bPtr
, int isSelected
)
413 bPtr
->flags
.selected
= isSelected
;
415 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
417 if (bPtr
->view
->flags
.realized
) {
424 WMGetButtonSelected(WMButton
*bPtr
)
426 CHECK_CLASS(bPtr
, WC_Button
);
428 return bPtr
->flags
.selected
;
433 WMSetButtonBordered(WMButton
*bPtr
, int isBordered
)
435 bPtr
->flags
.bordered
= isBordered
;
437 if (bPtr
->view
->flags
.realized
) {
444 WMSetButtonFont(WMButton
*bPtr
, WMFont
*font
)
447 WMReleaseFont(bPtr
->font
);
449 bPtr
->font
= WMRetainFont(font
);
454 WMSetButtonEnabled(WMButton
*bPtr
, Bool flag
)
456 bPtr
->flags
.enabled
= flag
;
458 if (bPtr
->view
->flags
.mapped
) {
465 WMSetButtonTag(WMButton
*bPtr
, int tag
)
473 WMPerformButtonClick(WMButton
*bPtr
)
475 CHECK_CLASS(bPtr
, WC_Button
);
477 if (!bPtr
->flags
.enabled
)
480 bPtr
->flags
.pushed
= 1;
481 bPtr
->flags
.selected
= 1;
483 if (bPtr
->view
->flags
.mapped
) {
485 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr
)));
489 if (bPtr
->groupIndex
>0) {
490 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
494 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
496 bPtr
->flags
.pushed
= 0;
498 if (bPtr
->view
->flags
.mapped
)
505 WMSetButtonAction(WMButton
*bPtr
, WMAction
*action
, void *clientData
)
507 CHECK_CLASS(bPtr
, WC_Button
);
509 bPtr
->action
= action
;
511 bPtr
->clientData
= clientData
;
518 radioPushObserver(void *observerData
, WMNotification
*notification
)
520 WMButton
*bPtr
= (WMButton
*)observerData
;
521 WMButton
*pushedButton
= (WMButton
*)WMGetNotificationObject(notification
);
523 if (bPtr
!=pushedButton
&& pushedButton
->groupIndex
== bPtr
->groupIndex
524 && bPtr
->groupIndex
!=0) {
525 if (bPtr
->flags
.selected
) {
526 bPtr
->flags
.selected
= 0;
535 WMGroupButtons(WMButton
*bPtr
, WMButton
*newMember
)
537 static int tagIndex
= 0;
539 CHECK_CLASS(bPtr
, WC_Button
);
540 CHECK_CLASS(newMember
, WC_Button
);
542 if (!bPtr
->flags
.addedObserver
) {
543 WMAddNotificationObserver(radioPushObserver
, bPtr
,
544 WMPushedRadioNotification
, NULL
);
545 bPtr
->flags
.addedObserver
= 1;
547 if (!newMember
->flags
.addedObserver
) {
548 WMAddNotificationObserver(radioPushObserver
, newMember
,
549 WMPushedRadioNotification
, NULL
);
550 newMember
->flags
.addedObserver
= 1;
553 if (bPtr
->groupIndex
==0) {
554 bPtr
->groupIndex
= ++tagIndex
;
556 newMember
->groupIndex
= bPtr
->groupIndex
;
561 WMSetButtonContinuous(WMButton
*bPtr
, Bool flag
)
563 bPtr
->flags
.continuous
= flag
;
565 WMDeleteTimerHandler(bPtr
->timer
);
572 WMSetButtonPeriodicDelay(WMButton
*bPtr
, float delay
, float interval
)
574 bPtr
->periodicInterval
= interval
;
575 bPtr
->periodicDelay
= delay
;
581 paintButton(Button
*bPtr
)
583 W_Screen
*scrPtr
= bPtr
->view
->screen
;
592 caption
= bPtr
->caption
;
594 if (bPtr
->flags
.enabled
) {
595 textColor
= (bPtr
->textColor
!=NULL
596 ? bPtr
->textColor
: scrPtr
->black
);
598 textColor
= (bPtr
->disTextColor
!=NULL
599 ? bPtr
->disTextColor
: scrPtr
->darkGray
);
602 if (bPtr
->flags
.enabled
|| !bPtr
->dimage
)
605 image
= bPtr
->dimage
;
607 if (bPtr
->flags
.bordered
)
612 if (bPtr
->flags
.selected
) {
613 if (bPtr
->flags
.stateLight
) {
614 gc
= WMColorGC(scrPtr
->white
);
615 textColor
= scrPtr
->black
;
618 if (bPtr
->flags
.stateChange
) {
619 if (bPtr
->altCaption
)
620 caption
= bPtr
->altCaption
;
622 image
= bPtr
->altImage
;
623 if (bPtr
->altTextColor
)
624 textColor
= bPtr
->altTextColor
;
627 if (bPtr
->flags
.statePush
&& bPtr
->flags
.bordered
) {
633 if (bPtr
->flags
.pushed
) {
634 if (bPtr
->flags
.pushIn
) {
638 if (bPtr
->flags
.pushLight
) {
639 gc
= WMColorGC(scrPtr
->white
);
640 textColor
= scrPtr
->black
;
643 if (bPtr
->flags
.pushChange
) {
644 if (bPtr
->altCaption
)
645 caption
= bPtr
->altCaption
;
647 image
= bPtr
->altImage
;
648 if (bPtr
->altTextColor
)
649 textColor
= bPtr
->altTextColor
;
653 W_PaintTextAndImage(bPtr
->view
, True
, WMColorGC(textColor
),
654 (bPtr
->font
!=NULL
? bPtr
->font
: scrPtr
->normalFont
),
655 relief
, caption
, bPtr
->flags
.alignment
, image
,
656 bPtr
->flags
.imagePosition
, gc
, offset
);
662 handleEvents(XEvent
*event
, void *data
)
664 Button
*bPtr
= (Button
*)data
;
666 CHECK_CLASS(data
, WC_Button
);
669 switch (event
->type
) {
671 if (event
->xexpose
.count
!=0)
684 autoRepeat(void *data
)
686 Button
*bPtr
= (Button
*)data
;
688 if (bPtr
->action
&& bPtr
->flags
.pushed
)
689 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
691 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicInterval
*1000),
697 handleActionEvents(XEvent
*event
, void *data
)
699 Button
*bPtr
= (Button
*)data
;
700 int doclick
= 0, dopaint
=0;
702 CHECK_CLASS(data
, WC_Button
);
704 if (!bPtr
->flags
.enabled
)
707 switch (event
->type
) {
709 if (bPtr
->groupIndex
== 0) {
710 bPtr
->flags
.pushed
= bPtr
->flags
.wasPushed
;
711 if (bPtr
->flags
.pushed
) {
712 bPtr
->flags
.selected
= !bPtr
->flags
.prevSelected
;
719 if (bPtr
->groupIndex
== 0) {
720 bPtr
->flags
.wasPushed
= bPtr
->flags
.pushed
;
721 if (bPtr
->flags
.pushed
) {
722 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
725 bPtr
->flags
.pushed
= 0;
730 if (event
->xbutton
.button
== Button1
) {
731 if (bPtr
->groupIndex
>0) {
732 if (!bPtr
->flags
.selected
)
734 bPtr
->flags
.pushed
= 1;
735 bPtr
->flags
.selected
= 1;
739 bPtr
->flags
.wasPushed
= 0;
740 bPtr
->flags
.pushed
= 1;
741 bPtr
->flags
.prevSelected
= bPtr
->flags
.selected
;
742 bPtr
->flags
.selected
= !bPtr
->flags
.selected
;
745 if (bPtr
->flags
.continuous
&& !bPtr
->timer
) {
746 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicDelay
*1000),
753 if (event
->xbutton
.button
== Button1
) {
754 if (bPtr
->flags
.pushed
) {
755 if (bPtr
->groupIndex
==0)
758 if (bPtr
->flags
.springLoaded
) {
759 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
762 bPtr
->flags
.pushed
= 0;
765 WMDeleteTimerHandler(bPtr
->timer
);
775 if (bPtr
->flags
.selected
&& bPtr
->groupIndex
>0) {
776 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
780 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
787 destroyButton(Button
*bPtr
)
789 if (bPtr
->flags
.addedObserver
) {
790 WMRemoveNotificationObserver(bPtr
);
794 WMDeleteTimerHandler(bPtr
->timer
);
797 WMReleaseFont(bPtr
->font
);
800 wfree(bPtr
->caption
);
802 if (bPtr
->altCaption
)
803 wfree(bPtr
->altCaption
);
806 WMReleaseColor(bPtr
->textColor
);
808 if (bPtr
->altTextColor
)
809 WMReleaseColor(bPtr
->altTextColor
);
811 if (bPtr
->disTextColor
)
812 WMReleaseColor(bPtr
->disTextColor
);
815 WMReleasePixmap(bPtr
->image
);
819 bPtr
->dimage
->pixmap
= None
;
821 WMReleasePixmap(bPtr
->dimage
);
824 WMReleasePixmap(bPtr
->altImage
);