wmaker: removed unused constant SCROLL_STEPS in the switchpanel code
[wmaker-crm.git] / WINGs / wbutton.c
blob8c8e4dcecc9b80f59a1e41506c4b12f4dcd5234e
2 #include "WINGsP.h"
4 typedef struct W_Button {
5 W_Class widgetClass;
6 WMView *view;
8 char *caption;
10 char *altCaption;
12 WMFont *font;
14 WMColor *textColor;
15 WMColor *altTextColor;
16 WMColor *disTextColor;
18 W_Pixmap *image;
19 W_Pixmap *altImage;
21 W_Pixmap *dimage;
23 void *clientData;
24 WMAction *action;
26 int tag;
28 int groupIndex;
30 float periodicDelay;
31 float periodicInterval;
33 WMHandlerID *timer; /* for continuous mode */
35 struct {
36 WMButtonType type:4;
37 WMImagePosition imagePosition:4;
38 WMAlignment alignment:2;
40 unsigned int selected:1;
42 unsigned int enabled:1;
44 unsigned int dimsWhenDisabled:1;
46 unsigned int bordered:1;
48 unsigned int springLoaded:1;
50 unsigned int pushIn:1; /* change relief while pushed */
52 unsigned int pushLight:1; /* highlight while pushed */
54 unsigned int pushChange:1; /* change caption while pushed */
56 unsigned int stateLight:1; /* state indicated by highlight */
58 unsigned int stateChange:1; /* state indicated by caption change */
60 unsigned int statePush:1; /* state indicated by relief */
62 unsigned int continuous:1; /* continually perform action */
64 unsigned int prevSelected:1;
66 unsigned int pushed:1;
68 unsigned int wasPushed:1;
70 unsigned int redrawPending:1;
72 unsigned int addedObserver:1;
73 } flags;
74 } Button;
76 #define DEFAULT_BUTTON_WIDTH 60
77 #define DEFAULT_BUTTON_HEIGHT 24
78 #define DEFAULT_BUTTON_ALIGNMENT WACenter
79 #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"
87 #define DEFAULT_SWITCH_WIDTH 100
88 #define DEFAULT_SWITCH_HEIGHT 20
89 #define DEFAULT_SWITCH_ALIGNMENT WALeft
90 #define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft
91 #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);
99 static char *WMPushedRadioNotification = "WMPushedRadioNotification";
102 WMButton *WMCreateCustomButton(WMWidget * parent, int behaviourMask)
104 Button *bPtr;
106 bPtr = wmalloc(sizeof(Button));
108 bPtr->widgetClass = WC_Button;
110 bPtr->view = W_CreateView(W_VIEW(parent));
111 if (!bPtr->view) {
112 wfree(bPtr);
113 return NULL;
115 bPtr->view->self = bPtr;
117 bPtr->flags.type = 0;
119 bPtr->flags.springLoaded = (behaviourMask & WBBSpringLoadedMask) != 0;
120 bPtr->flags.pushIn = (behaviourMask & WBBPushInMask) != 0;
121 bPtr->flags.pushChange = (behaviourMask & WBBPushChangeMask) != 0;
122 bPtr->flags.pushLight = (behaviourMask & WBBPushLightMask) != 0;
123 bPtr->flags.stateLight = (behaviourMask & WBBStateLightMask) != 0;
124 bPtr->flags.stateChange = (behaviourMask & WBBStateChangeMask) != 0;
125 bPtr->flags.statePush = (behaviourMask & WBBStatePushMask) != 0;
127 W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT);
128 bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT;
129 bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED;
131 bPtr->flags.enabled = 1;
132 bPtr->flags.dimsWhenDisabled = 1;
134 WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask, handleEvents, bPtr);
136 WMCreateEventHandler(bPtr->view, ButtonPressMask | ButtonReleaseMask
137 | EnterWindowMask | LeaveWindowMask, handleActionEvents, bPtr);
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 return bPtr;
146 WMButton *WMCreateButton(WMWidget * parent, WMButtonType type)
148 W_Screen *scrPtr = W_VIEW(parent)->screen;
149 Button *bPtr;
151 switch (type) {
152 case WBTMomentaryPush:
153 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushInMask | WBBPushLightMask);
154 break;
156 case WBTMomentaryChange:
157 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushChangeMask);
158 break;
160 case WBTPushOnPushOff:
161 bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStatePushMask | WBBStateLightMask);
162 break;
164 case WBTToggle:
165 bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStateChangeMask | WBBStatePushMask);
166 break;
168 case WBTOnOff:
169 bPtr = WMCreateCustomButton(parent, WBBStateLightMask);
170 break;
172 case WBTSwitch:
173 bPtr = WMCreateCustomButton(parent, WBBStateChangeMask);
174 bPtr->flags.bordered = 0;
175 bPtr->image = WMRetainPixmap(scrPtr->checkButtonImageOff);
176 bPtr->altImage = WMRetainPixmap(scrPtr->checkButtonImageOn);
177 break;
179 case WBTRadio:
180 bPtr = WMCreateCustomButton(parent, WBBStateChangeMask);
181 bPtr->flags.bordered = 0;
182 bPtr->image = WMRetainPixmap(scrPtr->radioButtonImageOff);
183 bPtr->altImage = WMRetainPixmap(scrPtr->radioButtonImageOn);
184 break;
186 default:
187 case WBTMomentaryLight:
188 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushLightMask);
189 bPtr->flags.bordered = 1;
190 break;
193 bPtr->flags.type = type;
195 if (type == WBTRadio) {
196 W_ResizeView(bPtr->view, DEFAULT_RADIO_WIDTH, DEFAULT_RADIO_HEIGHT);
197 WMSetButtonText(bPtr, DEFAULT_RADIO_TEXT);
198 bPtr->flags.alignment = DEFAULT_RADIO_ALIGNMENT;
199 bPtr->flags.imagePosition = DEFAULT_RADIO_IMAGE_POSITION;
200 } else if (type == WBTSwitch) {
201 W_ResizeView(bPtr->view, DEFAULT_SWITCH_WIDTH, DEFAULT_SWITCH_HEIGHT);
202 WMSetButtonText(bPtr, DEFAULT_SWITCH_TEXT);
203 bPtr->flags.alignment = DEFAULT_SWITCH_ALIGNMENT;
204 bPtr->flags.imagePosition = DEFAULT_SWITCH_IMAGE_POSITION;
207 return bPtr;
210 static void updateDisabledMask(WMButton * bPtr)
212 WMScreen *scr = WMWidgetScreen(bPtr);
213 Display *dpy = scr->display;
215 if (bPtr->image) {
216 XGCValues gcv;
218 if (bPtr->dimage->mask) {
219 XFreePixmap(dpy, bPtr->dimage->mask);
220 bPtr->dimage->mask = None;
223 if (bPtr->flags.dimsWhenDisabled) {
224 bPtr->dimage->mask = XCreatePixmap(dpy, scr->stipple,
225 bPtr->dimage->width, bPtr->dimage->height, 1);
227 XSetForeground(dpy, scr->monoGC, 0);
228 XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0,
229 bPtr->dimage->width, bPtr->dimage->height);
231 gcv.foreground = 1;
232 gcv.background = 0;
233 gcv.stipple = scr->stipple;
234 gcv.fill_style = FillStippled;
235 gcv.clip_mask = bPtr->image->mask;
236 gcv.clip_x_origin = 0;
237 gcv.clip_y_origin = 0;
239 XChangeGC(dpy, scr->monoGC, GCForeground | GCBackground | GCStipple
240 | GCFillStyle | GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
242 XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0,
243 bPtr->dimage->width, bPtr->dimage->height);
245 gcv.fill_style = FillSolid;
246 gcv.clip_mask = None;
247 XChangeGC(dpy, scr->monoGC, GCFillStyle | GCClipMask, &gcv);
252 void WMSetButtonImageDefault(WMButton * bPtr)
254 WMSetButtonImage(bPtr, WMWidgetScreen(bPtr)->buttonArrow);
255 WMSetButtonAltImage(bPtr, WMWidgetScreen(bPtr)->pushedButtonArrow);
258 void WMSetButtonImage(WMButton * bPtr, WMPixmap * image)
260 if (bPtr->image != NULL)
261 WMReleasePixmap(bPtr->image);
262 bPtr->image = WMRetainPixmap(image);
264 if (bPtr->dimage) {
265 bPtr->dimage->pixmap = None;
266 WMReleasePixmap(bPtr->dimage);
267 bPtr->dimage = NULL;
270 if (image) {
271 bPtr->dimage = WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr),
272 image->pixmap, None,
273 image->width, image->height, image->depth);
274 updateDisabledMask(bPtr);
277 if (bPtr->view->flags.realized) {
278 paintButton(bPtr);
282 void WMSetButtonAltImage(WMButton * bPtr, WMPixmap * image)
284 if (bPtr->altImage != NULL)
285 WMReleasePixmap(bPtr->altImage);
286 bPtr->altImage = WMRetainPixmap(image);
288 if (bPtr->view->flags.realized) {
289 paintButton(bPtr);
293 void WMSetButtonImagePosition(WMButton * bPtr, WMImagePosition position)
295 bPtr->flags.imagePosition = position;
297 if (bPtr->view->flags.realized) {
298 paintButton(bPtr);
302 void WMSetButtonTextAlignment(WMButton * bPtr, WMAlignment alignment)
304 bPtr->flags.alignment = alignment;
306 if (bPtr->view->flags.realized) {
307 paintButton(bPtr);
311 void WMSetButtonText(WMButton * bPtr, const char *text)
313 if (bPtr->caption)
314 wfree(bPtr->caption);
316 if (text != NULL) {
317 bPtr->caption = wstrdup(text);
318 } else {
319 bPtr->caption = NULL;
322 if (bPtr->view->flags.realized) {
323 paintButton(bPtr);
327 const char *WMGetButtonText(WMButton *bPtr)
329 return bPtr->caption;
332 void WMSetButtonAltText(WMButton * bPtr, const char *text)
334 if (bPtr->altCaption)
335 wfree(bPtr->altCaption);
337 if (text != NULL) {
338 bPtr->altCaption = wstrdup(text);
339 } else {
340 bPtr->altCaption = NULL;
343 if (bPtr->view->flags.realized) {
344 paintButton(bPtr);
348 void WMSetButtonTextColor(WMButton * bPtr, WMColor * color)
350 if (bPtr->textColor)
351 WMReleaseColor(bPtr->textColor);
353 bPtr->textColor = WMRetainColor(color);
356 void WMSetButtonAltTextColor(WMButton * bPtr, WMColor * color)
358 if (bPtr->altTextColor)
359 WMReleaseColor(bPtr->altTextColor);
361 bPtr->altTextColor = WMRetainColor(color);
364 void WMSetButtonDisabledTextColor(WMButton * bPtr, WMColor * color)
366 if (bPtr->disTextColor)
367 WMReleaseColor(bPtr->disTextColor);
369 bPtr->disTextColor = WMRetainColor(color);
372 void WMSetButtonSelected(WMButton * bPtr, int isSelected)
374 bPtr->flags.selected = isSelected ? 1 : 0;
376 if (bPtr->view->flags.realized) {
377 paintButton(bPtr);
379 if (bPtr->groupIndex > 0)
380 WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
383 int WMGetButtonSelected(WMButton * bPtr)
385 CHECK_CLASS(bPtr, WC_Button);
387 return bPtr->flags.selected;
390 void WMSetButtonBordered(WMButton * bPtr, int isBordered)
392 bPtr->flags.bordered = isBordered;
394 if (bPtr->view->flags.realized) {
395 paintButton(bPtr);
399 void WMSetButtonFont(WMButton * bPtr, WMFont * font)
401 if (bPtr->font)
402 WMReleaseFont(bPtr->font);
404 bPtr->font = WMRetainFont(font);
407 void WMSetButtonEnabled(WMButton * bPtr, Bool flag)
409 bPtr->flags.enabled = ((flag == 0) ? 0 : 1);
411 if (bPtr->view->flags.mapped) {
412 paintButton(bPtr);
416 int WMGetButtonEnabled(WMButton * bPtr)
418 CHECK_CLASS(bPtr, WC_Button);
420 return bPtr->flags.enabled;
423 void WMSetButtonImageDimsWhenDisabled(WMButton * bPtr, Bool flag)
425 bPtr->flags.dimsWhenDisabled = ((flag == 0) ? 0 : 1);
427 updateDisabledMask(bPtr);
430 void WMSetButtonTag(WMButton * bPtr, int tag)
432 bPtr->tag = tag;
435 void WMPerformButtonClick(WMButton * bPtr)
437 CHECK_CLASS(bPtr, WC_Button);
439 if (!bPtr->flags.enabled)
440 return;
442 bPtr->flags.pushed = 1;
443 bPtr->flags.selected = 1;
445 if (bPtr->view->flags.mapped) {
446 paintButton(bPtr);
447 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr)));
448 wusleep(20000);
451 bPtr->flags.pushed = 0;
453 if (bPtr->groupIndex > 0) {
454 WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
457 if (bPtr->action)
458 (*bPtr->action) (bPtr, bPtr->clientData);
460 if (bPtr->view->flags.mapped)
461 paintButton(bPtr);
464 void WMSetButtonAction(WMButton * bPtr, WMAction * action, void *clientData)
466 CHECK_CLASS(bPtr, WC_Button);
468 bPtr->action = action;
470 bPtr->clientData = clientData;
473 static void radioPushObserver(void *observerData, WMNotification * notification)
475 WMButton *bPtr = (WMButton *) observerData;
476 WMButton *pushedButton = (WMButton *) WMGetNotificationObject(notification);
478 if (bPtr != pushedButton && pushedButton->groupIndex == bPtr->groupIndex && bPtr->groupIndex != 0) {
479 if (bPtr->flags.selected) {
480 bPtr->flags.selected = 0;
481 paintButton(bPtr);
486 void WMGroupButtons(WMButton * bPtr, WMButton * newMember)
488 static int tagIndex = 0;
490 CHECK_CLASS(bPtr, WC_Button);
491 CHECK_CLASS(newMember, WC_Button);
493 if (!bPtr->flags.addedObserver) {
494 WMAddNotificationObserver(radioPushObserver, bPtr, WMPushedRadioNotification, NULL);
495 bPtr->flags.addedObserver = 1;
497 if (!newMember->flags.addedObserver) {
498 WMAddNotificationObserver(radioPushObserver, newMember, WMPushedRadioNotification, NULL);
499 newMember->flags.addedObserver = 1;
502 if (bPtr->groupIndex == 0) {
503 bPtr->groupIndex = ++tagIndex;
505 newMember->groupIndex = bPtr->groupIndex;
508 void WMSetButtonContinuous(WMButton * bPtr, Bool flag)
510 bPtr->flags.continuous = ((flag == 0) ? 0 : 1);
511 if (bPtr->timer) {
512 WMDeleteTimerHandler(bPtr->timer);
513 bPtr->timer = NULL;
517 void WMSetButtonPeriodicDelay(WMButton * bPtr, float delay, float interval)
519 bPtr->periodicInterval = interval;
520 bPtr->periodicDelay = delay;
523 static void paintButton(Button * bPtr)
525 W_Screen *scrPtr = bPtr->view->screen;
526 WMReliefType relief;
527 int offset;
528 char *caption;
529 WMPixmap *image;
530 WMColor *textColor;
531 WMColor *backColor;
533 backColor = NULL;
534 caption = bPtr->caption;
536 if (bPtr->flags.enabled) {
537 textColor = (bPtr->textColor != NULL ? bPtr->textColor : scrPtr->black);
538 } else {
539 textColor = (bPtr->disTextColor != NULL ? bPtr->disTextColor : scrPtr->darkGray);
542 if (bPtr->flags.enabled || !bPtr->dimage)
543 image = bPtr->image;
544 else
545 image = bPtr->dimage;
546 offset = 0;
547 if (bPtr->flags.bordered)
548 relief = WRRaised;
549 else
550 relief = WRFlat;
552 if (bPtr->flags.selected) {
553 if (bPtr->flags.stateLight) {
554 backColor = scrPtr->white;
555 textColor = scrPtr->black;
558 if (bPtr->flags.stateChange) {
559 if (bPtr->altCaption)
560 caption = bPtr->altCaption;
561 if (bPtr->altImage)
562 image = bPtr->altImage;
563 if (bPtr->altTextColor)
564 textColor = bPtr->altTextColor;
567 if (bPtr->flags.statePush && bPtr->flags.bordered) {
568 relief = WRSunken;
569 offset = 1;
573 if (bPtr->flags.pushed) {
574 if (bPtr->flags.pushIn) {
575 relief = WRPushed;
576 offset = 1;
578 if (bPtr->flags.pushLight) {
579 backColor = scrPtr->white;
580 textColor = scrPtr->black;
583 if (bPtr->flags.pushChange) {
584 if (bPtr->altCaption)
585 caption = bPtr->altCaption;
586 if (bPtr->altImage)
587 image = bPtr->altImage;
588 if (bPtr->altTextColor)
589 textColor = bPtr->altTextColor;
593 W_PaintTextAndImage(bPtr->view, True, textColor,
594 (bPtr->font != NULL ? bPtr->font : scrPtr->normalFont),
595 relief, caption, bPtr->flags.alignment, image,
596 bPtr->flags.imagePosition, backColor, offset);
599 static void handleEvents(XEvent * event, void *data)
601 Button *bPtr = (Button *) data;
603 CHECK_CLASS(data, WC_Button);
605 switch (event->type) {
606 case Expose:
607 if (event->xexpose.count != 0)
608 break;
609 paintButton(bPtr);
610 break;
612 case DestroyNotify:
613 destroyButton(bPtr);
614 break;
618 static void autoRepeat(void *data)
620 Button *bPtr = (Button *) data;
622 if (bPtr->action && bPtr->flags.pushed)
623 (*bPtr->action) (bPtr, bPtr->clientData);
625 bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicInterval * 1000), autoRepeat, bPtr);
628 static void handleActionEvents(XEvent * event, void *data)
630 Button *bPtr = (Button *) data;
631 int doclick = 0, dopaint = 0;
633 CHECK_CLASS(data, WC_Button);
635 if (!bPtr->flags.enabled)
636 return;
638 switch (event->type) {
639 case EnterNotify:
640 if (bPtr->groupIndex == 0) {
641 bPtr->flags.pushed = bPtr->flags.wasPushed;
642 if (bPtr->flags.pushed) {
643 bPtr->flags.selected = !bPtr->flags.prevSelected;
644 dopaint = 1;
647 break;
649 case LeaveNotify:
650 if (bPtr->groupIndex == 0) {
651 bPtr->flags.wasPushed = bPtr->flags.pushed;
652 if (bPtr->flags.pushed) {
653 bPtr->flags.selected = bPtr->flags.prevSelected;
654 dopaint = 1;
656 bPtr->flags.pushed = 0;
658 break;
660 case ButtonPress:
661 if (event->xbutton.button == Button1) {
662 bPtr->flags.prevSelected = bPtr->flags.selected;
663 bPtr->flags.wasPushed = 0;
664 bPtr->flags.pushed = 1;
665 if (bPtr->groupIndex > 0) {
666 bPtr->flags.selected = 1;
667 dopaint = 1;
668 break;
670 bPtr->flags.selected = !bPtr->flags.selected;
671 dopaint = 1;
673 if (bPtr->flags.continuous && !bPtr->timer) {
674 bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicDelay * 1000),
675 autoRepeat, bPtr);
678 break;
680 case ButtonRelease:
681 if (event->xbutton.button == Button1) {
682 if (bPtr->flags.pushed) {
683 if (bPtr->groupIndex == 0 || (bPtr->flags.selected && bPtr->groupIndex > 0))
684 doclick = 1;
685 dopaint = 1;
686 if (bPtr->flags.springLoaded) {
687 bPtr->flags.selected = bPtr->flags.prevSelected;
690 bPtr->flags.pushed = 0;
692 if (bPtr->timer) {
693 WMDeleteTimerHandler(bPtr->timer);
694 bPtr->timer = NULL;
696 break;
699 if (dopaint)
700 paintButton(bPtr);
702 if (doclick) {
703 if (bPtr->flags.selected && bPtr->groupIndex > 0) {
704 WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
707 if (bPtr->action)
708 (*bPtr->action) (bPtr, bPtr->clientData);
712 static void destroyButton(Button * bPtr)
714 if (bPtr->flags.addedObserver) {
715 WMRemoveNotificationObserver(bPtr);
718 if (bPtr->timer)
719 WMDeleteTimerHandler(bPtr->timer);
721 if (bPtr->font)
722 WMReleaseFont(bPtr->font);
724 if (bPtr->caption)
725 wfree(bPtr->caption);
727 if (bPtr->altCaption)
728 wfree(bPtr->altCaption);
730 if (bPtr->textColor)
731 WMReleaseColor(bPtr->textColor);
733 if (bPtr->altTextColor)
734 WMReleaseColor(bPtr->altTextColor);
736 if (bPtr->disTextColor)
737 WMReleaseColor(bPtr->disTextColor);
739 if (bPtr->image)
740 WMReleasePixmap(bPtr->image);
742 if (bPtr->dimage) {
743 /* yuck.. kluge */
744 bPtr->dimage->pixmap = None;
746 WMReleasePixmap(bPtr->dimage);
748 if (bPtr->altImage)
749 WMReleasePixmap(bPtr->altImage);
751 wfree(bPtr);