From 093ba20aa9429d1193d14f69c01efa197fb23b02 Mon Sep 17 00:00:00 2001 From: hobbs Date: Fri, 21 Jun 2002 02:38:54 +0000 Subject: * doc/listbox.n: * generic/tkListbox.c (DisplayListbox): * mac/tkMacDefault.h: TIP #94 implementation adding -activestyle * tests/listbox.test: option to the listbox. This adds the ability * unix/tkUnixDefault.h: to have listboxes look native on Windows, and * win/tkWinDefault.h: "nicer" elsewhere using the 'dotbox' style. --- doc/listbox.n | 35 ++++++++----- generic/tkListbox.c | 136 ++++++++++++++++++++++++++++++++++++++++----------- mac/tkMacDefault.h | 3 +- tests/listbox.test | 21 +++++++- unix/tkUnixDefault.h | 3 +- win/tkWinDefault.h | 3 +- 6 files changed, 155 insertions(+), 46 deletions(-) diff --git a/doc/listbox.n b/doc/listbox.n index cd1067c..7326497 100644 --- a/doc/listbox.n +++ b/doc/listbox.n @@ -5,10 +5,10 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: listbox.n,v 1.8 2000/08/25 06:58:32 ericm Exp $ +'\" RCS: @(#) $Id: listbox.n,v 1.9 2002/06/21 02:38:54 hobbs Exp $ '\" .so man.macros -.TH listbox n 8.0 Tk "Tk Built-In Commands" +.TH listbox n 8.4 Tk "Tk Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -16,15 +16,24 @@ listbox \- Create and manipulate listbox widgets .SH SYNOPSIS \fBlistbox\fR \fIpathName \fR?\fIoptions\fR? .SO -\-background \-height \-selectforeground -\-borderwidth \-highlightbackground \-setgrid -\-cursor \-highlightcolor \-state -\-disabledforeground \-highlightthickness \-takefocus -\-exportselection \-relief \-width -\-font \-selectbackground \-xscrollcommand -\-foreground \-selectborderwidth \-yscrollcommand +\-activestyle \-height \-selectforeground +\-background \-highlightbackground \-setgrid +\-borderwidth \-highlightcolor \-state +\-cursor \-highlightthickness \-takefocus +\-disabledforeground \-relief \-width +\-exportselection \-selectbackground \-xscrollcommand +\-font \-selectborderwidth \-yscrollcommand +\-foreground .SE .SH "WIDGET-SPECIFIC OPTIONS" +.VS 8.4 +.OP \-activestyle activeStyle ActiveStyle +Specifies the style in which to draw the active element. This must be +one of \fBdotbox\fR (show a focus ring around the active element), +\fBnone\fR (nospecial indication of active element) or +\fBunderline\fR (underline the active element). +The default is \fBunderline\fR. +.VS 8.4 .OP \-height height Height Specifies the desired height for the window, in lines. If zero or less, then the desired height for the window is made just @@ -100,8 +109,8 @@ to the first element in the listbox. .TP 12 \fBactive\fR Indicates the element that has the location cursor. This element -will be displayed with an underline when the listbox has the -keyboard focus, and it is specified with the \fBactivate\fR +will be displayed as specified by \fB\-activestyle\fR when the listbox +has the keyboard focus, and it is specified with the \fBactivate\fR widget command. .TP 12 \fBanchor\fR @@ -145,8 +154,8 @@ Sets the active element to the one indicated by \fIindex\fR. If \fIindex\fR is outside the range of elements in the listbox then the closest element is activated. .VE -The active element is drawn with an underline when the widget -has the input focus, and its index may be retrieved with the +The active element is drawn as specified by \fB\-activestyle\fR when the +widget has the input focus, and its index may be retrieved with the index \fBactive\fR. .TP \fIpathName \fBbbox\fR \fIindex\fR diff --git a/generic/tkListbox.c b/generic/tkListbox.c index e6483fd..03d130d 100644 --- a/generic/tkListbox.c +++ b/generic/tkListbox.c @@ -11,13 +11,17 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkListbox.c,v 1.26 2002/03/20 22:55:16 dgp Exp $ + * RCS: @(#) $Id: tkListbox.c,v 1.27 2002/06/21 02:38:54 hobbs Exp $ */ #include "tkPort.h" #include "default.h" #include "tkInt.h" +#ifdef WIN32 +#include "tkWinInt.h" +#endif + typedef struct { Tk_OptionTable listboxOptionTable; /* Table defining configuration options * available for the listbox */ @@ -128,6 +132,8 @@ typedef struct { int active; /* Index of "active" element (the one that * has been selected by keyboard traversal). * -1 means none. */ + int activeStyle; /* style in which to draw the active element. + * One of: underline, none, dotbox */ /* * Information for scanning: @@ -210,11 +216,22 @@ static char *stateStrings[] = { "disabled", "normal", (char *) NULL }; +enum activeStyle { + ACTIVE_STYLE_DOTBOX, ACTIVE_STYLE_NONE, ACTIVE_STYLE_UNDERLINE +}; + +static char *activeStyleStrings[] = { + "dotbox", "none", "underline", (char *) NULL +}; + /* * The optionSpecs table defines the valid configuration options for the * listbox widget */ static Tk_OptionSpec optionSpecs[] = { + {TK_OPTION_STRING_TABLE, "-activestyle", "activeStyle", "ActiveStyle", + DEF_LISTBOX_ACTIVE_STYLE, -1, Tk_Offset(Listbox, activeStyle), + 0, (ClientData) activeStyleStrings, 0}, {TK_OPTION_BORDER, "-background", "background", "Background", DEF_LISTBOX_BG_COLOR, -1, Tk_Offset(Listbox, normalBorder), 0, (ClientData) DEF_LISTBOX_BG_MONO, 0}, @@ -294,26 +311,26 @@ static Tk_OptionSpec optionSpecs[] = { */ static Tk_OptionSpec itemAttrOptionSpecs[] = { {TK_OPTION_BORDER, "-background", "background", "Background", - (char *)NULL, -1, Tk_Offset(ItemAttr, border), - TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (char *)NULL, -1, Tk_Offset(ItemAttr, border), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, (ClientData) DEF_LISTBOX_BG_MONO, 0}, {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL, - (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, + (char *) NULL, 0, -1, 0, (ClientData) "-background", 0}, {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL, - (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, + (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0}, {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground", - (char *) NULL, -1, Tk_Offset(ItemAttr, fgColor), - TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0}, + (char *) NULL, -1, Tk_Offset(ItemAttr, fgColor), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0}, {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground", - (char *) NULL, -1, Tk_Offset(ItemAttr, selBorder), - TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (char *) NULL, -1, Tk_Offset(ItemAttr, selBorder), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, (ClientData) DEF_LISTBOX_SELECT_MONO, 0}, {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background", - (char *) NULL, -1, Tk_Offset(ItemAttr, selFgColor), - TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, + (char *) NULL, -1, Tk_Offset(ItemAttr, selFgColor), + TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, (ClientData) DEF_LISTBOX_SELECT_FG_MONO, 0}, {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, -1, 0, 0, 0} + (char *) NULL, 0, -1, 0, 0, 0} }; /* @@ -323,17 +340,17 @@ static Tk_OptionSpec itemAttrOptionSpecs[] = { */ static CONST char *commandNames[] = { "activate", "bbox", "cget", "configure", "curselection", "delete", "get", - "index", "insert", "itemcget", "itemconfigure", "nearest", "scan", - "see", "selection", "size", "xview", "yview", + "index", "insert", "itemcget", "itemconfigure", "nearest", "scan", + "see", "selection", "size", "xview", "yview", (char *) NULL }; enum command { COMMAND_ACTIVATE, COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, - COMMAND_CURSELECTION, COMMAND_DELETE, COMMAND_GET, COMMAND_INDEX, - COMMAND_INSERT, COMMAND_ITEMCGET, COMMAND_ITEMCONFIGURE, - COMMAND_NEAREST, COMMAND_SCAN, COMMAND_SEE, COMMAND_SELECTION, - COMMAND_SIZE, COMMAND_XVIEW, COMMAND_YVIEW + COMMAND_CURSELECTION, COMMAND_DELETE, COMMAND_GET, COMMAND_INDEX, + COMMAND_INSERT, COMMAND_ITEMCGET, COMMAND_ITEMCONFIGURE, + COMMAND_NEAREST, COMMAND_SCAN, COMMAND_SEE, COMMAND_SELECTION, + COMMAND_SIZE, COMMAND_XVIEW, COMMAND_YVIEW }; static CONST char *selCommandNames[] = { @@ -1796,7 +1813,7 @@ DisplayListbox(clientData) register Listbox *listPtr = (Listbox *) clientData; register Tk_Window tkwin = listPtr->tkwin; GC gc; - int i, limit, x, y, width, prevSelected; + int i, limit, x, y, width, prevSelected, freeGC; Tk_FontMetrics fm; Tcl_Obj *curElement; Tcl_HashEntry *entry; @@ -1873,6 +1890,7 @@ DisplayListbox(clientData) y = ((i - listPtr->topIndex) * listPtr->lineHeight) + listPtr->inset; gc = listPtr->textGC; + freeGC = 0; /* * Lookup this item in the item attributes table, to see if it has * special foreground/background colors @@ -1908,27 +1926,29 @@ DisplayListbox(clientData) if (attrs->selFgColor != NULL) { gcValues.foreground = attrs->selFgColor->pixel; gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); + freeGC = 1; } } - + Tk_Fill3DRectangle(tkwin, pixmap, selectedBg, x, y, width, listPtr->lineHeight, 0, TK_RELIEF_FLAT); /* * Draw beveled edges around the selection, if there are - * visible edges next to this element. Special considerations: + * visible edges next to this element. Special considerations: + * * 1. The left and right bevels may not be visible if - * horizontal scrolling is enabled (the "left" and "right" + * horizontal scrolling is enabled (the "left" & "right" * variables are zero to indicate that the corresponding * bevel is visible). * 2. Top and bottom bevels are only drawn if this is the * first or last seleted item. - * 3. If the left or right bevel isn't visible, then the "left" - * and "right" variables, computed above, have non-zero + * 3. If the left or right bevel isn't visible, then the + * "left" & "right" vars, computed above, have non-zero * values that extend the top and bottom bevels so that * the mitered corners are off-screen. */ - + /* Draw left bevel */ if (left == 0) { Tk_3DVerticalBevel(tkwin, pixmap, selectedBg, @@ -1990,11 +2010,13 @@ DisplayListbox(clientData) && attrs->fgColor != NULL) { gcValues.foreground = attrs->fgColor->pixel; gc = Tk_GetGC(listPtr->tkwin, mask, &gcValues); + freeGC = 1; } } prevSelected = 0; } } + /* Draw the actual text of this item */ Tk_GetFontMetrics(listPtr->tkfont, &fm); y += fm.ascent + listPtr->selBorderWidth; @@ -2004,10 +2026,68 @@ DisplayListbox(clientData) Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont, stringRep, stringLen, x, y); - /* If this is the active element, underline it. */ + /* If this is the active element, apply the activestyle to it. */ if ((i == listPtr->active) && (listPtr->flags & GOT_FOCUS)) { - Tk_UnderlineChars(listPtr->display, pixmap, gc, listPtr->tkfont, - stringRep, x, y, 0, stringLen); + if (listPtr->activeStyle == ACTIVE_STYLE_UNDERLINE) { + /* Underline the text. */ + Tk_UnderlineChars(listPtr->display, pixmap, gc, + listPtr->tkfont, stringRep, x, y, 0, stringLen); + } else if (listPtr->activeStyle == ACTIVE_STYLE_DOTBOX) { +#ifdef WIN32 + /* + * This provides for exact default look and feel on Windows. + */ + TkWinDCState state; + HDC dc; + RECT rect; + + dc = TkWinGetDrawableDC(listPtr->display, pixmap, &state); + rect.left = listPtr->inset; + rect.top = ((i - listPtr->topIndex) * listPtr->lineHeight) + + listPtr->inset; + rect.right = rect.left + width; + rect.bottom = rect.top + listPtr->lineHeight; + DrawFocusRect(dc, &rect); + TkWinReleaseDrawableDC(pixmap, dc, &state); +#else + /* + * Draw a dotted box around the text. + */ + x = listPtr->inset; + y = ((i - listPtr->topIndex) * listPtr->lineHeight) + + listPtr->inset; + width = Tk_Width(tkwin) - 2*listPtr->inset - 1; + + gcValues.line_style = LineOnOffDash; + gcValues.line_width = listPtr->selBorderWidth; + if (gcValues.line_width <= 0) { + gcValues.line_width = 1; + } + gcValues.dash_offset = 0; + gcValues.dashes = 1; + /* + * You would think the XSetDashes was necessary, but it + * appears that the default dotting for just saying we + * want dashes appears to work correctly. + static char dashList[] = { 1 }; + static int dashLen = sizeof(dashList); + XSetDashes(listPtr->display, gc, 0, dashList, dashLen); + */ + mask = GCLineWidth | GCLineStyle | GCDashList | GCDashOffset; + XChangeGC(listPtr->display, gc, mask, &gcValues); + XDrawRectangle(listPtr->display, pixmap, gc, x, y, + (unsigned) width, (unsigned) listPtr->lineHeight - 1); + if (!freeGC) { + /* Don't bother changing if it is about to be freed. */ + gcValues.line_style = LineSolid; + XChangeGC(listPtr->display, gc, GCLineStyle, &gcValues); + } +#endif + } + } + + if (freeGC) { + Tk_FreeGC(listPtr->display, gc); } } diff --git a/mac/tkMacDefault.h b/mac/tkMacDefault.h index 48eff70..fd55d68 100644 --- a/mac/tkMacDefault.h +++ b/mac/tkMacDefault.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: tkMacDefault.h,v 1.14 2002/02/22 21:07:05 hobbs Exp $ + * RCS: @(#) $Id: tkMacDefault.h,v 1.15 2002/06/21 02:38:54 hobbs Exp $ */ #ifndef _TKMACDEFAULT @@ -213,6 +213,7 @@ * Defaults for listboxes: */ +#define DEF_LISTBOX_ACTIVE_STYLE "underline" #define DEF_LISTBOX_BG_COLOR NORMAL_BG #define DEF_LISTBOX_BG_MONO WHITE #define DEF_LISTBOX_BORDER_WIDTH "1" diff --git a/tests/listbox.test b/tests/listbox.test index 0033ee4..0b1b7a0 100644 --- a/tests/listbox.test +++ b/tests/listbox.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: listbox.test,v 1.17 2002/02/26 01:07:29 hobbs Exp $ +# RCS: @(#) $Id: listbox.test,v 1.18 2002/06/21 02:38:54 hobbs Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { source [file join [pwd] [file dirname [info script]] defs.tcl] @@ -73,6 +73,7 @@ resetGridInfo set i 1 foreach test { + {-activestyle under underline foo {bad activestyle "foo": must be dotbox, none, or underline}} {-background #ff0000 #ff0000 non-existent {unknown color name "non-existent"}} {-bd 4 4 badValue {bad screen distance "badValue"}} @@ -241,7 +242,7 @@ test listbox-3.22 {ListboxWidgetCmd procedure, "cget" option} { } {0} test listbox-3.23 {ListboxWidgetCmd procedure, "configure" option} { llength [.l configure] -} {26} +} {27} test listbox-3.24 {ListboxWidgetCmd procedure, "configure" option} { list [catch {.l configure -gorp} msg] $msg } {1 {unknown option "-gorp"}} @@ -2117,6 +2118,22 @@ test listbox-27.1 {widget deletion while active} { winfo exists .l } 0 +test listbox-28.1 {listbox -activestyle} { + catch {destroy .l} + listbox .l -activ non + .l cget -activestyle +} none +test listbox-28.2 {listbox -activestyle} { + catch {destroy .l} + listbox .l + .l cget -activestyle +} underline +test listbox-28.3 {listbox -activestyle} { + catch {destroy .l} + listbox .l -activestyle dot + .l cget -activestyle +} dotbox + resetGridInfo eval destroy [winfo children .] option clear diff --git a/unix/tkUnixDefault.h b/unix/tkUnixDefault.h index d5503c0..d0afe39 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.14 2002/02/22 21:07:05 hobbs Exp $ + * RCS: @(#) $Id: tkUnixDefault.h,v 1.15 2002/06/21 02:38:54 hobbs Exp $ */ #ifndef _TKUNIXDEFAULT @@ -208,6 +208,7 @@ * Defaults for listboxes: */ +#define DEF_LISTBOX_ACTIVE_STYLE "underline" #define DEF_LISTBOX_BG_COLOR NORMAL_BG #define DEF_LISTBOX_BG_MONO WHITE #define DEF_LISTBOX_BORDER_WIDTH "2" diff --git a/win/tkWinDefault.h b/win/tkWinDefault.h index 4a5b59d..e9f999b 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.14 2002/02/22 21:07:05 hobbs Exp $ + * RCS: @(#) $Id: tkWinDefault.h,v 1.15 2002/06/21 02:38:54 hobbs Exp $ */ #ifndef _TKWINDEFAULT @@ -213,6 +213,7 @@ * Defaults for listboxes: */ +#define DEF_LISTBOX_ACTIVE_STYLE "underline" #define DEF_LISTBOX_BG_COLOR "SystemWindow" #define DEF_LISTBOX_BG_MONO WHITE #define DEF_LISTBOX_BORDER_WIDTH "2" -- cgit v0.12