From f349a3827b7c3d5876b0531780396c6acda15450 Mon Sep 17 00:00:00 2001 From: hobbs Date: Wed, 18 Feb 2004 00:40:23 +0000 Subject: * doc/checkbutton.n: TIP#110 implementation * doc/radiobutton.n: Tristate Checkbutton and Radiobuttons * generic/tkButton.c: * generic/tkButton.h: * library/demos/check.tcl: * library/demos/radio.tcl: * macosx/tkMacOSXButton.c: * macosx/tkMacOSXDefault.h: * tests/button.test: * unix/tkUnixButton.c: * unix/tkUnixDefault.h: * win/tkWinButton.c: * win/tkWinDefault.h: --- ChangeLog | 20 +++++++++-- doc/checkbutton.n | 29 ++++++++++----- doc/radiobutton.n | 17 +++++++-- generic/tkButton.c | 94 +++++++++++++++++++++++++++++++++++++++++++++--- generic/tkButton.h | 14 +++++++- library/demos/check.tcl | 47 +++++++++++++++++++++--- library/demos/radio.tcl | 23 ++++++++---- macosx/tkMacOSXButton.c | 62 +++++++++++++++++++------------- macosx/tkMacOSXDefault.h | 3 +- tests/button.test | 8 +++-- unix/tkUnixButton.c | 33 +++++++++++------ unix/tkUnixDefault.h | 3 +- win/tkWinButton.c | 13 +++++-- win/tkWinDefault.h | 3 +- 14 files changed, 296 insertions(+), 73 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14acc21..7694b3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2004-02-17 Jeff Hobbs + + * doc/checkbutton.n: TIP#110 implementation + * doc/radiobutton.n: Tristate Checkbutton and Radiobuttons + * generic/tkButton.c: + * generic/tkButton.h: + * library/demos/check.tcl: + * library/demos/radio.tcl: + * macosx/tkMacOSXButton.c: + * macosx/tkMacOSXDefault.h: + * tests/button.test: + * unix/tkUnixButton.c: + * unix/tkUnixDefault.h: + * win/tkWinButton.c: + * win/tkWinDefault.h: + 2004-02-17 Don Porter * tests/imgPhoto.test (imgPhoto-16.1): Corrected incorrect @@ -5,7 +21,7 @@ 2004-02-15 Jim Ingham - * tkMacOSXDialog.c (MatchOneType): If the Macintosh filetype + * tkMacOSXDialog.c (MatchOneType): If the Macintosh filetype is 0, then automatically pass the fileType check. * tkMacOSXCarbonEvents.c: New file - this doesn't do anything @@ -34,7 +50,7 @@ * tkMacOSXSubwindows.c: Ditto * tkMacOSXWindowEvent.c: Ditto * tkMacOSXWm.c: Ditto - + 2004-02-13 Jim Ingham * tkMacOSXDialog.c (Tk_GetOpenFileObjCmd): Use CFStringRef for diff --git a/doc/checkbutton.n b/doc/checkbutton.n index 9e83699..ff8d74a 100644 --- a/doc/checkbutton.n +++ b/doc/checkbutton.n @@ -5,7 +5,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: checkbutton.n,v 1.6 2002/08/28 01:08:06 drh Exp $ +'\" RCS: @(#) $Id: checkbutton.n,v 1.7 2004/02/18 00:40:23 hobbs Exp $ '\" .so man.macros .TH checkbutton n 4.4 Tk "Tk Built-In Commands" @@ -95,6 +95,14 @@ should be insensitive: the default bindings will refuse to activate the widget and will ignore mouse button presses. In this state the \fBdisabledForeground\fR and \fBbackground\fR options determine how the checkbutton is displayed. +.OP \-tristateimage tristateImage TristateImage +Specifies an image to display (in place of the \fBimage\fR option) +when the checkbutton is in tri-state mode. +This option is ignored unless the \fBimage\fR option has been +specified. +.OP \-tristatevalue tristateValue Value +Specifies the value that causes the checkbutton to display the multi-value +selection, also known as the tri-state mode. Defaults to ``""'' .OP \-variable variable Variable Specifies name of global variable to set to indicate whether or not this button is selected. Defaults to the name of the @@ -145,18 +153,23 @@ If a checkbutton is selected then the indicator is normally drawn with a selected appearance, and a Tcl variable associated with the checkbutton is set to a particular value (normally 1). -Under Unix, the indicator is drawn with a sunken relief and a special -color. Under Windows, the indicator is drawn with a check mark inside. +The indicator is drawn with a check mark inside. If the checkbutton is not selected, then the indicator is drawn with a deselected appearance, and the associated variable is set to a different value (typically 0). -Under Unix, the indicator is drawn with a raised relief and no special -color. Under Windows, the indicator is drawn without a check mark inside. +The indicator is drawn without a check mark inside. In the special case +where the variable (if specified) has a value that matches the tristatevalue, +the indicator is drawn with a tri-state appearance and is in the tri-state +mode indicating mixed or multiple values. (This is used when the check +box represents the state of multiple items.) +The indicator is drawn in a platform dependent manner. Under Unix and +Windows, the background interior of the box is ``grayed''. Under Mac, +the indicator is drawn with a dash mark inside. .VE By default, the name of the variable associated with a checkbutton is the same as the \fIname\fR used to create the checkbutton. -The variable name, and the ``on'' and ``off'' values stored in it, -may be modified with options on the command line or in the option +The variable name, and the ``on'', ``off'' and ``tristate'' values stored in +it, may be modified with options on the command line or in the option database. Configuration options may also be used to modify the way the indicator is displayed (or whether it is displayed at all). @@ -164,7 +177,7 @@ By default a checkbutton is configured to select and deselect itself on alternate button clicks. In addition, each checkbutton monitors its associated variable and automatically selects and deselects itself when the variables value -changes to and from the button's ``on'' value. +changes to and from the button's ``on'', ``off'' and ``tristate'' values. .SH "WIDGET COMMAND" .PP diff --git a/doc/radiobutton.n b/doc/radiobutton.n index 2cc08e2..239d07a 100644 --- a/doc/radiobutton.n +++ b/doc/radiobutton.n @@ -5,7 +5,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: radiobutton.n,v 1.6 2002/08/28 01:08:06 drh Exp $ +'\" RCS: @(#) $Id: radiobutton.n,v 1.7 2004/02/18 00:40:24 hobbs Exp $ '\" .so man.macros .TH radiobutton n 4.4 Tk "Tk Built-In Commands" @@ -90,6 +90,14 @@ should be insensitive: the default bindings will refuse to activate the widget and will ignore mouse button presses. In this state the \fBdisabledForeground\fR and \fBbackground\fR options determine how the radiobutton is displayed. +.OP \-tristateimage tristateImage TristateImage +Specifies an image to display (in place of the \fBimage\fR option) +when the radiobutton is selected. +This option is ignored unless the \fBimage\fR option has been +specified. +.OP \-tristatevalue tristateValue Value +Specifies the value that causes the radiobutton to display the multi-value +selection, also known as the tri-state mode. Defaults to ``""'' .OP \-value value Value Specifies value to store in the button's associated variable whenever this button is selected. @@ -147,8 +155,7 @@ color. Under Windows, the indicator is drawn with a round mark inside. If the radiobutton is not selected, then the indicator is drawn with a deselected appearance, and the associated variable is set to a different value (typically 0). -Under Unix, the indicator is drawn with a raised relief and no special -color. Under Windows, the indicator is drawn without a round mark inside. +The indicator is drawn without a round mark inside. .VE Typically, several radiobuttons share a single variable and the value of the variable indicates which radiobutton is to be selected. @@ -156,6 +163,10 @@ When a radiobutton is selected it sets the value of the variable to indicate that fact; each radiobutton also monitors the value of the variable and automatically selects and deselects itself when the variable's value changes. +If the variable's value matches the tristatevalue, then the radiobutton is +drawn using the tri-state mode. This mode is used to indicate mixed or +multiple values. (This is used when the radio button represents the state +of multiple items.) By default the variable \fBselectedButton\fR is used; its contents give the name of the button that is selected, or the empty string if no button associated with that diff --git a/generic/tkButton.c b/generic/tkButton.c index bfd5010..b3ed6b0 100644 --- a/generic/tkButton.c +++ b/generic/tkButton.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkButton.c,v 1.22 2003/11/12 00:07:42 hobbs Exp $ + * RCS: @(#) $Id: tkButton.c,v 1.23 2004/02/18 00:40:24 hobbs Exp $ */ #include "tkButton.h" @@ -344,6 +344,11 @@ static Tk_OptionSpec checkbuttonOptionSpecs[] = { {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-tristateimage", "tristateImage", "TristateImage", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, tristateImagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-tristatevalue", "tristateValue", "TristateValue", + DEF_BUTTON_TRISTATE_VALUE, Tk_Offset(TkButton, tristateValuePtr), -1, 0, 0, 0}, {TK_OPTION_INT, "-underline", "underline", "Underline", DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, {TK_OPTION_STRING, "-variable", "variable", "Variable", @@ -450,6 +455,11 @@ static Tk_OptionSpec radiobuttonOptionSpecs[] = { {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1, TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-tristateimage", "tristateImage", "TristateImage", + DEF_BUTTON_IMAGE, Tk_Offset(TkButton, tristateImagePtr), -1, + TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_STRING, "-tristatevalue", "tristateValue", "TristateValue", + DEF_BUTTON_TRISTATE_VALUE, Tk_Offset(TkButton, tristateValuePtr), -1, 0, 0, 0}, {TK_OPTION_INT, "-underline", "underline", "Underline", DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0}, {TK_OPTION_STRING, "-value", "value", "Value", @@ -523,6 +533,9 @@ static void ButtonImageProc _ANSI_ARGS_((ClientData clientData, static void ButtonSelectImageProc _ANSI_ARGS_(( ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight)); +static void ButtonTristateImageProc _ANSI_ARGS_(( + ClientData clientData, int x, int y, int width, + int height, int imgWidth, int imgHeight)); static char * ButtonTextVarProc _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp, CONST char *name1, CONST char *name2, int flags)); @@ -681,6 +694,8 @@ ButtonCreate(clientData, interp, objc, objv, type) butPtr->image = NULL; butPtr->selectImagePtr = NULL; butPtr->selectImage = NULL; + butPtr->tristateImagePtr = NULL; + butPtr->tristateImage = NULL; butPtr->state = STATE_NORMAL; butPtr->normalBorder = NULL; butPtr->activeBorder = NULL; @@ -725,6 +740,7 @@ ButtonCreate(clientData, interp, objc, objv, type) butPtr->selVarNamePtr = NULL; butPtr->onValuePtr = NULL; butPtr->offValuePtr = NULL; + butPtr->tristateValuePtr = NULL; butPtr->cursor = None; butPtr->takeFocusPtr = NULL; butPtr->commandPtr = NULL; @@ -972,6 +988,9 @@ DestroyButton(butPtr) if (butPtr->selectImage != NULL) { Tk_FreeImage(butPtr->selectImage); } + if (butPtr->tristateImage != NULL) { + Tk_FreeImage(butPtr->tristateImage); + } if (butPtr->normalTextGC != None) { Tk_FreeGC(butPtr->display, butPtr->normalTextGC); } @@ -1131,11 +1150,15 @@ ConfigureButton(interp, butPtr, objc, objv) valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_GLOBAL_ONLY); butPtr->flags &= ~SELECTED; + butPtr->flags &= ~TRISTATED; if (valuePtr != NULL) { if (strcmp(Tcl_GetString(valuePtr), Tcl_GetString(butPtr->onValuePtr)) == 0) { butPtr->flags |= SELECTED; - } + } else if (strcmp(Tcl_GetString(valuePtr), + Tcl_GetString(butPtr->tristateValuePtr)) == 0) { + butPtr->flags |= TRISTATED; + } } else { if (Tcl_ObjSetVar2(interp, namePtr, NULL, (butPtr->type == TYPE_CHECK_BUTTON) @@ -1191,6 +1214,20 @@ ConfigureButton(interp, butPtr, objc, objv) Tk_FreeImage(butPtr->selectImage); } butPtr->selectImage = image; + if (butPtr->tristateImagePtr != NULL) { + image = Tk_GetImage(butPtr->interp, butPtr->tkwin, + Tcl_GetString(butPtr->tristateImagePtr), + ButtonTristateImageProc, (ClientData) butPtr); + if (image == NULL) { + continue; + } + } else { + image = NULL; + } + if (butPtr->tristateImage != NULL) { + Tk_FreeImage(butPtr->tristateImage); + } + butPtr->tristateImage = image; haveImage = 0; if (butPtr->imagePtr != NULL || butPtr->bitmap != None) { @@ -1591,6 +1628,7 @@ ButtonVarProc(clientData, interp, name1, name2, flags) if (flags & TCL_TRACE_UNSETS) { butPtr->flags &= ~SELECTED; + butPtr->flags &= ~TRISTATED; if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) { Tcl_TraceVar(interp, name, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS, @@ -1615,8 +1653,15 @@ ButtonVarProc(clientData, interp, name1, name2, flags) return (char *) NULL; } butPtr->flags |= SELECTED; - } else if (butPtr->flags & SELECTED) { - butPtr->flags &= ~SELECTED; + butPtr->flags &= ~TRISTATED; + } else if (strcmp(value, Tcl_GetString(butPtr->tristateValuePtr)) == 0) { + if (butPtr->flags & TRISTATED) { + return (char *) NULL; + } + butPtr->flags |= TRISTATED; + butPtr->flags &= ~SELECTED; + } else if (butPtr->flags & (SELECTED | TRISTATED)) { + butPtr->flags &= ~(SELECTED | TRISTATED); } else { return (char *) NULL; } @@ -1778,3 +1823,44 @@ ButtonSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight) butPtr->flags |= REDRAW_PENDING; } } + +/* + *---------------------------------------------------------------------- + * + * ButtonTristateImageProc -- + * + * This procedure is invoked by the image code whenever the manager + * for an image does something that affects the size or contents + * of the image displayed in a button when it is selected. + * + * Results: + * None. + * + * Side effects: + * May arrange for the button to get redisplayed. + * + *---------------------------------------------------------------------- + */ + +static void +ButtonTristateImageProc(clientData, x, y, width, height, imgWidth, imgHeight) + ClientData clientData; /* Pointer to widget record. */ + int x, y; /* Upper left pixel (within image) + * that must be redisplayed. */ + int width, height; /* Dimensions of area to redisplay + * (may be <= 0). */ + int imgWidth, imgHeight; /* New dimensions of image. */ +{ + register TkButton *butPtr = (TkButton *) clientData; + + /* + * Don't recompute geometry: it's controlled by the primary image. + */ + + if ((butPtr->flags & TRISTATED) && (butPtr->tkwin != NULL) + && Tk_IsMapped(butPtr->tkwin) + && !(butPtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr); + butPtr->flags |= REDRAW_PENDING; + } +} diff --git a/generic/tkButton.h b/generic/tkButton.h index d3f7cfa..78e0765 100644 --- a/generic/tkButton.h +++ b/generic/tkButton.h @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkButton.h,v 1.10 2003/04/26 02:59:20 hobbs Exp $ + * RCS: @(#) $Id: tkButton.h,v 1.11 2004/02/18 00:40:24 hobbs Exp $ */ #ifndef _TKBUTTON @@ -96,6 +96,13 @@ typedef struct { Tk_Image selectImage; /* Derived from selectImagePtr by calling * Tk_GetImage, or NULL if selectImagePtr * is NULL. */ + Tcl_Obj *tristateImagePtr; /* Value of -tristateimage option: specifies + * image to display in window when selected, + * or NULL if none. Ignored if imagePtr is + * NULL. */ + Tk_Image tristateImage; /* Derived from tristateImagePtr by calling + * Tk_GetImage, or NULL if tristateImagePtr + * is NULL. */ /* * Information used when displaying widget: @@ -228,6 +235,10 @@ typedef struct { * to store in variable when this button * isn't selected. Used only by * checkbuttons. */ + Tcl_Obj *tristateValuePtr; /* Value of -tristatevalue option: specifies value + * to display Tristate or Multivalue mode when + * variable matches this value. Used by check- + * buttons. */ /* * Miscellaneous information: @@ -286,6 +297,7 @@ typedef struct { #define SELECTED (1 << 1) #define GOT_FOCUS (1 << 2) #define BUTTON_DELETED (1 << 3) +#define TRISTATED (1 << 4) /* * Declaration of variables shared between the files in the button module. */ diff --git a/library/demos/check.tcl b/library/demos/check.tcl index 82c5d18..ef8c5c3 100644 --- a/library/demos/check.tcl +++ b/library/demos/check.tcl @@ -3,7 +3,7 @@ # This demonstration script creates a toplevel window containing # several checkbuttons. # -# RCS: @(#) $Id: check.tcl,v 1.3 2003/08/20 23:02:18 hobbs Exp $ +# RCS: @(#) $Id: check.tcl,v 1.4 2004/02/18 00:40:24 hobbs Exp $ if {![info exists widgetDemo]} { error "This script should be run from the \"widget\" demo." @@ -16,14 +16,53 @@ wm title $w "Checkbutton Demonstration" wm iconname $w "check" positionWindow $w -label $w.msg -font $font -wraplength 4i -justify left -text "Three checkbuttons are displayed below. If you click on a button, it will toggle the button's selection state and set a Tcl variable to a value indicating the state of the checkbutton. Click the \"See Variables\" button to see the current values of the variables." +label $w.msg -font $font -wraplength 4i -justify left -text "Four checkbuttons are displayed below. If you click on a button, it will toggle the button's selection state and set a Tcl variable to a value indicating the state of the checkbutton. The first button also follows the state of the other three. If only some of the three are checked, the first button will display the tri-state mode. Click the \"See Variables\" button to see the current values of the variables." pack $w.msg -side top ## See Code / Dismiss buttons -set btns [addSeeDismiss $w.buttons $w [list wipers brakes sober]] +set btns [addSeeDismiss $w.buttons $w [list safety wipers brakes sober]] pack $btns -side bottom -fill x +checkbutton $w.b0 -text "Safety Check" -variable safety -relief flat \ + -onvalue "all" \ + -offvalue "none" \ + -tristatevalue "partial" checkbutton $w.b1 -text "Wipers OK" -variable wipers -relief flat checkbutton $w.b2 -text "Brakes OK" -variable brakes -relief flat checkbutton $w.b3 -text "Driver Sober" -variable sober -relief flat -pack $w.b1 $w.b2 $w.b3 -side top -pady 2 -anchor w +pack $w.b0 -side top -pady 2 -anchor w +pack $w.b1 $w.b2 $w.b3 -side top -pady 2 -anchor w -padx 15 + +set in_check 0 +proc tristate_check {n1 n2 op} { + global safety wipers brakes sober in_check + if {$in_check} { + return + } + set in_check 1 + if {$n1 eq "safety"} { + if {$safety eq "none"} { + set wipers 0 + set brakes 0 + set sober 0 + } elseif {$safety eq "all"} { + set wipers 1 + set brakes 1 + set sober 1 + } + } else { + if {$wipers == 1 && $brakes == 1 && $sober == 1} { + set safety all + } elseif {$wipers == 1 || $brakes == 1 || $sober == 1} { + set safety partial + } else { + set safety none + } + } + set in_check 0 +} + +trace variable wipers w tristate_check +trace variable brakes w tristate_check +trace variable sober w tristate_check +trace variable safety w tristate_check diff --git a/library/demos/radio.tcl b/library/demos/radio.tcl index a636cb8..f637865 100644 --- a/library/demos/radio.tcl +++ b/library/demos/radio.tcl @@ -3,7 +3,7 @@ # This demonstration script creates a toplevel window containing # several radiobutton widgets. # -# RCS: @(#) $Id: radio.tcl,v 1.5 2003/08/20 23:02:18 hobbs Exp $ +# RCS: @(#) $Id: radio.tcl,v 1.6 2004/02/18 00:40:24 hobbs Exp $ if {![info exists widgetDemo]} { error "This script should be run from the \"widget\" demo." @@ -15,21 +15,27 @@ toplevel $w wm title $w "Radiobutton Demonstration" wm iconname $w "radio" positionWindow $w -label $w.msg -font $font -wraplength 5i -justify left -text "Three groups of radiobuttons are displayed below. If you click on a button then the button will become selected exclusively among all the buttons in its group. A Tcl variable is associated with each group to indicate which of the group's buttons is selected. Click the \"See Variables\" button to see the current values of the variables." -pack $w.msg -side top +label $w.msg -font $font -wraplength 5i -justify left -text "Three groups of radiobuttons are displayed below. If you click on a button then the button will become selected exclusively among all the buttons in its group. A Tcl variable is associated with each group to indicate which of the group's buttons is selected. When the 'Tristate' button is pressed, the radio buttons will display the tri-state mode. Selecting any radio button will return the buttons to their respective on/off state. Click the \"See Variables\" button to see the current values of the variables." +grid $w.msg -row 0 -column 0 -columnspan 3 -sticky nsew ## See Code / Dismiss buttons set btns [addSeeDismiss $w.buttons $w [list size color align]] -pack $btns -side bottom -fill x +grid $btns -row 3 -column 0 -columnspan 3 -sticky ew labelframe $w.left -pady 2 -text "Point Size" -padx 2 labelframe $w.mid -pady 2 -text "Color" -padx 2 labelframe $w.right -pady 2 -text "Alignment" -padx 2 -pack $w.left $w.mid $w.right -side left -expand yes -pady .5c -padx .5c +button $w.tristate -text Tristate -command "set size multi; set color multi" \ + -pady 2 -padx 2 + +grid $w.left -column 0 -row 1 -pady .5c -padx .5c -rowspan 2 +grid $w.mid -column 1 -row 1 -pady .5c -padx .5c -rowspan 2 +grid $w.right -column 2 -row 1 -pady .5c -padx .5c +grid $w.tristate -column 2 -row 2 -pady .5c -padx .5c foreach i {10 12 14 18 24} { radiobutton $w.left.b$i -text "Point Size $i" -variable size \ - -relief flat -value $i + -relief flat -value $i -tristatevalue "multi" pack $w.left.b$i -side top -pady 2 -anchor w -fill x } @@ -37,10 +43,12 @@ foreach c {Red Green Blue Yellow Orange Purple} { set lower [string tolower $c] radiobutton $w.mid.$lower -text $c -variable color \ -relief flat -value $lower -anchor w \ - -command "$w.mid configure -fg \$color" + -command "$w.mid configure -fg \$color" \ + -tristatevalue "multi" pack $w.mid.$lower -side top -pady 2 -fill x } + label $w.right.l -text "Label" -bitmap questhead -compound left $w.right.l configure -width [winfo reqwidth $w.right.l] -compound top $w.right.l configure -height [winfo reqheight $w.right.l] @@ -50,6 +58,7 @@ foreach a {Top Left Right Bottom} { -relief flat -value $lower -indicatoron 0 -width 7 \ -command "$w.right.l configure -compound \$align" } + grid x $w.right.top grid $w.right.left $w.right.l $w.right.right grid x $w.right.bottom diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 31cdb46..320ffe6 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXButton.c,v 1.8 2004/02/16 00:19:41 wolfsuit Exp $ + * RCS: @(#) $Id: tkMacOSXButton.c,v 1.9 2004/02/18 00:40:24 hobbs Exp $ */ #include "tkButton.h" @@ -382,6 +382,10 @@ TkpDisplayButton( (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -427,6 +431,10 @@ TkpDisplayButton( (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -822,13 +830,12 @@ TkMacOSXInitControl ( */ initiallyVisible = false; - initialValue = kControlSupportsEmbedding| - kControlHasSpecialBackground; - minValue = 0; - maxValue = 1; - procID = kControlUserPaneProc; + initialValue = kControlSupportsEmbedding|kControlHasSpecialBackground; + minValue = 0; + maxValue = 1; + procID = kControlUserPaneProc; controlReference = (SInt32)mbPtr; - mbPtr->userPane = NewControl(mbPtr->windowRef, + mbPtr->userPane = NewControl(mbPtr->windowRef, paneRect, "\p", initiallyVisible, initialValue, @@ -842,7 +849,7 @@ TkMacOSXInitControl ( return 1; } - if ((status=EmbedControl(mbPtr->userPane,rootControl)) != noErr) { + if ((status = EmbedControl(mbPtr->userPane,rootControl)) != noErr) { fprintf(stderr,"Failed to embed user pane control %d\n", status); return 1; } @@ -909,25 +916,27 @@ TkMacOSXDrawControl( TkWindow * winPtr; Rect paneRect; Rect cntrRect; + int hilitePart = -1; + winPtr = (TkWindow *)butPtr->tkwin; - paneRect.left = winPtr->privatePtr->xOff; - paneRect.top = winPtr->privatePtr->yOff; - paneRect.right = paneRect.left + Tk_Width(butPtr->tkwin); + paneRect.left = winPtr->privatePtr->xOff; + paneRect.top = winPtr->privatePtr->yOff; + paneRect.right = paneRect.left + Tk_Width(butPtr->tkwin); paneRect.bottom = paneRect.top + Tk_Height(butPtr->tkwin); cntrRect = paneRect; /* - cntrRect.left += butPtr->inset; - cntrRect.top += butPtr->inset; - cntrRect.right -= butPtr->inset; + cntrRect.left += butPtr->inset; + cntrRect.top += butPtr->inset; + cntrRect.right -= butPtr->inset; cntrRect.bottom -= butPtr->inset; */ - cntrRect.left += DEF_INSET_LEFT; - cntrRect.top += DEF_INSET_TOP; - cntrRect.right -= DEF_INSET_RIGHT; + cntrRect.left += DEF_INSET_LEFT; + cntrRect.top += DEF_INSET_TOP; + cntrRect.right -= DEF_INSET_RIGHT; cntrRect.bottom -= DEF_INSET_BOTTOM; /* @@ -999,6 +1008,8 @@ TkMacOSXDrawControl( if (butPtr->flags & SELECTED) { SetControlValue(mbPtr->control, 1); + } else if (butPtr->flags & TRISTATED) { + SetControlValue(mbPtr->control, 2); } else { SetControlValue(mbPtr->control, 0); } @@ -1125,6 +1136,9 @@ SetupBevelButton( if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, 0, 0); + } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, + pixmap, 0, 0); } else if (butPtr->image != NULL) { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, 0, 0); @@ -1140,7 +1154,7 @@ SetupBevelButton( if ((err = SetControlData(controlHandle, kControlButtonPart, kControlBevelButtonContentTag, sizeof(ControlButtonContentInfo), - (char *) &mbPtr->bevelButtonContent)) != noErr ) { + (char *) &mbPtr->bevelButtonContent)) != noErr) { fprintf(stderr, "SetControlData BevelButtonContent failed, %d\n", err ); } @@ -1168,7 +1182,7 @@ SetupBevelButton( if ((err = SetControlData(controlHandle, kControlButtonPart, kControlBevelButtonGraphicAlignTag, sizeof(ControlButtonGraphicAlignment), - (char *) &theAlignment)) != noErr ) { + (char *) &theAlignment)) != noErr) { fprintf(stderr, "SetControlData BevelButtonGraphicAlign failed, %d\n", err ); } @@ -1188,7 +1202,7 @@ SetupBevelButton( if ((err = SetControlData(controlHandle, kControlButtonPart, kControlBevelButtonTextPlaceTag, sizeof(ControlButtonTextPlacement), - (char *) &thePlacement)) != noErr ) { + (char *) &thePlacement)) != noErr) { fprintf(stderr, "SetControlData BevelButtonTextPlace failed, %d\n", err ); } @@ -1449,14 +1463,14 @@ TkMacOSXComputeControlParams(TkButton * butPtr, MacControlParams * paramsPtr ) || (butPtr->indicatorOn)) { paramsPtr->initialValue = 1; paramsPtr->minValue = 0; - paramsPtr->maxValue = 1; + paramsPtr->maxValue = 2; paramsPtr->procID = kControlRadioButtonProc; } else { paramsPtr->initialValue = 0; paramsPtr->minValue = kControlBehaviorOffsetContents| kControlBehaviorSticky| kControlContentPictHandle; - paramsPtr->maxValue = 1; + paramsPtr->maxValue = 2; if (butPtr->borderWidth <= 2) { paramsPtr->procID = kControlBevelButtonSmallBevelProc; } else if (butPtr->borderWidth == 3) { @@ -1473,14 +1487,14 @@ TkMacOSXComputeControlParams(TkButton * butPtr, MacControlParams * paramsPtr ) || (butPtr->indicatorOn)) { paramsPtr->initialValue = 1; paramsPtr->minValue = 0; - paramsPtr->maxValue = 1; + paramsPtr->maxValue = 2; paramsPtr->procID = kControlCheckBoxProc; } else { paramsPtr->initialValue = 0; paramsPtr->minValue = kControlBehaviorOffsetContents | kControlBehaviorSticky | kControlContentPictHandle; - paramsPtr->maxValue = 1; + paramsPtr->maxValue = 2; if (butPtr->borderWidth <= 2) { paramsPtr->procID = kControlBevelButtonSmallBevelProc; } else if (butPtr->borderWidth == 3) { diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h index 17d7d24..c3b8219 100644 --- a/macosx/tkMacOSXDefault.h +++ b/macosx/tkMacOSXDefault.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXDefault.h,v 1.3 2003/10/31 09:02:15 vincentdarley Exp $ + * RCS: @(#) $Id: tkMacOSXDefault.h,v 1.4 2004/02/18 00:40:24 hobbs Exp $ */ #ifndef _TKMACDEFAULT @@ -75,6 +75,7 @@ #define DEF_BUTTON_JUSTIFY "center" #define DEF_BUTTON_OFF_VALUE "0" #define DEF_BUTTON_ON_VALUE "1" +#define DEF_BUTTON_TRISTATE_VALUE "" #define DEF_BUTTON_OVER_RELIEF "" #define DEF_BUTTON_PADX "12" #define DEF_LABCHKRAD_PADX "1" diff --git a/tests/button.test b/tests/button.test index a087238..bc81d9a 100644 --- a/tests/button.test +++ b/tests/button.test @@ -7,7 +7,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: button.test,v 1.14 2003/04/01 21:06:17 dgp Exp $ +# RCS: @(#) $Id: button.test,v 1.15 2004/02/18 00:40:24 hobbs Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -75,7 +75,7 @@ foreach test { {-justify right right bogus {bad justification "bogus": must be left, right, or center} {1 1 1 1}} {-offrelief flat flat 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken} {0 0 1 1}} {-offvalue lousy lousy {} {} {0 0 1 0}} - {-offvalue fantastic fantastic {} {} {0 0 1 0}} + {-onvalue fantastic fantastic {} {} {0 0 1 0}} {-overrelief "" "" 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken} {0 1 1 1}} {-padx 12m 12m 420x {bad screen distance "420x"} {1 1 1 1}} {-pady 12m 12m 420x {bad screen distance "420x"} {1 1 1 1}} @@ -88,6 +88,8 @@ foreach test { {-takefocus "any string" "any string" {} {} {1 1 1 1}} {-text "Sample text" {Sample text} {} {} {1 1 1 1}} {-textvariable i i {} {} {1 1 1 1}} + {-tristateimage image1 image1 bogus {image "bogus" doesn't exist} {0 0 1 1}} + {-tristatevalue unknowable unknowable {} {} {0 0 1 1}} {-underline 5 5 3p {expected integer but got "3p"} {1 1 1 1}} {-value anyString anyString {} {} {0 0 0 1}} {-width 402 402 3p {expected integer but got "3p"} {1 1 1 1}} @@ -215,7 +217,7 @@ test button-4.13 {ButtonWidgetCmd procedure, "cget" option} { } {1 {unknown option "-onvalue"}} test button-4.14 {ButtonWidgetCmd procedure, "configure" option} { llength [.c configure] -} {39} +} {41} test button-4.15 {ButtonWidgetCmd procedure, "configure" option} { list [catch {.b configure -gorp} msg] $msg } {1 {unknown option "-gorp"}} diff --git a/unix/tkUnixButton.c b/unix/tkUnixButton.c index 9b3c11b..ef6d866 100644 --- a/unix/tkUnixButton.c +++ b/unix/tkUnixButton.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixButton.c,v 1.16 2003/10/10 20:19:51 hobbs Exp $ + * RCS: @(#) $Id: tkUnixButton.c,v 1.17 2004/02/18 00:40:24 hobbs Exp $ */ #include "tkButton.h" @@ -180,30 +180,34 @@ TkpDrawCheckIndicator(tkwin, display, d, x, y, bgBorder, indicatorColor, switch (mode) { default: case CHECK_BUTTON: - imgsel = on ? CHECK_ON_OFFSET : CHECK_OFF_OFFSET; - imgsel += disabled ? CHECK_DISOFF_OFFSET : 0; + imgsel = on == 2 ? CHECK_DISON_OFFSET : + on == 1 ? CHECK_ON_OFFSET : CHECK_OFF_OFFSET; + imgsel += disabled && on != 2 ? CHECK_DISOFF_OFFSET : 0; imgstart = CHECK_START; dim = CHECK_BUTTON_DIM; break; case CHECK_MENU: - imgsel = on ? CHECK_ON_OFFSET : CHECK_OFF_OFFSET; - imgsel += disabled ? CHECK_DISOFF_OFFSET : 0; + imgsel = on == 2 ? CHECK_DISOFF_OFFSET : + on == 1 ? CHECK_ON_OFFSET : CHECK_OFF_OFFSET; + imgsel += disabled && on != 2 ? CHECK_DISOFF_OFFSET : 0; imgstart = CHECK_START + 2; imgsel += 2; dim = CHECK_MENU_DIM; break; case RADIO_BUTTON: - imgsel = on ? RADIO_ON_OFFSET : RADIO_OFF_OFFSET; - imgsel += disabled ? RADIO_DISOFF_OFFSET : 0; + imgsel = on == 2 ? RADIO_DISON_OFFSET : + on==1 ? RADIO_ON_OFFSET : RADIO_OFF_OFFSET; + imgsel += disabled && on != 2 ? RADIO_DISOFF_OFFSET : 0; imgstart = RADIO_START; dim = RADIO_BUTTON_DIM; break; case RADIO_MENU: - imgsel = on ? RADIO_ON_OFFSET : RADIO_OFF_OFFSET; - imgsel += disabled ? RADIO_DISOFF_OFFSET : 0; + imgsel = on == 2 ? RADIO_DISOFF_OFFSET : + on==1 ? RADIO_ON_OFFSET : RADIO_OFF_OFFSET; + imgsel += disabled && on != 2 ? RADIO_DISOFF_OFFSET : 0; imgstart = RADIO_START + 3; imgsel += 3; dim = RADIO_MENU_DIM; @@ -515,6 +519,9 @@ TkpDisplayButton(clientData) if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -555,6 +562,10 @@ TkpDisplayButton(clientData) (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, + height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -608,7 +619,7 @@ TkpDisplayButton(clientData) y = Tk_Height(tkwin)/2; TkpDrawCheckIndicator(tkwin, butPtr->display, pixmap, x, y, border, butPtr->normalFg, selColor, butPtr->disabledFg, - (butPtr->flags & SELECTED), + ((butPtr->flags & SELECTED)?1:(butPtr->flags & TRISTATED)?2:0), (butPtr->state == STATE_DISABLED), CHECK_BUTTON); } } else if ((butPtr->type == TYPE_RADIO_BUTTON) && butPtr->indicatorOn) { @@ -623,7 +634,7 @@ TkpDisplayButton(clientData) y = Tk_Height(tkwin)/2; TkpDrawCheckIndicator(tkwin, butPtr->display, pixmap, x, y, border, butPtr->normalFg, selColor, butPtr->disabledFg, - (butPtr->flags & SELECTED), + ((butPtr->flags & SELECTED)?1:(butPtr->flags & TRISTATED)?2:0), (butPtr->state == STATE_DISABLED), RADIO_BUTTON); } } diff --git a/unix/tkUnixDefault.h b/unix/tkUnixDefault.h index e8bbea7..f9674d6 100644 --- a/unix/tkUnixDefault.h +++ b/unix/tkUnixDefault.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixDefault.h,v 1.19 2003/10/31 09:02:17 vincentdarley Exp $ + * RCS: @(#) $Id: tkUnixDefault.h,v 1.20 2004/02/18 00:40:24 hobbs Exp $ */ #ifndef _TKUNIXDEFAULT @@ -88,6 +88,7 @@ #define DEF_BUTTON_JUSTIFY "center" #define DEF_BUTTON_OFF_VALUE "0" #define DEF_BUTTON_ON_VALUE "1" +#define DEF_BUTTON_TRISTATE_VALUE "" #define DEF_BUTTON_OVER_RELIEF "" #define DEF_BUTTON_PADX "3m" #define DEF_LABCHKRAD_PADX "1" diff --git a/win/tkWinButton.c b/win/tkWinButton.c index b10f35f..5b12e0c 100644 --- a/win/tkWinButton.c +++ b/win/tkWinButton.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinButton.c,v 1.24 2004/01/13 02:06:01 davygrvy Exp $ + * RCS: @(#) $Id: tkWinButton.c,v 1.25 2004/02/18 00:40:24 hobbs Exp $ */ #define OEMRESOURCE @@ -530,6 +530,9 @@ TkpDisplayButton(clientData) if ((butPtr->selectImage != NULL) && (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, + width, height, pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -566,6 +569,10 @@ TkpDisplayButton(clientData) (butPtr->flags & SELECTED)) { Tk_RedrawImage(butPtr->selectImage, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); + } else if ((butPtr->tristateImage != NULL) && + (butPtr->flags & TRISTATED)) { + Tk_RedrawImage(butPtr->tristateImage, 0, 0, width, height, + pixmap, imageXOffset, imageYOffset); } else { Tk_RedrawImage(butPtr->image, 0, 0, width, height, pixmap, imageXOffset, imageYOffset); @@ -638,7 +645,7 @@ TkpDisplayButton(clientData) x -= butPtr->indicatorSpace; y -= butPtr->indicatorDiameter / 2; - xSrc = (butPtr->flags & SELECTED) ? tsdPtr->boxWidth : 0; + xSrc = (butPtr->flags & (SELECTED|TRISTATED)) ? tsdPtr->boxWidth : 0; if (butPtr->state == STATE_ACTIVE) { xSrc += tsdPtr->boxWidth*2; } @@ -668,7 +675,7 @@ TkpDisplayButton(clientData) border, TK_3D_LIGHT2)); boxesPalette[PAL_BOTTOM_OUTER] = FlipColor(TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT_GC)); - if (butPtr->state == STATE_DISABLED) { + if ((butPtr->state == STATE_DISABLED) || (butPtr->flags & TRISTATED)) { boxesPalette[PAL_INTERIOR] = FlipColor(TkWinGetBorderPixels(tkwin, border, TK_3D_LIGHT2)); } else if (butPtr->selectBorder != NULL) { diff --git a/win/tkWinDefault.h b/win/tkWinDefault.h index 51bb74c..1e3e2bf 100644 --- a/win/tkWinDefault.h +++ b/win/tkWinDefault.h @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinDefault.h,v 1.17 2003/10/31 09:02:18 vincentdarley Exp $ + * RCS: @(#) $Id: tkWinDefault.h,v 1.18 2004/02/18 00:40:24 hobbs Exp $ */ #ifndef _TKWINDEFAULT @@ -93,6 +93,7 @@ #define DEF_BUTTON_TAKE_FOCUS (char *) NULL #define DEF_BUTTON_TEXT "" #define DEF_BUTTON_TEXT_VARIABLE "" +#define DEF_BUTTON_TRISTATE_VALUE "" #define DEF_BUTTON_UNDERLINE "-1" #define DEF_BUTTON_VALUE "" #define DEF_BUTTON_WIDTH "0" -- cgit v0.12