#include "tkInt.h"
#ifdef MAX
# undef MAX
#endif
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#ifdef MIN
# undef MIN
#endif
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#define COLUMN (1)
#define ROW (2)
#define CHECK_ONLY (1)
#define CHECK_SPACE (2)
#define TYPICAL_SIZE 25
#define PREALLOC 10
#define MAX_ELEMENT 10000
#define REL_SKIP 'x'
#define REL_HORIZ '-'
#define REL_VERT '^'
typedef struct SlotInfo {
int minSize;
int weight;
int pad;
int offset;
int temp;
} SlotInfo;
typedef struct GridLayout {
struct Gridder *binNextPtr;
int minSize;
int pad;
int weight;
int minOffset;
int maxOffset;
} GridLayout;
typedef struct {
SlotInfo *columnPtr;
SlotInfo *rowPtr;
int columnEnd;
int columnMax;
int columnSpace;
int rowEnd;
int rowMax;
int rowSpace;
int startX;
int startY;
} GridMaster;
typedef struct Gridder {
Tk_Window tkwin;
struct Gridder *masterPtr;
struct Gridder *nextPtr;
struct Gridder *slavePtr;
GridMaster *masterDataPtr;
int column, row;
int numCols, numRows;
int padX, padY;
int iPadX, iPadY;
int sticky;
int doubleBw;
int *abortPtr;
int flags;
struct Gridder *binNextPtr;
int size;
} Gridder;
#define STICK_NORTH 1
#define STICK_EAST 2
#define STICK_SOUTH 4
#define STICK_WEST 8
#define REQUESTED_RELAYOUT 1
#define DONT_PROPAGATE 2
static Tcl_HashTable gridHashTable;
static int initialized = 0;
static int AdjustOffsets _ANSI_ARGS_((int width,
int elements, SlotInfo *slotPtr));
static void ArrangeGrid _ANSI_ARGS_((ClientData clientData));
static int CheckSlotData _ANSI_ARGS_((Gridder *masterPtr, int slot,
int slotType, int checkOnly));
static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
Tk_Window tkwin, int argc, char *argv[]));
static void DestroyGrid _ANSI_ARGS_((char *memPtr));
static Gridder *GetGrid _ANSI_ARGS_((Tk_Window tkwin));
static void GridStructureProc _ANSI_ARGS_((
ClientData clientData, XEvent *eventPtr));
static void GridLostSlaveProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin));
static void GridReqProc _ANSI_ARGS_((ClientData clientData,
Tk_Window tkwin));
static void InitMasterData _ANSI_ARGS_((Gridder *masterPtr));
static int ResolveConstraints _ANSI_ARGS_((Gridder *gridPtr,
int rowOrColumn, int maxOffset));
static void SetGridSize _ANSI_ARGS_((Gridder *gridPtr));
static void StickyToString _ANSI_ARGS_((int flags, char *result));
static int StringToSticky _ANSI_ARGS_((char *string));
static void Unlink _ANSI_ARGS_((Gridder *gridPtr));
static Tk_GeomMgr gridMgrType = {
"grid",
GridReqProc,
GridLostSlaveProc,
};
int
Tk_GridCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
Tk_Window tkwin = (Tk_Window) clientData;
Gridder *masterPtr;
GridMaster *gridPtr;
size_t length;
char c;
if ((argc >= 2) && ((argv[1][0] == '.') || (argv[1][0] == REL_SKIP) ||
(argv[1][0] == REL_VERT))) {
return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
}
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " option arg ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
c = argv[1][0];
length = strlen(argv[1]);
if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
Tk_Window master;
int row, column;
int row2, column2;
int endX, endY;
int x=0, y=0;
int width, height;
if (argc!=3 && argc != 5 && argc != 7) {
Tcl_AppendResult(interp, "wrong number of arguments: ",
"must be \"",argv[0],
" bbox master ?column row ?column row??\"",
(char *) NULL);
return TCL_ERROR;
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
masterPtr = GetGrid(master);
if (argc >= 5) {
if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) {
return TCL_ERROR;
}
column2 = column;
row2 = row;
}
if (argc == 7) {
if (Tcl_GetInt(interp, argv[5], &column2) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetInt(interp, argv[6], &row2) != TCL_OK) {
return TCL_ERROR;
}
}
gridPtr = masterPtr->masterDataPtr;
if (gridPtr == NULL) {
sprintf(interp->result, "%d %d %d %d",0,0,0,0);
return(TCL_OK);
}
SetGridSize(masterPtr);
endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
if (endX == 0 || endY == 0) {
sprintf(interp->result, "%d %d %d %d",0,0,0,0);
return(TCL_OK);
}
if (argc == 3) {
row = column = 0;
row2 = endY;
column2 = endX;
}
if (column > column2) {
int temp = column;
column = column2, column2 = temp;
}
if (row > row2) {
int temp = row;
row = row2, row2 = temp;
}
if (column > 0 && column < endX) {
x = gridPtr->columnPtr[column-1].offset;
} else if (column > 0) {
x = gridPtr->columnPtr[endX-1].offset;
}
if (row > 0 && row < endY) {
y = gridPtr->rowPtr[row-1].offset;
} else if (row > 0) {
y = gridPtr->rowPtr[endY-1].offset;
}
if (column2 < 0) {
width = 0;
} else if (column2 >= endX) {
width = gridPtr->columnPtr[endX-1].offset - x;
} else {
width = gridPtr->columnPtr[column2].offset - x;
}
if (row2 < 0) {
height = 0;
} else if (row2 >= endY) {
height = gridPtr->rowPtr[endY-1].offset - y;
} else {
height = gridPtr->rowPtr[row2].offset - y;
}
sprintf(interp->result, "%d %d %d %d",
x + gridPtr->startX, y + gridPtr->startY, width, height);
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
if (argv[2][0] != '.') {
Tcl_AppendResult(interp, "bad argument \"", argv[2],
"\": must be name of window", (char *) NULL);
return TCL_ERROR;
}
return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
} else if (((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) ||
((c == 'r') && (strncmp(argv[1], "remove", length) == 0))) {
Tk_Window slave;
Gridder *slavePtr;
int i;
for (i = 2; i < argc; i++) {
slave = Tk_NameToWindow(interp, argv[i], tkwin);
if (slave == NULL) {
return TCL_ERROR;
}
slavePtr = GetGrid(slave);
if (slavePtr->masterPtr != NULL) {
if (c == 'f') {
slavePtr->column = slavePtr->row = -1;
slavePtr->numCols = 1;
slavePtr->numRows = 1;
slavePtr->padX = slavePtr->padY = 0;
slavePtr->iPadX = slavePtr->iPadY = 0;
slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
slavePtr->flags = 0;
slavePtr->sticky = 0;
}
Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
(ClientData) NULL);
Unlink(slavePtr);
Tk_UnmapWindow(slavePtr->tkwin);
}
}
} else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
register Gridder *slavePtr;
Tk_Window slave;
char buffer[70];
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " info window\"", (char *) NULL);
return TCL_ERROR;
}
slave = Tk_NameToWindow(interp, argv[2], tkwin);
if (slave == NULL) {
return TCL_ERROR;
}
slavePtr = GetGrid(slave);
if (slavePtr->masterPtr == NULL) {
interp->result[0] = '\0';
return TCL_OK;
}
Tcl_AppendElement(interp, "-in");
Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d",
slavePtr->column, slavePtr->row,
slavePtr->numCols, slavePtr->numRows);
Tcl_AppendResult(interp, buffer, (char *) NULL);
sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
slavePtr->padY/2);
Tcl_AppendResult(interp, buffer, (char *) NULL);
StickyToString(slavePtr->sticky,buffer);
Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL);
} else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) {
Tk_Window master;
register SlotInfo *slotPtr;
int x, y;
int i, j;
int endX, endY;
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " location master x y\"", (char *)NULL);
return TCL_ERROR;
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) {
return TCL_ERROR;
}
if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) {
return TCL_ERROR;
}
masterPtr = GetGrid(master);
if (masterPtr->masterDataPtr == NULL) {
sprintf(interp->result, "%d %d", -1, -1);
return TCL_OK;
}
gridPtr = masterPtr->masterDataPtr;
while (masterPtr->flags & REQUESTED_RELAYOUT) {
Tk_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);
ArrangeGrid ((ClientData) masterPtr);
}
SetGridSize(masterPtr);
endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
slotPtr = masterPtr->masterDataPtr->columnPtr;
if (x < masterPtr->masterDataPtr->startX) {
i = -1;
} else {
x -= masterPtr->masterDataPtr->startX;
for (i=0;slotPtr[i].offset < x && i < endX; i++) {
}
}
slotPtr = masterPtr->masterDataPtr->rowPtr;
if (y < masterPtr->masterDataPtr->startY) {
j = -1;
} else {
y -= masterPtr->masterDataPtr->startY;
for (j=0;slotPtr[j].offset < y && j < endY; j++) {
}
}
sprintf(interp->result, "%d %d", i, j);
} else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
Tk_Window master;
int propagate;
if (argc > 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " propagate window ?boolean?\"",
(char *) NULL);
return TCL_ERROR;
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
masterPtr = GetGrid(master);
if (argc == 3) {
interp->result = (masterPtr->flags & DONT_PROPAGATE) ? "0" : "1";
return TCL_OK;
}
if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
return TCL_ERROR;
}
if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) {
masterPtr->flags ^= DONT_PROPAGATE;
if (masterPtr->abortPtr != NULL) {
*masterPtr->abortPtr = 1;
}
if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
}
}
} else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)
&& (length > 1)) {
Tk_Window master;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " size window\"", (char *) NULL);
return TCL_ERROR;
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
masterPtr = GetGrid(master);
if (masterPtr->masterDataPtr != NULL) {
SetGridSize(masterPtr);
gridPtr = masterPtr->masterDataPtr;
sprintf(interp->result, "%d %d",
MAX(gridPtr->columnEnd, gridPtr->columnMax),
MAX(gridPtr->rowEnd, gridPtr->rowMax));
} else {
sprintf(interp->result, "%d %d",0, 0);
}
} else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)
&& (length > 1)) {
Tk_Window master;
Gridder *slavePtr;
int i, value;
int row = -1, column = -1;
if ((argc < 3) || ((argc%2) == 0)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " slaves window ?-option value...?\"",
(char *) NULL);
return TCL_ERROR;
}
for (i=3; i<argc; i+=2) {
length = strlen(argv[i]);
if ((*argv[i] != '-') || (length < 2)) {
Tcl_AppendResult(interp, "invalid args: should be \"",
argv[0], " slaves window ?-option value...?\"",
(char *) NULL);
return TCL_ERROR;
}
if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) {
return TCL_ERROR;
}
if (value < 0) {
Tcl_AppendResult(interp, argv[i],
" is an invalid value: should NOT be < 0",
(char *) NULL);
return TCL_ERROR;
}
if (strncmp(argv[i], "-column", length) == 0) {
column = value;
} else if (strncmp(argv[i], "-row", length) == 0) {
row = value;
} else {
Tcl_AppendResult(interp, argv[i],
" is an invalid option: should be \"",
"-row, -column\"",
(char *) NULL);
return TCL_ERROR;
}
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
masterPtr = GetGrid(master);
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
slavePtr = slavePtr->nextPtr) {
if (column>=0 && (slavePtr->column > column
|| slavePtr->column+slavePtr->numCols-1 < column)) {
continue;
}
if (row>=0 && (slavePtr->row > row ||
slavePtr->row+slavePtr->numRows-1 < row)) {
continue;
}
Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
}
} else if(((c=='c') && (strncmp(argv[1], "columnconfigure", length) == 0)
&& (length >= 3)) ||
((c=='r') && (strncmp(argv[1], "rowconfigure", length) == 0)
&& (length >=2))) {
Tk_Window master;
SlotInfo *slotPtr = NULL;
int slot;
size_t length;
int slotType;
int size;
int checkOnly;
int ok;
int i;
if (((argc%2 != 0) && (argc>6)) || (argc < 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " master index ?-option value...?\"",
(char *)NULL);
return TCL_ERROR;
}
master = Tk_NameToWindow(interp, argv[2], tkwin);
if (master == NULL) {
return TCL_ERROR;
}
if (Tcl_GetInt(interp, argv[3], &slot) != TCL_OK) {
return TCL_ERROR;
}
slotType = (c == 'c') ? COLUMN : ROW;
masterPtr = GetGrid(master);
checkOnly = ((argc==4) || (argc==5));
ok = CheckSlotData(masterPtr, slot, slotType, checkOnly);
if ((ok!=TCL_OK) && (argc!=4)) {
Tcl_AppendResult(interp, argv[0],
" ", argv[1], ": \"", argv[3],"\" is out of range",
(char *) NULL);
return TCL_ERROR;
} else if (ok == TCL_OK) {
slotPtr = (slotType == COLUMN) ?
masterPtr->masterDataPtr->columnPtr :
masterPtr->masterDataPtr->rowPtr;
}
if ((argc==4) && (ok == TCL_OK)) {
sprintf(interp->result,"-minsize %d -pad %d -weight %d",
slotPtr[slot].minSize,slotPtr[slot].pad,
slotPtr[slot].weight);
return (TCL_OK);
} else if (argc == 4) {
sprintf(interp->result,"-minsize %d -pad %d -weight %d", 0,0,0);
return (TCL_OK);
}
for (i=4; i<argc; i+=2) {
length = strlen(argv[i]);
if ((*argv[i] != '-') || length < 2) {
Tcl_AppendResult(interp, "invalid arg \"",
argv[i], "\" :expecting -minsize, -pad, or -weight.",
(char *) NULL);
return TCL_ERROR;
}
if (strncmp(argv[i], "-minsize", length) == 0) {
if (argc == 5) {
sprintf(interp->result,"%d",slotPtr[slot].minSize);
} else if (Tk_GetPixels(interp, master, argv[i+1], &size)
!= TCL_OK) {
return TCL_ERROR;
} else {
slotPtr[slot].minSize = size;
}
}
else if (strncmp(argv[i], "-weight", length) == 0) {
int wt;
if (argc == 5) {
sprintf(interp->result,"%d",slotPtr[slot].weight);
} else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) {
return TCL_ERROR;
} else if (wt < 0) {
Tcl_AppendResult(interp, "invalid arg \"", argv[i],
"\": should be non-negative", (char *) NULL);
return TCL_ERROR;
} else {
slotPtr[slot].weight = wt;
}
}
else if (strncmp(argv[i], "-pad", length) == 0) {
if (argc == 5) {
sprintf(interp->result,"%d",slotPtr[slot].pad);
} else if (Tk_GetPixels(interp, master, argv[i+1], &size)
!= TCL_OK) {
return TCL_ERROR;
} else if (size < 0) {
Tcl_AppendResult(interp, "invalid arg \"", argv[i],
"\": should be non-negative", (char *) NULL);
return TCL_ERROR;
} else {
slotPtr[slot].pad = size;
}
} else {
Tcl_AppendResult(interp, "invalid arg \"",
argv[i], "\": expecting -minsize, -pad, or -weight.",
(char *) NULL);
return TCL_ERROR;
}
}
if (argc != 5) {
if (slotType==ROW) {
int last = masterPtr->masterDataPtr->rowMax - 1;
while (last>=0 && slotPtr[last].weight==0 &&
slotPtr[last].pad==0 && slotPtr[last].minSize==0) {
last--;
}
masterPtr->masterDataPtr->rowMax = last+1;
} else {
int last = masterPtr->masterDataPtr->columnMax - 1;
while (last>=0 && slotPtr[last].weight==0 &&
slotPtr[last].pad==0 && slotPtr[last].minSize==0) {
last--;
}
masterPtr->masterDataPtr->columnMax = last + 1;
}
if (masterPtr->abortPtr != NULL) {
*masterPtr->abortPtr = 1;
}
if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
}
}
} else {
Tcl_AppendResult(interp, "bad option \"", argv[1],
"\": must be bbox, columnconfigure, configure, forget, info, ",
"location, propagate, remove, rowconfigure, size, or slaves.",
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static void
GridReqProc(clientData, tkwin)
ClientData clientData;
Tk_Window tkwin;
{
register Gridder *gridPtr = (Gridder *) clientData;
gridPtr = gridPtr->masterPtr;
if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
gridPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
}
}
static void
GridLostSlaveProc(clientData, tkwin)
ClientData clientData;
Tk_Window tkwin;
{
register Gridder *slavePtr = (Gridder *) clientData;
if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
}
Unlink(slavePtr);
Tk_UnmapWindow(slavePtr->tkwin);
}
static int
AdjustOffsets(size, slots, slotPtr)
int size;
int slots;
register SlotInfo *slotPtr;
{
register int slot;
int diff = 0;
int totalWeight = 0;
int weight = 0;
int minSize = 0;
int newDiff = 0;
diff = size - slotPtr[slots-1].offset;
if (diff == 0) {
return(0);
}
for (slot=0; slot < slots; slot++) {
totalWeight += slotPtr[slot].weight;
}
if (totalWeight == 0 ) {
return(diff > 0 ? diff/2 : 0);
}
if (diff > 0) {
for (weight=slot=0; slot < slots; slot++) {
weight += slotPtr[slot].weight;
slotPtr[slot].offset += diff * weight / totalWeight;
}
return(0);
}
for (slot=0; slot < slots; slot++) {
if (slotPtr[slot].weight > 0) {
minSize += slotPtr[slot].minSize;
} else if (slot > 0) {
minSize += slotPtr[slot].offset - slotPtr[slot-1].offset;
} else {
minSize += slotPtr[slot].offset;
}
}
if (size <= minSize) {
int offset = 0;
for (slot=0; slot < slots; slot++) {
if (slotPtr[slot].weight > 0) {
offset += slotPtr[slot].minSize;
} else if (slot > 0) {
offset += slotPtr[slot].offset - slotPtr[slot-1].offset;
} else {
offset += slotPtr[slot].offset;
}
slotPtr[slot].offset = offset;
}
return(0);
}
while (diff < 0) {
for (totalWeight=slot=0; slot < slots; slot++) {
int current = (slot==0) ? slotPtr[slot].offset :
slotPtr[slot].offset - slotPtr[slot-1].offset;
if (current > slotPtr[slot].minSize) {
totalWeight += slotPtr[slot].weight;
slotPtr[slot].temp = slotPtr[slot].weight;
} else {
slotPtr[slot].temp = 0;
}
}
if (totalWeight == 0) {
break;
}
newDiff = diff;
for (weight=slot=0; slot < slots; slot++) {
int current;
int maxDiff;
if (slotPtr[slot].temp == 0) {
continue;
}
weight += slotPtr[slot].temp;
current = (slot==0) ? slotPtr[slot].offset :
slotPtr[slot].offset - slotPtr[slot-1].offset;
maxDiff = totalWeight * (slotPtr[slot].minSize - current)
/ slotPtr[slot].temp;
if (maxDiff > newDiff) {
newDiff = maxDiff;
}
}
for (weight=slot=0; slot < slots; slot++) {
weight += slotPtr[slot].temp;
slotPtr[slot].offset += newDiff * weight / totalWeight;
}
diff -= newDiff;
}
return(0);
}
static void
AdjustForSticky(slavePtr, xPtr, yPtr, widthPtr, heightPtr)
Gridder *slavePtr;
int *xPtr;
int *yPtr;
int *widthPtr;
int *heightPtr;
{
int diffx=0;
int diffy=0;
int sticky = slavePtr->sticky;
*xPtr += slavePtr->padX/2;
*widthPtr -= slavePtr->padX;
*yPtr += slavePtr->padY/2;
*heightPtr -= slavePtr->padY;
if (*widthPtr > (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX)) {
diffx = *widthPtr - (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX);
*widthPtr = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX;
}
if (*heightPtr > (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY)) {
diffy = *heightPtr - (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY);
*heightPtr = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY;
}
if (sticky&STICK_EAST && sticky&STICK_WEST) {
*widthPtr += diffx;
}
if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {
*heightPtr += diffy;
}
if (!(sticky&STICK_WEST)) {
*xPtr += (sticky&STICK_EAST) ? diffx : diffx/2;
}
if (!(sticky&STICK_NORTH)) {
*yPtr += (sticky&STICK_SOUTH) ? diffy : diffy/2;
}
}
static void
ArrangeGrid(clientData)
ClientData clientData;
{
register Gridder *masterPtr = (Gridder *) clientData;
register Gridder *slavePtr;
GridMaster *slotPtr = masterPtr->masterDataPtr;
int abort;
int width, height;
int realWidth, realHeight;
masterPtr->flags &= ~REQUESTED_RELAYOUT;
if (masterPtr->slavePtr == NULL) {
return;
}
if (masterPtr->masterDataPtr == NULL) {
return;
}
if (masterPtr->abortPtr != NULL) {
*masterPtr->abortPtr = 1;
}
masterPtr->abortPtr = &abort;
abort = 0;
Tcl_Preserve((ClientData) masterPtr);
SetGridSize(masterPtr);
width = ResolveConstraints(masterPtr, COLUMN, 0);
height = ResolveConstraints(masterPtr, ROW, 0);
width += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
height += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
if (((width != Tk_ReqWidth(masterPtr->tkwin))
|| (height != Tk_ReqHeight(masterPtr->tkwin)))
&& !(masterPtr->flags & DONT_PROPAGATE)) {
Tk_GeometryRequest(masterPtr->tkwin, width, height);
if (width>1 && height>1) {
masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
}
masterPtr->abortPtr = NULL;
Tcl_Release((ClientData) masterPtr);
return;
}
realWidth = Tk_Width(masterPtr->tkwin) -
2*Tk_InternalBorderWidth(masterPtr->tkwin);
realHeight = Tk_Height(masterPtr->tkwin) -
2*Tk_InternalBorderWidth(masterPtr->tkwin);
slotPtr->startX = AdjustOffsets(realWidth,
MAX(slotPtr->columnEnd,slotPtr->columnMax), slotPtr->columnPtr);
slotPtr->startY = AdjustOffsets(realHeight,
MAX(slotPtr->rowEnd,slotPtr->rowMax), slotPtr->rowPtr);
slotPtr->startX += Tk_InternalBorderWidth(masterPtr->tkwin);
slotPtr->startY += Tk_InternalBorderWidth(masterPtr->tkwin);
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort;
slavePtr = slavePtr->nextPtr) {
int x, y;
int width, height;
int col = slavePtr->column;
int row = slavePtr->row;
x = (col>0) ? slotPtr->columnPtr[col-1].offset : 0;
y = (row>0) ? slotPtr->rowPtr[row-1].offset : 0;
width = slotPtr->columnPtr[slavePtr->numCols+col-1].offset - x;
height = slotPtr->rowPtr[slavePtr->numRows+row-1].offset - y;
x += slotPtr->startX;
y += slotPtr->startY;
AdjustForSticky(slavePtr, &x, &y, &width, &height);
if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
if ((width <= 0) || (height <= 0)) {
Tk_UnmapWindow(slavePtr->tkwin);
} else {
if ((x != Tk_X(slavePtr->tkwin))
|| (y != Tk_Y(slavePtr->tkwin))
|| (width != Tk_Width(slavePtr->tkwin))
|| (height != Tk_Height(slavePtr->tkwin))) {
Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
}
if (abort) {
break;
}
if (Tk_IsMapped(masterPtr->tkwin)) {
Tk_MapWindow(slavePtr->tkwin);
}
}
} else {
if ((width <= 0) || (height <= 0)) {
Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
Tk_UnmapWindow(slavePtr->tkwin);
} else {
Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
x, y, width, height);
}
}
}
masterPtr->abortPtr = NULL;
Tcl_Release((ClientData) masterPtr);
}
static int
ResolveConstraints(masterPtr, slotType, maxOffset)
Gridder *masterPtr;
int slotType;
int maxOffset;
{
register SlotInfo *slotPtr;
register Gridder *slavePtr;
int constraintCount;
int slotCount;
int gridCount;
GridLayout *layoutPtr;
int requiredSize;
int offset;
int slot;
int start;
int end;
GridLayout layoutData[TYPICAL_SIZE + 1];
if (slotType == COLUMN) {
constraintCount = masterPtr->masterDataPtr->columnMax;
slotCount = masterPtr->masterDataPtr->columnEnd;
slotPtr = masterPtr->masterDataPtr->columnPtr;
} else {
constraintCount = masterPtr->masterDataPtr->rowMax;
slotCount = masterPtr->masterDataPtr->rowEnd;
slotPtr = masterPtr->masterDataPtr->rowPtr;
}
gridCount = MAX(constraintCount,slotCount);
if (gridCount >= TYPICAL_SIZE) {
layoutPtr = (GridLayout *) ckalloc(sizeof(GridLayout) * (1+gridCount));
} else {
layoutPtr = layoutData;
}
layoutPtr->minOffset = 0;
layoutPtr->maxOffset = 0;
layoutPtr++;
for (slot=0; slot < constraintCount; slot++) {
layoutPtr[slot].minSize = slotPtr[slot].minSize;
layoutPtr[slot].weight = slotPtr[slot].weight;
layoutPtr[slot].pad = slotPtr[slot].pad;
layoutPtr[slot].binNextPtr = NULL;
}
for(;slot<gridCount;slot++) {
layoutPtr[slot].minSize = 0;
layoutPtr[slot].weight = 0;
layoutPtr[slot].pad = 0;
layoutPtr[slot].binNextPtr = NULL;
}
switch (slotType) {
case COLUMN:
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
slavePtr = slavePtr->nextPtr) {
int rightEdge = slavePtr->column + slavePtr->numCols - 1;
slavePtr->size = Tk_ReqWidth(slavePtr->tkwin) +
slavePtr->padX + slavePtr->iPadX + slavePtr->doubleBw;
if (slavePtr->numCols > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
} else {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
layoutPtr[rightEdge].minSize = size;
}
}
}
break;
case ROW:
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
slavePtr = slavePtr->nextPtr) {
int rightEdge = slavePtr->row + slavePtr->numRows - 1;
slavePtr->size = Tk_ReqHeight(slavePtr->tkwin) +
slavePtr->padY + slavePtr->iPadY + slavePtr->doubleBw;
if (slavePtr->numRows > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
} else {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
layoutPtr[rightEdge].minSize = size;
}
}
}
break;
}
for (offset=slot=0; slot < gridCount; slot++) {
layoutPtr[slot].minOffset = layoutPtr[slot].minSize + offset;
for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
slavePtr = slavePtr->binNextPtr) {
int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
int required = slavePtr->size + layoutPtr[slot - span].minOffset;
if (required > layoutPtr[slot].minOffset) {
layoutPtr[slot].minOffset = required;
}
}
offset = layoutPtr[slot].minOffset;
}
requiredSize = offset;
if (maxOffset > offset) {
offset=maxOffset;
}
for (slot=0; slot < gridCount; slot++) {
layoutPtr[slot].maxOffset = offset;
}
for (slot=gridCount-1; slot > 0;) {
for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
slavePtr = slavePtr->binNextPtr) {
int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
int require = offset - slavePtr->size;
int startSlot = slot - span;
if (startSlot >=0 && require < layoutPtr[startSlot].maxOffset) {
layoutPtr[startSlot].maxOffset = require;
}
}
offset -= layoutPtr[slot].minSize;
slot--;
if (layoutPtr[slot].maxOffset < offset) {
offset = layoutPtr[slot].maxOffset;
} else {
layoutPtr[slot].maxOffset = offset;
}
}
for (start=0; start < gridCount;) {
int totalWeight = 0;
int need = 0;
int have = 0;
int weight = 0;
int noWeights = 0;
if (layoutPtr[start].minOffset == layoutPtr[start].maxOffset) {
start++;
continue;
}
for (end=start+1; end<gridCount; end++) {
if (layoutPtr[end].minOffset == layoutPtr[end].maxOffset) {
break;
}
}
for (slot=start; slot<=end; slot++) {
totalWeight += layoutPtr[slot].weight;
need += layoutPtr[slot].minSize;
}
have = layoutPtr[end].maxOffset - layoutPtr[start-1].minOffset;
if (totalWeight == 0) {
noWeights++;
totalWeight = end - start + 1;
}
for (weight=0,slot=start; slot<end; slot++) {
int diff = layoutPtr[slot].maxOffset - layoutPtr[slot].minOffset;
weight += noWeights ? 1 : layoutPtr[slot].weight;
if ((noWeights || layoutPtr[slot].weight>0) &&
(diff*totalWeight/weight) < (have-need)) {
have = diff * totalWeight / weight + need;
}
}
for (weight=0,slot=start; slot<end; slot++) {
weight += noWeights ? 1 : layoutPtr[slot].weight;
layoutPtr[slot].minOffset +=
(int)((double) (have-need) * weight/totalWeight + 0.5);
layoutPtr[slot].minSize = layoutPtr[slot].minOffset
- layoutPtr[slot-1].minOffset;
}
layoutPtr[slot].minSize = layoutPtr[slot].minOffset
- layoutPtr[slot-1].minOffset;
for (slot=end; slot > start; slot--) {
layoutPtr[slot-1].maxOffset =
layoutPtr[slot].maxOffset-layoutPtr[slot].minSize;
}
}
for (slot=0; slot < gridCount; slot++) {
slotPtr[slot].offset = layoutPtr[slot].minOffset;
}
--layoutPtr;
if (layoutPtr != layoutData) {
ckfree((char *)layoutPtr);
}
return requiredSize;
}
static Gridder *
GetGrid(tkwin)
Tk_Window tkwin;
{
register Gridder *gridPtr;
Tcl_HashEntry *hPtr;
int new;
if (!initialized) {
initialized = 1;
Tcl_InitHashTable(&gridHashTable, TCL_ONE_WORD_KEYS);
}
hPtr = Tcl_CreateHashEntry(&gridHashTable, (char *) tkwin, &new);
if (!new) {
return (Gridder *) Tcl_GetHashValue(hPtr);
}
gridPtr = (Gridder *) ckalloc(sizeof(Gridder));
gridPtr->tkwin = tkwin;
gridPtr->masterPtr = NULL;
gridPtr->masterDataPtr = NULL;
gridPtr->nextPtr = NULL;
gridPtr->slavePtr = NULL;
gridPtr->binNextPtr = NULL;
gridPtr->column = gridPtr->row = -1;
gridPtr->numCols = 1;
gridPtr->numRows = 1;
gridPtr->padX = gridPtr->padY = 0;
gridPtr->iPadX = gridPtr->iPadY = 0;
gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
gridPtr->abortPtr = NULL;
gridPtr->flags = 0;
gridPtr->sticky = 0;
gridPtr->size = 0;
gridPtr->masterDataPtr = NULL;
Tcl_SetHashValue(hPtr, gridPtr);
Tk_CreateEventHandler(tkwin, StructureNotifyMask,
GridStructureProc, (ClientData) gridPtr);
return gridPtr;
}
static void
SetGridSize(masterPtr)
Gridder *masterPtr;
{
register Gridder *slavePtr;
int maxX = 0, maxY = 0;
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
slavePtr = slavePtr->nextPtr) {
maxX = MAX(maxX,slavePtr->numCols + slavePtr->column);
maxY = MAX(maxY,slavePtr->numRows + slavePtr->row);
}
masterPtr->masterDataPtr->columnEnd = maxX;
masterPtr->masterDataPtr->rowEnd = maxY;
CheckSlotData(masterPtr, maxX, COLUMN, CHECK_SPACE);
CheckSlotData(masterPtr, maxY, ROW, CHECK_SPACE);
}
static int
CheckSlotData(masterPtr, slot, slotType, checkOnly)
Gridder *masterPtr;
int slot;
int slotType;
int checkOnly;
{
int last;
int end;
if (slot < 0 || slot >= MAX_ELEMENT) {
return TCL_ERROR;
}
if (checkOnly==CHECK_ONLY && (masterPtr->masterDataPtr == NULL)) {
return TCL_ERROR;
}
InitMasterData(masterPtr);
end = (slotType==ROW) ? masterPtr->masterDataPtr->rowMax :
masterPtr->masterDataPtr->columnMax;
if (checkOnly==CHECK_ONLY) {
return (end < slot) ? TCL_ERROR : TCL_OK;
} else {
last = (slotType==ROW) ? masterPtr->masterDataPtr->rowSpace :
masterPtr->masterDataPtr->columnSpace;
if (last < slot) {
size_t size = sizeof(SlotInfo) * (slot + PREALLOC);
SlotInfo *new = (SlotInfo *) ckalloc(size);
SlotInfo *old = (slotType == ROW) ?
masterPtr->masterDataPtr->rowPtr :
masterPtr->masterDataPtr->columnPtr;
memcpy((VOID *) new, (VOID *) old, last * sizeof(SlotInfo));
memset((VOID *) (new+last), 0,
(sizeof(SlotInfo) * (PREALLOC+slot-last)));
ckfree((char *) old);
if (slotType == ROW) {
masterPtr->masterDataPtr->rowPtr = new;
masterPtr->masterDataPtr->rowSpace = slot+PREALLOC;
} else {
masterPtr->masterDataPtr->columnPtr = new;
masterPtr->masterDataPtr->columnSpace = slot+PREALLOC;
}
}
if (slot >= end && checkOnly != CHECK_SPACE) {
if (slotType==ROW) {
masterPtr->masterDataPtr->rowMax = slot+1;
} else {
masterPtr->masterDataPtr->columnMax = slot+1;
}
}
return TCL_OK;
}
}
static void
InitMasterData(masterPtr)
Gridder *masterPtr;
{
size_t size;
if (masterPtr->masterDataPtr == NULL) {
GridMaster *gridPtr = masterPtr->masterDataPtr =
(GridMaster *) ckalloc(sizeof(GridMaster));
size = sizeof(SlotInfo) * TYPICAL_SIZE;
gridPtr->columnEnd = 0;
gridPtr->columnMax = 0;
gridPtr->columnPtr = (SlotInfo *) ckalloc(size);
gridPtr->columnSpace = 0;
gridPtr->columnSpace = TYPICAL_SIZE;
gridPtr->rowEnd = 0;
gridPtr->rowMax = 0;
gridPtr->rowPtr = (SlotInfo *) ckalloc(size);
gridPtr->rowSpace = 0;
gridPtr->rowSpace = TYPICAL_SIZE;
memset((VOID *) gridPtr->columnPtr, 0, size);
memset((VOID *) gridPtr->rowPtr, 0, size);
}
}
static void
Unlink(slavePtr)
register Gridder *slavePtr;
{
register Gridder *masterPtr, *slavePtr2;
GridMaster *gridPtr;
masterPtr = slavePtr->masterPtr;
if (masterPtr == NULL) {
return;
}
gridPtr = masterPtr->masterDataPtr;
if (masterPtr->slavePtr == slavePtr) {
masterPtr->slavePtr = slavePtr->nextPtr;
}
else {
for (slavePtr2 = masterPtr->slavePtr; ; slavePtr2 = slavePtr2->nextPtr) {
if (slavePtr2 == NULL) {
panic("Unlink couldn't find previous window");
}
if (slavePtr2->nextPtr == slavePtr) {
slavePtr2->nextPtr = slavePtr->nextPtr;
break;
}
}
}
if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
}
if (masterPtr->abortPtr != NULL) {
*masterPtr->abortPtr = 1;
}
if (slavePtr->numCols+slavePtr->column == gridPtr->columnMax ||
slavePtr->numRows+slavePtr->row == gridPtr->rowMax) {
}
slavePtr->masterPtr = NULL;
}
static void
DestroyGrid(memPtr)
char *memPtr;
{
register Gridder *gridPtr = (Gridder *) memPtr;
if (gridPtr->masterDataPtr != NULL) {
if (gridPtr->masterDataPtr->rowPtr != NULL) {
ckfree((char *) gridPtr->masterDataPtr -> rowPtr);
}
if (gridPtr->masterDataPtr->columnPtr != NULL) {
ckfree((char *) gridPtr->masterDataPtr -> columnPtr);
}
ckfree((char *) gridPtr->masterDataPtr);
}
ckfree((char *) gridPtr);
}
static void
GridStructureProc(clientData, eventPtr)
ClientData clientData;
XEvent *eventPtr;
{
register Gridder *gridPtr = (Gridder *) clientData;
if (eventPtr->type == ConfigureNotify) {
if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
gridPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
}
if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) {
if ((gridPtr->masterPtr != NULL) &&
!(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) {
gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width;
gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr);
}
}
} else if (eventPtr->type == DestroyNotify) {
register Gridder *gridPtr2, *nextPtr;
if (gridPtr->masterPtr != NULL) {
Unlink(gridPtr);
}
for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
gridPtr2 = nextPtr) {
Tk_UnmapWindow(gridPtr2->tkwin);
gridPtr2->masterPtr = NULL;
nextPtr = gridPtr2->nextPtr;
gridPtr2->nextPtr = NULL;
}
Tcl_DeleteHashEntry(Tcl_FindHashEntry(&gridHashTable,
(char *) gridPtr->tkwin));
if (gridPtr->flags & REQUESTED_RELAYOUT) {
Tk_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr);
}
gridPtr->tkwin = NULL;
Tk_EventuallyFree((ClientData) gridPtr, DestroyGrid);
} else if (eventPtr->type == MapNotify) {
if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
gridPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
}
} else if (eventPtr->type == UnmapNotify) {
register Gridder *gridPtr2;
for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
gridPtr2 = gridPtr2->nextPtr) {
Tk_UnmapWindow(gridPtr2->tkwin);
}
}
}
static int
ConfigureSlaves(interp, tkwin, argc, argv)
Tcl_Interp *interp;
Tk_Window tkwin;
int argc;
char *argv[];
{
Gridder *masterPtr = (Gridder *)NULL;
Gridder *slavePtr;
Tk_Window other, slave, parent, ancestor;
int i, j, c, length, tmp;
int numWindows = 0;
int width;
int defaultColumn = 0;
int defaultColumnSpan = 1;
char *lastWindow = NULL;
for(numWindows=i=0;i<argc;i++) {
char firstChar = *argv[i];
if (firstChar == '.') {
numWindows++;
continue;
}
length = strlen(argv[i]);
if (length > 1 && firstChar == '-') {
break;
}
if (length > 1) {
Tcl_AppendResult(interp, "unexpected parameter, \"",
argv[i], "\", in configure list. ",
"Should be window name or option", (char *) NULL);
return TCL_ERROR;
}
if (firstChar==REL_HORIZ && (numWindows==0 ||
*argv[i-1]==REL_SKIP || *argv[i-1]==REL_VERT)) {
Tcl_AppendResult(interp,
"Must specify window before shortcut '-'.",
(char *) NULL);
return TCL_ERROR;
}
if (firstChar==REL_VERT || firstChar==REL_SKIP ||
firstChar==REL_HORIZ) {
continue;
}
Tcl_AppendResult(interp, "invalid window shortcut, \"",
argv[i], "\" should be '-', 'x', or '^'", (char *) NULL);
return TCL_ERROR;
}
numWindows = i;
if ((argc-numWindows)&1) {
Tcl_AppendResult(interp, "extra option or",
" option with no value", (char *) NULL);
return TCL_ERROR;
}
masterPtr = NULL;
for (j = 0; j < numWindows; j++) {
char firstChar = *argv[j];
if (firstChar==REL_VERT || firstChar==REL_SKIP) {
defaultColumn++;
continue;
}
if (firstChar==REL_HORIZ) {
continue;
}
for (defaultColumnSpan=1;
j+defaultColumnSpan < numWindows &&
*argv[j+defaultColumnSpan] == REL_HORIZ;
defaultColumnSpan++) {
}
slave = Tk_NameToWindow(interp, argv[j], tkwin);
if (slave == NULL) {
return TCL_ERROR;
}
if (Tk_IsTopLevel(slave)) {
Tcl_AppendResult(interp, "can't manage \"", argv[j],
"\": it's a top-level window", (char *) NULL);
return TCL_ERROR;
}
slavePtr = GetGrid(slave);
for (i = numWindows; i < argc; i+=2) {
length = strlen(argv[i]);
c = argv[i][1];
if (length < 2) {
Tcl_AppendResult(interp, "unknown or ambiguous option \"",
argv[i], "\": must be ",
"-column, -columnspan, -in, -ipadx, -ipady, ",
"-padx, -pady, -row, -rowspan, or -sticky",
(char *) NULL);
return TCL_ERROR;
}
if ((c == 'c') && (strcmp(argv[i], "-column") == 0)) {
if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad column value \"", argv[i+1],
"\": must be a non-negative integer", (char *)NULL);
return TCL_ERROR;
}
slavePtr->column = tmp;
} else if ((c == 'c') && (strcmp(argv[i], "-columnspan") == 0)) {
if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1],
"\": must be a positive integer", (char *)NULL);
return TCL_ERROR;
}
slavePtr->numCols = tmp;
} else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) {
other = Tk_NameToWindow(interp, argv[i+1], tkwin);
if (other == NULL) {
return TCL_ERROR;
}
if (other == slave) {
sprintf(interp->result,"Window can't be managed in itself");
return TCL_ERROR;
}
masterPtr = GetGrid(other);
InitMasterData(masterPtr);
} else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) {
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
|| (tmp < 0)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1],
"\": must be positive screen distance",
(char *) NULL);
return TCL_ERROR;
}
slavePtr->iPadX = tmp*2;
} else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) {
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
|| (tmp< 0)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1],
"\": must be positive screen distance",
(char *) NULL);
return TCL_ERROR;
}
slavePtr->iPadY = tmp*2;
} else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) {
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
|| (tmp< 0)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad padx value \"", argv[i+1],
"\": must be positive screen distance",
(char *) NULL);
return TCL_ERROR;
}
slavePtr->padX = tmp*2;
} else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) {
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
|| (tmp< 0)) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad pady value \"", argv[i+1],
"\": must be positive screen distance",
(char *) NULL);
return TCL_ERROR;
}
slavePtr->padY = tmp*2;
} else if ((c == 'r') && (strcmp(argv[i], "-row") == 0)) {
if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad grid value \"", argv[i+1],
"\": must be a non-negative integer", (char *)NULL);
return TCL_ERROR;
}
slavePtr->row = tmp;
} else if ((c == 'r') && (strcmp(argv[i], "-rowspan") == 0)) {
if ((Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) || tmp<=0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1],
"\": must be a positive integer", (char *)NULL);
return TCL_ERROR;
}
slavePtr->numRows = tmp;
} else if ((c == 's') && strcmp(argv[i], "-sticky") == 0) {
int sticky = StringToSticky(argv[i+1]);
if (sticky == -1) {
Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1],
"\": must be a string containing n, e, s, and/or w",
(char *)NULL);
return TCL_ERROR;
}
slavePtr->sticky = sticky;
} else {
Tcl_AppendResult(interp, "unknown or ambiguous option \"",
argv[i], "\": must be ",
"-column, -columnspan, -in, -ipadx, -ipady, ",
"-padx, -pady, -row, -rowspan, or -sticky",
(char *) NULL);
return TCL_ERROR;
}
}
if (masterPtr == NULL) {
masterPtr = slavePtr->masterPtr;
}
parent = Tk_Parent(slave);
if (masterPtr == NULL) {
masterPtr = GetGrid(parent);
InitMasterData(masterPtr);
}
if (slavePtr->masterPtr != NULL && slavePtr->masterPtr != masterPtr) {
Unlink(slavePtr);
slavePtr->masterPtr = NULL;
}
if (slavePtr->masterPtr == NULL) {
Gridder *tempPtr = masterPtr->slavePtr;
slavePtr->masterPtr = masterPtr;
masterPtr->slavePtr = slavePtr;
slavePtr->nextPtr = tempPtr;
}
for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
if (ancestor == parent) {
break;
}
if (Tk_IsTopLevel(ancestor)) {
Tcl_AppendResult(interp, "can't put ", argv[j],
" inside ", Tk_PathName(masterPtr->tkwin),
(char *) NULL);
Unlink(slavePtr);
return TCL_ERROR;
}
}
if (masterPtr->masterPtr == slavePtr) {
Tcl_AppendResult(interp, "can't put ", argv[j],
" inside ", Tk_PathName(masterPtr->tkwin),
", would cause management loop.",
(char *) NULL);
Unlink(slavePtr);
return TCL_ERROR;
}
Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr);
if (slavePtr->column == -1) {
slavePtr->column = defaultColumn;
}
slavePtr->numCols += defaultColumnSpan - 1;
if (slavePtr->row == -1) {
if (masterPtr->masterDataPtr == NULL) {
slavePtr->row = 0;
} else {
slavePtr->row = masterPtr->masterDataPtr->rowEnd;
}
}
defaultColumn += slavePtr->numCols;
defaultColumnSpan = 1;
if (masterPtr->abortPtr != NULL) {
*masterPtr->abortPtr = 1;
}
if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
masterPtr->flags |= REQUESTED_RELAYOUT;
Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
}
}
lastWindow = NULL;
for (j = 0; j < numWindows; j++) {
struct Gridder *otherPtr;
int match;
int lastRow, lastColumn;
if (*argv[j] == '.') {
lastWindow = argv[j];
}
if (*argv[j] != REL_VERT) {
continue;
}
if (masterPtr == NULL) {
Tcl_AppendResult(interp, "can't use '^', cant find master",
(char *) NULL);
return TCL_ERROR;
}
for (width=1; width+j < numWindows && *argv[j+width] == REL_VERT;
width++) {
}
if (lastWindow == NULL) {
if (masterPtr->masterDataPtr != NULL) {
SetGridSize(masterPtr);
lastRow = masterPtr->masterDataPtr->rowEnd - 1;
} else {
lastRow = 0;
}
lastColumn = 0;
} else {
other = Tk_NameToWindow(interp, lastWindow, tkwin);
otherPtr = GetGrid(other);
lastRow = otherPtr->row;
lastColumn = otherPtr->column + otherPtr->numCols;
}
for (match=0, slavePtr = masterPtr->slavePtr; slavePtr != NULL;
slavePtr = slavePtr->nextPtr) {
if (slavePtr->numCols == width
&& slavePtr->column == lastColumn
&& slavePtr->row + slavePtr->numRows == lastRow) {
slavePtr->numRows++;
match++;
}
lastWindow = Tk_PathName(slavePtr->tkwin);
}
if (!match) {
Tcl_AppendResult(interp, "can't find slave to extend with \"^\".",
(char *) NULL);
return TCL_ERROR;
}
j += width - 1;
}
if (masterPtr == NULL) {
Tcl_AppendResult(interp, "can't determine master window",
(char *) NULL);
return TCL_ERROR;
}
SetGridSize(masterPtr);
return TCL_OK;
}
static void
StickyToString(flags, result)
int flags;
char *result;
{
int count = 0;
if (flags&STICK_NORTH) {
result[count++] = 'n';
}
if (flags&STICK_EAST) {
result[count++] = 'e';
}
if (flags&STICK_SOUTH) {
result[count++] = 's';
}
if (flags&STICK_WEST) {
result[count++] = 'w';
}
if (count) {
result[count] = '\0';
} else {
sprintf(result,"{}");
}
}
static int
StringToSticky(string)
char *string;
{
int sticky = 0;
char c;
while ((c = *string++) != '\0') {
switch (c) {
case 'n': case 'N': sticky |= STICK_NORTH; break;
case 'e': case 'E': sticky |= STICK_EAST; break;
case 's': case 'S': sticky |= STICK_SOUTH; break;
case 'w': case 'W': sticky |= STICK_WEST; break;
case ' ': case ',': case '\t': case '\r': case '\n': break;
default: return -1;
}
}
return sticky;
}