There are some times when we need a Switch Button (aka CheckBox) with more
than 2 states, generally to express check/uncheck/leave-as-is.

This patch extends the Button widget to support the new WBTTriState type,
similar to the existing WBTSwitch except it supports a 3rd state which is
reported to application as '-1'.

The implementation was done in order to not break the binary API. The
version have been incremented in the WINGs header to reflect the change,
but not the version in the 'configure.ac' because that have already been
done in commit c6e323e75d for the next Window Maker release.

Signed-off-by: Christophe CURIS <christophe.cu...@free.fr>
---
 WINGs/WINGs/WINGs.h  |  5 ++--
 WINGs/WINGs/WINGsP.h | 10 ++++++++
 WINGs/wbutton.c      | 35 ++++++++++++++++++++++----
 WINGs/widgets.c      | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 7 deletions(-)

diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h
index 4798174..5235c20 100644
--- a/WINGs/WINGs/WINGs.h
+++ b/WINGs/WINGs/WINGs.h
@@ -26,7 +26,7 @@
 #include <WINGs/WUtil.h>
 #include <X11/Xlib.h>
 
-#define WINGS_H_VERSION  20141205
+#define WINGS_H_VERSION  20150508
 
 
 #ifdef __cplusplus
@@ -127,7 +127,8 @@ typedef enum {
     WBTRadio = 5,
     WBTMomentaryChange = 6,
     WBTOnOff = 7,
-    WBTMomentaryLight = 8
+    WBTMomentaryLight = 8,
+    WBTTriState = 9
 } WMButtonType;
 
 /* button behaviour masks */
diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h
index fc18b1c..4cbe0fc 100644
--- a/WINGs/WINGs/WINGsP.h
+++ b/WINGs/WINGs/WINGsP.h
@@ -268,6 +268,16 @@ typedef struct W_Screen {
     struct W_View *modalView;
     unsigned modalLoop:1;
     unsigned ignoreNextDoubleClick:1;
+
+    /*
+     * New stuff in Window Maker 0.95.7
+     * Added at the end of the structure to avoid breaking binary compatibility
+     * with previous versions of the toolkit
+     */
+    W_Pixmap *tristateButtonImageOn;
+    W_Pixmap *tristateButtonImageOff;
+    W_Pixmap *tristateButtonImageTri;
+
 } W_Screen;
 
 #define W_DRAWABLE(scr)                (scr)->rcontext->drawable
diff --git a/WINGs/wbutton.c b/WINGs/wbutton.c
index 8c8e4dc..c8d78d9 100644
--- a/WINGs/wbutton.c
+++ b/WINGs/wbutton.c
@@ -17,6 +17,7 @@ typedef struct W_Button {
 
        W_Pixmap *image;
        W_Pixmap *altImage;
+       W_Pixmap *tsImage;
 
        W_Pixmap *dimage;
 
@@ -37,7 +38,7 @@ typedef struct W_Button {
                WMImagePosition imagePosition:4;
                WMAlignment alignment:2;
 
-               unsigned int selected:1;
+               unsigned int selected:2;
 
                unsigned int enabled:1;
 
@@ -183,6 +184,14 @@ WMButton *WMCreateButton(WMWidget * parent, WMButtonType 
type)
                bPtr->altImage = WMRetainPixmap(scrPtr->radioButtonImageOn);
                break;
 
+       case WBTTriState:
+               bPtr = WMCreateCustomButton(parent, WBBStateChangeMask);
+               bPtr->flags.bordered = 0;
+               bPtr->image = WMRetainPixmap(scrPtr->tristateButtonImageOff);
+               bPtr->altImage = WMRetainPixmap(scrPtr->tristateButtonImageOn);
+               bPtr->tsImage = WMRetainPixmap(scrPtr->tristateButtonImageTri);
+               break;
+
        default:
        case WBTMomentaryLight:
                bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | 
WBBPushLightMask);
@@ -197,7 +206,7 @@ WMButton *WMCreateButton(WMWidget * parent, WMButtonType 
type)
                WMSetButtonText(bPtr, DEFAULT_RADIO_TEXT);
                bPtr->flags.alignment = DEFAULT_RADIO_ALIGNMENT;
                bPtr->flags.imagePosition = DEFAULT_RADIO_IMAGE_POSITION;
-       } else if (type == WBTSwitch) {
+       } else if (type == WBTSwitch || type == WBTTriState) {
                W_ResizeView(bPtr->view, DEFAULT_SWITCH_WIDTH, 
DEFAULT_SWITCH_HEIGHT);
                WMSetButtonText(bPtr, DEFAULT_SWITCH_TEXT);
                bPtr->flags.alignment = DEFAULT_SWITCH_ALIGNMENT;
@@ -371,7 +380,10 @@ void WMSetButtonDisabledTextColor(WMButton * bPtr, WMColor 
* color)
 
 void WMSetButtonSelected(WMButton * bPtr, int isSelected)
 {
-       bPtr->flags.selected = isSelected ? 1 : 0;
+       if ((bPtr->flags.type == WBTTriState) && (isSelected < 0))
+               bPtr->flags.selected = 2;
+       else
+               bPtr->flags.selected = isSelected ? 1 : 0;
 
        if (bPtr->view->flags.realized) {
                paintButton(bPtr);
@@ -384,6 +396,9 @@ int WMGetButtonSelected(WMButton * bPtr)
 {
        CHECK_CLASS(bPtr, WC_Button);
 
+       if ((bPtr->flags.type == WBTTriState) && (bPtr->flags.selected == 2))
+               return -1;
+
        return bPtr->flags.selected;
 }
 
@@ -558,7 +573,9 @@ static void paintButton(Button * bPtr)
                if (bPtr->flags.stateChange) {
                        if (bPtr->altCaption)
                                caption = bPtr->altCaption;
-                       if (bPtr->altImage)
+                       if (bPtr->flags.selected == 2)
+                               image = bPtr->tsImage;
+                       else if (bPtr->altImage)
                                image = bPtr->altImage;
                        if (bPtr->altTextColor)
                                textColor = bPtr->altTextColor;
@@ -659,6 +676,8 @@ static void handleActionEvents(XEvent * event, void *data)
 
        case ButtonPress:
                if (event->xbutton.button == Button1) {
+                       static const unsigned int next_state[4] = { [0] = 1, 
[1] = 2, [2] = 0 };
+
                        bPtr->flags.prevSelected = bPtr->flags.selected;
                        bPtr->flags.wasPushed = 0;
                        bPtr->flags.pushed = 1;
@@ -667,7 +686,10 @@ static void handleActionEvents(XEvent * event, void *data)
                                dopaint = 1;
                                break;
                        }
-                       bPtr->flags.selected = !bPtr->flags.selected;
+                       if (bPtr->flags.type == WBTTriState)
+                               bPtr->flags.selected = 
next_state[bPtr->flags.selected];
+                       else
+                               bPtr->flags.selected = !bPtr->flags.selected;
                        dopaint = 1;
 
                        if (bPtr->flags.continuous && !bPtr->timer) {
@@ -748,5 +770,8 @@ static void destroyButton(Button * bPtr)
        if (bPtr->altImage)
                WMReleasePixmap(bPtr->altImage);
 
+       if (bPtr->tsImage)
+               WMReleasePixmap(bPtr->tsImage);
+
        wfree(bPtr);
 }
diff --git a/WINGs/widgets.c b/WINGs/widgets.c
index 4c9c687..177ad3c 100644
--- a/WINGs/widgets.c
+++ b/WINGs/widgets.c
@@ -97,6 +97,66 @@ static char *RADIO_BUTTON_OFF[] = {
        ".....     .....",
 };
 
+#define TRISTATE_BUTTON_ON_WIDTH       15
+#define TRISTATE_BUTTON_ON_HEIGHT      15
+static char *TRISTATE_BUTTON_ON[] = {
+       "%%%%%%%%%%%%%%.",
+       "%%%%%%%%%%%%%. ",
+       "%%           . ",
+       "%% ##     ## . ",
+       "%% ###   ### . ",
+       "%%  ### ###  . ",
+       "%%   #####   . ",
+       "%%    ###    . ",
+       "%%   #####   . ",
+       "%%  ### ###  . ",
+       "%% ###   ### . ",
+       "%% ##     ## . ",
+       "%%           . ",
+       "%............. ",
+       ".              ",
+};
+
+#define TRISTATE_BUTTON_OFF_WIDTH      15
+#define TRISTATE_BUTTON_OFF_HEIGHT     15
+static char *TRISTATE_BUTTON_OFF[] = {
+       "%%%%%%%%%%%%%%.",
+       "%%%%%%%%%%%%%. ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%%           . ",
+       "%............. ",
+       ".              ",
+};
+
+#define TRISTATE_BUTTON_TRI_WIDTH      15
+#define TRISTATE_BUTTON_TRI_HEIGHT     15
+static char *TRISTATE_BUTTON_TRI[] = {
+       "%%%%%%%%%%%%%%.",
+       "%%%%%%%%%%%%%. ",
+       "%%           . ",
+       "%% # # # # # . ",
+       "%%  # # # #  . ",
+       "%% # # # # # . ",
+       "%%  # # # #  . ",
+       "%% # # # # # . ",
+       "%%  # # # #  . ",
+       "%% # # # # # . ",
+       "%%  # # # #  . ",
+       "%% # # # # # . ",
+       "%%           . ",
+       "%............. ",
+       ".              ",
+};
+
 static char *BUTTON_ARROW[] = {
        "..................",
        "....##....#### ...",
@@ -729,6 +789,15 @@ WMScreen *WMCreateScreenWithRContext(Display * display, 
int screen, RContext * c
        scrPtr->radioButtonImageOff = makePixmap(scrPtr, RADIO_BUTTON_OFF,
                                                 RADIO_BUTTON_OFF_WIDTH, 
RADIO_BUTTON_OFF_HEIGHT, False);
 
+       scrPtr->tristateButtonImageOn = makePixmap(scrPtr, TRISTATE_BUTTON_ON,
+                                                  TRISTATE_BUTTON_ON_WIDTH, 
TRISTATE_BUTTON_ON_HEIGHT, False);
+
+       scrPtr->tristateButtonImageOff = makePixmap(scrPtr, TRISTATE_BUTTON_OFF,
+                                                   TRISTATE_BUTTON_OFF_WIDTH, 
TRISTATE_BUTTON_OFF_HEIGHT, False);
+
+       scrPtr->tristateButtonImageTri = makePixmap(scrPtr, TRISTATE_BUTTON_TRI,
+                                                   TRISTATE_BUTTON_TRI_WIDTH, 
TRISTATE_BUTTON_TRI_HEIGHT, False);
+
        scrPtr->buttonArrow = makePixmap(scrPtr, BUTTON_ARROW, 
BUTTON_ARROW_WIDTH, BUTTON_ARROW_HEIGHT, False);
 
        scrPtr->pushedButtonArrow = makePixmap(scrPtr, BUTTON_ARROW2,
-- 
2.1.4


-- 
To unsubscribe, send mail to wmaker-dev-unsubscr...@lists.windowmaker.org.

Reply via email to