diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | doc/grid.n | 55 | ||||
-rw-r--r-- | generic/tkGrid.c | 145 | ||||
-rw-r--r-- | tests/grid.test | 109 |
4 files changed, 295 insertions, 21 deletions
@@ -1,3 +1,10 @@ +2001-09-30 Peter Spjuth <peter.spjuth@space.se> + + * doc/grid.n: + * generic/tkGrid.c: + * tests/grid.test: Added -uniform option to grid's row/column- + configure. [TIP 37] [Patch 459343] + 2001-09-26 Peter Spjuth <peter.spjuth@space.se> * win/tkWinFont.c (Tk_DrawChars): Added support for clipping text. @@ -4,10 +4,10 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: grid.n,v 1.4 2001/08/18 20:03:16 pspjuth Exp $ +'\" RCS: @(#) $Id: grid.n,v 1.5 2001/09/30 19:01:58 pspjuth Exp $ '\" .so man.macros -.TH grid n 4.1 Tk "Tk Built-In Commands" +.TH grid n 8.4 Tk "Tk Built-In Commands" .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME @@ -46,11 +46,12 @@ indicated is returned. \fBgrid columnconfigure \fImaster index \fR?\fI\-option value...\fR? Query or set the column properties of the \fIindex\fP column of the geometry master, \fImaster\fP. -The valid options are \fB\-minsize\fP, \fB\-weight\fP and \fB-pad\fP. -.VS +.VS 8.4 +The valid options are \fB\-minsize\fP, \fB\-weight\fP, \fB\-uniform\fP +and \fB-pad\fP. +.VE If one or more options are provided, then \fIindex\fP may be given as a list of column indeces to which the configuration options will operate on. -.VE The \fB\-minsize\fP option sets the minimum size, in screen units, that will be permitted for this column. The \fB\-weight\fP option (an integer value) @@ -60,6 +61,14 @@ columns. A weight of zero (0) indicates the column will not deviate from its requested size. A column whose weight is two will grow at twice the rate as a column of weight one when extra space is allocated to the layout. +.VS 8.4 +The \fB-uniform\fP option, when a non-empty value is supplied, places +the column in a \fIuniform group\fP with other columns that have the +same value for \fB-uniform\fP. The space for columns belonging to a +uniform group is allocated so that their sizes are always in strict +proportion to their \fB-weight\fP values. See +``THE GRID ALGORITHM'' below for further details. +.VE The \fB-pad\fP option specifies the number of screen units that will be added to the largest window contained completely in that column when the grid geometry manager requests a size from the containing window. @@ -195,11 +204,12 @@ Propagation is enabled by default. \fBgrid rowconfigure \fImaster index \fR?\fI\-option value...\fR? Query or set the row properties of the \fIindex\fP row of the geometry master, \fImaster\fP. -The valid options are \fB\-minsize\fP, \fB\-weight\fP and \fB-pad\fP. -.VS +.VS 8.4 +The valid options are \fB\-minsize\fP, \fB\-weight\fP, \fB\-uniform\fP +and \fB-pad\fP. +.VE If one or more options are provided, then \fIindex\fP may be given as a list of row indeces to which the configuration options will operate on. -.VE The \fB\-minsize\fP option sets the minimum size, in screen units, that will be permitted for this row. The \fB\-weight\fP option (an integer value) @@ -209,6 +219,14 @@ rows. A weight of zero (0) indicates the row will not deviate from its requested size. A row whose weight is two will grow at twice the rate as a row of weight one when extra space is allocated to the layout. +.VS 8.4 +The \fB-uniform\fP option, when a non-empty value is supplied, places +the row in a \fIuniform group\fP with other rows that have the +same value for \fB-uniform\fP. The space for rows belonging to a +uniform group is allocated so that their sizes are always in strict +proportion to their \fB-weight\fP values. See +``THE GRID ALGORITHM'' below for further details. +.VE The \fB-pad\fP option specifies the number of screen units that will be added to the largest window contained completely in that row when the grid geometry manager requests a size from the containing window. @@ -286,14 +304,31 @@ To compute the minimum size of a layout, the grid geometry manager first looks at all slaves whose columnspan and rowspan values are one, and computes the nominal size of each row or column to be either the \fIminsize\fP for that row or column, or the sum of the \fIpad\fPding -plus the size of the largest slave, whichever is greater. Then the -slaves whose rowspans or columnspans are greater than one are +plus the size of the largest slave, whichever is greater. After that +the rows or columns in each uniform group adapt to each other. Then +the slaves whose rowspans or columnspans are greater than one are examined. If a group of rows or columns need to be increased in size in order to accommodate these slaves, then extra space is added to each row or column in the group according to its \fIweight\fP. For each group whose weights are all zero, the additional space is apportioned equally. .PP +When multiple rows or columns belong to a uniform group, the space +allocated to them is always in proportion to their weights. (A weight +of zero is considered to be 1.) In other words, a row or column +configured with \fB-weight 1 -uniform a\fP will have exactly the same +size as any other row or column configured with \fB-weight 1 -uniform +a\fP. A row or column configured with \fB-weight 2 -uniform b\fR will +be exactly twice as large as one that is configured with \fB-weight 1 +-uniform b\fP. +.PP +More technically, each row or column in the group will have a size +equal to \fIk*weight\fP for some constant \fIk\fP. The constant +\fIk\fP is chosen so that no row or column becomes smaller than its +minimum size. For example, if all rows or columns in a group have the +same weight, then each row or column will have the same size as the +largest row or column in the group. +.PP For masters whose size is larger than the requested layout, the additional space is apportioned according to the row and column weights. If all of the weights are zero, the layout is centered within its master. diff --git a/generic/tkGrid.c b/generic/tkGrid.c index 6737e0a..05f5a00 100644 --- a/generic/tkGrid.c +++ b/generic/tkGrid.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkGrid.c,v 1.16 2001/09/26 20:25:17 pspjuth Exp $ + * RCS: @(#) $Id: tkGrid.c,v 1.17 2001/09/30 19:01:58 pspjuth Exp $ */ #include "tkInt.h" @@ -42,6 +42,12 @@ #define TYPICAL_SIZE 25 /* (arbitrary guess) */ #define PREALLOC 10 /* extra slots to allocate */ +/* + * Pre-allocate room for uniform groups during layout. + */ + +#define UNIFORM_PREALLOC 10 + /* * Data structures are allocated dynamically to support arbitrary sized tables. * However, the space is proportional to the highest numbered slot with @@ -75,6 +81,9 @@ typedef struct SlotInfo { int pad; /* Extra padding, in pixels, required for * this slot. This amount is "added" to the * largest slave in the slot. */ + Tk_Uid uniform; /* Value of -uniform option. It is used to + * group slots that should have the same + * size. */ int offset; /* This is a cached value used for * introspection. It is the pixel * offset of the right or bottom edge @@ -103,6 +112,9 @@ typedef struct GridLayout { * constrants, such as size or padding. */ int pad; /* Padding needed for this slot */ int weight; /* Slot weight, controls resizing. */ + Tk_Uid uniform; /* Value of -uniform option. It is used to + * group slots that should have the same + * size. */ int minOffset; /* The minimum offset, in pixels, from * the beginning of the layout to the * right/bottom edge of the slot calculated @@ -208,6 +220,16 @@ typedef struct Gridder { #define STICK_SOUTH 4 #define STICK_WEST 8 + +/* + * Structure to gather information about uniform groups during layout. + */ + +typedef struct UniformGroup { + Tk_Uid group; + int minSize; +} UniformGroup; + /* * Flag values for Grid structures: * @@ -828,8 +850,8 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) int i, j; char *string; static char *optionStrings[] = { - "-minsize", "-pad", "-weight", (char *) NULL }; - enum options { ROWCOL_MINSIZE, ROWCOL_PAD, ROWCOL_WEIGHT }; + "-minsize", "-pad", "-uniform", "-weight", (char *) NULL }; + enum options { ROWCOL_MINSIZE, ROWCOL_PAD, ROWCOL_UNIFORM, ROWCOL_WEIGHT }; int index; if (((objc % 2 != 0) && (objc > 6)) || (objc < 4)) { @@ -877,12 +899,14 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) if (objc == 4) { int minsize = 0, pad = 0, weight = 0; + char *uniform = NULL; Tcl_Obj *res = Tcl_NewListObj(0, NULL); if (ok == TCL_OK) { minsize = slotPtr[slot].minSize; pad = slotPtr[slot].pad; weight = slotPtr[slot].weight; + uniform = slotPtr[slot].uniform; } Tcl_ListObjAppendElement(interp, res, @@ -892,6 +916,10 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) Tcl_NewStringObj("-pad", -1)); Tcl_ListObjAppendElement(interp, res, Tcl_NewIntObj(pad)); Tcl_ListObjAppendElement(interp, res, + Tcl_NewStringObj("-uniform", -1)); + Tcl_ListObjAppendElement(interp, res, + Tcl_NewStringObj(uniform == NULL ? "" : uniform, -1)); + Tcl_ListObjAppendElement(interp, res, Tcl_NewStringObj("-weight", -1)); Tcl_ListObjAppendElement(interp, res, Tcl_NewIntObj(weight)); Tcl_SetObjResult(interp, res); @@ -937,6 +965,22 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) slotPtr[slot].weight = wt; } } + else if (index == ROWCOL_UNIFORM) { + if (objc == 5) { + char *value; + value = (ok == TCL_OK) ? slotPtr[slot].uniform : ""; + if (value == NULL) { + value = ""; + } + Tcl_SetObjResult(interp, Tcl_NewStringObj(value, -1)); + } else { + slotPtr[slot].uniform = Tk_GetUid(Tcl_GetString(objv[i+1])); + if (slotPtr[slot].uniform != NULL && + slotPtr[slot].uniform[0] == 0) { + slotPtr[slot].uniform = NULL; + } + } + } else if (index == ROWCOL_PAD) { if (objc == 5) { Tcl_SetObjResult(interp, Tcl_NewIntObj( @@ -966,7 +1010,8 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) int last = masterPtr->masterDataPtr->rowMax - 1; while ((last >= 0) && (slotPtr[last].weight == 0) && (slotPtr[last].pad == 0) - && (slotPtr[last].minSize == 0)) { + && (slotPtr[last].minSize == 0) + && (slotPtr[last].uniform == NULL)) { last--; } masterPtr->masterDataPtr->rowMax = last+1; @@ -974,7 +1019,8 @@ GridRowColumnConfigureCommand(tkwin, interp, objc, objv) int last = masterPtr->masterDataPtr->columnMax - 1; while ((last >= 0) && (slotPtr[last].weight == 0) && (slotPtr[last].pad == 0) - && (slotPtr[last].minSize == 0)) { + && (slotPtr[last].minSize == 0) + && (slotPtr[last].uniform == NULL)) { last--; } masterPtr->masterDataPtr->columnMax = last + 1; @@ -1648,6 +1694,14 @@ ResolveConstraints(masterPtr, slotType, maxOffset) * constraints are not yet fully resolved. */ int end; /* The Last slot of a contiguous set whose * constraints are not yet fully resolved. */ + UniformGroup uniformPre[UNIFORM_PREALLOC]; + /* Pre-allocated space for uniform groups. */ + UniformGroup *uniformGroupPtr; + /* Uniform groups data. */ + int uniformGroups; /* Number of currently used uniform groups. */ + int uniformGroupsAlloced; /* Size of allocated space for uniform groups. + */ + int weight, minSize; /* * For typical sized tables, we'll use stack space for the layout data @@ -1697,13 +1751,15 @@ ResolveConstraints(masterPtr, slotType, maxOffset) for (slot=0; slot < constraintCount; slot++) { layoutPtr[slot].minSize = slotPtr[slot].minSize; - layoutPtr[slot].weight = slotPtr[slot].weight; + layoutPtr[slot].weight = slotPtr[slot].weight; + layoutPtr[slot].uniform = slotPtr[slot].uniform; layoutPtr[slot].pad = slotPtr[slot].pad; layoutPtr[slot].binNextPtr = NULL; } for(;slot<gridCount;slot++) { layoutPtr[slot].minSize = 0; layoutPtr[slot].weight = 0; + layoutPtr[slot].uniform = NULL; layoutPtr[slot].pad = 0; layoutPtr[slot].binNextPtr = NULL; } @@ -1759,6 +1815,83 @@ ResolveConstraints(masterPtr, slotType, maxOffset) } /* + * Step 2b. + * Consider demands on uniform sizes. + */ + + uniformGroupPtr = uniformPre; + uniformGroupsAlloced = UNIFORM_PREALLOC; + uniformGroups = 0; + + for (slot = 0; slot < gridCount; slot++) { + if (layoutPtr[slot].uniform != NULL) { + for (start = 0; start < uniformGroups; start++) { + if (uniformGroupPtr[start].group == layoutPtr[slot].uniform) { + break; + } + } + if (start >= uniformGroups) { + /* + * Have not seen that group before, set up data for it. + */ + + if (uniformGroups >= uniformGroupsAlloced) { + /* + * We need to allocate more space. + */ + + size_t oldSize = uniformGroupsAlloced + * sizeof(UniformGroup); + size_t newSize = (uniformGroupsAlloced + UNIFORM_PREALLOC) + * sizeof(UniformGroup); + UniformGroup *new = (UniformGroup *) ckalloc(newSize); + UniformGroup *old = uniformGroupPtr; + memcpy((VOID *) new, (VOID *) old, oldSize); + if (old != uniformPre) { + Tcl_Free((char *) old); + } + uniformGroupPtr = new; + uniformGroupsAlloced += UNIFORM_PREALLOC; + } + uniformGroups++; + uniformGroupPtr[start].group = layoutPtr[slot].uniform; + uniformGroupPtr[start].minSize = 0; + } + weight = layoutPtr[slot].weight; + weight = weight > 0 ? weight : 1; + minSize = (layoutPtr[slot].minSize + weight - 1) / weight; + if (minSize > uniformGroupPtr[start].minSize) { + uniformGroupPtr[start].minSize = minSize; + } + } + } + + /* + * Data has been gathered about uniform groups. Now relayout accordingly. + */ + + if (uniformGroups > 0) { + for (slot = 0; slot < gridCount; slot++) { + if (layoutPtr[slot].uniform != NULL) { + for (start = 0; start < uniformGroups; start++) { + if (uniformGroupPtr[start].group == + layoutPtr[slot].uniform) { + weight = layoutPtr[slot].weight; + weight = weight > 0 ? weight : 1; + layoutPtr[slot].minSize = + uniformGroupPtr[start].minSize * weight; + break; + } + } + } + } + } + + if (uniformGroupPtr != uniformPre) { + Tcl_Free((char *) uniformGroupPtr); + } + + /* * Step 3. * Determine the minimum slot offsets going from left to right * that would fit all of the slaves. This determines the minimum diff --git a/tests/grid.test b/tests/grid.test index 9342d9f..471226f 100644 --- a/tests/grid.test +++ b/tests/grid.test @@ -5,7 +5,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: grid.test,v 1.14 2001/09/26 21:36:19 pspjuth Exp $ +# RCS: @(#) $Id: grid.test,v 1.15 2001/09/30 19:01:58 pspjuth Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { source [file join [pwd] [file dirname [info script]] defs.tcl] @@ -28,10 +28,10 @@ proc grid_reset {{test ?} {top .}} { update foreach {cols rows} [grid size .] {} for {set i 0} {$i <= $cols} {incr i} { - grid columnconfigure . $i -weight 0 -minsize 0 -pad 0 + grid columnconfigure . $i -weight 0 -minsize 0 -pad 0 -uniform "" } for {set i 0} {$i <= $rows} {incr i} { - grid rowconfigure . $i -weight 0 -minsize 0 -pad 0 + grid rowconfigure . $i -weight 0 -minsize 0 -pad 0 -uniform "" } grid propagate . 1 update @@ -592,12 +592,12 @@ grid_reset 10.5 test grid-10.6 {column/row configure} { list [catch {grid columnconfigure . 0} msg] $msg -} {0 {-minsize 0 -pad 0 -weight 0}} +} {0 {-minsize 0 -pad 0 -uniform {} -weight 0}} grid_reset 10.6 test grid-10.7 {column/row configure} { list [catch {grid columnconfigure . 0 -foo} msg] $msg -} {1 {bad option "-foo": must be -minsize, -pad, or -weight}} +} {1 {bad option "-foo": must be -minsize, -pad, -uniform, or -weight}} grid_reset 10.7 test grid-10.8 {column/row configure} { @@ -681,6 +681,12 @@ test grid-10.19 {column/row configure} { } {1 {grid columnconfigure: "-1" is out of range}} grid_reset 10.19 +test grid-10.20 {column/row configure} { + grid columnconfigure . 0 -uniform foo + grid columnconfigure . 0 -uniform +} {foo} +grid_reset 10.20 + # auto-placement tests test grid-11.1 {default widget placement} { @@ -1336,6 +1342,86 @@ test grid-16.8 {layout internal constraints} { } set a } {0 30 70 250 280 , 0 30 130 230 260 , 0 30 113 197 280 , 0 30 60 90 120 } +grid_reset 16.8 + +test grid-16.9 {layout uniform} { + frame .f1 -width 75 -height 50 + frame .f2 -width 60 -height 25 + frame .f3 -width 95 -height 75 + frame .f4 -width 135 -height 100 + frame .f5 -width 80 -height 40 + for {set t 1} {$t <= 5} {incr t} { + grid .f$t + } + grid rowconfigure . {0 2} -uniform a + grid rowconfigure . {1 3} -uniform b + update + list [grid bbox . 0 0] [grid bbox . 0 1] [grid bbox . 0 2] \ + [grid bbox . 0 3] [grid bbox . 0 4] +} {{0 0 135 75} {0 75 135 100} {0 175 135 75} {0 250 135 100} {0 350 135 40}} +grid_reset 16.9 + +test grid-16.10 {layout uniform} { + grid [frame .f1 -width 75 -height 50] -row 0 -column 0 + grid [frame .f2 -width 60 -height 30] -row 1 -column 2 + grid [frame .f3 -width 95 -height 90] -row 2 -column 1 + grid [frame .f4 -width 60 -height 100] -row 3 -column 4 + grid [frame .f5 -width 60 -height 40] -row 4 -column 3 + + grid rowconfigure . {0 1} -uniform a + grid rowconfigure . {2 4} -uniform b + grid rowconfigure . {0 2} -weight 2 + grid columnconfigure . {0 2} -uniform a + grid columnconfigure . {3 4} -uniform b + grid columnconfigure . {2 4} -weight 2 + grid columnconfigure . 3 -minsize 70 + grid columnconfigure . 4 -minsize 130 + update + list [grid bbox . 0 0] [grid bbox . 2 1] [grid bbox . 1 2] \ + [grid bbox . 4 3] [grid bbox . 3 4] +} {{0 0 75 60} {170 60 150 30} {75 90 95 90} {390 180 140 100} {320 280 70 45}} +grid_reset 16.10 + +test grid-16.11 {layout uniform (shrink)} { + frame .f1 -width 75 -height 50 + frame .f2 -width 100 -height 95 + grid .f1 .f2 -sticky news + grid columnconfigure . {0 1} -uniform a + grid columnconfigure . 0 -weight 1 + update + set res {} + lappend res [grid bbox . 0 0] [grid bbox . 1 0] + grid propagate . 0 + . configure -width 150 -height 95 + update + lappend res [grid bbox . 0 0] [grid bbox . 1 0] +} {{0 0 100 95} {100 0 100 95} {0 0 50 95} {50 0 100 95}} +grid_reset 16.11 + +test grid-16.12 {layout uniform (grow)} { + frame .f1 -width 40 -height 50 + frame .f2 -width 50 -height 95 + frame .f3 -width 60 -height 50 + frame .f4 -width 70 -height 95 + grid .f1 .f2 .f3 .f4 -sticky news + grid columnconfigure . {0 1 2} -uniform a + # Put weight 2 on the biggest in the group to see that the groups + # adapts to one of the smaller. + grid columnconfigure . 2 -weight 2 + grid columnconfigure . {0 3} -weight 1 + update + set res {} + lappend res [grid bbox . 0 0] [grid bbox . 1 0] + lappend res [grid bbox . 2 0] [grid bbox . 3 0] + + grid propagate . 0 + . configure -width 350 -height 95 + update + lappend res [grid bbox . 0 0] [grid bbox . 1 0] + lappend res [grid bbox . 2 0] [grid bbox . 3 0] +} [list {0 0 50 95} {50 0 50 95} {100 0 100 95} {200 0 70 95} \ + {0 0 70 95} {70 0 50 95} {120 0 140 95} {260 0 90 95}] +grid_reset 16.12 test grid-17.1 {forget and pending idle handlers} { # This test is intended to detect a crash caused by a failure to remove @@ -1395,6 +1481,19 @@ test grid-18.2 {test support for minreqsize} { set res } {162x127+0+0 172x112+0+0} +test grid-19.1 {uniform realloc} { + # Use a lot of uniform groups to test the reallocation mechanism + for {set t 0} {$t < 100} {incr t 2} { + frame .fa$t -width 5 -height 20 + frame .fb$t -width 6 -height 20 + grid .fa$t .fb$t -row 0 -column $t -sticky news + grid columnconfigure . [list $t [expr {$t + 1}]] -uniform a$t + } + update + grid bbox . +} {0 0 600 20} +grid_reset 19.1 + # cleanup ::tcltest::cleanupTests return |