Index: doc/frame.n ================================================================== --- doc/frame.n +++ doc/frame.n @@ -23,10 +23,20 @@ This option is the same as the standard \fB\-background\fR option except that its value may also be specified as an empty string. In this case, the widget will display no background or border, and no colors will be consumed from its colormap for its background and border. +.VS "8.7, TIP262" +An empty background will disable drawing the background image. +.OP \-backgroundimage backgroundImage BackgroundImage +This specifies an image to display on the frame's background within +the border of the frame (i.e., the image will be clipped by the +frame's highlight ring and border, if either are present); subwidgets +of the frame will be drawn on top. The image must have been created +with the \fBimage create\fR command. If specified as the empty string, +no image will be displayed. +.VE "8.7, TIP262" .OP \-class class Class Specifies a class for the window. This class will be used when querying the option database for the window's other options, and it will also be used later for other purposes such as bindings. @@ -60,10 +70,19 @@ to zero then the window will not request any size at all. Note that this sets the total height of the frame, any \fB\-borderwidth\fR or similar is not added. Normally \fB\-height\fR should not be used if a propagating geometry manager, such as \fBgrid\fR or \fBpack\fR, is used within the frame since the geometry manager will override the height of the frame. +.OP \-tile tile Tile +.VS "8.7, TIP262" +This specifies how to draw the background image (see +\fB\-backgroundimage\fR) on the frame. +If true (according to \fBTcl_GetBoolean\fR), the image will be tiled +to fill the whole frame, with the origin of the first copy of the +image being the top left of the interior of the frame. +If false (the default), the image will be centered within the frame. +.VE "8.7, TIP262" .OP \-visual visual Visual Specifies visual information for the new window in any of the forms accepted by \fBTk_GetVisual\fR. If this option is not specified, the new window will use the same visual as its parent. @@ -89,11 +108,11 @@ and relief. The \fBframe\fR command returns the path name of the new window. .PP A frame is a simple widget. Its primary purpose is to act as a spacer or container for complex window layouts. The only features -of a frame are its background color and an optional 3-D border to make the +of a frame are its background and an optional 3-D border to make the frame appear raised or sunken. .SH "WIDGET COMMAND" .PP The \fBframe\fR command creates a new Tcl command whose name is the same as the path name of the frame's window. This Index: doc/toplevel.n ================================================================== --- doc/toplevel.n +++ doc/toplevel.n @@ -23,10 +23,21 @@ This option is the same as the standard \fB\-background\fR option except that its value may also be specified as an empty string. In this case, the widget will display no background or border, and no colors will be consumed from its colormap for its background and border. +.VS "8.7, TIP262" +An empty background will disable drawing the background image. +.OP \-backgroundimage backgroundImage BackgroundImage +This specifies an image to display on the toplevel's background within +the border of the toplevel (i.e., the image will be clipped by the +toplevel's highlight ring and border, if either are present) on top of +the background; +subwidgets of the toplevel will be drawn on top. The image must have +been created with the \fBimage create\fR command. If specified as the +empty string, no image will be displayed. +.VE "8.7, TIP262" .OP \-class class Class Specifies a class for the window. This class will be used when querying the option database for the window's other options, and it will also be used later for other purposes such as bindings. @@ -69,10 +80,19 @@ different display. Defaults to the same screen as its parent. This option is special in that it may not be specified via the option database, and it may not be modified with the \fBconfigure\fR widget command. +.OP \-tile tile Tile +.VS "8.7, TIP262" +This specifies how to draw the background image (see +\fB\-backgroundimage\fR) on the toplevel. +If true (according to \fBTcl_GetBoolean\fR), the image will be tiled +to fill the whole toplevel, with the origin of the first copy of the +image being the top left of the interior of the toplevel. +If false (the default), the image will be centered within the toplevel. +.VE "8.7, TIP262" .OP \-use use Use This option is used for embedding. If the value is not an empty string, it must be the window identifier of a container window, specified as a hexadecimal string like the ones returned by the \fBwinfo id\fR command. The toplevel widget will be created as a child of the given @@ -107,11 +127,11 @@ A toplevel is similar to a \fBframe\fR except that it is created as a top-level window: its X parent is the root window of a screen rather than the logical parent from its Tk path name. The primary purpose of a toplevel is to serve as a container for dialog boxes and other collections of widgets. The only visible features -of a toplevel are its background color and an optional 3-D border +of a toplevel are its background and an optional 3-D border to make the toplevel appear raised or sunken. .SH "WIDGET COMMAND" .PP The \fBtoplevel\fR command creates a new Tcl command whose name is the same as the path name of the toplevel's window. This Index: generic/tkFrame.c ================================================================== --- generic/tkFrame.c +++ generic/tkFrame.c @@ -92,10 +92,20 @@ int padX; /* Integer value corresponding to padXPtr. */ Tcl_Obj *padYPtr; /* Value of -padx option: specifies how many * pixels of extra space to leave above and * below child area. */ int padY; /* Integer value corresponding to padYPtr. */ + Tcl_Obj *bgimgPtr; /* Value of -backgroundimage option: specifies + * image to display on window's background, or + * NULL if none. */ + Tk_Image bgimg; /* Derived from bgimgPtr by calling + * Tk_GetImage, or NULL if bgimgPtr is + * NULL. */ + int tile; /* Whether to tile the bgimg. */ +#ifndef TK_NO_DOUBLE_BUFFERING + GC copyGC; /* GC for copying when double-buffering. */ +#endif /* TK_NO_DOUBLE_BUFFERING */ } Frame; /* * A data structure of the following type is kept for each labelframe widget * managed by this file: @@ -217,25 +227,37 @@ DEF_FRAME_WIDTH, -1, Tk_Offset(Frame, width), 0, 0, 0}, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0} }; static const Tk_OptionSpec frameOptSpec[] = { + {TK_OPTION_STRING, "-backgroundimage", "backgroundImage", "BackgroundImage", + DEF_FRAME_BG_IMAGE, Tk_Offset(Frame, bgimgPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_SYNONYM, "-bd", NULL, NULL, NULL, 0, -1, 0, "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bgimg", NULL, NULL, + NULL, 0, -1, 0, "-backgroundimage", 0}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth), 0, 0, 0}, {TK_OPTION_STRING, "-class", "class", "Class", DEF_FRAME_CLASS, -1, Tk_Offset(Frame, className), 0, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief), 0, 0, 0}, + {TK_OPTION_BOOLEAN, "-tile", "tile", "Tile", + DEF_FRAME_BG_TILE, -1, Tk_Offset(Frame, tile), 0, 0, 0}, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, commonOptSpec, 0} }; static const Tk_OptionSpec toplevelOptSpec[] = { + {TK_OPTION_STRING, "-backgroundimage", "backgroundImage", "BackgroundImage", + DEF_FRAME_BG_IMAGE, Tk_Offset(Frame, bgimgPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_SYNONYM, "-bd", NULL, NULL, NULL, 0, -1, 0, "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bgimg", NULL, NULL, + NULL, 0, -1, 0, "-backgroundimage", 0}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, -1, Tk_Offset(Frame, borderWidth), 0, 0, 0}, {TK_OPTION_STRING, "-class", "class", "Class", DEF_TOPLEVEL_CLASS, -1, Tk_Offset(Frame, className), 0, 0, 0}, {TK_OPTION_STRING, "-menu", "menu", "Menu", @@ -244,10 +266,12 @@ {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_FRAME_RELIEF, -1, Tk_Offset(Frame, relief), 0, 0, 0}, {TK_OPTION_STRING, "-screen", "screen", "Screen", DEF_TOPLEVEL_SCREEN, -1, Tk_Offset(Frame, screenName), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-tile", "tile", "Tile", + DEF_FRAME_BG_TILE, -1, Tk_Offset(Frame, tile), 0, 0, 0}, {TK_OPTION_STRING, "-use", "use", "Use", DEF_TOPLEVEL_USE, -1, Tk_Offset(Frame, useThis), TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, commonOptSpec, 0} @@ -309,10 +333,16 @@ int objc, Tcl_Obj *const argv[], enum FrameType type, const char *appName); static void DestroyFrame(void *memPtr); static void DestroyFramePartly(Frame *framePtr); static void DisplayFrame(ClientData clientData); +static void DrawFrameBackground(Tk_Window tkwin, Pixmap pixmap, + int highlightWidth, int borderWidth, + Tk_Image bgimg, int bgtile); +static void FrameBgImageProc(ClientData clientData, + int x, int y, int width, int height, + int imgWidth, int imgHeight); static void FrameCmdDeletedProc(ClientData clientData); static void FrameEventProc(ClientData clientData, XEvent *eventPtr); static void FrameLostSlaveProc(ClientData clientData, Tk_Window tkwin); @@ -868,13 +898,21 @@ Tk_FreeTextLayout(labelframePtr->textLayout); if (labelframePtr->textGC != NULL) { Tk_FreeGC(framePtr->display, labelframePtr->textGC); } } +#ifndef TK_NO_DOUBLE_BUFFERING + if (framePtr->copyGC != NULL) { + Tk_FreeGC(framePtr->display, framePtr->copyGC); + } +#endif /* TK_NO_DOUBLE_BUFFERING */ if (framePtr->colormap != None) { Tk_FreeColormap(framePtr->display, framePtr->colormap); } + if (framePtr->bgimg) { + Tk_FreeImage(framePtr->bgimg); + } ckfree(framePtr); } /* *---------------------------------------------------------------------- @@ -945,10 +983,11 @@ { Tk_SavedOptions savedOptions; char *oldMenuName; Tk_Window oldWindow = NULL; Labelframe *labelframePtr = (Labelframe *) framePtr; + Tk_Image image = NULL; /* * Need the old menubar name for the menu code to delete it. */ @@ -968,10 +1007,24 @@ if (oldMenuName != NULL) { ckfree(oldMenuName); } return TCL_ERROR; } + + if (framePtr->bgimgPtr) { + image = Tk_GetImage(interp, framePtr->tkwin, + Tcl_GetString(framePtr->bgimgPtr), FrameBgImageProc, framePtr); + if (image == NULL) { + Tk_RestoreSavedOptions(&savedOptions); + return TCL_ERROR; + } + } + if (framePtr->bgimg) { + Tk_FreeImage(framePtr->bgimg); + } + framePtr->bgimg = image; + Tk_FreeSavedOptions(&savedOptions); /* * A few of the options require additional processing. */ @@ -1109,10 +1162,19 @@ (labelframePtr->textPtr != NULL) && (labelframePtr->labelWin == NULL); anyWindowLabel = (framePtr->type == TYPE_LABELFRAME) && (labelframePtr->labelWin != NULL); +#ifndef TK_NO_DOUBLE_BUFFERING + gcValues.graphics_exposures = False; + gc = Tk_GetGC(tkwin, GCGraphicsExposures, &gcValues); + if (framePtr->copyGC != NULL) { + Tk_FreeGC(framePtr->display, framePtr->copyGC); + } + framePtr->copyGC = gc; +#endif /* TK_NO_DOUBLE_BUFFERING */ + if (framePtr->type == TYPE_LABELFRAME) { /* * The textGC is needed even in the labelWin case, so it's always * created for a labelframe. */ @@ -1453,41 +1515,45 @@ if (framePtr->border == NULL) { return; } +#ifndef TK_NO_DOUBLE_BUFFERING + /* + * In order to avoid screen flashes, this function redraws the frame into + * off-screen memory, then copies it back on-screen in a single operation. + * This means there's no point in time where the on-screen image has been + * cleared. + */ + + pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin), + Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); +#else + pixmap = Tk_WindowId(tkwin); +#endif /* TK_NO_DOUBLE_BUFFERING */ + if (framePtr->type != TYPE_LABELFRAME) { /* * Pass to platform specific draw function. In general, it just draws * a simple rectangle, but it may "theme" the background. */ noLabel: - TkpDrawFrame(tkwin, framePtr->border, hlWidth, + TkpDrawFrameEx(tkwin, pixmap, framePtr->border, hlWidth, framePtr->borderWidth, framePtr->relief); + if (framePtr->bgimg) { + DrawFrameBackground(tkwin, pixmap, hlWidth, framePtr->borderWidth, + framePtr->bgimg, framePtr->tile); + } } else { Labelframe *labelframePtr = (Labelframe *) framePtr; if ((labelframePtr->textPtr == NULL) && (labelframePtr->labelWin == NULL)) { goto noLabel; } -#ifndef TK_NO_DOUBLE_BUFFERING - /* - * In order to avoid screen flashes, this function redraws the frame - * into off-screen memory, then copies it back on-screen in a single - * operation. This means there's no point in time where the on-screen - * image has been cleared. - */ - - pixmap = Tk_GetPixmap(framePtr->display, Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); -#else - pixmap = Tk_WindowId(tkwin); -#endif /* TK_NO_DOUBLE_BUFFERING */ - /* * Clear the pixmap. */ Tk_Fill3DRectangle(tkwin, pixmap, framePtr->border, 0, 0, @@ -1595,26 +1661,58 @@ labelframePtr->labelBox.x, labelframePtr->labelBox.y, labelframePtr->labelBox.width, labelframePtr->labelBox.height); } } + } #ifndef TK_NO_DOUBLE_BUFFERING - /* - * Everything's been redisplayed; now copy the pixmap onto the screen - * and free up the pixmap. - */ - - XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), - labelframePtr->textGC, hlWidth, hlWidth, - (unsigned) (Tk_Width(tkwin) - 2 * hlWidth), - (unsigned) (Tk_Height(tkwin) - 2 * hlWidth), - hlWidth, hlWidth); - Tk_FreePixmap(framePtr->display, pixmap); + /* + * Everything's been redisplayed; now copy the pixmap onto the screen and + * free up the pixmap. + */ + + XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), + framePtr->copyGC, hlWidth, hlWidth, + (unsigned) (Tk_Width(tkwin) - 2 * hlWidth), + (unsigned) (Tk_Height(tkwin) - 2 * hlWidth), + hlWidth, hlWidth); + Tk_FreePixmap(framePtr->display, pixmap); #endif /* TK_NO_DOUBLE_BUFFERING */ - } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDrawFrame -- + * + * This procedure draws the rectangular frame area. + * + * Results: + * None. + * + * Side effects: + * Draws inside the tkwin area. + * + *---------------------------------------------------------------------- + */ + +void +TkpDrawFrame( + Tk_Window tkwin, + Tk_3DBorder border, + int highlightWidth, + int borderWidth, + int relief) +{ + /* + * Legacy shim to allow for external callers. Internal ones use + * non-exposed TkpDrawFrameEx directly so they can use double-buffering. + */ + TkpDrawFrameEx(tkwin, Tk_WindowId(tkwin), border, + highlightWidth, borderWidth, relief); } /* *-------------------------------------------------------------- * @@ -2028,13 +2126,135 @@ if (framePtr->type != TYPE_TOPLEVEL) { return NULL; } return framePtr->tkwin; } + +/* + *---------------------------------------------------------------------- + * + * FrameBgImageProc -- + * + * This function is invoked by the image code whenever the manager for an + * image does something that affects the size or contents of an image + * displayed on a frame's background. + * + * Results: + * None. + * + * Side effects: + * Arranges for the button to get redisplayed. + * + *---------------------------------------------------------------------- + */ + +static void +FrameBgImageProc( + ClientData clientData, /* Pointer to widget record. */ + int x, int y, /* Upper left pixel (within image) that must + * be redisplayed. */ + int width, int height, /* Dimensions of area to redisplay (might be + * <= 0). */ + int imgWidth, int imgHeight)/* New dimensions of image. */ +{ + register Frame *framePtr = clientData; + + /* + * Changing the background image never alters the dimensions of the frame. + */ + + if (framePtr->tkwin && Tk_IsMapped(framePtr->tkwin) && + !(framePtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayFrame, framePtr); + framePtr->flags |= REDRAW_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawFrameBackground -- + * + * This function draws the background image of a rectangular frame area. + * + * Results: + * None. + * + * Side effects: + * Draws inside the tkwin area. + * + *---------------------------------------------------------------------- + */ + +static void +DrawFrameBackground( + Tk_Window tkwin, + Pixmap pixmap, + int highlightWidth, + int borderWidth, + Tk_Image bgimg, + int bgtile) +{ + int width, height; /* Area to paint on. */ + int imageWidth, imageHeight; /* Dimensions of image. */ + const int bw = highlightWidth + borderWidth; + + Tk_SizeOfImage(bgimg, &imageWidth, &imageHeight); + width = Tk_Width(tkwin) - 2*bw; + height = Tk_Height(tkwin) - 2*bw; + + if (bgtile) { + /* + * Draw the image tiled in the widget (inside the border). + */ + + int x, y; + + for (x = bw; x - bw < width; x += imageWidth) { + int w = imageWidth; + if (x - bw + imageWidth > width) { + w = (width + bw) - x; + } + for (y = bw; y < height + bw; y += imageHeight) { + int h = imageHeight; + if (y - bw + imageHeight > height) { + h = (height + bw) - y; + } + Tk_RedrawImage(bgimg, 0, 0, w, h, pixmap, x, y); + } + } + } else { + /* + * Draw the image centred in the widget (inside the border). + */ + + int x, y, xOff, yOff, w, h; + + if (width > imageWidth) { + x = 0; + xOff = (Tk_Width(tkwin) - imageWidth) / 2; + w = imageWidth; + } else { + x = (imageWidth - width) / 2; + xOff = bw; + w = width; + } + if (height > imageHeight) { + y = 0; + yOff = (Tk_Height(tkwin) - imageHeight) / 2; + h = imageHeight; + } else { + y = (imageHeight - height) / 2; + yOff = bw; + h = height; + } + Tk_RedrawImage(bgimg, x, y, w, h, pixmap, xOff, yOff); + } +} /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ Index: generic/tkInt.h ================================================================== --- generic/tkInt.h +++ generic/tkInt.h @@ -1241,10 +1241,13 @@ Drawable drawable, GC gc, Tk_Font tkfont, const char *string, int numBytes, int x, int y, int firstByte, int lastByte); MODULE_SCOPE void TkpGetFontAttrsForChar(Tk_Window tkwin, Tk_Font tkfont, int c, struct TkFontAttributes *faPtr); +MODULE_SCOPE void TkpDrawFrameEx(Tk_Window tkwin, Drawable drawable, + Tk_3DBorder border, int highlightWidth, + int borderWidth, int relief); MODULE_SCOPE Tcl_Obj * TkNewWindowObj(Tk_Window tkwin); MODULE_SCOPE void TkpShowBusyWindow(TkBusy busy); MODULE_SCOPE void TkpHideBusyWindow(TkBusy busy); MODULE_SCOPE void TkpMakeTransparentWindowExist(Tk_Window tkwin, Window parent); Index: macosx/tkMacOSXDefault.h ================================================================== --- macosx/tkMacOSXDefault.h +++ macosx/tkMacOSXDefault.h @@ -212,11 +212,13 @@ /* * Defaults for frames: */ #define DEF_FRAME_BG_COLOR NORMAL_BG +#define DEF_FRAME_BG_IMAGE NULL #define DEF_FRAME_BG_MONO WHITE +#define DEF_FRAME_BG_TILE "0" #define DEF_FRAME_BORDER_WIDTH "0" #define DEF_FRAME_CLASS "Frame" #define DEF_FRAME_COLORMAP "" #define DEF_FRAME_CONTAINER "0" #define DEF_FRAME_CURSOR "" Index: macosx/tkMacOSXDraw.c ================================================================== --- macosx/tkMacOSXDraw.c +++ macosx/tkMacOSXDraw.c @@ -2025,11 +2025,11 @@ } /* *---------------------------------------------------------------------- * - * TkpDrawFrame -- + * TkpDrawFrameEx -- * * This procedure draws the rectangular frame area. If the user has * requested themeing, it draws with the background theme. * * Results: @@ -2040,12 +2040,13 @@ * *---------------------------------------------------------------------- */ void -TkpDrawFrame( +TkpDrawFrameEx( Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int highlightWidth, int borderWidth, int relief) { @@ -2059,15 +2060,13 @@ if (themedBorder) { border = themedBorder; } } - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), - border, highlightWidth, highlightWidth, - Tk_Width(tkwin) - 2 * highlightWidth, - Tk_Height(tkwin) - 2 * highlightWidth, - borderWidth, relief); + Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth, + highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, + Tk_Height(tkwin) - 2 * highlightWidth, borderWidth, relief); } /* * Local Variables: * mode: objc Index: tests/frame.test ================================================================== --- tests/frame.test +++ tests/frame.test @@ -50,10 +50,34 @@ proc colorsFree {w {red 31} {green 245} {blue 192}} { lassign [winfo rgb $w [format "#%02x%02x%02x" $red $green $blue]] r g b expr {($r/256 == $red) && ($g/256 == $green) && ($b/256 == $blue)} } + +# uniq -- +# +# Returns the unique items of a list in the order they first appear. +# +# Arguments: +# list - The list to uniq-ify. +proc uniq {list} { + set d {} + foreach item $list { + dict set d $item {} + } + return [dict keys $d] +} + +# optnames -- +# +# Returns the option names out of a list of option details. +# +# Arguments: +# options - The option detail list. +proc optnames {options} { + lsort [lmap desc $options {lindex $desc 0}] +} test frame-1.1 {frame configuration options} -setup { deleteWindows } -body { frame .f -class NewFrame @@ -467,11 +491,11 @@ wm geometry .t +0+0 update test frame-2.20 {toplevel configuration options} -body { .t configure -background #ff0000 lindex [.t configure -background] 4 -} -result {#ff0000} +} -result "#ff0000" test frame-2.21 {toplevel configuration options} -body { .t configure -background non-existent } -returnCodes error -result {unknown color name "non-existent"} test frame-2.22 {toplevel configuration options} -body { .t configure -bd 4 @@ -481,11 +505,11 @@ .t configure -bd badValue } -returnCodes error -result {bad screen distance "badValue"} test frame-2.24 {toplevel configuration options} -body { .t configure -bg #00ff00 lindex [.t configure -bg] 4 -} -result {#00ff00} +} -result "#00ff00" test frame-2.25 {toplevel configuration options} -body { .t configure -bg non-existent } -returnCodes error -result {unknown color name "non-existent"} test frame-2.26 {toplevel configuration options} -body { .t configure -borderwidth 1.3 @@ -509,11 +533,11 @@ .t configure -height not_a_number } -returnCodes error -result {bad screen distance "not_a_number"} test frame-2.32 {toplevel configuration options} -body { .t configure -highlightcolor #123456 lindex [.t configure -highlightcolor] 4 -} -result {#123456} +} -result "#123456" test frame-2.33 {toplevel configuration options} -body { .t configure -highlightcolor non-existent } -returnCodes error -result {unknown color name "non-existent"} test frame-2.34 {toplevel configuration options} -body { .t configure -highlightthickness 3 @@ -582,11 +606,10 @@ [lindex [.t configure -background] 4] \ [lindex [.t configure -height] 4] } -cleanup { deleteWindows } -result {350 black 90} - # Be sure that the -class, -colormap, and -visual options are processed # before configuring the widget. test frame-3.5 {TkCreateFrame procedure} -setup { deleteWindows } -body { @@ -667,11 +690,10 @@ [winfo width .t] [winfo height .t] } -cleanup { destroy .t option clear } -result {0 0 140 300} - # The tests below require specific display characteristics (i.e. that they are # run on a pseudocolor display of depth 8). Even so, they are non-portable: # some machines don't seem to ever run out of colors. if {[testConstraint defaultPseudocolor8]} { eatColors .t1 @@ -823,11 +845,10 @@ destroy .t } -result {1} if {[testConstraint defaultPseudocolor8]} { destroy .t1 } - test frame-3.22 {TkCreateFrame procedure, default dimensions} -setup { deleteWindows } -body { toplevel .t wm geometry .t +0+0 @@ -892,12 +913,12 @@ .t cget -screen } -cleanup { destroy .t } -returnCodes ok -match glob -result * test frame-5.8 {FrameWidgetCommand procedure, configure option} -body { - llength [.f configure] -} -result {18} + optnames [.f configure] +} -result {-background -backgroundimage -bd -bg -bgimg -borderwidth -class -colormap -container -cursor -height -highlightbackground -highlightcolor -highlightthickness -padx -pady -relief -takefocus -tile -visual -width} test frame-5.9 {FrameWidgetCommand procedure, configure option} -body { .f configure -gorp } -returnCodes error -result {unknown option "-gorp"} test frame-5.10 {FrameWidgetCommand procedure, configure option} -body { .f configure -gorp bogus @@ -907,12 +928,12 @@ } -returnCodes error -result {value for "-height" missing} test frame-5.12 {FrameWidgetCommand procedure} -body { .f swizzle } -returnCodes error -result {bad option "swizzle": must be cget or configure} test frame-5.13 {FrameWidgetCommand procedure, configure option} -body { - llength [. configure] -} -result {21} + optnames [. configure] +} -result {-background -backgroundimage -bd -bg -bgimg -borderwidth -class -colormap -container -cursor -height -highlightbackground -highlightcolor -highlightthickness -menu -padx -pady -relief -screen -takefocus -tile -use -visual -width} destroy .f test frame-6.1 {ConfigureFrame procedure} -setup { deleteWindows } -body { @@ -1091,17 +1112,14 @@ } -body { # Test all -labelanchor positions set font {helvetica 12} labelframe .f -highlightthickness 1 -bd 3 -padx 1 -pady 2 -font $font \ -text "Mupp" - set fh [expr {[font metrics $font -linespace] + 2 - 3}] - set fw [expr {[font measure $font "Mupp"] + 2 - 3}] - if {$fw < 0} {set fw 0} - if {$fh < 0} {set fh 0} + set fh [expr {max([font metrics $font -linespace] + 2 - 3, 0)}] + set fw [expr {max([font measure $font "Mupp"] + 2 - 3, 0)}] place .f -x 0 -y 0 -width 100 -height 100 pack [frame .f.f] -fill both -expand 1 - set result {} foreach lp {nw n ne en e es se s sw ws w wn} { .f configure -labelanchor $lp update set expx 5 @@ -1209,11 +1227,10 @@ labelframe .f .f configure -container 1 } -returnCodes error -cleanup { deleteWindows } -result {can't modify -container option after widget is created} - destroy .f labelframe .f test frame-13.10 {labelframe configuration options} -body { .f configure -background #ff0000 lindex [.f configure -background] 4 @@ -1481,17 +1498,300 @@ .f configure -labelwidget .f.l update } -cleanup { deleteWindows } -result {} - -deleteWindows -rename eatColors {} -rename colorsFree {} +test frame-15.1 {TIP 262: frame background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + frame .f -width 100 -height 100 + pack .f + list [image inuse gorp] [.f configure -backgroundimage gorp;update] \ + [image inuse gorp] [winfo width .f] [winfo height .f] +} -cleanup { + image delete gorp + deleteWindows +} -result {0 {} 1 100 100} +test frame-15.2 {TIP 262: frame background images} -setup { + deleteWindows + catch {rename gorp ""} +} -body { + frame .f -width 100 -height 100 + pack .f + update + .f configure -backgroundimage gorp +} -returnCodes error -cleanup { + deleteWindows +} -result {image "gorp" doesn't exist} +test frame-15.3 {TIP 262: frame background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + frame .f -width 100 -height 100 -backgroundimage gorp + pack .f + .f configure -tile yes + update + list [.f cget -bgimg] [.f cget -tile] +} -cleanup { + image delete gorp + deleteWindows +} -result {gorp 1} +test frame-15.4 {TIP 262: frame background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + frame .f -width 100 -height 100 -backgroundimage gorp + pack .f + .f configure -tile yes + update + gorp put red -to 15 15 20 20 + update + list [.f cget -bgimg] [.f cget -tile] +} -cleanup { + image delete gorp + deleteWindows +} -result {gorp 1} +test frame-15.5 {TIP 262: frame background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 + set result {} +} -body { + frame .f -width 100 -height 100 -backgroundimage gorp + pack .f + .f configure -tile yes + update + image delete gorp + update + set result [list [.f cget -bgimg] [.f cget -tile]] + image create photo gorp -width 250 -height 250 + update + lappend result [.f cget -backgroundimage] +} -cleanup { + catch {image delete gorp} + deleteWindows +} -result {gorp 1 gorp} +test frame-15.6 {TIP 262: frame background images} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 100 -height 100 -bgimg gorp] + update idletasks; update + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15}} +test frame-15.6a {TIP 262: frame background images (offsets)} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 10 -height 10 -bgimg gorp] + update idletasks; update + # On MacOS must wait for the test image display procedure to run. + set timer [after 300 {lappend result "timedout"}] + while {"timedout" ni $result && + "gorp display 10 2 10 10" ni $result} { + vwait result + } + after cancel $timer + update idletasks; update + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 10 2 10 10}} +test frame-15.7 {TIP 262: frame background images} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 50 -height 25 -bgimg gorp -tile 1] + update idletasks; update + # On MacOS must wait for the test image display procedure to run. + set timer [after 300 {lappend result "timedout"}] + while {"timedout" ni $result && + "gorp display 0 0 20 10" ni $result} { + vwait result + } + after cancel $timer + if {[lindex $result end] eq "timedout"} { + return [lreplace $result end end] + } + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15} {gorp display 0 0 30 10} {gorp display 0 0 20 15} {gorp display 0 0 20 10}} +test frame-15.7a {TIP 262: frame background images (offsets)} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 50 -height 25 -bgimg gorp -tile 1 -highlightthick 1] + update idletasks; update + # On MacOS must wait for the test image display procedure to run. + set timer [after 300 {lappend result "timedout"}] + while {"timedout" ni $result && + "gorp display 0 0 18 8" ni $result} { + vwait result + } + after cancel $timer + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15} {gorp display 0 0 30 8} {gorp display 0 0 18 15} {gorp display 0 0 18 8}} +test frame-15.7b {TIP 262: frame background images (offsets)} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 50 -height 25 -bgimg gorp -tile 1 -bd 2] + update idletasks; update + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15} {gorp display 0 0 30 6} {gorp display 0 0 16 15} {gorp display 0 0 16 6}} +test frame-15.7c {TIP 262: frame background images (offsets)} -setup { + deleteWindows + set result {} + . configure -width 200 -height 200 +} -constraints testImageType -body { + image create test gorp -variable result + pack [frame .f -width 50 -height 25 -bgimg gorp -tile 1 -bd 2 -highlightthick 1] + update idletasks; update + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15} {gorp display 0 0 30 4} {gorp display 0 0 14 15} {gorp display 0 0 14 4}} +test frame-15.8 {TIP 262: toplevel background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + toplevel .t -width 100 -height 100 + update + # Used to verify that setting a background image doesn't change the widget size + set w [winfo width .t] + set h [winfo height .t] + list [image inuse gorp] [.t configure -backgroundimage gorp;update] \ + [image inuse gorp] \ + [expr {$w-[winfo width .t]}] [expr {$h-[winfo height .t]}] +} -cleanup { + image delete gorp + deleteWindows +} -result {0 {} 1 0 0} +test frame-15.9 {TIP 262: toplevel background images} -setup { + deleteWindows + catch {rename gorp ""} +} -body { + toplevel .t -width 100 -height 100 + update + .t configure -backgroundimage gorp +} -returnCodes error -cleanup { + deleteWindows +} -result {image "gorp" doesn't exist} +test frame-15.10 {TIP 262: toplevel background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + toplevel .t -width 100 -height 100 -backgroundimage gorp -tile yes + update + list [.t cget -bgimg] [.t cget -tile] +} -cleanup { + image delete gorp + deleteWindows +} -result {gorp 1} +test frame-15.11 {TIP 262: toplevel background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 +} -body { + toplevel .t -width 100 -height 100 -backgroundimage gorp -tile yes + update + gorp put red -to 15 15 20 20 + update + list [.t cget -bgimg] [.t cget -tile] +} -cleanup { + image delete gorp + deleteWindows +} -result {gorp 1} +test frame-15.12 {TIP 262: toplevel background images} -setup { + deleteWindows + image create photo gorp -width 10 -height 10 + gorp put black -to 2 2 7 7 + set result {} +} -body { + toplevel .t -width 100 -height 100 -backgroundimage gorp -tile yes + update + image delete gorp + update + set result [list [.t cget -bgimg] [.t cget -tile]] + image create photo gorp -width 250 -height 250 + update + lappend result [.t cget -backgroundimage] +} -cleanup { + catch {image delete gorp} + deleteWindows +} -result {gorp 1 gorp} +test frame-15.13 {TIP 262: toplevel background images} -setup { + deleteWindows + set result {} +} -constraints testImageType -body { + image create test gorp -variable result + toplevel .t -width 100 -height 100 -bgimg gorp + wm overrideredirect .t 1; # Reduce trouble from window managers + update idletasks; update + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15}} +test frame-15.14 {TIP 262: toplevel background images} -setup { + deleteWindows + set result {} +} -constraints testImageType -body { + image create test gorp -variable result + toplevel .t -width 50 -height 25 -bgimg gorp -tile 1 + wm overrideredirect .t 1; # Reduce trouble from window managers + update idletasks; update + # On MacOS must wait for the test image display procedure to run. + set timer [after 300 {lappend result "timedout"}] + while {"timedout" ni $result && + "gorp display 0 0 20 10" ni $result} { + vwait result + } + after cancel $timer + return [uniq $result] +} -cleanup { + deleteWindows + catch {image delete gorp} +} -result {{gorp get} {gorp display 0 0 30 15} {gorp display 0 0 30 10} {gorp display 0 0 20 15} {gorp display 0 0 20 10}} + # cleanup +deleteWindows +apply {cmds {foreach cmd $cmds {rename $cmd {}}}} { + eatColors colorsFree uniq optnames +} + cleanupTests return # Local Variables: # mode: tcl # End: Index: unix/tkUnixDefault.h ================================================================== --- unix/tkUnixDefault.h +++ unix/tkUnixDefault.h @@ -173,11 +173,13 @@ /* * Defaults for frames: */ #define DEF_FRAME_BG_COLOR NORMAL_BG +#define DEF_FRAME_BG_IMAGE NULL #define DEF_FRAME_BG_MONO WHITE +#define DEF_FRAME_BG_TILE "0" #define DEF_FRAME_BORDER_WIDTH "0" #define DEF_FRAME_CLASS "Frame" #define DEF_FRAME_COLORMAP "" #define DEF_FRAME_CONTAINER "0" #define DEF_FRAME_CURSOR "" Index: unix/tkUnixDraw.c ================================================================== --- unix/tkUnixDraw.c +++ unix/tkUnixDraw.c @@ -206,11 +206,11 @@ } /* *---------------------------------------------------------------------- * - * TkpDrawFrame -- + * TkpDrawFrameEx -- * * This function draws the rectangular frame area. * * Results: * None. @@ -220,18 +220,19 @@ * *---------------------------------------------------------------------- */ void -TkpDrawFrame( +TkpDrawFrameEx( Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int highlightWidth, int borderWidth, int relief) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, + Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2*highlightWidth, Tk_Height(tkwin) - 2*highlightWidth, borderWidth, relief); } /* Index: win/tkWinDefault.h ================================================================== --- win/tkWinDefault.h +++ win/tkWinDefault.h @@ -178,11 +178,13 @@ /* * Defaults for frames: */ #define DEF_FRAME_BG_COLOR NORMAL_BG +#define DEF_FRAME_BG_IMAGE NULL #define DEF_FRAME_BG_MONO WHITE +#define DEF_FRAME_BG_TILE "0" #define DEF_FRAME_BORDER_WIDTH "0" #define DEF_FRAME_CLASS "Frame" #define DEF_FRAME_COLORMAP "" #define DEF_FRAME_CONTAINER "0" #define DEF_FRAME_CURSOR "" Index: win/tkWinDraw.c ================================================================== --- win/tkWinDraw.c +++ win/tkWinDraw.c @@ -1493,11 +1493,11 @@ } /* *---------------------------------------------------------------------- * - * TkpDrawFrame -- + * TkpDrawFrameEx -- * * This function draws the rectangular frame area. * * Results: * None. @@ -1507,18 +1507,19 @@ * *---------------------------------------------------------------------- */ void -TkpDrawFrame( +TkpDrawFrameEx( Tk_Window tkwin, + Drawable drawable, Tk_3DBorder border, int highlightWidth, int borderWidth, int relief) { - Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, + Tk_Fill3DRectangle(tkwin, drawable, border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, Tk_Height(tkwin) - 2 * highlightWidth, borderWidth, relief); } /*