X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/WINGs/wbutton.c diff --git a/WINGs/wbutton.c b/WINGs/wbutton.c dissimilarity index 95% index 3ea6752b..ae4ed4e0 100644 --- a/WINGs/wbutton.c +++ b/WINGs/wbutton.c @@ -1,853 +1,749 @@ - - - - -#include "WINGsP.h" - -typedef struct W_Button { - W_Class widgetClass; - WMView *view; - - char *caption; - - char *altCaption; - - WMFont *font; - - WMColor *textColor; - WMColor *altTextColor; - WMColor *disTextColor; - - W_Pixmap *image; - W_Pixmap *altImage; - - W_Pixmap *dimage; - - void *clientData; - WMAction *action; - - int tag; - - int groupIndex; - - float periodicDelay; - float periodicInterval; - - WMHandlerID *timer; /* for continuous mode */ - - struct { - WMButtonType type:4; - WMImagePosition imagePosition:4; - WMAlignment alignment:2; - - unsigned int selected:1; - - unsigned int enabled:1; - - unsigned int dimsWhenDisabled:1; - - unsigned int bordered:1; - - unsigned int springLoaded:1; - - unsigned int pushIn:1; /* change relief while pushed */ - - unsigned int pushLight:1; /* highlight while pushed */ - - unsigned int pushChange:1; /* change caption while pushed */ - - unsigned int stateLight:1; /* state indicated by highlight */ - - unsigned int stateChange:1; /* state indicated by caption change */ - - unsigned int statePush:1; /* state indicated by relief */ - - unsigned int continuous:1; /* continually perform action */ - - unsigned int prevSelected:1; - - unsigned int pushed:1; - - unsigned int wasPushed:1; - - unsigned int redrawPending:1; - - unsigned int addedObserver:1; - } flags; -} Button; - - - -#define DEFAULT_BUTTON_WIDTH 60 -#define DEFAULT_BUTTON_HEIGHT 24 -#define DEFAULT_BUTTON_ALIGNMENT WACenter -#define DEFAULT_BUTTON_IS_BORDERED True - - -#define DEFAULT_RADIO_WIDTH 100 -#define DEFAULT_RADIO_HEIGHT 20 -#define DEFAULT_RADIO_ALIGNMENT WALeft -#define DEFAULT_RADIO_IMAGE_POSITION WIPLeft -#define DEFAULT_RADIO_TEXT "Radio" - - -#define DEFAULT_SWITCH_WIDTH 100 -#define DEFAULT_SWITCH_HEIGHT 20 -#define DEFAULT_SWITCH_ALIGNMENT WALeft -#define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft -#define DEFAULT_SWITCH_TEXT "Switch" - - -static void destroyButton(Button *bPtr); -static void paintButton(Button *bPtr); - -static void handleEvents(XEvent *event, void *data); -static void handleActionEvents(XEvent *event, void *data); - - -static char *WMPushedRadioNotification="WMPushedRadioNotification"; - - -#define NFONT(b) (b)->view->screen->normalFont - - -WMButton* -WMCreateCustomButton(WMWidget *parent, int behaviourMask) -{ - Button *bPtr; - - bPtr = wmalloc(sizeof(Button)); - memset(bPtr, 0, sizeof(Button)); - - bPtr->widgetClass = WC_Button; - - bPtr->view = W_CreateView(W_VIEW(parent)); - if (!bPtr->view) { - wfree(bPtr); - return NULL; - } - bPtr->view->self = bPtr; - - bPtr->flags.type = 0; - - bPtr->flags.springLoaded = (behaviourMask & WBBSpringLoadedMask)!=0; - bPtr->flags.pushIn = (behaviourMask & WBBPushInMask)!=0; - bPtr->flags.pushChange = (behaviourMask & WBBPushChangeMask)!=0; - bPtr->flags.pushLight = (behaviourMask & WBBPushLightMask)!=0; - bPtr->flags.stateLight = (behaviourMask & WBBStateLightMask)!=0; - bPtr->flags.stateChange = (behaviourMask & WBBStateChangeMask)!=0; - bPtr->flags.statePush = (behaviourMask & WBBStatePushMask)!=0; - - W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT); - bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT; - bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED; - - bPtr->flags.enabled = 1; - bPtr->flags.dimsWhenDisabled = 1; - - WMCreateEventHandler(bPtr->view, ExposureMask|StructureNotifyMask, - handleEvents, bPtr); - - WMCreateEventHandler(bPtr->view, ButtonPressMask|ButtonReleaseMask - |EnterWindowMask|LeaveWindowMask, - handleActionEvents, bPtr); - - W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT); - bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT; - bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED; - - return bPtr; -} - - - -WMButton* -WMCreateButton(WMWidget *parent, WMButtonType type) -{ - W_Screen *scrPtr = W_VIEW(parent)->screen; - Button *bPtr; - - switch (type) { - case WBTMomentaryPush: - bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask - |WBBPushInMask|WBBPushLightMask); - break; - - case WBTMomentaryChange: - bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask - |WBBPushChangeMask); - break; - - case WBTPushOnPushOff: - bPtr = WMCreateCustomButton(parent, WBBPushInMask|WBBStatePushMask - |WBBStateLightMask); - break; - - case WBTToggle: - bPtr = WMCreateCustomButton(parent, WBBPushInMask|WBBStateChangeMask - |WBBStatePushMask); - break; - - case WBTOnOff: - bPtr = WMCreateCustomButton(parent, WBBStateLightMask); - break; - - case WBTSwitch: - bPtr = WMCreateCustomButton(parent, WBBStateChangeMask); - bPtr->flags.bordered = 0; - bPtr->image = WMRetainPixmap(scrPtr->checkButtonImageOff); - bPtr->altImage = WMRetainPixmap(scrPtr->checkButtonImageOn); - break; - - case WBTRadio: - bPtr = WMCreateCustomButton(parent, WBBStateChangeMask); - bPtr->flags.bordered = 0; - bPtr->image = WMRetainPixmap(scrPtr->radioButtonImageOff); - bPtr->altImage = WMRetainPixmap(scrPtr->radioButtonImageOn); - break; - - default: - case WBTMomentaryLight: - bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask - |WBBPushLightMask); - bPtr->flags.bordered = 1; - break; - } - - bPtr->flags.type = type; - - if (type==WBTRadio) { - W_ResizeView(bPtr->view, DEFAULT_RADIO_WIDTH, DEFAULT_RADIO_HEIGHT); - WMSetButtonText(bPtr, DEFAULT_RADIO_TEXT); - bPtr->flags.alignment = DEFAULT_RADIO_ALIGNMENT; - bPtr->flags.imagePosition = DEFAULT_RADIO_IMAGE_POSITION; - } else if (type==WBTSwitch) { - W_ResizeView(bPtr->view, DEFAULT_SWITCH_WIDTH, DEFAULT_SWITCH_HEIGHT); - WMSetButtonText(bPtr, DEFAULT_SWITCH_TEXT); - bPtr->flags.alignment = DEFAULT_SWITCH_ALIGNMENT; - bPtr->flags.imagePosition = DEFAULT_SWITCH_IMAGE_POSITION; - } - - return bPtr; -} - - -static void -updateDisabledMask(WMButton *bPtr) -{ - WMScreen *scr = WMWidgetScreen(bPtr); - Display *dpy = scr->display; - - if (bPtr->image) { - XGCValues gcv; - - if (bPtr->dimage->mask) { - XFreePixmap(dpy, bPtr->dimage->mask); - bPtr->dimage->mask = None; - } - - if (bPtr->flags.dimsWhenDisabled) { - bPtr->dimage->mask = XCreatePixmap(dpy, scr->stipple, - bPtr->dimage->width, - bPtr->dimage->height, 1); - - XSetForeground(dpy, scr->monoGC, 0); - XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0, - bPtr->dimage->width, bPtr->dimage->height); - - gcv.foreground = 1; - gcv.background = 0; - gcv.stipple = scr->stipple; - gcv.fill_style = FillStippled; - gcv.clip_mask = bPtr->image->mask; - gcv.clip_x_origin = 0; - gcv.clip_y_origin = 0; - - XChangeGC(dpy, scr->monoGC, GCForeground|GCBackground|GCStipple - |GCFillStyle|GCClipMask|GCClipXOrigin|GCClipYOrigin, &gcv); - - XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0, - bPtr->dimage->width, bPtr->dimage->height); - - gcv.fill_style = FillSolid; - gcv.clip_mask = None; - XChangeGC(dpy, scr->monoGC, GCFillStyle|GCClipMask, &gcv); - } - } -} - -void -WMSetButtonImageDefault(WMButton *bPtr) -{ - WMSetButtonImage (bPtr, WMWidgetScreen(bPtr)->buttonArrow); - WMSetButtonAltImage (bPtr, WMWidgetScreen(bPtr)->pushedButtonArrow); -} - -void -WMSetButtonImage(WMButton *bPtr, WMPixmap *image) -{ - if (bPtr->image!=NULL) - WMReleasePixmap(bPtr->image); - bPtr->image = WMRetainPixmap(image); - - if (bPtr->dimage) { - bPtr->dimage->pixmap = None; - WMReleasePixmap(bPtr->dimage); - bPtr->dimage = NULL; - } - - if (image) { - bPtr->dimage = WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr), - image->pixmap, None, - image->width, image->height, - image->depth); - updateDisabledMask(bPtr); - } - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - -void -WMSetButtonAltImage(WMButton *bPtr, WMPixmap *image) -{ - if (bPtr->altImage!=NULL) - WMReleasePixmap(bPtr->altImage); - bPtr->altImage = WMRetainPixmap(image); - - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - -void -WMSetButtonImagePosition(WMButton *bPtr, WMImagePosition position) -{ - bPtr->flags.imagePosition = position; - - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - - - -void -WMSetButtonTextAlignment(WMButton *bPtr, WMAlignment alignment) -{ - bPtr->flags.alignment = alignment; - - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - -void -WMSetButtonText(WMButton *bPtr, char *text) -{ - if (bPtr->caption) - wfree(bPtr->caption); - - if (text!=NULL) { - bPtr->caption = wstrdup(text); - } else { - bPtr->caption = NULL; - } - - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - -void -WMSetButtonAltText(WMButton *bPtr, char *text) -{ - if (bPtr->altCaption) - wfree(bPtr->altCaption); - - if (text!=NULL) { - bPtr->altCaption = wstrdup(text); - } else { - bPtr->altCaption = NULL; - } - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - -void -WMSetButtonTextColor(WMButton *bPtr, WMColor *color) -{ - if (bPtr->textColor) - WMReleaseColor(bPtr->textColor); - - bPtr->textColor = WMRetainColor(color); -} - - -void -WMSetButtonAltTextColor(WMButton *bPtr, WMColor *color) -{ - if (bPtr->altTextColor) - WMReleaseColor(bPtr->altTextColor); - - bPtr->altTextColor = WMRetainColor(color); -} - - -void -WMSetButtonDisabledTextColor(WMButton *bPtr, WMColor *color) -{ - if (bPtr->disTextColor) - WMReleaseColor(bPtr->disTextColor); - - bPtr->disTextColor = WMRetainColor(color); -} - - -void -WMSetButtonSelected(WMButton *bPtr, int isSelected) -{ - bPtr->flags.selected = isSelected ? 1 : 0; - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } - if (bPtr->groupIndex > 0) - WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); -} - - -int -WMGetButtonSelected(WMButton *bPtr) -{ - CHECK_CLASS(bPtr, WC_Button); - - return bPtr->flags.selected; -} - - -void -WMSetButtonBordered(WMButton *bPtr, int isBordered) -{ - bPtr->flags.bordered = isBordered; - - if (bPtr->view->flags.realized) { - paintButton(bPtr); - } -} - - -void -WMSetButtonFont(WMButton *bPtr, WMFont *font) -{ - if (bPtr->font) - WMReleaseFont(bPtr->font); - - bPtr->font = WMRetainFont(font); -} - - -void -WMSetButtonEnabled(WMButton *bPtr, Bool flag) -{ - bPtr->flags.enabled = ((flag==0) ? 0 : 1); - - if (bPtr->view->flags.mapped) { - paintButton(bPtr); - } -} - - -int -WMGetButtonEnabled(WMButton *bPtr) -{ - CHECK_CLASS(bPtr, WC_Button); - - return bPtr->flags.enabled; -} - - -void -WMSetButtonImageDimsWhenDisabled(WMButton *bPtr, Bool flag) -{ - bPtr->flags.dimsWhenDisabled = ((flag==0) ? 0 : 1); - - updateDisabledMask(bPtr); -} - - -void -WMSetButtonTag(WMButton *bPtr, int tag) -{ - bPtr->tag = tag; -} - - -void -WMPerformButtonClick(WMButton *bPtr) -{ - CHECK_CLASS(bPtr, WC_Button); - - if (!bPtr->flags.enabled) - return; - - bPtr->flags.pushed = 1; - bPtr->flags.selected = 1; - - if (bPtr->view->flags.mapped) { - paintButton(bPtr); - XFlush(WMScreenDisplay(WMWidgetScreen(bPtr))); - wusleep(20000); - } - - bPtr->flags.pushed = 0; - - if (bPtr->groupIndex > 0) { - WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); - } - - if (bPtr->action) - (*bPtr->action)(bPtr, bPtr->clientData); - - if (bPtr->view->flags.mapped) - paintButton(bPtr); -} - - - -void -WMSetButtonAction(WMButton *bPtr, WMAction *action, void *clientData) -{ - CHECK_CLASS(bPtr, WC_Button); - - bPtr->action = action; - - bPtr->clientData = clientData; -} - - - - -static void -radioPushObserver(void *observerData, WMNotification *notification) -{ - WMButton *bPtr = (WMButton*)observerData; - WMButton *pushedButton = (WMButton*)WMGetNotificationObject(notification); - - if (bPtr!=pushedButton && pushedButton->groupIndex == bPtr->groupIndex - && bPtr->groupIndex!=0) { - if (bPtr->flags.selected) { - bPtr->flags.selected = 0; - paintButton(bPtr); - } - } -} - - - -void -WMGroupButtons(WMButton *bPtr, WMButton *newMember) -{ - static int tagIndex = 0; - - CHECK_CLASS(bPtr, WC_Button); - CHECK_CLASS(newMember, WC_Button); - - if (!bPtr->flags.addedObserver) { - WMAddNotificationObserver(radioPushObserver, bPtr, - WMPushedRadioNotification, NULL); - bPtr->flags.addedObserver = 1; - } - if (!newMember->flags.addedObserver) { - WMAddNotificationObserver(radioPushObserver, newMember, - WMPushedRadioNotification, NULL); - newMember->flags.addedObserver = 1; - } - - if (bPtr->groupIndex==0) { - bPtr->groupIndex = ++tagIndex; - } - newMember->groupIndex = bPtr->groupIndex; -} - - -void -WMSetButtonContinuous(WMButton *bPtr, Bool flag) -{ - bPtr->flags.continuous = ((flag==0) ? 0 : 1); - if (bPtr->timer) { - WMDeleteTimerHandler(bPtr->timer); - bPtr->timer = NULL; - } -} - - -void -WMSetButtonPeriodicDelay(WMButton *bPtr, float delay, float interval) -{ - bPtr->periodicInterval = interval; - bPtr->periodicDelay = delay; -} - - - -static void -paintButton(Button *bPtr) -{ - W_Screen *scrPtr = bPtr->view->screen; - WMReliefType relief; - int offset; - char *caption; - WMPixmap *image; - WMColor *textColor; - WMColor *backColor; - - backColor = NULL; - caption = bPtr->caption; - - if (bPtr->flags.enabled) { - textColor = (bPtr->textColor!=NULL - ? bPtr->textColor : scrPtr->black); - } else { - textColor = (bPtr->disTextColor!=NULL - ? bPtr->disTextColor : scrPtr->darkGray); - } - - if (bPtr->flags.enabled || !bPtr->dimage) - image = bPtr->image; - else - image = bPtr->dimage; - offset = 0; - if (bPtr->flags.bordered) - relief = WRRaised; - else - relief = WRFlat; - - if (bPtr->flags.selected) { - if (bPtr->flags.stateLight) { - backColor = scrPtr->white; - textColor = scrPtr->black; - } - - if (bPtr->flags.stateChange) { - if (bPtr->altCaption) - caption = bPtr->altCaption; - if (bPtr->altImage) - image = bPtr->altImage; - if (bPtr->altTextColor) - textColor = bPtr->altTextColor; - } - - if (bPtr->flags.statePush && bPtr->flags.bordered) { - relief = WRSunken; - offset = 1; - } - } - - if (bPtr->flags.pushed) { - if (bPtr->flags.pushIn) { - relief = WRPushed; - offset = 1; - } - if (bPtr->flags.pushLight) { - backColor = scrPtr->white; - textColor = scrPtr->black; - } - - if (bPtr->flags.pushChange) { - if (bPtr->altCaption) - caption = bPtr->altCaption; - if (bPtr->altImage) - image = bPtr->altImage; - if (bPtr->altTextColor) - textColor = bPtr->altTextColor; - } - } - - W_PaintTextAndImage(bPtr->view, True, textColor, - (bPtr->font!=NULL ? bPtr->font : scrPtr->normalFont), - relief, caption, bPtr->flags.alignment, image, - bPtr->flags.imagePosition, backColor, offset); -} - - - -static void -handleEvents(XEvent *event, void *data) -{ - Button *bPtr = (Button*)data; - - CHECK_CLASS(data, WC_Button); - - - switch (event->type) { - case Expose: - if (event->xexpose.count!=0) - break; - paintButton(bPtr); - break; - - case DestroyNotify: - destroyButton(bPtr); - break; - } -} - - -static void -autoRepeat(void *data) -{ - Button *bPtr = (Button*)data; - - if (bPtr->action && bPtr->flags.pushed) - (*bPtr->action)(bPtr, bPtr->clientData); - - bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicInterval*1000), - autoRepeat, bPtr); -} - - -static void -handleActionEvents(XEvent *event, void *data) -{ - Button *bPtr = (Button*)data; - int doclick = 0, dopaint=0; - - CHECK_CLASS(data, WC_Button); - - if (!bPtr->flags.enabled) - return; - - switch (event->type) { - case EnterNotify: - if (bPtr->groupIndex == 0) { - bPtr->flags.pushed = bPtr->flags.wasPushed; - if (bPtr->flags.pushed) { - bPtr->flags.selected = !bPtr->flags.prevSelected; - dopaint = 1; - } - } - break; - - case LeaveNotify: - if (bPtr->groupIndex == 0) { - bPtr->flags.wasPushed = bPtr->flags.pushed; - if (bPtr->flags.pushed) { - bPtr->flags.selected = bPtr->flags.prevSelected; - dopaint = 1; - } - bPtr->flags.pushed = 0; - } - break; - - case ButtonPress: - if (event->xbutton.button == Button1) { - bPtr->flags.prevSelected = bPtr->flags.selected; - bPtr->flags.wasPushed = 0; - bPtr->flags.pushed = 1; - if (bPtr->groupIndex>0) { - bPtr->flags.selected = 1; - dopaint = 1; - break; - } - bPtr->flags.selected = !bPtr->flags.selected; - dopaint = 1; - - if (bPtr->flags.continuous && !bPtr->timer) { - bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicDelay*1000), - autoRepeat, bPtr); - } - } - break; - - case ButtonRelease: - if (event->xbutton.button == Button1) { - if (bPtr->flags.pushed) { - if (bPtr->groupIndex==0 || - (bPtr->flags.selected && bPtr->groupIndex > 0)) - doclick = 1; - dopaint = 1; - if (bPtr->flags.springLoaded) { - bPtr->flags.selected = bPtr->flags.prevSelected; - } - } - bPtr->flags.pushed = 0; - } - if (bPtr->timer) { - WMDeleteTimerHandler(bPtr->timer); - bPtr->timer = NULL; - } - break; - } - - if (dopaint) - paintButton(bPtr); - - if (doclick) { - if (bPtr->flags.selected && bPtr->groupIndex > 0) { - WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); - } - - if (bPtr->action) - (*bPtr->action)(bPtr, bPtr->clientData); - } -} - - - -static void -destroyButton(Button *bPtr) -{ - if (bPtr->flags.addedObserver) { - WMRemoveNotificationObserver(bPtr); - } - - if (bPtr->timer) - WMDeleteTimerHandler(bPtr->timer); - - if (bPtr->font) - WMReleaseFont(bPtr->font); - - if (bPtr->caption) - wfree(bPtr->caption); - - if (bPtr->altCaption) - wfree(bPtr->altCaption); - - if (bPtr->textColor) - WMReleaseColor(bPtr->textColor); - - if (bPtr->altTextColor) - WMReleaseColor(bPtr->altTextColor); - - if (bPtr->disTextColor) - WMReleaseColor(bPtr->disTextColor); - - if (bPtr->image) - WMReleasePixmap(bPtr->image); - - if (bPtr->dimage) { - /* yuck.. kluge */ - bPtr->dimage->pixmap = None; - - WMReleasePixmap(bPtr->dimage); - } - if (bPtr->altImage) - WMReleasePixmap(bPtr->altImage); - - wfree(bPtr); -} - - + +#include "WINGsP.h" + +typedef struct W_Button { + W_Class widgetClass; + WMView *view; + + char *caption; + + char *altCaption; + + WMFont *font; + + WMColor *textColor; + WMColor *altTextColor; + WMColor *disTextColor; + + W_Pixmap *image; + W_Pixmap *altImage; + + W_Pixmap *dimage; + + void *clientData; + WMAction *action; + + int tag; + + int groupIndex; + + float periodicDelay; + float periodicInterval; + + WMHandlerID *timer; /* for continuous mode */ + + struct { + WMButtonType type:4; + WMImagePosition imagePosition:4; + WMAlignment alignment:2; + + unsigned int selected:1; + + unsigned int enabled:1; + + unsigned int dimsWhenDisabled:1; + + unsigned int bordered:1; + + unsigned int springLoaded:1; + + unsigned int pushIn:1; /* change relief while pushed */ + + unsigned int pushLight:1; /* highlight while pushed */ + + unsigned int pushChange:1; /* change caption while pushed */ + + unsigned int stateLight:1; /* state indicated by highlight */ + + unsigned int stateChange:1; /* state indicated by caption change */ + + unsigned int statePush:1; /* state indicated by relief */ + + unsigned int continuous:1; /* continually perform action */ + + unsigned int prevSelected:1; + + unsigned int pushed:1; + + unsigned int wasPushed:1; + + unsigned int redrawPending:1; + + unsigned int addedObserver:1; + } flags; +} Button; + +#define DEFAULT_BUTTON_WIDTH 60 +#define DEFAULT_BUTTON_HEIGHT 24 +#define DEFAULT_BUTTON_ALIGNMENT WACenter +#define DEFAULT_BUTTON_IS_BORDERED True + +#define DEFAULT_RADIO_WIDTH 100 +#define DEFAULT_RADIO_HEIGHT 20 +#define DEFAULT_RADIO_ALIGNMENT WALeft +#define DEFAULT_RADIO_IMAGE_POSITION WIPLeft +#define DEFAULT_RADIO_TEXT "Radio" + +#define DEFAULT_SWITCH_WIDTH 100 +#define DEFAULT_SWITCH_HEIGHT 20 +#define DEFAULT_SWITCH_ALIGNMENT WALeft +#define DEFAULT_SWITCH_IMAGE_POSITION WIPLeft +#define DEFAULT_SWITCH_TEXT "Switch" + +static void destroyButton(Button * bPtr); +static void paintButton(Button * bPtr); + +static void handleEvents(XEvent * event, void *data); +static void handleActionEvents(XEvent * event, void *data); + +static char *WMPushedRadioNotification = "WMPushedRadioNotification"; + +#define NFONT(b) (b)->view->screen->normalFont + +WMButton *WMCreateCustomButton(WMWidget * parent, int behaviourMask) +{ + Button *bPtr; + + bPtr = wmalloc(sizeof(Button)); + memset(bPtr, 0, sizeof(Button)); + + bPtr->widgetClass = WC_Button; + + bPtr->view = W_CreateView(W_VIEW(parent)); + if (!bPtr->view) { + wfree(bPtr); + return NULL; + } + bPtr->view->self = bPtr; + + bPtr->flags.type = 0; + + bPtr->flags.springLoaded = (behaviourMask & WBBSpringLoadedMask) != 0; + bPtr->flags.pushIn = (behaviourMask & WBBPushInMask) != 0; + bPtr->flags.pushChange = (behaviourMask & WBBPushChangeMask) != 0; + bPtr->flags.pushLight = (behaviourMask & WBBPushLightMask) != 0; + bPtr->flags.stateLight = (behaviourMask & WBBStateLightMask) != 0; + bPtr->flags.stateChange = (behaviourMask & WBBStateChangeMask) != 0; + bPtr->flags.statePush = (behaviourMask & WBBStatePushMask) != 0; + + W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT); + bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT; + bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED; + + bPtr->flags.enabled = 1; + bPtr->flags.dimsWhenDisabled = 1; + + WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask, handleEvents, bPtr); + + WMCreateEventHandler(bPtr->view, ButtonPressMask | ButtonReleaseMask + | EnterWindowMask | LeaveWindowMask, handleActionEvents, bPtr); + + W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT); + bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT; + bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED; + + return bPtr; +} + +WMButton *WMCreateButton(WMWidget * parent, WMButtonType type) +{ + W_Screen *scrPtr = W_VIEW(parent)->screen; + Button *bPtr; + + switch (type) { + case WBTMomentaryPush: + bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushInMask | WBBPushLightMask); + break; + + case WBTMomentaryChange: + bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushChangeMask); + break; + + case WBTPushOnPushOff: + bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStatePushMask | WBBStateLightMask); + break; + + case WBTToggle: + bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStateChangeMask | WBBStatePushMask); + break; + + case WBTOnOff: + bPtr = WMCreateCustomButton(parent, WBBStateLightMask); + break; + + case WBTSwitch: + bPtr = WMCreateCustomButton(parent, WBBStateChangeMask); + bPtr->flags.bordered = 0; + bPtr->image = WMRetainPixmap(scrPtr->checkButtonImageOff); + bPtr->altImage = WMRetainPixmap(scrPtr->checkButtonImageOn); + break; + + case WBTRadio: + bPtr = WMCreateCustomButton(parent, WBBStateChangeMask); + bPtr->flags.bordered = 0; + bPtr->image = WMRetainPixmap(scrPtr->radioButtonImageOff); + bPtr->altImage = WMRetainPixmap(scrPtr->radioButtonImageOn); + break; + + default: + case WBTMomentaryLight: + bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushLightMask); + bPtr->flags.bordered = 1; + break; + } + + bPtr->flags.type = type; + + if (type == WBTRadio) { + W_ResizeView(bPtr->view, DEFAULT_RADIO_WIDTH, DEFAULT_RADIO_HEIGHT); + WMSetButtonText(bPtr, DEFAULT_RADIO_TEXT); + bPtr->flags.alignment = DEFAULT_RADIO_ALIGNMENT; + bPtr->flags.imagePosition = DEFAULT_RADIO_IMAGE_POSITION; + } else if (type == WBTSwitch) { + W_ResizeView(bPtr->view, DEFAULT_SWITCH_WIDTH, DEFAULT_SWITCH_HEIGHT); + WMSetButtonText(bPtr, DEFAULT_SWITCH_TEXT); + bPtr->flags.alignment = DEFAULT_SWITCH_ALIGNMENT; + bPtr->flags.imagePosition = DEFAULT_SWITCH_IMAGE_POSITION; + } + + return bPtr; +} + +static void updateDisabledMask(WMButton * bPtr) +{ + WMScreen *scr = WMWidgetScreen(bPtr); + Display *dpy = scr->display; + + if (bPtr->image) { + XGCValues gcv; + + if (bPtr->dimage->mask) { + XFreePixmap(dpy, bPtr->dimage->mask); + bPtr->dimage->mask = None; + } + + if (bPtr->flags.dimsWhenDisabled) { + bPtr->dimage->mask = XCreatePixmap(dpy, scr->stipple, + bPtr->dimage->width, bPtr->dimage->height, 1); + + XSetForeground(dpy, scr->monoGC, 0); + XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0, + bPtr->dimage->width, bPtr->dimage->height); + + gcv.foreground = 1; + gcv.background = 0; + gcv.stipple = scr->stipple; + gcv.fill_style = FillStippled; + gcv.clip_mask = bPtr->image->mask; + gcv.clip_x_origin = 0; + gcv.clip_y_origin = 0; + + XChangeGC(dpy, scr->monoGC, GCForeground | GCBackground | GCStipple + | GCFillStyle | GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv); + + XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0, + bPtr->dimage->width, bPtr->dimage->height); + + gcv.fill_style = FillSolid; + gcv.clip_mask = None; + XChangeGC(dpy, scr->monoGC, GCFillStyle | GCClipMask, &gcv); + } + } +} + +void WMSetButtonImageDefault(WMButton * bPtr) +{ + WMSetButtonImage(bPtr, WMWidgetScreen(bPtr)->buttonArrow); + WMSetButtonAltImage(bPtr, WMWidgetScreen(bPtr)->pushedButtonArrow); +} + +void WMSetButtonImage(WMButton * bPtr, WMPixmap * image) +{ + if (bPtr->image != NULL) + WMReleasePixmap(bPtr->image); + bPtr->image = WMRetainPixmap(image); + + if (bPtr->dimage) { + bPtr->dimage->pixmap = None; + WMReleasePixmap(bPtr->dimage); + bPtr->dimage = NULL; + } + + if (image) { + bPtr->dimage = WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr), + image->pixmap, None, + image->width, image->height, image->depth); + updateDisabledMask(bPtr); + } + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonAltImage(WMButton * bPtr, WMPixmap * image) +{ + if (bPtr->altImage != NULL) + WMReleasePixmap(bPtr->altImage); + bPtr->altImage = WMRetainPixmap(image); + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonImagePosition(WMButton * bPtr, WMImagePosition position) +{ + bPtr->flags.imagePosition = position; + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonTextAlignment(WMButton * bPtr, WMAlignment alignment) +{ + bPtr->flags.alignment = alignment; + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonText(WMButton * bPtr, char *text) +{ + if (bPtr->caption) + wfree(bPtr->caption); + + if (text != NULL) { + bPtr->caption = wstrdup(text); + } else { + bPtr->caption = NULL; + } + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonAltText(WMButton * bPtr, char *text) +{ + if (bPtr->altCaption) + wfree(bPtr->altCaption); + + if (text != NULL) { + bPtr->altCaption = wstrdup(text); + } else { + bPtr->altCaption = NULL; + } + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonTextColor(WMButton * bPtr, WMColor * color) +{ + if (bPtr->textColor) + WMReleaseColor(bPtr->textColor); + + bPtr->textColor = WMRetainColor(color); +} + +void WMSetButtonAltTextColor(WMButton * bPtr, WMColor * color) +{ + if (bPtr->altTextColor) + WMReleaseColor(bPtr->altTextColor); + + bPtr->altTextColor = WMRetainColor(color); +} + +void WMSetButtonDisabledTextColor(WMButton * bPtr, WMColor * color) +{ + if (bPtr->disTextColor) + WMReleaseColor(bPtr->disTextColor); + + bPtr->disTextColor = WMRetainColor(color); +} + +void WMSetButtonSelected(WMButton * bPtr, int isSelected) +{ + bPtr->flags.selected = isSelected ? 1 : 0; + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } + if (bPtr->groupIndex > 0) + WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); +} + +int WMGetButtonSelected(WMButton * bPtr) +{ + CHECK_CLASS(bPtr, WC_Button); + + return bPtr->flags.selected; +} + +void WMSetButtonBordered(WMButton * bPtr, int isBordered) +{ + bPtr->flags.bordered = isBordered; + + if (bPtr->view->flags.realized) { + paintButton(bPtr); + } +} + +void WMSetButtonFont(WMButton * bPtr, WMFont * font) +{ + if (bPtr->font) + WMReleaseFont(bPtr->font); + + bPtr->font = WMRetainFont(font); +} + +void WMSetButtonEnabled(WMButton * bPtr, Bool flag) +{ + bPtr->flags.enabled = ((flag == 0) ? 0 : 1); + + if (bPtr->view->flags.mapped) { + paintButton(bPtr); + } +} + +int WMGetButtonEnabled(WMButton * bPtr) +{ + CHECK_CLASS(bPtr, WC_Button); + + return bPtr->flags.enabled; +} + +void WMSetButtonImageDimsWhenDisabled(WMButton * bPtr, Bool flag) +{ + bPtr->flags.dimsWhenDisabled = ((flag == 0) ? 0 : 1); + + updateDisabledMask(bPtr); +} + +void WMSetButtonTag(WMButton * bPtr, int tag) +{ + bPtr->tag = tag; +} + +void WMPerformButtonClick(WMButton * bPtr) +{ + CHECK_CLASS(bPtr, WC_Button); + + if (!bPtr->flags.enabled) + return; + + bPtr->flags.pushed = 1; + bPtr->flags.selected = 1; + + if (bPtr->view->flags.mapped) { + paintButton(bPtr); + XFlush(WMScreenDisplay(WMWidgetScreen(bPtr))); + wusleep(20000); + } + + bPtr->flags.pushed = 0; + + if (bPtr->groupIndex > 0) { + WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); + } + + if (bPtr->action) + (*bPtr->action) (bPtr, bPtr->clientData); + + if (bPtr->view->flags.mapped) + paintButton(bPtr); +} + +void WMSetButtonAction(WMButton * bPtr, WMAction * action, void *clientData) +{ + CHECK_CLASS(bPtr, WC_Button); + + bPtr->action = action; + + bPtr->clientData = clientData; +} + +static void radioPushObserver(void *observerData, WMNotification * notification) +{ + WMButton *bPtr = (WMButton *) observerData; + WMButton *pushedButton = (WMButton *) WMGetNotificationObject(notification); + + if (bPtr != pushedButton && pushedButton->groupIndex == bPtr->groupIndex && bPtr->groupIndex != 0) { + if (bPtr->flags.selected) { + bPtr->flags.selected = 0; + paintButton(bPtr); + } + } +} + +void WMGroupButtons(WMButton * bPtr, WMButton * newMember) +{ + static int tagIndex = 0; + + CHECK_CLASS(bPtr, WC_Button); + CHECK_CLASS(newMember, WC_Button); + + if (!bPtr->flags.addedObserver) { + WMAddNotificationObserver(radioPushObserver, bPtr, WMPushedRadioNotification, NULL); + bPtr->flags.addedObserver = 1; + } + if (!newMember->flags.addedObserver) { + WMAddNotificationObserver(radioPushObserver, newMember, WMPushedRadioNotification, NULL); + newMember->flags.addedObserver = 1; + } + + if (bPtr->groupIndex == 0) { + bPtr->groupIndex = ++tagIndex; + } + newMember->groupIndex = bPtr->groupIndex; +} + +void WMSetButtonContinuous(WMButton * bPtr, Bool flag) +{ + bPtr->flags.continuous = ((flag == 0) ? 0 : 1); + if (bPtr->timer) { + WMDeleteTimerHandler(bPtr->timer); + bPtr->timer = NULL; + } +} + +void WMSetButtonPeriodicDelay(WMButton * bPtr, float delay, float interval) +{ + bPtr->periodicInterval = interval; + bPtr->periodicDelay = delay; +} + +static void paintButton(Button * bPtr) +{ + W_Screen *scrPtr = bPtr->view->screen; + WMReliefType relief; + int offset; + char *caption; + WMPixmap *image; + WMColor *textColor; + WMColor *backColor; + + backColor = NULL; + caption = bPtr->caption; + + if (bPtr->flags.enabled) { + textColor = (bPtr->textColor != NULL ? bPtr->textColor : scrPtr->black); + } else { + textColor = (bPtr->disTextColor != NULL ? bPtr->disTextColor : scrPtr->darkGray); + } + + if (bPtr->flags.enabled || !bPtr->dimage) + image = bPtr->image; + else + image = bPtr->dimage; + offset = 0; + if (bPtr->flags.bordered) + relief = WRRaised; + else + relief = WRFlat; + + if (bPtr->flags.selected) { + if (bPtr->flags.stateLight) { + backColor = scrPtr->white; + textColor = scrPtr->black; + } + + if (bPtr->flags.stateChange) { + if (bPtr->altCaption) + caption = bPtr->altCaption; + if (bPtr->altImage) + image = bPtr->altImage; + if (bPtr->altTextColor) + textColor = bPtr->altTextColor; + } + + if (bPtr->flags.statePush && bPtr->flags.bordered) { + relief = WRSunken; + offset = 1; + } + } + + if (bPtr->flags.pushed) { + if (bPtr->flags.pushIn) { + relief = WRPushed; + offset = 1; + } + if (bPtr->flags.pushLight) { + backColor = scrPtr->white; + textColor = scrPtr->black; + } + + if (bPtr->flags.pushChange) { + if (bPtr->altCaption) + caption = bPtr->altCaption; + if (bPtr->altImage) + image = bPtr->altImage; + if (bPtr->altTextColor) + textColor = bPtr->altTextColor; + } + } + + W_PaintTextAndImage(bPtr->view, True, textColor, + (bPtr->font != NULL ? bPtr->font : scrPtr->normalFont), + relief, caption, bPtr->flags.alignment, image, + bPtr->flags.imagePosition, backColor, offset); +} + +static void handleEvents(XEvent * event, void *data) +{ + Button *bPtr = (Button *) data; + + CHECK_CLASS(data, WC_Button); + + switch (event->type) { + case Expose: + if (event->xexpose.count != 0) + break; + paintButton(bPtr); + break; + + case DestroyNotify: + destroyButton(bPtr); + break; + } +} + +static void autoRepeat(void *data) +{ + Button *bPtr = (Button *) data; + + if (bPtr->action && bPtr->flags.pushed) + (*bPtr->action) (bPtr, bPtr->clientData); + + bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicInterval * 1000), autoRepeat, bPtr); +} + +static void handleActionEvents(XEvent * event, void *data) +{ + Button *bPtr = (Button *) data; + int doclick = 0, dopaint = 0; + + CHECK_CLASS(data, WC_Button); + + if (!bPtr->flags.enabled) + return; + + switch (event->type) { + case EnterNotify: + if (bPtr->groupIndex == 0) { + bPtr->flags.pushed = bPtr->flags.wasPushed; + if (bPtr->flags.pushed) { + bPtr->flags.selected = !bPtr->flags.prevSelected; + dopaint = 1; + } + } + break; + + case LeaveNotify: + if (bPtr->groupIndex == 0) { + bPtr->flags.wasPushed = bPtr->flags.pushed; + if (bPtr->flags.pushed) { + bPtr->flags.selected = bPtr->flags.prevSelected; + dopaint = 1; + } + bPtr->flags.pushed = 0; + } + break; + + case ButtonPress: + if (event->xbutton.button == Button1) { + bPtr->flags.prevSelected = bPtr->flags.selected; + bPtr->flags.wasPushed = 0; + bPtr->flags.pushed = 1; + if (bPtr->groupIndex > 0) { + bPtr->flags.selected = 1; + dopaint = 1; + break; + } + bPtr->flags.selected = !bPtr->flags.selected; + dopaint = 1; + + if (bPtr->flags.continuous && !bPtr->timer) { + bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicDelay * 1000), + autoRepeat, bPtr); + } + } + break; + + case ButtonRelease: + if (event->xbutton.button == Button1) { + if (bPtr->flags.pushed) { + if (bPtr->groupIndex == 0 || (bPtr->flags.selected && bPtr->groupIndex > 0)) + doclick = 1; + dopaint = 1; + if (bPtr->flags.springLoaded) { + bPtr->flags.selected = bPtr->flags.prevSelected; + } + } + bPtr->flags.pushed = 0; + } + if (bPtr->timer) { + WMDeleteTimerHandler(bPtr->timer); + bPtr->timer = NULL; + } + break; + } + + if (dopaint) + paintButton(bPtr); + + if (doclick) { + if (bPtr->flags.selected && bPtr->groupIndex > 0) { + WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); + } + + if (bPtr->action) + (*bPtr->action) (bPtr, bPtr->clientData); + } +} + +static void destroyButton(Button * bPtr) +{ + if (bPtr->flags.addedObserver) { + WMRemoveNotificationObserver(bPtr); + } + + if (bPtr->timer) + WMDeleteTimerHandler(bPtr->timer); + + if (bPtr->font) + WMReleaseFont(bPtr->font); + + if (bPtr->caption) + wfree(bPtr->caption); + + if (bPtr->altCaption) + wfree(bPtr->altCaption); + + if (bPtr->textColor) + WMReleaseColor(bPtr->textColor); + + if (bPtr->altTextColor) + WMReleaseColor(bPtr->altTextColor); + + if (bPtr->disTextColor) + WMReleaseColor(bPtr->disTextColor); + + if (bPtr->image) + WMReleasePixmap(bPtr->image); + + if (bPtr->dimage) { + /* yuck.. kluge */ + bPtr->dimage->pixmap = None; + + WMReleasePixmap(bPtr->dimage); + } + if (bPtr->altImage) + WMReleasePixmap(bPtr->altImage); + + wfree(bPtr); +}