7 typedef struct W_Button
{
28 float periodicInterval
;
30 WMHandlerID
*timer
; /* for continuous mode */
34 WMImagePosition imagePosition
:4;
35 WMAlignment alignment
:2;
37 unsigned int selected
:1;
39 unsigned int enabled
:1;
41 unsigned int bordered
:1;
43 unsigned int springLoaded
:1;
45 unsigned int pushIn
:1; /* change relief while pushed */
47 unsigned int pushLight
:1; /* highlight while pushed */
49 unsigned int pushChange
:1; /* change caption while pushed */
51 unsigned int stateLight
:1; /* state indicated by highlight */
53 unsigned int stateChange
:1; /* state indicated by caption change */
55 unsigned int statePush
:1; /* state indicated by relief */
57 unsigned int continuous
:1; /* continually perform action */
59 unsigned int prevSelected
:1;
61 unsigned int pushed
:1;
63 unsigned int wasPushed
:1;
65 unsigned int redrawPending
:1;
67 unsigned int addedObserver
:1;
73 #define DEFAULT_BUTTON_WIDTH 60
74 #define DEFAULT_BUTTON_HEIGHT 24
75 #define DEFAULT_BUTTON_ALIGNMENT WACenter
76 #define DEFAULT_BUTTON_IS_BORDERED True
79 #define DEFAULT_RADIO_WIDTH 100
80 #define DEFAULT_RADIO_HEIGHT 20
81 #define DEFAULT_RADIO_ALIGNMENT WALeft
82 #define DEFAULT_RADIO_IMAGE_POSITION WIPLeft
83 #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"
93 static void destroyButton(Button
*bPtr
);
94 static void paintButton(Button
*bPtr
);
96 static void handleEvents(XEvent
*event
, void *data
);
97 static void handleActionEvents(XEvent
*event
, void *data
);
100 W_ViewProcedureTable _ButtonViewProcedures
= {
107 static char *WMPushedRadioNotification
="WMPushedRadioNotification";
110 #define NFONT(b) (b)->view->screen->normalFont
114 WMCreateCustomButton(WMWidget
*parent
, int behaviourMask
)
118 bPtr
= wmalloc(sizeof(Button
));
119 memset(bPtr
, 0, sizeof(Button
));
121 bPtr
->widgetClass
= WC_Button
;
123 bPtr
->view
= W_CreateView(W_VIEW(parent
));
128 bPtr
->view
->self
= bPtr
;
130 bPtr
->flags
.type
= 0;
132 bPtr
->flags
.springLoaded
= (behaviourMask
& WBBSpringLoadedMask
)!=0;
133 bPtr
->flags
.pushIn
= (behaviourMask
& WBBPushInMask
)!=0;
134 bPtr
->flags
.pushChange
= (behaviourMask
& WBBPushChangeMask
)!=0;
135 bPtr
->flags
.pushLight
= (behaviourMask
& WBBPushLightMask
)!=0;
136 bPtr
->flags
.stateLight
= (behaviourMask
& WBBStateLightMask
)!=0;
137 bPtr
->flags
.stateChange
= (behaviourMask
& WBBStateChangeMask
)!=0;
138 bPtr
->flags
.statePush
= (behaviourMask
& WBBStatePushMask
)!=0;
140 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
141 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
142 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
144 bPtr
->flags
.enabled
= 1;
147 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
,
150 WMCreateEventHandler(bPtr
->view
, ButtonPressMask
|ButtonReleaseMask
151 |EnterWindowMask
|LeaveWindowMask
,
152 handleActionEvents
, bPtr
);
154 W_ResizeView(bPtr
->view
, DEFAULT_BUTTON_WIDTH
, DEFAULT_BUTTON_HEIGHT
);
155 bPtr
->flags
.alignment
= DEFAULT_BUTTON_ALIGNMENT
;
156 bPtr
->flags
.bordered
= DEFAULT_BUTTON_IS_BORDERED
;
164 WMCreateButton(WMWidget
*parent
, WMButtonType type
)
166 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
170 case WBTMomentaryPush
:
171 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
172 |WBBPushInMask
|WBBPushLightMask
);
175 case WBTMomentaryChange
:
176 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
180 case WBTPushOnPushOff
:
181 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStatePushMask
186 bPtr
= WMCreateCustomButton(parent
, WBBPushInMask
|WBBStateChangeMask
191 bPtr
= WMCreateCustomButton(parent
, WBBStateLightMask
);
195 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
196 bPtr
->flags
.bordered
= 0;
197 bPtr
->image
= WMRetainPixmap(scrPtr
->checkButtonImageOff
);
198 bPtr
->altImage
= WMRetainPixmap(scrPtr
->checkButtonImageOn
);
202 bPtr
= WMCreateCustomButton(parent
, WBBStateChangeMask
);
203 bPtr
->flags
.bordered
= 0;
204 bPtr
->image
= WMRetainPixmap(scrPtr
->radioButtonImageOff
);
205 bPtr
->altImage
= WMRetainPixmap(scrPtr
->radioButtonImageOn
);
209 case WBTMomentaryLight
:
210 bPtr
= WMCreateCustomButton(parent
, WBBSpringLoadedMask
212 bPtr
->flags
.bordered
= 1;
216 bPtr
->flags
.type
= type
;
218 if (type
==WBTRadio
) {
219 W_ResizeView(bPtr
->view
, DEFAULT_RADIO_WIDTH
, DEFAULT_RADIO_HEIGHT
);
220 WMSetButtonText(bPtr
, DEFAULT_RADIO_TEXT
);
221 bPtr
->flags
.alignment
= DEFAULT_RADIO_ALIGNMENT
;
222 bPtr
->flags
.imagePosition
= DEFAULT_RADIO_IMAGE_POSITION
;
223 } else if (type
==WBTSwitch
) {
224 W_ResizeView(bPtr
->view
, DEFAULT_SWITCH_WIDTH
, DEFAULT_SWITCH_HEIGHT
);
225 WMSetButtonText(bPtr
, DEFAULT_SWITCH_TEXT
);
226 bPtr
->flags
.alignment
= DEFAULT_SWITCH_ALIGNMENT
;
227 bPtr
->flags
.imagePosition
= DEFAULT_SWITCH_IMAGE_POSITION
;
235 WMSetButtonImage(WMButton
*bPtr
, WMPixmap
*image
)
237 if (bPtr
->image
!=NULL
)
238 WMReleasePixmap(bPtr
->image
);
239 bPtr
->image
= WMRetainPixmap(image
);
242 if (bPtr
->view
->flags
.realized
) {
249 WMSetButtonAltImage(WMButton
*bPtr
, WMPixmap
*image
)
251 if (bPtr
->altImage
!=NULL
)
252 WMReleasePixmap(bPtr
->altImage
);
253 bPtr
->altImage
= WMRetainPixmap(image
);
256 if (bPtr
->view
->flags
.realized
) {
263 WMSetButtonImagePosition(WMButton
*bPtr
, WMImagePosition position
)
265 bPtr
->flags
.imagePosition
= position
;
268 if (bPtr
->view
->flags
.realized
) {
277 WMSetButtonTextAlignment(WMButton
*bPtr
, WMAlignment alignment
)
279 bPtr
->flags
.alignment
= alignment
;
282 if (bPtr
->view
->flags
.realized
) {
288 WMSetButtonText(WMButton
*bPtr
, char *text
)
294 bPtr
->caption
= wstrdup(text
);
296 bPtr
->caption
= NULL
;
300 if (bPtr
->view
->flags
.realized
) {
307 WMSetButtonAltText(WMButton
*bPtr
, char *text
)
309 if (bPtr
->altCaption
)
310 free(bPtr
->altCaption
);
313 bPtr
->altCaption
= wstrdup(text
);
315 bPtr
->altCaption
= NULL
;
318 if (bPtr
->view
->flags
.realized
) {
325 WMSetButtonSelected(WMButton
*bPtr
, int isSelected
)
327 bPtr
->flags
.selected
= isSelected
;
329 if (bPtr
->view
->flags
.realized
) {
336 WMGetButtonSelected(WMButton
*bPtr
)
338 CHECK_CLASS(bPtr
, WC_Button
);
340 return bPtr
->flags
.selected
;
345 WMSetButtonBordered(WMButton
*bPtr
, int isBordered
)
347 bPtr
->flags
.bordered
= isBordered
;
349 if (bPtr
->view
->flags
.realized
) {
356 WMSetButtonFont(WMButton
*bPtr
, WMFont
*font
)
359 WMReleaseFont(bPtr
->font
);
361 bPtr
->font
= WMRetainFont(font
);
366 WMSetButtonEnabled(WMButton
*bPtr
, Bool flag
)
368 bPtr
->flags
.enabled
= flag
;
370 if (bPtr
->view
->flags
.mapped
) {
377 WMSetButtonTag(WMButton
*bPtr
, int tag
)
385 WMPerformButtonClick(WMButton
*bPtr
)
387 CHECK_CLASS(bPtr
, WC_Button
);
389 if (!bPtr
->flags
.enabled
)
392 bPtr
->flags
.pushed
= 1;
393 bPtr
->flags
.selected
= 1;
395 if (bPtr
->view
->flags
.mapped
) {
397 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr
)));
401 if (bPtr
->groupIndex
>0) {
402 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
406 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
408 bPtr
->flags
.pushed
= 0;
410 if (bPtr
->view
->flags
.mapped
)
417 WMSetButtonAction(WMButton
*bPtr
, WMAction
*action
, void *clientData
)
419 CHECK_CLASS(bPtr
, WC_Button
);
421 bPtr
->action
= action
;
423 bPtr
->clientData
= clientData
;
430 radioPushObserver(void *observerData
, WMNotification
*notification
)
432 WMButton
*bPtr
= (WMButton
*)observerData
;
433 WMButton
*pushedButton
= (WMButton
*)WMGetNotificationObject(notification
);
435 if (bPtr
!=pushedButton
&& pushedButton
->groupIndex
== bPtr
->groupIndex
436 && bPtr
->groupIndex
!=0) {
437 if (bPtr
->flags
.selected
) {
438 bPtr
->flags
.selected
= 0;
447 WMGroupButtons(WMButton
*bPtr
, WMButton
*newMember
)
449 static int tagIndex
= 0;
451 CHECK_CLASS(bPtr
, WC_Button
);
452 CHECK_CLASS(newMember
, WC_Button
);
454 if (!bPtr
->flags
.addedObserver
) {
455 WMAddNotificationObserver(radioPushObserver
, bPtr
,
456 WMPushedRadioNotification
, NULL
);
457 bPtr
->flags
.addedObserver
= 1;
459 if (!newMember
->flags
.addedObserver
) {
460 WMAddNotificationObserver(radioPushObserver
, newMember
,
461 WMPushedRadioNotification
, NULL
);
462 newMember
->flags
.addedObserver
= 1;
465 if (bPtr
->groupIndex
==0) {
466 bPtr
->groupIndex
= ++tagIndex
;
468 newMember
->groupIndex
= bPtr
->groupIndex
;
473 WMSetButtonContinuous(WMButton
*bPtr
, Bool flag
)
475 bPtr
->flags
.continuous
= flag
;
477 WMDeleteTimerHandler(bPtr
->timer
);
484 WMSetButtonPeriodicDelay(WMButton
*bPtr
, float delay
, float interval
)
486 bPtr
->periodicInterval
= interval
;
487 bPtr
->periodicDelay
= delay
;
493 paintButton(Button
*bPtr
)
495 W_Screen
*scrPtr
= bPtr
->view
->screen
;
504 caption
= bPtr
->caption
;
507 if (bPtr
->flags
.bordered
)
512 if (bPtr
->flags
.selected
) {
513 if (bPtr
->flags
.stateLight
)
514 gc
= WMColorGC(scrPtr
->white
);
516 if (bPtr
->flags
.stateChange
) {
517 if (bPtr
->altCaption
) {
518 caption
= bPtr
->altCaption
;
521 image
= bPtr
->altImage
;
524 if (bPtr
->flags
.statePush
&& bPtr
->flags
.bordered
) {
530 if (bPtr
->flags
.pushed
) {
531 if (bPtr
->flags
.pushIn
) {
535 if (bPtr
->flags
.pushLight
)
536 gc
= WMColorGC(scrPtr
->white
);
538 if (bPtr
->flags
.pushChange
) {
539 if (bPtr
->altCaption
) {
540 caption
= bPtr
->altCaption
;
543 image
= bPtr
->altImage
;
548 if (bPtr
->flags
.enabled
)
549 textGC
= WMColorGC(scrPtr
->black
);
551 textGC
= WMColorGC(scrPtr
->darkGray
);
553 W_PaintTextAndImage(bPtr
->view
, True
, textGC
,
554 (bPtr
->font
!=NULL
? bPtr
->font
: scrPtr
->normalFont
),
555 relief
, caption
, bPtr
->flags
.alignment
, image
,
556 bPtr
->flags
.imagePosition
, gc
, offset
);
562 handleEvents(XEvent
*event
, void *data
)
564 Button
*bPtr
= (Button
*)data
;
566 CHECK_CLASS(data
, WC_Button
);
569 switch (event
->type
) {
571 if (event
->xexpose
.count
!=0)
584 autoRepeat(void *data
)
586 Button
*bPtr
= (Button
*)data
;
588 if (bPtr
->action
&& bPtr
->flags
.pushed
)
589 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
591 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicInterval
*1000),
597 handleActionEvents(XEvent
*event
, void *data
)
599 Button
*bPtr
= (Button
*)data
;
600 int doclick
= 0, dopaint
=0;
602 CHECK_CLASS(data
, WC_Button
);
604 if (!bPtr
->flags
.enabled
)
607 switch (event
->type
) {
609 if (bPtr
->groupIndex
== 0) {
610 bPtr
->flags
.pushed
= bPtr
->flags
.wasPushed
;
611 if (bPtr
->flags
.pushed
) {
612 bPtr
->flags
.selected
= !bPtr
->flags
.prevSelected
;
619 if (bPtr
->groupIndex
== 0) {
620 bPtr
->flags
.wasPushed
= bPtr
->flags
.pushed
;
621 if (bPtr
->flags
.pushed
) {
622 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
625 bPtr
->flags
.pushed
= 0;
630 if (event
->xbutton
.button
== Button1
) {
631 if (bPtr
->groupIndex
>0) {
632 if (!bPtr
->flags
.selected
)
634 bPtr
->flags
.pushed
= 1;
635 bPtr
->flags
.selected
= 1;
639 bPtr
->flags
.wasPushed
= 0;
640 bPtr
->flags
.pushed
= 1;
641 bPtr
->flags
.prevSelected
= bPtr
->flags
.selected
;
642 bPtr
->flags
.selected
= !bPtr
->flags
.selected
;
645 if (bPtr
->flags
.continuous
&& !bPtr
->timer
) {
646 bPtr
->timer
= WMAddTimerHandler((int)(bPtr
->periodicDelay
*1000),
653 if (event
->xbutton
.button
== Button1
) {
654 if (bPtr
->flags
.pushed
) {
655 if (bPtr
->groupIndex
==0)
658 if (bPtr
->flags
.springLoaded
) {
659 bPtr
->flags
.selected
= bPtr
->flags
.prevSelected
;
662 bPtr
->flags
.pushed
= 0;
665 WMDeleteTimerHandler(bPtr
->timer
);
675 if (bPtr
->flags
.selected
&& bPtr
->groupIndex
>0) {
676 WMPostNotificationName(WMPushedRadioNotification
, bPtr
, NULL
);
680 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
687 destroyButton(Button
*bPtr
)
689 if (bPtr
->flags
.addedObserver
) {
690 WMRemoveNotificationObserver(bPtr
);
694 WMDeleteTimerHandler(bPtr
->timer
);
697 WMReleaseFont(bPtr
->font
);
702 if (bPtr
->altCaption
)
703 free(bPtr
->altCaption
);
706 WMReleasePixmap(bPtr
->image
);
709 WMReleasePixmap(bPtr
->altImage
);