📄 tkgrid.c
字号:
/* * tkGrid.c -- * * Grid based geometry manager. * * Copyright (c) 1996-1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tkGrid.c 1.39 97/10/10 10:12:03 */#include "tkInt.h"/* * Convenience Macros */#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) /* working on column offsets */#define ROW (2) /* working on row offsets */#define CHECK_ONLY (1) /* check max slot constraint */#define CHECK_SPACE (2) /* alloc more space, don't change max *//* * Pre-allocate enough row and column slots for "typical" sized tables * this value should be chosen so by the time the extra malloc's are * required, the layout calculations overwehlm them. [A "slot" contains * information for either a row or column, depending upon the context.] */#define TYPICAL_SIZE 25 /* (arbitrary guess) */#define PREALLOC 10 /* extra slots to allocate *//* * Data structures are allocated dynamically to support arbitrary sized tables. * However, the space is proportional to the highest numbered slot with * some non-default property. This limit is used to head off mistakes and * denial of service attacks by limiting the amount of storage required. */#define MAX_ELEMENT 10000/* * Special characters to support relative layouts. */#define REL_SKIP 'x' /* Skip this column. */#define REL_HORIZ '-' /* Extend previous widget horizontally. */#define REL_VERT '^' /* Extend widget from row above. *//* * Structure to hold information for grid masters. A slot is either * a row or column. */typedef struct SlotInfo { int minSize; /* The minimum size of this slot (in pixels). * It is set via the rowconfigure or * columnconfigure commands. */ int weight; /* The resize weight of this slot. (0) means * this slot doesn't resize. Extra space in * the layout is given distributed among slots * inproportion to their weights. */ int pad; /* Extra padding, in pixels, required for * this slot. This amount is "added" to the * largest slave in the slot. */ int offset; /* This is a cached value used for * introspection. It is the pixel * offset of the right or bottom edge * of this slot from the beginning of the * layout. */ int temp; /* This is a temporary value used for * calculating adjusted weights when * shrinking the layout below its * nominal size. */} SlotInfo;/* * Structure to hold information during layout calculations. There * is one of these for each slot, an array for each of the rows or columns. */typedef struct GridLayout { struct Gridder *binNextPtr; /* The next slave window in this bin. * Each bin contains a list of all * slaves whose spans are >1 and whose * right edges fall in this slot. */ int minSize; /* Minimum size needed for this slot, * in pixels. This is the space required * to hold any slaves contained entirely * in this slot, adjusted for any slot * constrants, such as size or padding. */ int pad; /* Padding needed for this slot */ int weight; /* Slot weight, controls resizing. */ int minOffset; /* The minimum offset, in pixels, from * the beginning of the layout to the * right/bottom edge of the slot calculated * from top/left to bottom/right. */ int maxOffset; /* The maximum offset, in pixels, from * the beginning of the layout to the * right-or-bottom edge of the slot calculated * from bottom-or-right to top-or-left. */} GridLayout;/* * Keep one of these for each geometry master. */typedef struct { SlotInfo *columnPtr; /* Pointer to array of column constraints. */ SlotInfo *rowPtr; /* Pointer to array of row constraints. */ int columnEnd; /* The last column occupied by any slave. */ int columnMax; /* The number of columns with constraints. */ int columnSpace; /* The number of slots currently allocated for * column constraints. */ int rowEnd; /* The last row occupied by any slave. */ int rowMax; /* The number of rows with constraints. */ int rowSpace; /* The number of slots currently allocated * for row constraints. */ int startX; /* Pixel offset of this layout within its * parent. */ int startY; /* Pixel offset of this layout within its * parent. */} GridMaster;/* * For each window that the grid cares about (either because * the window is managed by the grid or because the window * has slaves that are managed by the grid), there is a * structure of the following type: */typedef struct Gridder { Tk_Window tkwin; /* Tk token for window. NULL means that * the window has been deleted, but the * gridder hasn't had a chance to clean up * yet because the structure is still in * use. */ struct Gridder *masterPtr; /* Master window within which this window * is managed (NULL means this window * isn't managed by the gridder). */ struct Gridder *nextPtr; /* Next window managed within same * parent. List order doesn't matter. */ struct Gridder *slavePtr; /* First in list of slaves managed * inside this window (NULL means * no grid slaves). */ GridMaster *masterDataPtr; /* Additional data for geometry master. */ int column, row; /* Location in the grid (starting * from zero). */ int numCols, numRows; /* Number of columns or rows this slave spans. * Should be at least 1. */ int padX, padY; /* Total additional pixels to leave around the * window (half of this space is left on each * side). This is space *outside* the window: * we'll allocate extra space in frame but * won't enlarge window). */ int iPadX, iPadY; /* Total extra pixels to allocate inside the * window (half this amount will appear on * each side). */ int sticky; /* which sides of its cavity this window * sticks to. See below for definitions */ int doubleBw; /* Twice the window's last known border * width. If this changes, the window * must be re-arranged within its parent. */ int *abortPtr; /* If non-NULL, it means that there is a nested * call to ArrangeGrid already working on * this window. *abortPtr may be set to 1 to * abort that nested call. This happens, for * example, if tkwin or any of its slaves * is deleted. */ int flags; /* Miscellaneous flags; see below * for definitions. */ /* * These fields are used temporarily for layout calculations only. */ struct Gridder *binNextPtr; /* Link to next span>1 slave in this bin. */ int size; /* Nominal size (width or height) in pixels * of the slave. This includes the padding. */} Gridder;/* Flag values for "sticky"ness The 16 combinations subsume the packer's * notion of anchor and fill. * * STICK_NORTH This window sticks to the top of its cavity. * STICK_EAST This window sticks to the right edge of its cavity. * STICK_SOUTH This window sticks to the bottom of its cavity. * STICK_WEST This window sticks to the left edge of its cavity. */#define STICK_NORTH 1#define STICK_EAST 2#define STICK_SOUTH 4#define STICK_WEST 8/* * Flag values for Grid structures: * * REQUESTED_RELAYOUT: 1 means a Tcl_DoWhenIdle request * has already been made to re-arrange * all the slaves of this window. * * DONT_PROPAGATE: 1 means don't set this window's requested * size. 0 means if this window is a master * then Tk will set its requested size to fit * the needs of its slaves. */#define REQUESTED_RELAYOUT 1#define DONT_PROPAGATE 2/* * Hash table used to map from Tk_Window tokens to corresponding * Grid structures: */static Tcl_HashTable gridHashTable;static int initialized = 0;/* * Prototypes for procedures used only in this file: */static void AdjustForSticky _ANSI_ARGS_((Gridder *slavePtr, int *xPtr, int *yPtr, int *widthPtr, int *heightPtr));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", /* name */ GridReqProc, /* requestProc */ GridLostSlaveProc, /* lostSlaveProc */};/* *-------------------------------------------------------------- * * Tk_GridCmd -- * * This procedure is invoked to process the "grid" Tcl command. * See the user documentation for details on what it does. * * Results: * A standard Tcl result. * * Side effects: * See the user documentation. * *-------------------------------------------------------------- */intTk_GridCmd(clientData, interp, argc, argv) ClientData clientData; /* Main window associated with * interpreter. */ Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */{ Tk_Window tkwin = (Tk_Window) clientData; Gridder *masterPtr; /* master grid record */ GridMaster *gridPtr; /* pointer to grid data */ size_t length; /* streing length of argument */ char c; /* 1st character of argument */ 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; /* origin for bounding box */ int row2, column2; /* end of bounding box */ int endX, endY; /* last column/row in the layout */ int x=0, y=0; /* starting pixels for this bounding box */ int width, height; /* size of the bounding box */ 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -