#include "WINGsP.h" typedef struct W_Button { W_Class widgetClass; WMView *view; char *caption; char *altCaption; WMFont *font; W_Pixmap *image; W_Pixmap *altImage; 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 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); W_ViewProcedureTable _ButtonViewProcedures = { NULL, NULL, NULL }; 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) { free(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; 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; } void WMSetButtonImage(WMButton *bPtr, WMPixmap *image) { if (bPtr->image!=NULL) WMReleasePixmap(bPtr->image); bPtr->image = WMRetainPixmap(image); 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) free(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) free(bPtr->altCaption); if (text!=NULL) { bPtr->altCaption = wstrdup(text); } else { bPtr->altCaption = NULL; } if (bPtr->view->flags.realized) { paintButton(bPtr); } } void WMSetButtonSelected(WMButton *bPtr, int isSelected) { bPtr->flags.selected = isSelected; if (bPtr->view->flags.realized) { paintButton(bPtr); } } 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; if (bPtr->view->flags.mapped) { paintButton(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); } if (bPtr->groupIndex>0) { WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL); } if (bPtr->action) (*bPtr->action)(bPtr, bPtr->clientData); bPtr->flags.pushed = 0; 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; 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; GC gc; WMReliefType relief; int offset; char *caption; WMPixmap *image; GC textGC; gc = NULL; caption = bPtr->caption; image = bPtr->image; offset = 0; if (bPtr->flags.bordered) relief = WRRaised; else relief = WRFlat; if (bPtr->flags.selected) { if (bPtr->flags.stateLight) gc = W_GC(scrPtr->white); if (bPtr->flags.stateChange) { if (bPtr->altCaption) { caption = bPtr->altCaption; } if (bPtr->altImage) image = bPtr->altImage; } 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) gc = W_GC(scrPtr->white); if (bPtr->flags.pushChange) { if (bPtr->altCaption) { caption = bPtr->altCaption; } if (bPtr->altImage) image = bPtr->altImage; } } if (bPtr->flags.enabled) textGC = W_GC(scrPtr->black); else textGC = W_GC(scrPtr->darkGray); W_PaintTextAndImage(bPtr->view, True, textGC, (bPtr->font!=NULL ? bPtr->font : scrPtr->normalFont), relief, caption, bPtr->flags.alignment, image, bPtr->flags.imagePosition, gc, 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) { if (bPtr->groupIndex>0) { if (!bPtr->flags.selected) doclick = 1; bPtr->flags.pushed = 1; bPtr->flags.selected = 1; dopaint = 1; break; } bPtr->flags.wasPushed = 0; bPtr->flags.pushed = 1; bPtr->flags.prevSelected = bPtr->flags.selected; 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) 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) free(bPtr->caption); if (bPtr->altCaption) free(bPtr->altCaption); if (bPtr->image) WMReleasePixmap(bPtr->image); if (bPtr->altImage) WMReleasePixmap(bPtr->altImage); free(bPtr); }