1from __future__ import division, print_function 2"""Tools for gridding widgets 3 4History: 52003-05-06 ROwen Adapted from ChangedGridder. 62004-05-18 ROwen Modified _StatusConfigGridSet._makeChangedWdg 7 to eliminate two unused args (colSpan and sticky). 82004-08-11 ROwen Renamed StatusConfigGridSet->_StatusConfigGridSet. 9 Define __all__ to restrict import. 102004-09-14 ROwen Stopped importing RO.Wdg to avoid circular imports. 112004-11-29 ROwen Modified to include ConfigCat as a class constant. 122005-01-05 ROwen Got rid of the changed widget; use autoIsCurrent mode 13 in RO.Wdg widgets to indicate "changed", instead. 142005-05-26 ROwen Bug fix: gridWdg mis-set nextCol if cfgWdg False or None. 15 Improved error message for units and cfgUnits being the same widget. 162006-04-27 ROwen Removed ignored clearMenu and defMenu arguments (thanks pychecker!). 172006-10-31 ROwen Added support adding help text and URL to created widgets. 18 Modified for changed Gridder._BaseGridSet. 192007-12-19 ROwen Added numStatusCols argument. This makes it easier to start all configuration widgets 20 in the same column. 212008-03-14 ROwen Bug fix: removed unused statusCols argument. 222011-05-04 ROwen Bug fix: was not setting _maxNextCol 232015-09-24 ROwen Replace "== None" with "is None" to modernize the code. 242015-11-03 ROwen Replace "!= None" with "is not None" to modernize the code. 252015-11-05 ROwen Changed ==/!= True/False to is/is not True/False to modernize the code. 26""" 27__all__ = ['StatusConfigGridder'] 28 29import Gridder 30 31ConfigCat = "config" 32 33class StatusConfigGridder(Gridder.Gridder): 34 ConfigCat = ConfigCat 35 def __init__(self, 36 master, 37 row = 0, 38 col = 0, 39 sticky = "e", 40 numStatusCols = None, 41 ): 42 """Create an object that grids a set of status and configuration widgets. 43 44 Inputs: 45 - master Master widget into which to grid 46 - row Starting row 47 - col Starting column 48 - sticky Default sticky setting for the status and config widgets 49 - numStatusCols default number of columns for status widgets (including units but not label); 50 if None then the first configuration widget is gridded in the next column after 51 the last status widget. 52 You may wish to specify more columns than required; it is almost always harmless 53 and your code will still work if you add status widgets that use more columns. 54 55 """ 56 Gridder.Gridder.__init__(self, 57 master = master, 58 row = row, 59 col = col, 60 sticky = sticky, 61 ) 62 if numStatusCols is not None: 63 numStatusCols = int(numStatusCols) 64 self._numStatusCols = numStatusCols 65 66 def gridWdg(self, 67 label = None, 68 dataWdg = None, 69 units = None, 70 cfgWdg = None, 71 cat = None, 72 **kargs): 73 """Grids (in order) 74 - labelWdg: a label widget 75 - dataWdg: one or more status widgets 76 - unitsWdg: units 77 (the following are all None if cfgWdg not specified): 78 - cfgWdg: one or more config widgets 79 - cfgUnitsWdg: a config units label 80 81 Configuration widgets are automatically added 82 to the show/hide set ConfigCat and so are hidded by default. 83 To display them you must call showHideWdg(config=True) 84 85 Warning: a widget cannot be gridded twice, so: 86 - Units cannot be an actual widget; it must be a string 87 or variable (or None) 88 - There should be no common widgets in dataWdg or cfgWdg 89 90 Returns a _StatusConfigGridSet object that allows easy access 91 to the various widgets and related information. 92 Increments row.next. 93 94 Notes: 95 - If a widget is None or False then nothing is gridded or added to gs.wdgSet for that widget, 96 but space is handled differently in the two cases: 97 - If a widget is None then the appropriate number of empty columns are used for it 98 - If a widget is False then no columns are used for it 99 - If a label or units widget is "" then an empty RO.Wdg.StrLabel is gridded (which you can then 100 set as you desire). 101 """ 102 basicArgs = self._basicKArgs(**kargs) 103 basicArgs.setdefault("numStatusCols", self._numStatusCols) 104 gs = _StatusConfigGridSet( 105 master = self._master, 106 label = label, 107 dataWdg = dataWdg, 108 cfgWdg = cfgWdg, 109 units = units, 110 **basicArgs) 111 self._nextRow = gs.row + 1 112 self._nextCol = max(gs.nextCol, self._nextCol) 113 self._maxNextCol = max(self._maxNextCol, self._nextCol) 114 115 if cat is not None: 116 self.addShowHideWdg(cat, gs.wdgSet) 117 118 # set show/hide category ConfigCat for configuration widgets 119 if cfgWdg: 120 self.addShowHideWdg(ConfigCat, gs.cfgWdg) 121 self.addShowHideWdg(ConfigCat, gs.cfgUnitsWdg) 122 123 return gs 124 125 126class _StatusConfigGridSet(Gridder._BaseGridSet): 127 def __init__ (self, 128 master, 129 label = None, 130 dataWdg = None, 131 units = None, 132 cfgWdg = None, 133 cfgUnits = None, 134 row = 0, 135 col = 0, 136 colSpan = 1, 137 cfgColSpan = None, 138 sticky = "e", 139 cfgSticky = None, 140 numStatusCols = None, 141 helpText = None, 142 helpURL = None, 143 ): 144 """Creates and grids (in order) the following attributes: 145 - labelWdg: a label widget 146 - dataWdg: one or more status widgets 147 - unitsWdg: units 148 (the following are all None if cfgWdg not specified): 149 - cfgWdg: one or more config widgets 150 - cfgUnitsWdg: a config units label 151 152 Inputs: 153 - label label text, variable, widget, None, False or "" (see Notes) 154 - dataWdg the status widgets: a widget or sequence of widgets, 155 each of which can be None or False (see Notes) 156 - units status units text, variable, widget, None, False or "" (see Notes) 157 - cfgWdg one or more configuration widgets (same rules as dataWdg) 158 - cfgUnits units for the config widget; defaults to units (but see Error Conditions below); 159 ignored if cfgWdg is None or True 160 - cat one or more show/hide categories; if specified then all widgets are added 161 to the show/hide list using these categories 162 - row row in which to grid; -1 means the same row as last time; default is the next row 163 - col column at which to start gridding; default is the default column 164 - colSpan column span for each of the data (status) widgets 165 - cfgColSpan column span for each of the config widgets; defaults to colSpan 166 - sticky sticky option for the status widgets 167 - cfgSticky sticky option for the config widgets; defaults to sticky 168 - numStatusCols number of columns for status widgets (including units but not label); 169 if None then the first configuration widget is gridded in the next column after 170 the last status widget. 171 - helpText help text for any created widgets; if True then copied from the first dataWdg 172 - helpURL help URL for any created widgets; if True then copied from the first dataWdg 173 174 Error Conditions: 175 - Raise ValueError if units and cfgUnits are the same widget (but only if cfgWdg is 176 not None or False, because otherwise cfgUnits is ignored). 177 This is because a widget cannot be gridded in two places. 178 - Raise RuntimeError if numStatusCols is not None and you use more than numStatusCols columns 179 for status widgets 180 """ 181 if cfgColSpan is None: 182 cfgColSpan = colSpan 183 if cfgUnits is None: 184 cfgUnits = units 185 if cfgSticky is None: 186 cfgSticky = sticky 187 if numStatusCols is not None: 188 numStatusCols = int(numStatusCols) 189 190 Gridder._BaseGridSet.__init__(self, 191 master, 192 row, 193 col, 194 helpText = helpText, 195 helpURL = helpURL, 196 ) 197 198 self._numStatusCols = numStatusCols 199 200 self._setHelpFromDataWdg(dataWdg) 201 202 self.labelWdg = self._makeWdg(label) 203 self._gridWdg(self.labelWdg, sticky="e", colSpan=1) 204 205 self.dataWdg = dataWdg 206 self._gridWdg(self.dataWdg, sticky=sticky, colSpan=colSpan) 207 208 self.unitsWdg = self._makeWdg(units) 209 self._gridWdg(self.unitsWdg, sticky="w", colSpan=1) 210 211 if self._numStatusCols is not None: 212 cfgStartCol = self.begCol + 1 + self._numStatusCols # 1 for label 213 overflowCols = self.nextCol - cfgStartCol 214 if overflowCols > 0: 215 raise RuntimeError("Too many status widgets; numStatusCols=%s; num used=%s" % 216 (self._numStatusCols, self._numStatusCols + overflowCols)) 217 self.nextCol = cfgStartCol 218 219 if cfgWdg: 220 self.cfgWdg = cfgWdg 221 self._gridWdg(self.cfgWdg, sticky=cfgSticky, colSpan=cfgColSpan) 222 223 self.cfgUnitsWdg = self._makeWdg(cfgUnits) 224 if self.cfgUnitsWdg and self.cfgUnitsWdg == self.unitsWdg: 225 raise ValueError("units is a widget, so cfgUnits must be specified and must be a different widget") 226 self._gridWdg(self.cfgUnitsWdg, sticky="w", colSpan=1) 227 else: 228 self.cfgWdg = None 229 self.cfgUnitsWdg = None 230 if cfgWdg is not False: 231 self.nextCol += cfgColSpan 232 if cfgUnits is not False: 233 self.nextCol += 1 234