/* PlacePanes -- * Places slave panes based on sash positions. */ static void PlacePanes(Paned *pw) { int horizontal = pw->paned.orient == TTK_ORIENT_HORIZONTAL; int width = Tk_Width(pw->core.tkwin), height = Tk_Height(pw->core.tkwin); int sashThickness = pw->paned.sashThickness; int pos = 0; int index; for (index = 0; index < Ttk_NumberSlaves(pw->paned.mgr); ++index) { Pane *pane = Ttk_SlaveData(pw->paned.mgr, index); int size = pane->sashPos - pos; if (size > 0) { if (horizontal) { Ttk_PlaceSlave(pw->paned.mgr, index, pos, 0, size, height); } else { Ttk_PlaceSlave(pw->paned.mgr, index, 0, pos, width, size); } } else { Ttk_UnmapSlave(pw->paned.mgr, index); } pos = pane->sashPos + sashThickness; } }
/* PanedSize -- * Compute the requested size of the paned widget * from the individual pane request sizes. * * Used as the WidgetSpec sizeProc and the ManagerSpec sizeProc. */ static int PanedSize(void *recordPtr, int *widthPtr, int *heightPtr) { Paned *pw = recordPtr; int nPanes = Ttk_NumberSlaves(pw->paned.mgr); int nSashes = nPanes - 1; int sashThickness = pw->paned.sashThickness; int width = 0, height = 0; int index; if (pw->paned.orient == TTK_ORIENT_HORIZONTAL) { for (index = 0; index < nPanes; ++index) { Pane *pane = Ttk_SlaveData(pw->paned.mgr, index); Tk_Window slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, index); if (height < Tk_ReqHeight(slaveWindow)) height = Tk_ReqHeight(slaveWindow); width += pane->reqSize; } width += nSashes * sashThickness; } else { for (index = 0; index < nPanes; ++index) { Pane *pane = Ttk_SlaveData(pw->paned.mgr, index); Tk_Window slaveWindow = Ttk_SlaveWindow(pw->paned.mgr, index); if (width < Tk_ReqWidth(slaveWindow)) width = Tk_ReqWidth(slaveWindow); height += pane->reqSize; } height += nSashes * sashThickness; } *widthPtr = pw->paned.width > 0 ? pw->paned.width : width; *heightPtr = pw->paned.height > 0 ? pw->paned.height : height; return 1; }
static void PanedDisplay(void *recordPtr, Drawable d) { Paned *pw = recordPtr; int i, nSashes = Ttk_NumberSlaves(pw->paned.mgr) - 1; TtkWidgetDisplay(recordPtr, d); for (i = 0; i < nSashes; ++i) { DrawSash(pw, i, d); } }
/* $pw insert $index $slave ?-option value ...? * Insert new slave, or move existing one. */ static int PanedInsertCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Paned *pw = recordPtr; int nSlaves = Ttk_NumberSlaves(pw->paned.mgr); int srcIndex, destIndex; Tk_Window slaveWindow; if (objc < 4) { Tcl_WrongNumArgs(interp, 2,objv, "index slave ?-option value ...?"); return TCL_ERROR; } slaveWindow = Tk_NameToWindow( interp, Tcl_GetString(objv[3]), pw->core.tkwin); if (!slaveWindow) { return TCL_ERROR; } if (!strcmp(Tcl_GetString(objv[2]), "end")) { destIndex = Ttk_NumberSlaves(pw->paned.mgr); } else if (TCL_OK != Ttk_GetSlaveIndexFromObj( interp,pw->paned.mgr,objv[2],&destIndex)) { return TCL_ERROR; } srcIndex = Ttk_SlaveIndex(pw->paned.mgr, slaveWindow); if (srcIndex < 0) { /* New slave: */ return AddPane(interp, pw, destIndex, slaveWindow, objc-4, objv+4); } /* else -- move existing slave: */ if (destIndex >= nSlaves) destIndex = nSlaves - 1; Ttk_ReorderSlave(pw->paned.mgr, srcIndex, destIndex); return objc == 4 ? TCL_OK : ConfigurePane(interp, pw, Ttk_SlaveData(pw->paned.mgr, destIndex), Ttk_SlaveWindow(pw->paned.mgr, destIndex), objc-4,objv+4); }
/* LabelframePlaceSlaves -- * Sets the position and size of the labelwidget. */ static void LabelframePlaceSlaves(void *recordPtr) { Labelframe *lframe = recordPtr; if (Ttk_NumberSlaves(lframe->label.mgr) == 1) { Ttk_Box b; LabelframeDoLayout(recordPtr); b = lframe->label.labelParcel; /* ASSERT: slave #0 is lframe->label.labelWidget */ Ttk_PlaceSlave(lframe->label.mgr, 0, b.x,b.y,b.width,b.height); } }
/* AdjustPanes -- * Set pane request sizes from sash positions. * * NOTE: * AdjustPanes followed by PlaceSashes (called during relayout) * will leave the sashes in the same place, as long as available size * remains contant. */ static void AdjustPanes(Paned *pw) { int sashThickness = pw->paned.sashThickness; int pos = 0; int index; for (index = 0; index < Ttk_NumberSlaves(pw->paned.mgr); ++index) { Pane *pane = Ttk_SlaveData(pw->paned.mgr, index); int size = pane->sashPos - pos; pane->reqSize = size >= 0 ? size : 0; pos = pane->sashPos + sashThickness; } }
/* $pw identify ?what? $x $y -- * Return index of sash at $x,$y */ static int PanedIdentifyCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { const char *whatTable[] = { "element", "sash", NULL }; enum { IDENTIFY_ELEMENT, IDENTIFY_SASH }; int what = IDENTIFY_SASH; Paned *pw = recordPtr; int sashThickness = pw->paned.sashThickness; int nSashes = Ttk_NumberSlaves(pw->paned.mgr) - 1; int x, y, pos; int index; if (objc < 4 || objc > 5) { Tcl_WrongNumArgs(interp, 2,objv, "?what? x y"); return TCL_ERROR; } if ( Tcl_GetIntFromObj(interp, objv[objc-2], &x) != TCL_OK || Tcl_GetIntFromObj(interp, objv[objc-1], &y) != TCL_OK || (objc == 5 && Tcl_GetIndexFromObj(interp, objv[2], whatTable, "option", 0, &what) != TCL_OK) ) { return TCL_ERROR; } pos = pw->paned.orient == TTK_ORIENT_HORIZONTAL ? x : y; for (index = 0; index < nSashes; ++index) { Pane *pane = Ttk_SlaveData(pw->paned.mgr, index); if (pane->sashPos <= pos && pos <= pane->sashPos + sashThickness) { /* Found it. */ switch (what) { case IDENTIFY_SASH: Tcl_SetObjResult(interp, Tcl_NewIntObj(index)); return TCL_OK; case IDENTIFY_ELEMENT: { Ttk_Element element = Ttk_IdentifyElement(SashLayout(pw, index), x, y); if (element) { Tcl_SetObjResult(interp, Tcl_NewStringObj(Ttk_ElementName(element), -1)); } return TCL_OK; } } } } return TCL_OK; /* nothing found - return empty string */ }
/* ShoveDown -- * Same as ShoveUp, but going in the opposite direction * and stopping at the sentinel sash. */ static int ShoveDown(Paned *pw, int i, int pos) { Pane *pane = Ttk_SlaveData(pw->paned.mgr,i); int sashThickness = pw->paned.sashThickness; if (i == Ttk_NumberSlaves(pw->paned.mgr) - 1) { pos = pane->sashPos; /* Sentinel value == master window size */ } else { Pane *nextPane = Ttk_SlaveData(pw->paned.mgr,i+1); if (pos + sashThickness > nextPane->sashPos) pos = ShoveDown(pw, i+1, pos + sashThickness) - sashThickness; } return pane->sashPos = pos; }
/* LabelframeConfigure -- * Configuration hook. */ static int LabelframeConfigure(Tcl_Interp *interp,void *recordPtr,int mask) { Labelframe *lframePtr = recordPtr; Tk_Window labelWidget = lframePtr->label.labelWidget; Ttk_PositionSpec unused; /* Validate options: */ if (mask & LABELWIDGET_CHANGED && labelWidget != NULL) { if (!Ttk_Maintainable(interp, labelWidget, lframePtr->core.tkwin)) { return TCL_ERROR; } } if (TtkGetLabelAnchorFromObj( interp, lframePtr->label.labelAnchorObj, &unused) != TCL_OK) { return TCL_ERROR; } /* Base class configuration: */ if (FrameConfigure(interp, recordPtr, mask) != TCL_OK) { return TCL_ERROR; } /* Update -labelwidget changes, if any: */ if (mask & LABELWIDGET_CHANGED) { if (Ttk_NumberSlaves(lframePtr->label.mgr) == 1) { Ttk_ForgetSlave(lframePtr->label.mgr, 0); /* Restore labelWidget field (see <<NOTE-LABELREMOVED>>) */ lframePtr->label.labelWidget = labelWidget; } if (labelWidget) { Ttk_InsertSlave(lframePtr->label.mgr, 0, labelWidget, NULL); RaiseLabelWidget(lframePtr); } } if (mask & GEOMETRY_CHANGED) { Ttk_ManagerSizeChanged(lframePtr->label.mgr); Ttk_ManagerLayoutChanged(lframePtr->label.mgr); } return TCL_OK; }
/* $pw sashpos $index ?$newpos? * Query or modify sash position. */ static int PanedSashposCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Paned *pw = recordPtr; int sashIndex, position = -1; Pane *pane; if (objc < 3 || objc > 4) { Tcl_WrongNumArgs(interp, 2,objv, "index ?newpos?"); return TCL_ERROR; } if (Tcl_GetIntFromObj(interp, objv[2], &sashIndex) != TCL_OK) { return TCL_ERROR; } if (sashIndex < 0 || sashIndex >= Ttk_NumberSlaves(pw->paned.mgr) - 1) { Tcl_AppendResult(interp, "sash index ", Tcl_GetString(objv[2]), " out of range", NULL); return TCL_ERROR; } pane = Ttk_SlaveData(pw->paned.mgr, sashIndex); if (objc == 3) { Tcl_SetObjResult(interp, Tcl_NewIntObj(pane->sashPos)); return TCL_OK; } /* else -- set new sash position */ if (Tcl_GetIntFromObj(interp, objv[3], &position) != TCL_OK) { return TCL_ERROR; } if (position < pane->sashPos) { ShoveUp(pw, sashIndex, position); } else { ShoveDown(pw, sashIndex, position); } AdjustPanes(pw); Ttk_ManagerLayoutChanged(pw->paned.mgr); Tcl_SetObjResult(interp, Tcl_NewIntObj(pane->sashPos)); return TCL_OK; }
/* $pw add window [ options ... ] */ static int PanedAddCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Paned *pw = recordPtr; Tk_Window slaveWindow; if (objc < 3) { Tcl_WrongNumArgs(interp, 2, objv, "window"); return TCL_ERROR; } slaveWindow = Tk_NameToWindow( interp, Tcl_GetString(objv[2]), pw->core.tkwin); if (!slaveWindow) { return TCL_ERROR; } return AddPane(interp, pw, Ttk_NumberSlaves(pw->paned.mgr), slaveWindow, objc - 3, objv + 3); }
/* $pw panes -- * Return list of managed panes. */ static int PanedPanesCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Paned *pw = recordPtr; Ttk_Manager *mgr = pw->paned.mgr; Tcl_Obj *panes; int i; if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } panes = Tcl_NewListObj(0, NULL); for (i = 0; i < Ttk_NumberSlaves(mgr); ++i) { const char *pathName = Tk_PathName(Ttk_SlaveWindow(mgr,i)); Tcl_ListObjAppendElement(interp, panes, Tcl_NewStringObj(pathName,-1)); } Tcl_SetObjResult(interp, panes); return TCL_OK; }
/* PlaceSashes -- * Set sash positions from pane request sizes and available space. * The sentinel sash position is set to the available space. * * Allocate pane->reqSize pixels to each pane, and distribute * the difference = available size - requested size according * to pane->weight. * * If there's still some left over, squeeze panes from the bottom up * (This can happen if all weights are zero, or if one or more panes * are too small to absorb the required shrinkage). * * Notes: * This doesn't distribute the remainder pixels as evenly as it could * when more than one pane has weight > 1. */ static void PlaceSashes(Paned *pw, int width, int height) { Ttk_Manager *mgr = pw->paned.mgr; int nPanes = Ttk_NumberSlaves(mgr); int sashThickness = pw->paned.sashThickness; int available = pw->paned.orient == TTK_ORIENT_HORIZONTAL ? width : height; int reqSize = 0, totalWeight = 0; int difference, delta, remainder, pos, i; if (nPanes == 0) return; /* Compute total required size and total available weight: */ for (i = 0; i < nPanes; ++i) { Pane *pane = Ttk_SlaveData(mgr, i); reqSize += pane->reqSize; totalWeight += pane->weight * (pane->reqSize != 0); } /* Compute difference to be redistributed: */ difference = available - reqSize - sashThickness*(nPanes-1); if (totalWeight != 0) { delta = difference / totalWeight; remainder = difference % totalWeight; if (remainder < 0) { --delta; remainder += totalWeight; } } else { delta = remainder = 0; } /* ASSERT: 0 <= remainder < totalWeight */ /* Place sashes: */ pos = 0; for (i = 0; i < nPanes; ++i) { Pane *pane = Ttk_SlaveData(mgr, i); int weight = pane->weight * (pane->reqSize != 0); int size = pane->reqSize + delta * weight; if (weight > remainder) weight = remainder; remainder -= weight; size += weight; if (size < 0) size = 0; pane->sashPos = (pos += size); pos += sashThickness; } /* Handle emergency shrink/emergency stretch: * Set sentinel sash position to end of widget, * shove preceding sashes up. */ ShoveUp(pw, nPanes - 1, available); }