📄 tkpack.c
字号:
* * Side effects: * Arranges for tkwin, and all its managed siblings, to * be re-packed at the next idle point. * *-------------------------------------------------------------- */ /* ARGSUSED */static voidPackReqProc(clientData, tkwin) ClientData clientData; /* Packer's information about * window that got new preferred * geometry. */ Tk_Window tkwin; /* Other Tk-related information * about the window. */{ register Packer *packPtr = (Packer *) clientData; packPtr = packPtr->masterPtr; if (!(packPtr->flags & REQUESTED_REPACK)) { packPtr->flags |= REQUESTED_REPACK; Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); }}/* *-------------------------------------------------------------- * * PackLostSlaveProc -- * * This procedure is invoked by Tk whenever some other geometry * claims control over a slave that used to be managed by us. * * Results: * None. * * Side effects: * Forgets all packer-related information about the slave. * *-------------------------------------------------------------- */ /* ARGSUSED */static voidPackLostSlaveProc(clientData, tkwin) ClientData clientData; /* Packer structure for slave window that * was stolen away. */ Tk_Window tkwin; /* Tk's handle for the slave window. */{ register Packer *slavePtr = (Packer *) clientData; if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); } Unlink(slavePtr); Tk_UnmapWindow(slavePtr->tkwin);}/* *-------------------------------------------------------------- * * ArrangePacking -- * * This procedure is invoked (using the Tcl_DoWhenIdle * mechanism) to re-layout a set of windows managed by * the packer. It is invoked at idle time so that a * series of packer requests can be merged into a single * layout operation. * * Results: * None. * * Side effects: * The packed slaves of masterPtr may get resized or * moved. * *-------------------------------------------------------------- */static voidArrangePacking(clientData) ClientData clientData; /* Structure describing parent whose slaves * are to be re-layed out. */{ register Packer *masterPtr = (Packer *) clientData; register Packer *slavePtr; int cavityX, cavityY, cavityWidth, cavityHeight; /* These variables keep track of the * as-yet-unallocated space remaining in * the middle of the parent window. */ int frameX, frameY, frameWidth, frameHeight; /* These variables keep track of the frame * allocated to the current window. */ int x, y, width, height; /* These variables are used to hold the * actual geometry of the current window. */ int intBWidth; /* Width of internal border in parent window, * if any. */ int abort; /* May get set to non-zero to abort this * repacking operation. */ int borderX, borderY; int maxWidth, maxHeight, tmp; masterPtr->flags &= ~REQUESTED_REPACK; /* * If the parent has no slaves anymore, then don't do anything * at all: just leave the parent's size as-is. */ if (masterPtr->slavePtr == NULL) { return; } /* * Abort any nested call to ArrangePacking for this window, since * we'll do everything necessary here, and set up so this call * can be aborted if necessary. */ if (masterPtr->abortPtr != NULL) { *masterPtr->abortPtr = 1; } masterPtr->abortPtr = &abort; abort = 0; Tcl_Preserve((ClientData) masterPtr); /* * Pass #1: scan all the slaves to figure out the total amount * of space needed. Two separate width and height values are * computed: * * width - Holds the sum of the widths (plus padding) of * all the slaves seen so far that were packed LEFT * or RIGHT. * height - Holds the sum of the heights (plus padding) of * all the slaves seen so far that were packed TOP * or BOTTOM. * * maxWidth - Gradually builds up the width needed by the master * to just barely satisfy all the slave's needs. For * each slave, the code computes the width needed for * all the slaves so far and updates maxWidth if the * new value is greater. * maxHeight - Same as maxWidth, except keeps height info. */ intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin); width = height = maxWidth = maxHeight = 2*intBWidth; for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padX + slavePtr->iPadX + width; if (tmp > maxWidth) { maxWidth = tmp; } height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padY + slavePtr->iPadY; } else { tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padY + slavePtr->iPadY + height; if (tmp > maxHeight) { maxHeight = tmp; } width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padX + slavePtr->iPadX; } } if (width > maxWidth) { maxWidth = width; } if (height > maxHeight) { maxHeight = height; } /* * If the total amount of space needed in the parent window has * changed, and if we're propagating geometry information, then * notify the next geometry manager up and requeue ourselves to * start again after the parent has had a chance to * resize us. */ if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin)) || (maxHeight != Tk_ReqHeight(masterPtr->tkwin))) && !(masterPtr->flags & DONT_PROPAGATE)) { Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight); masterPtr->flags |= REQUESTED_REPACK; Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); goto done; } /* * Pass #2: scan the slaves a second time assigning * new sizes. The "cavity" variables keep track of the * unclaimed space in the cavity of the window; this * shrinks inward as we allocate windows around the * edges. The "frame" variables keep track of the space * allocated to the current window and its frame. The * current window is then placed somewhere inside the * frame, depending on anchor. */ cavityX = cavityY = x = y = intBWidth; cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth; cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth; for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { frameWidth = cavityWidth; frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padY + slavePtr->iPadY; if (slavePtr->flags & EXPAND) { frameHeight += YExpansion(slavePtr, cavityHeight); } cavityHeight -= frameHeight; if (cavityHeight < 0) { frameHeight += cavityHeight; cavityHeight = 0; } frameX = cavityX; if (slavePtr->side == TOP) { frameY = cavityY; cavityY += frameHeight; } else { frameY = cavityY + cavityHeight; } } else { frameHeight = cavityHeight; frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padX + slavePtr->iPadX; if (slavePtr->flags & EXPAND) { frameWidth += XExpansion(slavePtr, cavityWidth); } cavityWidth -= frameWidth; if (cavityWidth < 0) { frameWidth += cavityWidth; cavityWidth = 0; } frameY = cavityY; if (slavePtr->side == LEFT) { frameX = cavityX; cavityX += frameWidth; } else { frameX = cavityX + cavityWidth; } } /* * Now that we've got the size of the frame for the window, * compute the window's actual size and location using the * fill, padding, and frame factors. The variables "borderX" * and "borderY" are used to handle the differences between * old-style packing and the new style (in old-style, iPadX * and iPadY are always zero and padding is completely ignored * except when computing frame size). */ if (slavePtr->flags & OLD_STYLE) { borderX = borderY = 0; } else { borderX = slavePtr->padX; borderY = slavePtr->padY; } width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->iPadX; if ((slavePtr->flags & FILLX) || (width > (frameWidth - borderX))) { width = frameWidth - borderX; } height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->iPadY; if ((slavePtr->flags & FILLY) || (height > (frameHeight - borderY))) { height = frameHeight - borderY; } borderX /= 2; borderY /= 2; switch (slavePtr->anchor) { case TK_ANCHOR_N: x = frameX + (frameWidth - width)/2; y = frameY + borderY; break; case TK_ANCHOR_NE: x = frameX + frameWidth - width - borderX; y = frameY + borderY; break; case TK_ANCHOR_E: x = frameX + frameWidth - width - borderX; y = frameY + (frameHeight - height)/2; break; case TK_ANCHOR_SE: x = frameX + frameWidth - width - borderX; y = frameY + frameHeight - height - borderY; break; case TK_ANCHOR_S: x = frameX + (frameWidth - width)/2; y = frameY + frameHeight - height - borderY; break; case TK_ANCHOR_SW: x = frameX + borderX; y = frameY + frameHeight - height - borderY; break; case TK_ANCHOR_W: x = frameX + borderX; y = frameY + (frameHeight - height)/2; break; case TK_ANCHOR_NW: x = frameX + borderX; y = frameY + borderY; break; case TK_ANCHOR_CENTER: x = frameX + (frameWidth - width)/2; y = frameY + (frameHeight - height)/2; break; default: panic("bad frame factor in ArrangePacking"); } width -= slavePtr->doubleBw; height -= slavePtr->doubleBw; /* * The final step is to set the position, size, and mapped/unmapped * state of the slave. If the slave is a child of the master, then * do this here. Otherwise let Tk_MaintainGeometry do the work. */ 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) { goto done; } /* * Don't map the slave if the master isn't mapped: wait * until the master gets mapped later. */ 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); } } /* * Changes to the window's structure could cause almost anything * to happen, including deleting the parent or child. If this * happens, we'll be told to abort. */ if (abort) { goto done; } } done: masterPtr->abortPtr = NULL; Tcl_Release((ClientData) masterPtr);}/* *---------------------------------------------------------------------- * * XExpansion -- * * Given a list of packed slaves, the first of which is packed * on the left or right and is expandable, compute how much to * expand the child. * * Results: * The return value is the number of additional pixels to give to * the child. * * Side effects: * None. * *---------------------------------------------------------------------- */static intXExpansion(slavePtr, cavityWidth) register Packer *slavePtr; /* First in list of remaining * slaves. */ int cavityWidth; /* Horizontal space left for all * remaining slaves. */{ int numExpand, minExpand, curExpand; int childWidth; /* * This procedure is tricky because windows packed top or bottom can * be interspersed among expandable windows packed left or right. * Scan through the list, keeping a running sum of the widths of * all left and right windows (actually, count the cavity space not * allocated) and a running count of all expandable left and right * windows. At each top or bottom window, and at the end of the * list, compute the expansion factor that seems reasonable at that * point. Return the smallest factor seen at any of these points. */ minExpand = cavityWidth; numExpand = 0; for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw + slavePtr->padX + slavePtr->iPadX; if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { curExpand = (cavityWidth - childWidth)/numExpand; if (curExpand < minExpand) { minExpand = curExpand; } } else { cavityWidth -= childWidth; if (slavePtr->flags & EXPAND) { numExpand++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -