From 6acebb377a1ab28047fa6515df71d1ab25db6e72 Mon Sep 17 00:00:00 2001 From: "donal.k.fellows@manchester.ac.uk" Date: Sun, 24 Oct 2004 17:22:53 +0000 Subject: Add -hide and -stretch options to panedwindow widgets. (TIPs 177 and 179) Thanks to Brian Griffin for developing these! [Patch 983886] --- ChangeLog | 12 ++ doc/panedwindow.n | 39 +++- generic/tkPanedWindow.c | 449 +++++++++++++++++++++++++++++++++++++++-------- macosx/tkMacOSXDefault.h | 4 +- tests/panedwindow.test | 211 ++++++++++++++++------ unix/tkUnixDefault.h | 4 +- win/tkWinDefault.h | 4 +- 7 files changed, 591 insertions(+), 132 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42610bc..a7b2e27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-10-24 Donal K. Fellows + + TIP#177 AND TIP#179 IMPLEMENTATIONS + + * doc/panedwindow.n: Docs for -hide and -stretch options. + * tests/panedwindow.test: Basic tests of -hide and -stretch options. + * generic/tkPanedWindow.c (Slave,slaveOptionSpecs,ComputeGeometry): + (DisplayPanedWindow,ArrangePanes,MoveSash,PanedWindowIdentifyCoords): + Add hide flag and stretch setting to list of options supported on + a panedwindow's slaves. [Patch 983886] Much thanks to Brian Griffin + for these options. + 2004-10-20 Jeff Hobbs * win/tkWinWm.c (UpdateWrapper): pass SWP_NOOWNERZORDER to diff --git a/doc/panedwindow.n b/doc/panedwindow.n index 891f102..fbecd9e 100644 --- a/doc/panedwindow.n +++ b/doc/panedwindow.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: panedwindow.n,v 1.4 2004/08/17 22:37:24 dkf Exp $ +'\" RCS: @(#) $Id: panedwindow.n,v 1.5 2004/10/24 17:22:55 dkf Exp $ '\" .so man.macros .TH panedwindow n 8.4 Tk "Tk Built-In Commands" @@ -63,7 +63,6 @@ horizontally or vertically, according to the value of the \fB\-orient\fR option. Each pane contains one widget, and each pair of panes is separated by a moveable (via mouse movements) sash. Moving a sash causes the widgets on either side of the sash to be resized. - .SH "WIDGET COMMAND" .PP The \fBpanedwindow\fR command creates a new Tcl command whose name is @@ -191,6 +190,11 @@ height requested internally by the window will be used initially; the height may later be adjusted by the movement of sashes in the panedwindow. \fISize\fR may be any value accepted by \fBTk_GetPixels\fR. .TP +\fB\-hide \fIboolean\fR +Controls the visibility of a pane. When the \fIboolean\fR is true +(according to \fBTcl_GetBoolean\fR) the pane will not be visible, but +it will still be maintained in the list of panes. +.TP \fB\-minsize \fIn\fR Specifies that the size of the window cannot be made less than \fIn\fR. This constraint only affects the size of the widget in the @@ -219,6 +223,35 @@ will "stick" to. If both \fBn\fP and \fBs\fP (or \fBe\fP and \fBw\fP) are specified, the window will be stretched to fill the entire height (or width) of its cavity. .TP +\fB\-stretch \fIwhen\fR +Controls how extra space is allocated to each of the panes. +\fIWhen\fR is one of \fBalways\fR, \fBfirst\fR, \fBlast\fR, +\fBmiddle\fR, and \fBnever\fR. +The panedwindow will calculate the required size of all its panes. Any +remaining (or deficit) space will be distributed to those panes marked +for stretching. The space will be distributed based on each panes +current ratio of the whole. The \fIwhen\fR values have the following +definition: +.RS +.TP +\fBalways\fR +This pane will always stretch. +.TP +\fBfirst\fR +Only if this pane is the first pane (left-most or top-most) will it +stretch. +.TP +\fBlast\fR +Only if this pane is the last pane (right-most or bottom-most) will it +stretch. This is the default value. +.TP +\fBmiddle\fR +Only if this pane is not the first or last pane will it stretch. +.TP +\fBnever\fR +This pane will never stretch. +.RE +.TP \fB\-width \fIsize\fR Specify a width for the window. The width will be the outer dimension of the window including its border, if any. If \fIsize\fR @@ -230,9 +263,7 @@ panedwindow. \fISize\fR may be any value accepted by \fBTk_GetPixels\fR. .TP \fIpathName \fBpanes\fR Returns an ordered list of the widgets managed by \fIpathName\fR. - .SH "RESIZING PANES" - A pane is resized by grabbing the sash (or sash handle if present) and dragging with the mouse. This is accomplished via mouse motion bindings on the widget. When a sash is moved, the sizes of the panes diff --git a/generic/tkPanedWindow.c b/generic/tkPanedWindow.c index e5aaff4..a180ca6 100644 --- a/generic/tkPanedWindow.c +++ b/generic/tkPanedWindow.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkPanedWindow.c,v 1.20 2004/08/18 08:20:20 dkf Exp $ + * RCS: @(#) $Id: tkPanedWindow.c,v 1.21 2004/10/24 17:22:55 dkf Exp $ */ #include "tkPort.h" @@ -32,6 +32,7 @@ #define STICK_EAST 2 #define STICK_SOUTH 4 #define STICK_WEST 8 + /* * The following table defines the legal values for the -orient option. */ @@ -42,6 +43,33 @@ static char *orientStrings[] = { enum orient { ORIENT_HORIZONTAL, ORIENT_VERTICAL }; +/* + * The following table defines the legal values for the -stretch option. + */ + +static char *stretchStrings[] = { + "always", "first", "last", "middle", "never", (char *) NULL +}; + +enum stretch { + STRETCH_ALWAYS, /* Always give extra space to this pane. */ + STRETCH_FIRST, /* Give extra space to pane if it is first. */ + STRETCH_LAST, /* Give extra space to pane if it is last. */ + STRETCH_MIDDLE, /* Give extra space to pane only if it is + * neither first nor last. */ + STRETCH_NEVER /* Never give extra space to this pane. */ +}; + +/* + * Codify the stretchiness rule in one place. + */ + +#define IsStretchable(stretch,index,first,last) \ + (((stretch) == STRETCH_ALWAYS) || \ + ((stretch) == STRETCH_FIRST && (index) == (first)) || \ + ((stretch) == STRETCH_LAST && (index) == (last)) || \ + ((stretch) == STRETCH_MIDDLE && (index) != (first) && (index) != (last))) + typedef struct { Tk_OptionTable pwOptions; /* Token for paned window option table. */ Tk_OptionTable slaveOpts; /* Token for slave cget option table. */ @@ -74,6 +102,8 @@ typedef struct Slave { int markx, marky; /* Coordinates of the last mark set * for the sash. */ int handlex, handley; /* Coordinates of the sash handle. */ + enum stretch stretch; /* Controls how slave grows/shrinks */ + int hide; /* Controls visibility of pane */ struct PanedWindow *masterPtr; /* Paned window managing the window. */ Tk_Window after; /* Placeholder for parsing options. */ Tk_Window before; /* Placeholder for parsing options. */ @@ -298,6 +328,8 @@ static Tk_OptionSpec slaveOptionSpecs[] = { {TK_OPTION_PIXELS, "-height", (char *) NULL, (char *) NULL, DEF_PANEDWINDOW_PANE_HEIGHT, Tk_Offset(Slave, heightPtr), Tk_Offset(Slave, height), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-hide", "hide", "Hide", + DEF_PANEDWINDOW_PANE_HIDE, -1, Tk_Offset(Slave, hide), 0,0,GEOMETRY}, {TK_OPTION_PIXELS, "-minsize", (char *) NULL, (char *) NULL, DEF_PANEDWINDOW_PANE_MINSIZE, -1, Tk_Offset(Slave, minSize), 0, 0, 0}, {TK_OPTION_PIXELS, "-padx", (char *) NULL, (char *) NULL, @@ -307,6 +339,9 @@ static Tk_OptionSpec slaveOptionSpecs[] = { {TK_OPTION_CUSTOM, "-sticky", (char *) NULL, (char *) NULL, DEF_PANEDWINDOW_PANE_STICKY, -1, Tk_Offset(Slave, sticky), 0, (ClientData) &stickyOption, 0}, + {TK_OPTION_STRING_TABLE, "-stretch", "stretch", "Stretch", + DEF_PANEDWINDOW_PANE_STRETCH, -1, Tk_Offset(Slave, stretch), 0, + (ClientData) stretchStrings, 0}, {TK_OPTION_PIXELS, "-width", (char *) NULL, (char *) NULL, DEF_PANEDWINDOW_PANE_WIDTH, Tk_Offset(Slave, widthPtr), Tk_Offset(Slave, width), TK_OPTION_NULL_OK, 0, 0}, @@ -1336,9 +1371,11 @@ DisplayPanedWindow(clientData) ClientData clientData; /* Information about window. */ { PanedWindow *pwPtr = (PanedWindow *) clientData; + Slave *slavePtr; Pixmap pixmap; Tk_Window tkwin = pwPtr->tkwin; int i, sashWidth, sashHeight; + int n, sashCount, pwWidth = 0, pwHeight = 0; pwPtr->flags &= ~REDRAW_PENDING; if ((pwPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { @@ -1371,25 +1408,72 @@ DisplayPanedWindow(clientData) if (pwPtr->orient == ORIENT_HORIZONTAL) { sashHeight = Tk_Height(tkwin) - (2 * Tk_InternalBorderWidth(tkwin)); sashWidth = pwPtr->sashWidth; + pwWidth = Tk_Width(tkwin) - (2 * Tk_InternalBorderWidth(tkwin)); } else { sashWidth = Tk_Width(tkwin) - (2 * Tk_InternalBorderWidth(tkwin)); sashHeight = pwPtr->sashWidth; + pwHeight = Tk_Height(tkwin) - (2 * Tk_InternalBorderWidth(tkwin)); } /* * Draw the sashes. */ - for (i = 0; i < pwPtr->numSlaves - 1; i++) { - Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, - pwPtr->slaves[i]->sashx, pwPtr->slaves[i]->sashy, - sashWidth, sashHeight, 1, pwPtr->sashRelief); - - if (pwPtr->showHandle) { + /* quickly count the visible sashes */ + for (i = sashCount = 0; i < pwPtr->numSlaves - 1; i++) { + if (pwPtr->slaves[i]->hide) { + continue; + } + sashCount++; + } + for (i = n = 0; i < pwPtr->numSlaves - 1; i++) { + int x, y; + slavePtr = pwPtr->slaves[i]; + if (slavePtr->hide) { + continue; + } + if (pwPtr->orient == ORIENT_HORIZONTAL && + pwWidth < slavePtr->sashx) { + x = pwWidth - (pwPtr->sashWidth * (sashCount - n)); + if (x < Tk_InternalBorderWidth(tkwin)) { + x = Tk_InternalBorderWidth(tkwin); + } Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, - pwPtr->slaves[i]->handlex, pwPtr->slaves[i]->handley, - pwPtr->handleSize, pwPtr->handleSize, 1, - TK_RELIEF_RAISED); + x, slavePtr->sashy, sashWidth, sashHeight, + 1, pwPtr->sashRelief); + if (pwPtr->showHandle) { + Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, + x - slavePtr->sashx + slavePtr->handlex, + slavePtr->handley, pwPtr->handleSize, + pwPtr->handleSize, 1, TK_RELIEF_RAISED); + } + } else if (pwPtr->orient == ORIENT_VERTICAL && + pwHeight < slavePtr->sashy) { + y = pwHeight - (pwPtr->sashWidth * (sashCount - n)); + if (y < Tk_InternalBorderWidth(tkwin)) { + y = Tk_InternalBorderWidth(tkwin); + } + Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, + slavePtr->sashx, y, sashWidth, sashHeight, 1, + pwPtr->sashRelief); + if (pwPtr->showHandle) { + Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, + slavePtr->handlex, + y - (slavePtr->sashy - slavePtr->handley), + pwPtr->handleSize, pwPtr->handleSize, 1, + TK_RELIEF_RAISED); + } + } else { + Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, + slavePtr->sashx, slavePtr->sashy, + sashWidth, sashHeight, 1, pwPtr->sashRelief); + if (pwPtr->showHandle) { + Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, + slavePtr->handlex, slavePtr->handley, + pwPtr->handleSize, pwPtr->handleSize, 1, + TK_RELIEF_RAISED); + } } + n++; } /* @@ -1594,6 +1678,14 @@ ArrangePanes(clientData) register Slave *slavePtr; int i, slaveWidth, slaveHeight, slaveX, slaveY, paneWidth, paneHeight; int doubleBw; + int stretchWidth = 0; + int stretchHeight = 0; + int x, y; + int sxOff, syOff, sashWidth, hxOff, hyOff; + int internalBW; + int panedSize, pwHeight, pwWidth, tmpHeight, tmpWidth; + int first, last; + const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL); pwPtr->flags &= ~(REQUESTED_RELAYOUT|RESIZE_PENDING); @@ -1609,9 +1701,107 @@ ArrangePanes(clientData) } Tcl_Preserve((ClientData) pwPtr); + + /* + * Find index of last visible pane. + */ + + for (i = 0, last = 0, first = -1; i < pwPtr->numSlaves; i++) { + if (pwPtr->slaves[i]->hide == 0) { + if (first < 0) { + first = i; + } + last = i; + } + } + + panedSize = 0; + internalBW = Tk_InternalBorderWidth(pwPtr->tkwin); + pwHeight = Tk_Height(pwPtr->tkwin) - (2 * internalBW); + pwWidth = Tk_Width(pwPtr->tkwin) - (2 * internalBW); + sxOff = syOff = hxOff = hyOff = 0; + if (pwPtr->showHandle && pwPtr->handleSize > pwPtr->sashWidth) { + sashWidth = pwPtr->handleSize; + if (horizontal) { + sxOff = (pwPtr->handleSize - pwPtr->sashWidth) / 2; + hyOff = pwPtr->handlePad; + } else { + syOff = (pwPtr->handleSize - pwPtr->sashWidth) / 2; + hxOff = pwPtr->handlePad; + } + } else { + sashWidth = pwPtr->sashWidth; + if (horizontal) { + hxOff = (pwPtr->handleSize - pwPtr->sashWidth) / 2; + hyOff = pwPtr->handlePad; + } else { + hyOff = (pwPtr->handleSize - pwPtr->sashWidth) / 2; + hxOff = pwPtr->handlePad; + } + } + + /* + * First pass; compute sizes + */ + + for (i = 0; i < pwPtr->numSlaves; i++) { + slavePtr = pwPtr->slaves[i]; + + if (slavePtr->hide) { + continue; + } + + /* + * Compute the total size needed by all the slaves and the + * left-over, or shortage of space available. + */ + + if (horizontal) { + paneWidth = slavePtr->paneWidth; + if (i == last && Tk_IsMapped(pwPtr->tkwin)) { + if (Tk_Width(pwPtr->tkwin) != Tk_ReqWidth(pwPtr->tkwin)) { + stretchWidth = + Tk_Width(pwPtr->tkwin) - Tk_ReqWidth(pwPtr->tkwin); + } + } + if (IsStretchable(slavePtr->stretch,i,first,last) && + Tk_IsMapped(pwPtr->tkwin)) { + panedSize += paneWidth; + } + paneHeight = Tk_Height(pwPtr->tkwin) - (2 * slavePtr->pady) - + (2 * Tk_InternalBorderWidth(pwPtr->tkwin)); + } else { + paneHeight = slavePtr->paneHeight; + if (i == last && Tk_IsMapped(pwPtr->tkwin)) { + if (Tk_Height(pwPtr->tkwin) != Tk_ReqHeight(pwPtr->tkwin)) { + stretchHeight = + Tk_Height(pwPtr->tkwin)-Tk_ReqHeight(pwPtr->tkwin); + } + } + if (IsStretchable(slavePtr->stretch, i, first, last) && + Tk_IsMapped(pwPtr->tkwin)) { + panedSize += paneHeight; + } + paneWidth = Tk_Width(pwPtr->tkwin) - (2 * slavePtr->padx) - + (2 * Tk_InternalBorderWidth(pwPtr->tkwin)); + } + } + + /* + * Second pass; adjust/arrange panes. + */ + + x = y = internalBW; + for (i = 0; i < pwPtr->numSlaves; i++) { slavePtr = pwPtr->slaves[i]; + if (slavePtr->hide) { + Tk_UnmaintainGeometry(slavePtr->tkwin, pwPtr->tkwin); + Tk_UnmapWindow(slavePtr->tkwin); + continue; + } + /* * Compute the size of this slave. The algorithm (assuming a * horizontal paned window) is: @@ -1630,28 +1820,42 @@ ArrangePanes(clientData) slaveHeight = (slavePtr->height > 0 ? slavePtr->height : Tk_ReqHeight(slavePtr->tkwin) + doubleBw); - if (pwPtr->orient == ORIENT_HORIZONTAL) { + if (horizontal) { paneWidth = slavePtr->paneWidth; - if (i == pwPtr->numSlaves - 1 && Tk_IsMapped(pwPtr->tkwin)) { - if (Tk_Width(pwPtr->tkwin) != Tk_ReqWidth(pwPtr->tkwin)) { - paneWidth += Tk_Width(pwPtr->tkwin) - - Tk_ReqWidth(pwPtr->tkwin); - if (paneWidth < 0) { - paneWidth = 0; + if (Tk_IsMapped(pwPtr->tkwin)) { + if (IsStretchable(slavePtr->stretch, i, first, last)) { + double frac; + if (panedSize > 0) { + frac = (double)paneWidth / (double)panedSize; + } else { + frac = (double)paneWidth / (double)pwWidth; } + paneWidth += (int) (frac * stretchWidth); + } else if ((i == last) && + ((Tk_Width(pwPtr->tkwin) - (2 * slavePtr->padx) - + (2 * internalBW)) <= paneWidth)) { + paneWidth = Tk_Width(pwPtr->tkwin) - + (2 * slavePtr->padx) - (2 * internalBW); } } paneHeight = Tk_Height(pwPtr->tkwin) - (2 * slavePtr->pady) - (2 * Tk_InternalBorderWidth(pwPtr->tkwin)); } else { paneHeight = slavePtr->paneHeight; - if (i == pwPtr->numSlaves - 1 && Tk_IsMapped(pwPtr->tkwin)) { - if (Tk_Height(pwPtr->tkwin) != Tk_ReqHeight(pwPtr->tkwin)) { - paneHeight += Tk_Height(pwPtr->tkwin) - - Tk_ReqHeight(pwPtr->tkwin); - if (paneHeight < 0) { - paneHeight = 0; + if (Tk_IsMapped(pwPtr->tkwin)) { + if (IsStretchable(slavePtr->stretch, i, first, last)) { + double frac; + if (panedSize > 0) { + frac = (double)paneHeight / (double)panedSize; + } else { + frac = (double)paneHeight / (double)pwHeight; } + paneHeight += (int) (frac * stretchHeight); + } else if ((i == last) && + ((Tk_Height(pwPtr->tkwin) - (2 * slavePtr->pady) - + (2 * internalBW)) <= paneHeight)) { + paneHeight = Tk_Height(pwPtr->tkwin) - + (2 * slavePtr->pady) - (2 * internalBW); } } paneWidth = Tk_Width(pwPtr->tkwin) - (2 * slavePtr->padx) - @@ -1665,6 +1869,39 @@ ArrangePanes(clientData) slaveHeight = paneHeight; } + slavePtr->x = x; + slavePtr->y = y; + + /* + * Compute the location of the sash at the right or bottom of the + * parcel. + */ + if (horizontal) { + x += paneWidth + (2 * slavePtr->padx) + pwPtr->sashPad; + if (x < internalBW) { + x = internalBW; + } + } else { + y += paneHeight + (2 * slavePtr->pady) + pwPtr->sashPad; + if (y < internalBW) { + y = internalBW; + } + } + slavePtr->sashx = x + sxOff; + slavePtr->sashy = y + syOff; + slavePtr->handlex = x + hxOff; + slavePtr->handley = y + hyOff; + + /* + * Compute the location of the next parcel. + */ + + if (horizontal) { + x += sashWidth + pwPtr->sashPad; + } else { + y += sashWidth + pwPtr->sashPad; + } + slaveX = slavePtr->x; slaveY = slavePtr->y; AdjustForSticky(slavePtr->sticky, paneWidth, paneHeight, @@ -1676,12 +1913,33 @@ ArrangePanes(clientData) /* * Now put the window in the proper spot. */ - if ((slaveWidth <= 0) || (slaveHeight <= 0)) { + if (pwWidth < slaveX + slaveWidth) { + tmpWidth = pwWidth - slaveX; + } else { + tmpWidth = slaveWidth; + } + if (pwHeight < slaveY + slaveHeight) { + tmpHeight = pwHeight - slaveY; + } else { + tmpHeight = slaveHeight; + } + + if (tmpWidth <= 0 || tmpHeight <= 0 || + (horizontal ? slaveX>pwWidth : slaveY>pwHeight)) { Tk_UnmaintainGeometry(slavePtr->tkwin, pwPtr->tkwin); Tk_UnmapWindow(slavePtr->tkwin); } else { + int mgWidth = ((pwWidth < (slaveX+slaveWidth-internalBW)) ? + (pwWidth - slaveX) : slaveWidth); + int mgHeight = ((pwHeight < (slaveY+slaveHeight-internalBW)) ? + (pwHeight - slaveY) : slaveHeight); + Tk_MaintainGeometry(slavePtr->tkwin, pwPtr->tkwin, - slaveX, slaveY, slaveWidth, slaveHeight); + slaveX, slaveY, mgWidth, mgHeight); + if (slavePtr->stretch == STRETCH_NEVER) { + slavePtr->paneWidth = slaveWidth; + slavePtr->paneHeight = slaveHeight; + } } } Tcl_Release((ClientData) pwPtr); @@ -1884,6 +2142,11 @@ ComputeGeometry(pwPtr) for (i = 0; i < pwPtr->numSlaves; i++) { slavePtr = pwPtr->slaves[i]; + + if (slavePtr->hide) { + continue; + } + /* * First set the coordinates for the top left corner of the slave's * parcel. @@ -2201,17 +2464,18 @@ RestoreSticky(clientData, tkwin, internalPtr, oldInternalPtr) static void AdjustForSticky(sticky, cavityWidth, cavityHeight, xPtr, yPtr, slaveWidthPtr, slaveHeightPtr) - int sticky; /* Sticky value; see top of file for definition. */ - int cavityWidth; /* Width of the cavity. */ - int cavityHeight; /* Height of the cavity. */ + int sticky; /* Sticky value; see top of file for + * definition. */ + int cavityWidth; /* Width of the cavity. */ + int cavityHeight; /* Height of the cavity. */ int *xPtr, *yPtr; /* Initially, coordinates of the top-left * corner of cavity; also return values for * actual x, y coords of slave. */ int *slaveWidthPtr; /* Slave width. */ int *slaveHeightPtr; /* Slave height. */ { - int diffx=0; /* Cavity width - slave width. */ - int diffy=0; /* Cavity hight - slave height. */ + int diffx = 0; /* Cavity width - slave width. */ + int diffy = 0; /* Cavity hight - slave height. */ if (cavityWidth > *slaveWidthPtr) { diffx = cavityWidth - *slaveWidthPtr; @@ -2257,9 +2521,53 @@ MoveSash(pwPtr, sash, diff) int sash; int diff; { - int diffConsumed = 0, i, extra, maxCoord, currCoord; + int diffConsumed = 0, i, maxCoord, currCoord; int *lengthPtr, newLength; Slave *slave; + int first, last; + int next_sash = sash+1; + + if (diff == 0) + return; + + /* + * There must be a next sash since it is only possible to enter + * this routine when moving an actual sash which implies there + * exists a visible pane to either side of the sash. + */ + + while (next_sash < pwPtr->numSlaves-1 && pwPtr->slaves[next_sash]->hide) { + next_sash++; + } + + /* + * Find index of first and last visible panes. Also, update the + * slave size with it's real size. + */ + + for (i = 0, last = 0, first = -1; i < pwPtr->numSlaves; i++) { + slave = pwPtr->slaves[i]; + if (slave->hide == 0) { + if (first < 0) { + first = i; + } + last = i; + } + if (!Tk_IsMapped(pwPtr->tkwin)) { + continue; + } + if (pwPtr->orient == ORIENT_HORIZONTAL) { + if (Tk_Width(slave->tkwin) > slave->minSize) { + slave->paneWidth = Tk_Width(slave->tkwin) - + (1 * Tk_InternalBorderWidth(slave->tkwin)); + } + } else { + if (Tk_Height(slave->tkwin) > slave->minSize) { + slave->paneHeight = Tk_Height(slave->tkwin) - + (1 * Tk_InternalBorderWidth(slave->tkwin)); + } + } + } if (diff > 0) { /* @@ -2277,7 +2585,6 @@ MoveSash(pwPtr, sash, diff) } else { maxCoord = Tk_ReqWidth(pwPtr->tkwin); } - extra = Tk_Width(pwPtr->tkwin) - Tk_ReqWidth(pwPtr->tkwin); currCoord = pwPtr->slaves[sash]->sashx; } else { if (Tk_IsMapped(pwPtr->tkwin)) { @@ -2285,7 +2592,6 @@ MoveSash(pwPtr, sash, diff) } else { maxCoord = Tk_ReqHeight(pwPtr->tkwin); } - extra = Tk_Height(pwPtr->tkwin) - Tk_ReqHeight(pwPtr->tkwin); currCoord = pwPtr->slaves[sash]->sashy; } @@ -2300,6 +2606,10 @@ MoveSash(pwPtr, sash, diff) } slave = pwPtr->slaves[i]; + if (slave->hide) { + continue; + } + if (pwPtr->orient == ORIENT_HORIZONTAL) { lengthPtr = &(slave->paneWidth); } else { @@ -2311,38 +2621,15 @@ MoveSash(pwPtr, sash, diff) * by the minsize value and the visible dimensions of the window). */ - if (i == pwPtr->numSlaves - 1 && extra > 0) { - /* - * The last pane may have some additional "virtual" space, - * if the width (or height) of the paned window is bigger - * than the requested width (or height). - * - * That extra space is not included in the paneWidth - * (or paneHeight) value, so we have to handle the last - * pane specially. - */ - newLength = (*lengthPtr + extra) - (diff - diffConsumed); - if (newLength < slave->minSize) { - newLength = slave->minSize; - } - if (newLength < 0) { - newLength = 0; - } - diffConsumed += (*lengthPtr + extra) - newLength; - if (newLength < *lengthPtr) { - *lengthPtr = newLength; - } - } else { - newLength = *lengthPtr - (diff - diffConsumed); - if (newLength < slave->minSize) { - newLength = slave->minSize; - } - if (newLength < 0) { - newLength = 0; - } - diffConsumed += *lengthPtr - newLength; - *lengthPtr = newLength; + newLength = *lengthPtr - (diff - diffConsumed); + if (newLength < slave->minSize) { + newLength = slave->minSize; + } + if (newLength < 0) { + newLength = 0; } + diffConsumed += *lengthPtr - newLength; + *lengthPtr = newLength; } if (pwPtr->orient == ORIENT_HORIZONTAL) { pwPtr->slaves[sash]->paneWidth += diffConsumed; @@ -2350,10 +2637,22 @@ MoveSash(pwPtr, sash, diff) pwPtr->slaves[sash]->paneHeight += diffConsumed; } } else if (diff < 0) { + int *recipientLenPtr, delta; + /* * Shrinking the pane; additional space is given to the pane to the * right. */ + if (sash <= last) { + if (pwPtr->orient == ORIENT_HORIZONTAL) { + recipientLenPtr = &(pwPtr->slaves[next_sash]->paneWidth); + } else { + recipientLenPtr = &(pwPtr->slaves[next_sash]->paneHeight); + } + } else { + recipientLenPtr = NULL; + } + for (i = sash; i >= 0; i--) { if (diffConsumed == diff) { break; @@ -2363,6 +2662,10 @@ MoveSash(pwPtr, sash, diff) */ slave = pwPtr->slaves[i]; + if (slave->hide) { + continue; + } + if (pwPtr->orient == ORIENT_HORIZONTAL) { lengthPtr = &(slave->paneWidth); } else { @@ -2376,13 +2679,16 @@ MoveSash(pwPtr, sash, diff) if (newLength < 0) { newLength = 0; } - diffConsumed -= *lengthPtr - newLength; + delta = *lengthPtr - newLength; + diffConsumed -= delta; *lengthPtr = newLength; - } - if (pwPtr->orient == ORIENT_HORIZONTAL) { - pwPtr->slaves[sash + 1]->paneWidth -= diffConsumed; - } else { - pwPtr->slaves[sash + 1]->paneHeight -= diffConsumed; + + /* + * Give the extra space to the recipient pane. + */ + if (recipientLenPtr) { + *recipientLenPtr += delta; + } } } } @@ -2735,6 +3041,9 @@ PanedWindowIdentifyCoords(pwPtr, interp, x, y) isHandle = 0; found = -1; for (i = 0; i < pwPtr->numSlaves - 1; i++) { + if (pwPtr->slaves[i]->hide) { + continue; + } thisx = pwPtr->slaves[i]->sashx; thisy = pwPtr->slaves[i]->sashy; diff --git a/macosx/tkMacOSXDefault.h b/macosx/tkMacOSXDefault.h index c3b8219..97878a1 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.4 2004/02/18 00:40:24 hobbs Exp $ + * RCS: @(#) $Id: tkMacOSXDefault.h,v 1.5 2004/10/24 17:22:55 dkf Exp $ */ #ifndef _TKMACDEFAULT @@ -396,6 +396,8 @@ #define DEF_PANEDWINDOW_PANE_PADY "0" #define DEF_PANEDWINDOW_PANE_STICKY "nsew" #define DEF_PANEDWINDOW_PANE_WIDTH "" +#define DEF_PANEDWINDOW_PANE_HIDE "0" +#define DEF_PANEDWINDOW_PANE_STRETCH "last" /* * Defaults for scales: diff --git a/tests/panedwindow.test b/tests/panedwindow.test index 1ca995d..b8881d6 100644 --- a/tests/panedwindow.test +++ b/tests/panedwindow.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: panedwindow.test,v 1.15 2004/09/10 06:58:42 hobbs Exp $ +# RCS: @(#) $Id: panedwindow.test,v 1.16 2004/10/24 17:22:55 dkf Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -14,65 +14,79 @@ tcltest::loadTestedCommands set i 1 panedwindow .p -foreach test { - {-background "#ff0000" "#ff0000" non-existent - {unknown color name "non-existent"}} - {-bd 4 4 badValue {bad screen distance "badValue"}} - {-bg "#ff0000" "#ff0000" non-existent {unknown color name "non-existent"}} - {-borderwidth 1.3 1 badValue {bad screen distance "badValue"}} - {-cursor arrow arrow badValue {bad cursor spec "badValue"}} - {-handlesize 20 20 badValue {bad screen distance "badValue"}} - {-height 20 20 badValue {bad screen distance "badValue"}} - {-opaqueresize true 1 foo {expected boolean value but got "foo"}} - {-orient horizontal horizontal badValue - {bad orient "badValue": must be horizontal or vertical}} - {-relief groove groove 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken}} - {-sashcursor arrow arrow badValue {bad cursor spec "badValue"}} - {-sashpad 1.3 1 badValue {bad screen distance "badValue"}} - {-sashrelief groove groove 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken}} - {-sashwidth 10 10 badValue {bad screen distance "badValue"}} - {-showhandle true 1 foo {expected boolean value but got "foo"}} - {-width 402 402 badValue {bad screen distance "badValue"}} +foreach {testName testData} { + panedwindow-1.1 {-background + "#ff0000" "#ff0000" non-existent {unknown color name "non-existent"}} + panedwindow-1.2 {-bd + 4 4 badValue {bad screen distance "badValue"}} + panedwindow-1.3 {-bg + "#ff0000" "#ff0000" non-existent {unknown color name "non-existent"}} + panedwindow-1.4 {-borderwidth + 1.3 1 badValue {bad screen distance "badValue"}} + panedwindow-1.5 {-cursor + arrow arrow badValue {bad cursor spec "badValue"}} + panedwindow-1.6 {-handlesize + 20 20 badValue {bad screen distance "badValue"}} + panedwindow-1.7 {-height + 20 20 badValue {bad screen distance "badValue"}} + panedwindow-1.8 {-opaqueresize + true 1 foo {expected boolean value but got "foo"}} + panedwindow-1.9 {-orient + horizontal horizontal + badValue {bad orient "badValue": must be horizontal or vertical}} + panedwindow-1.10 {-relief + groove groove + 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken}} + panedwindow-1.11 {-sashcursor + arrow arrow badValue {bad cursor spec "badValue"}} + panedwindow-1.12 {-sashpad + 1.3 1 badValue {bad screen distance "badValue"}} + panedwindow-1.13 {-sashrelief + groove groove + 1.5 {bad relief "1.5": must be flat, groove, raised, ridge, solid, or sunken}} + panedwindow-1.14 {-sashwidth + 10 10 badValue {bad screen distance "badValue"}} + panedwindow-1.15 {-showhandle + true 1 foo {expected boolean value but got "foo"}} + panedwindow-1.16 {-width + 402 402 badValue {bad screen distance "badValue"}} } { - set name [lindex $test 0] - test panedwindow-1.$i {configuration options} { - .p configure $name [lindex $test 1] - list [lindex [.p configure $name] 4] [.p cget $name] - } [list [lindex $test 2] [lindex $test 2]] - incr i - if {[lindex $test 3] ne ""} { - test panedwindow-1.$i {configuration options} { - list [catch {.p configure $name [lindex $test 3]} msg] $msg - } [list 1 [lindex $test 4]] - } - .p configure $name [lindex [.p configure $name] 3] - incr i + lassign $testData optionName goodIn goodOut badIn badOut + test ${testName}(good) "configuration options: $optionName" { + .p configure $optionName $goodIn + list [lindex [.p configure $optionName] 4] [.p cget $optionName] + } [list $goodOut $goodOut] + test ${testName}(bad) "configuration options: $optionName" -body { + .p configure $optionName $badIn + } -returnCodes error -result $badOut + # Reset to default + .p configure $optionName [lindex [.p configure $optionName] 3] } .p add [button .b] .p add [button .c] -foreach test { - {-after .c .c badValue {bad window path name "badValue"}} - {-before .c .c badValue {bad window path name "badValue"}} - {-height 10 10 badValue {bad screen distance "badValue"}} - {-minsize 10 10 badValue {bad screen distance "badValue"}} - {-padx 1.3 1 badValue {bad screen distance "badValue"}} - {-pady 1.3 1 badValue {bad screen distance "badValue"}} - {-sticky nsew nesw abcd {bad stickyness value "abcd": must be a string containing zero or more of n, e, s, and w}} - {-width 10 10 badValue {bad screen distance "badValue"}} +foreach {testName testData} { + panedwindow-1a.1 {-after .c .c badValue {bad window path name "badValue"}} + panedwindow-1a.2 {-before .c .c badValue {bad window path name "badValue"}} + panedwindow-1a.3 {-height 10 10 badValue {bad screen distance "badValue"}} + panedwindow-1a.4 {-hide false 0 foo {expected boolean value but got "foo"}} + panedwindow-1a.5 {-minsize 10 10 badValue {bad screen distance "badValue"}} + panedwindow-1a.6 {-padx 1.3 1 badValue {bad screen distance "badValue"}} + panedwindow-1a.7 {-pady 1.3 1 badValue {bad screen distance "badValue"}} + panedwindow-1a.8 {-sticky nsew nesw abcd {bad stickyness value "abcd": must be a string containing zero or more of n, e, s, and w}} + panedwindow-1a.9 {-stretch alw always foo {bad stretch "foo": must be one of always, first, last, middle, or never}} + panedwindow-1a.10 {-width 10 10 badValue {bad screen distance "badValue"}} } { - set name [lindex $test 0] - test panedwindow-1.$i {configuration options} { - .p paneconfigure .b $name [lindex $test 1] - list [lindex [.p paneconfigure .b $name] 4] [.p panecget .b $name] - } [list [lindex $test 2] [lindex $test 2]] - incr i - if {[lindex $test 3] ne ""} { - test panedwindow-1.$i {configuration options} { - list [catch {.p paneconfigure .b $name [lindex $test 3]} msg] $msg - } [list 1 [lindex $test 4]] - } - .p paneconfigure .b $name [lindex [.p paneconfigure .b $name] 3] - incr i + lassign $test testName optionName goodIn goodOut badIn badOut + test ${testName}(good) "configuration options: $optionName" { + .p paneconfigure .b $optionName $goodIn + list [lindex [.p paneconfigure .b $optionName] 4] \ + [.p panecget .b $optionName] + } [list $goodOut $goodOut] + test ${testName}(bad) "configuration options: $optionName" -body { + .p paneconfigure .b $optionName $badIn + } -returnCodes error -result $badOut + # Reset to default + .p paneconfig .b $optionName [lindex [.p paneconfig .b $optionName] 3] } destroy .p .b .c @@ -2199,6 +2213,93 @@ test panedwindow-24.28 {ConfigurePanes, restrict possible panes} { destroy .f .f.f .f.f.f .f.f.f.p .b set result } [list 0 ""] +test panedwindow-24.29 {ConfigurePanes, -hide works} { + panedwindow .p + frame .f1 -width 10 -bg red + frame .f2 -width 10 -bg white + frame .f3 -width 10 -bg blue + frame .f4 -width 10 -bg green + .p add .f1 .f2 .f3 .f4 + pack .p -fill both -expand 1 + update + set result [list] + lappend result [winfo ismapped .f1] [winfo ismapped .f2] [winfo ismapped .f3] [winfo ismapped .f4] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + .p paneconfigure .f2 -hide 1 + update + lappend result [winfo ismapped .f1] [winfo ismapped .f2] [winfo ismapped .f3] [winfo ismapped .f4] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + destroy .f1 .f2 .f3 .f4 .p + set result +} [list 1 1 1 1 10 10 10 10 1 0 1 1 10 10 10 24] +test panedwindow-24.30 {ConfigurePanes, -stretch first} { + panedwindow .p + frame .f1 -width 10 -bg red + frame .f2 -width 10 -bg white + frame .f3 -width 10 -bg blue + frame .f4 -width 10 -bg green + .p add .f1 .f2 .f3 .f4 -stretch first + pack .p -fill both -expand 1 + update + set result [list] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + .p paneconfigure .f2 -hide 1 + update + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + destroy .f1 .f2 .f3 .f4 .p + set result +} [list 10 10 10 10 24 10 10 10] +test panedwindow-24.31 {ConfigurePanes, -stretch middle} { + panedwindow .p + frame .f1 -width 10 -bg red + frame .f2 -width 10 -bg white + frame .f3 -width 10 -bg blue + frame .f4 -width 10 -bg green + .p add .f1 .f2 .f3 .f4 -stretch middle + pack .p -fill both -expand 1 + update + set result [list] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + .p paneconfigure .f2 -hide 1 + update + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + destroy .f1 .f2 .f3 .f4 .p + set result +} [list 10 10 10 10 10 10 24 10] +test panedwindow-24.32 {ConfigurePanes, -stretch always} { + panedwindow .p + frame .f1 -width 10 -bg red + frame .f2 -width 10 -bg white + frame .f3 -width 10 -bg blue + frame .f4 -width 10 -bg green + .p add .f1 .f2 .f3 .f4 -stretch always + pack .p -fill both -expand 1 + update + set result [list] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + .p paneconfigure .f2 -hide 1 + update + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + destroy .f1 .f2 .f3 .f4 .p + set result +} [list 10 10 10 10 14 10 14 14] +test panedwindow-24.33 {ConfigurePanes, -stretch never} { + panedwindow .p + frame .f1 -width 10 -bg red + frame .f2 -width 10 -bg white + frame .f3 -width 10 -bg blue + frame .f4 -width 10 -bg green + .p add .f1 .f2 .f3 .f4 -stretch never + pack .p -fill both -expand 1 + update + set result [list] + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + .p paneconfigure .f2 -hide 1 + update + lappend result [winfo width .f1] [winfo width .f2] [winfo width .f3] [winfo width .f4] + destroy .f1 .f2 .f3 .f4 .p + set result +} [list 10 10 10 10 10 10 10 10] test panedwindow-25.1 {Unlink, remove a paned with -before/-after refs} { # Bug 928413 diff --git a/unix/tkUnixDefault.h b/unix/tkUnixDefault.h index f9674d6..bfea82b 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.20 2004/02/18 00:40:24 hobbs Exp $ + * RCS: @(#) $Id: tkUnixDefault.h,v 1.21 2004/10/24 17:22:55 dkf Exp $ */ #ifndef _TKUNIXDEFAULT @@ -406,6 +406,8 @@ #define DEF_PANEDWINDOW_PANE_PADY "0" #define DEF_PANEDWINDOW_PANE_STICKY "nsew" #define DEF_PANEDWINDOW_PANE_WIDTH "" +#define DEF_PANEDWINDOW_PANE_HIDE "0" +#define DEF_PANEDWINDOW_PANE_STRETCH "last" /* * Defaults for scales: diff --git a/win/tkWinDefault.h b/win/tkWinDefault.h index 1e3e2bf..56ee831 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.18 2004/02/18 00:40:24 hobbs Exp $ + * RCS: @(#) $Id: tkWinDefault.h,v 1.19 2004/10/24 17:22:55 dkf Exp $ */ #ifndef _TKWINDEFAULT @@ -393,6 +393,8 @@ #define DEF_PANEDWINDOW_PANE_PADY "0" #define DEF_PANEDWINDOW_PANE_STICKY "nsew" #define DEF_PANEDWINDOW_PANE_WIDTH "" +#define DEF_PANEDWINDOW_PANE_HIDE "0" +#define DEF_PANEDWINDOW_PANE_STRETCH "last" /* * Defaults for scales: -- cgit v0.12