layoutGrid.py (26762B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\primitives\layoutGrid.py 2 from __future__ import print_function 3 import weakref 4 from carbonui import uiconst 5 from carbonui.primitives.childrenlist import PyChildrenList as ChildrenList 6 from carbonui.primitives.container import Container 7 from carbonui.primitives.frame import Frame 8 from carbonui.uicore import uicore 9 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay 10 CELLUSED = 1 11 CELLUSED_ROWSPAN = 2 12 TOPBOTTOM_ALIGNMENTS = (uiconst.TOTOP, 13 uiconst.TOBOTTOM, 14 uiconst.TOTOP_NOPUSH, 15 uiconst.TOBOTTOM_NOPUSH, 16 uiconst.TOTOP_PROP, 17 uiconst.TOBOTTOM_PROP) 18 LEFTRIGHT_ALIGNMENTS = (uiconst.TOLEFT, 19 uiconst.TORIGHT, 20 uiconst.TOLEFT_NOPUSH, 21 uiconst.TORIGHT_NOPUSH, 22 uiconst.TOLEFT_PROP, 23 uiconst.TORIGHT_PROP) 24 CENTER_ALIGNMENTS = (uiconst.CENTER, uiconst.CENTERBOTTOM, uiconst.CENTERTOP) 25 26 class LayoutGridCell(Container): 27 rowSpan = 1 28 colSpan = 1 29 gridCellPadding = None 30 _cellPadding = None 31 32 def ApplyAttributes(self, attributes): 33 attributes.state = uiconst.UI_PICKCHILDREN 34 Container.ApplyAttributes(self, attributes) 35 self._content = Container(name='Content', parent=self, align=uiconst.TOALL) 36 self.cellPadding = attributes.cellPadding 37 self.gridCellPadding = attributes.gridCellPadding 38 self.colSpan = attributes.colSpan or 1 39 self.rowSpan = attributes.rowSpan or 1 40 cellObject = attributes.cellObject 41 if cellObject: 42 cellObjectRef = weakref.ref(cellObject) 43 if cellObject.align != uiconst.TOALL: 44 cellObject._originalUpdateAlignment = cellObject.UpdateAlignment 45 cellObject.UpdateAlignment = lambda *args, **kwds: self.UpdateCellObjectAlignment(cellObjectRef(), *args, **kwds) 46 cellObject._originalClose = cellObject.Close 47 cellObject.Close = lambda *args: self.CloseCellObject(cellObjectRef(), *args) 48 cellObject.on_display_changed.connect(self._on_cell_object_display_changed) 49 self._content.children.append(cellObject) 50 51 def _on_cell_object_display_changed(self, cell_object): 52 if self.parent: 53 self.parent.FlagGridLayoutDirty() 54 55 def CloseCellObject(self, cellObject, *args): 56 if cellObject.destroyed: 57 return 58 cellObject._originalClose() 59 cellObject._originalUpdateAlignment = None 60 cellObject._originalClose = None 61 if not self._containerClosing: 62 self.Close() 63 64 def Close(self, *args): 65 parent = self.parent 66 Container.Close(self, *args) 67 if parent and not parent.destroyed and not parent._containerClosing: 68 parent.FlagGridLayoutDirty() 69 70 def UpdateCellObjectAlignment(self, cellObject, *args, **kwds): 71 preX = cellObject.renderObject.displayX 72 preY = cellObject.renderObject.displayY 73 preWidth = cellObject.renderObject.displayWidth 74 preHeight = cellObject.renderObject.displayHeight 75 ret = cellObject._originalUpdateAlignment(*args) 76 if not self.parent: 77 return ret 78 align = cellObject.align 79 if align in TOPBOTTOM_ALIGNMENTS: 80 if preHeight != cellObject.renderObject.displayHeight or preY != cellObject.renderObject.displayY: 81 self.parent.FlagCellSizesDirty() 82 elif align in LEFTRIGHT_ALIGNMENTS: 83 if preWidth != cellObject.renderObject.displayWidth or preX != cellObject.renderObject.displayX: 84 self.parent.FlagCellSizesDirty() 85 elif preX != cellObject.renderObject.displayX: 86 self.parent.FlagCellSizesDirty() 87 elif preY != cellObject.renderObject.displayY: 88 self.parent.FlagCellSizesDirty() 89 elif preWidth != cellObject.renderObject.displayWidth: 90 self.parent.FlagCellSizesDirty() 91 elif preHeight != cellObject.renderObject.displayHeight: 92 self.parent.FlagCellSizesDirty() 93 return ret 94 95 def UpdateBackgrounds(self): 96 if len(self.background) > 0: 97 for each in self.background: 98 each.displayRect = (0, 99 0, 100 self._displayWidth, 101 self._displayHeight) 102 103 @property 104 def cellPadding(self): 105 if self._cellPadding: 106 return self._cellPadding 107 if self.gridCellPadding: 108 return self.gridCellPadding 109 return (0, 0, 0, 0) 110 111 @cellPadding.setter 112 def cellPadding(self, value): 113 if isinstance(value, (tuple, list)): 114 if len(value) == 4: 115 pass 116 elif len(value) == 2: 117 value = (value[0], 118 value[1], 119 value[0], 120 value[1]) 121 elif isinstance(value, int): 122 value = (value, 123 value, 124 value, 125 value) 126 else: 127 value = None 128 if self._cellPadding != value: 129 self._cellPadding = value 130 131 def GetCellObject(self): 132 if self._content.children: 133 return self._content.children[0] 134 135 def GetCellSize(self): 136 neededCellWidth = 0 137 neededCellHeight = 0 138 if self._content.children: 139 self._content.padding = self.cellPadding 140 cellObject = self.GetCellObject() 141 cellObjectAlign = cellObject.align 142 if cellObjectAlign in (uiconst.CENTERLEFT, uiconst.CENTERRIGHT): 143 neededCellWidth = cellObject.left + cellObject.width 144 neededCellHeight = cellObject.top * 2 + cellObject.height 145 elif cellObjectAlign in (uiconst.CENTERTOP, uiconst.CENTERBOTTOM): 146 neededCellWidth = cellObject.left * 2 + cellObject.width 147 neededCellHeight = cellObject.top + cellObject.height 148 elif cellObjectAlign == uiconst.CENTER: 149 neededCellWidth = cellObject.left * 2 + cellObject.width 150 neededCellHeight = cellObject.top * 2 + cellObject.height 151 elif not cellObject.isAffectedByPushAlignment: 152 neededCellWidth = cellObject.left + cellObject.width 153 neededCellHeight = cellObject.top + cellObject.height 154 elif cellObjectAlign in TOPBOTTOM_ALIGNMENTS: 155 neededCellWidth = cellObject.padLeft + cellObject.padRight 156 neededCellHeight = cellObject.height + (cellObject.padTop + cellObject.padBottom + cellObject.top) 157 elif cellObjectAlign in LEFTRIGHT_ALIGNMENTS: 158 neededCellWidth = cellObject.width + (cellObject.padLeft + cellObject.padRight + cellObject.left) 159 neededCellHeight = cellObject.padTop + cellObject.padBottom 160 elif cellObject.align == uiconst.TOALL: 161 neededCellWidth = cellObject.padLeft + cellObject.padRight 162 neededCellHeight = cellObject.padTop + cellObject.padBottom 163 else: 164 neededCellWidth = uicore.ReverseScaleDpi(cellObject.displayWidth) + (cellObject.padLeft + cellObject.padRight) 165 neededCellHeight = uicore.ReverseScaleDpi(cellObject.displayHeight) + (cellObject.padTop + cellObject.padBottom) 166 if self.minWidth: 167 neededCellWidth = max(self.minWidth, neededCellHeight) 168 if self.minHeight: 169 neededCellHeight = max(self.minHeight, neededCellHeight) 170 ccpl, ccpt, ccpr, ccpb = self.cellPadding 171 return (ccpl + neededCellWidth + ccpr, ccpt + neededCellHeight + ccpb) 172 173 @property 174 def pos(self): 175 return (self._left, 176 self._top, 177 self._width, 178 self._height) 179 180 @pos.setter 181 def pos(self, value): 182 left, top, width, height = value 183 self._left = left 184 self._top = top 185 self._width = width 186 self._height = height 187 self.displayX = uicore.ScaleDpiF(self._left) 188 self.displayY = uicore.ScaleDpiF(self._top) 189 self.FlagAlignmentDirty() 190 191 def _SetDisplay(self, value): 192 super(LayoutGridCell, self)._SetDisplay(value) 193 if self.parent: 194 self.parent.FlagGridLayoutDirty() 195 196 197 class LayoutGridRowCell(LayoutGridCell): 198 199 def ApplyAttributes(self, attributes): 200 attributes.align = uiconst.TOPLEFT 201 LayoutGridCell.ApplyAttributes(self, attributes) 202 203 204 class LayoutGrid(Container): 205 default_align = uiconst.TOPLEFT 206 default_columns = 2 207 default_margin = 0 208 default_cellPadding = 0 209 default_cellSpacing = (0, 0) 210 default_cellBgColor = None 211 _nextColumnIndex = 0 212 _sizesDirty = False 213 _layoutDirty = False 214 _fixedGridWidth = None 215 _columns = 2 216 _grid_cellSpacing = (0, 0) 217 _grid_cellPadding = (0, 0, 0, 0) 218 _grid_margin = (0, 0, 0, 0) 219 debug_showCells = False 220 gridSize = (0, 0) 221 OnGridSizeChanged = None 222 223 def ApplyAttributes(self, attributes): 224 Container.ApplyAttributes(self, attributes) 225 self.cellPadding = attributes.get('cellPadding', self.default_cellPadding) 226 self.cellSpacing = attributes.get('cellSpacing', self.default_cellSpacing) 227 self.columns = attributes.get('columns', self.default_columns) 228 self.margin = attributes.get('margin', self.default_margin) 229 self._grid_cellBgColor = attributes.get('cellBgColor', self.default_cellBgColor) 230 self._layoutData = [] 231 self.children.insert = self._InsertChild 232 self.children.append = self._AppendChild 233 self.children.remove = self._RemoveChild 234 self.OnGridSizeChanged = attributes.OnGridSizeChanged 235 236 @property 237 def columns(self): 238 return self._columns 239 240 @columns.setter 241 def columns(self, value): 242 if self._columns != value: 243 self._columns = value 244 self.FlagGridLayoutDirty() 245 246 @property 247 def margin(self): 248 return self._grid_margin 249 250 @margin.setter 251 def margin(self, value): 252 if isinstance(value, (tuple, list)): 253 if len(value) == 4: 254 pass 255 elif len(value) == 2: 256 value = (value[0], 257 value[1], 258 value[0], 259 value[1]) 260 elif isinstance(value, int): 261 value = (value, 262 value, 263 value, 264 value) 265 else: 266 value = (0, 0, 0, 0) 267 if self._grid_margin != value: 268 self._grid_margin = value 269 self.FlagCellSizesDirty() 270 271 @property 272 def cellPadding(self): 273 return self._grid_cellPadding 274 275 @cellPadding.setter 276 def cellPadding(self, value): 277 if isinstance(value, (tuple, list)): 278 if len(value) == 4: 279 pass 280 elif len(value) == 2: 281 value = (value[0], 282 value[1], 283 value[0], 284 value[1]) 285 elif isinstance(value, int): 286 value = (value, 287 value, 288 value, 289 value) 290 else: 291 value = (0, 0, 0, 0) 292 if self._grid_cellPadding != value: 293 self._grid_cellPadding = value 294 for each in self.children: 295 if isinstance(each, LayoutGridCell): 296 each.gridCellPadding = value 297 298 self.FlagCellSizesDirty() 299 300 @property 301 def cellSpacing(self): 302 return self._grid_cellSpacing 303 304 @cellSpacing.setter 305 def cellSpacing(self, value): 306 if isinstance(value, int): 307 value = (value, value) 308 elif isinstance(value, (tuple, list)) and len(value) == 2: 309 value = value 310 else: 311 value = (0, 0) 312 if self._grid_cellSpacing != value: 313 self._grid_cellSpacing = value 314 self.FlagCellSizesDirty() 315 316 def _InsertChild(self, idx, obj): 317 if not isinstance(obj, LayoutGridCell): 318 return self.AddCell(cellObject=obj, idx=idx) 319 return ChildrenList.insert(self.children, idx, obj) 320 321 def _AppendChild(self, obj): 322 self._InsertChild(-1, obj) 323 324 def _RemoveChild(self, obj): 325 if isinstance(obj, LayoutGridCell): 326 return ChildrenList.remove(self.children, obj) 327 return ChildrenList.remove(self.children, obj.parent) 328 329 def FlagCellSizesDirty(self): 330 self._sizesDirty = True 331 self.FlagAlignmentDirty() 332 333 def FlagGridLayoutDirty(self): 334 self._layoutDirty = True 335 self.FlagAlignmentDirty() 336 337 def AddCell(self, cellObject = None, colSpan = 1, rowSpan = 1, cellPadding = None, bgColor = None, cellClipChildren = False, cellClass = None, minWidth = None, minHeight = None, **keywords): 338 if self.destroyed: 339 return 340 if cellObject is None: 341 cellObject = Container() 342 else: 343 cellObjects = [ child.GetCellObject() for child in self.children if isinstance(child, LayoutGridCell) ] 344 if cellObject in cellObjects: 345 raise RuntimeError('This object has already been inserted to the layout grid', cellObject) 346 if cellClass is None: 347 cellClass = LayoutGridCell 348 cell = cellClass(parent=self, align=uiconst.NOALIGN, colSpan=colSpan, rowSpan=rowSpan, cellObject=cellObject, cellPadding=cellPadding, gridCellPadding=self.cellPadding, clipChildren=cellClipChildren, bgColor=bgColor, minWidth=minWidth, minHeight=minHeight) 349 if self.debug_showCells: 350 Frame(bgParent=cell, color=(1, 0, 0, 0.5)) 351 self.FlagGridLayoutDirty() 352 return cell 353 354 def DebugCells(self): 355 self.debug_showCells = True 356 357 def AddRow(self, rowObjects = None, rowClass = None, **keywords): 358 colSpan = keywords.get('colSpan', self.columns) 359 keywords['columns'] = colSpan 360 keywords.setdefault('cellPadding', self.cellPadding) 361 keywords.setdefault('cellSpacing', self.cellSpacing) 362 if rowClass is None: 363 rowClass = LayoutGridRow 364 elif not issubclass(rowClass, LayoutGridRow): 365 raise RuntimeError('rowClass has to be based on LayoutGridRow') 366 rowGrid = rowClass(parentGrid=self, **keywords) 367 if rowObjects: 368 for each in rowObjects: 369 rowGrid.AddCell(cellObject=each) 370 371 self.AddCell(cellObject=rowGrid, colSpan=self.columns, cellClass=LayoutGridRowCell) 372 self.FillRow() 373 return rowGrid 374 375 def Flush(self): 376 for child in self.children[:]: 377 child.Close() 378 379 self.FlagGridLayoutDirty() 380 381 def SetFixedGridWidth(self, fixedWidth = None): 382 if fixedWidth and self.align in TOPBOTTOM_ALIGNMENTS: 383 raise RuntimeError('Cannot set fixedWidth when using TOTOP or TOBOTTOM alignment') 384 elif self.isAffectedByPushAlignment: 385 raise RuntimeError('Cannot set fixed grid size when alignment is', self.alignment) 386 self._fixedGridWidth = fixedWidth 387 self.FlagCellSizesDirty() 388 389 def RefreshGridLayout(self): 390 if self._layoutDirty: 391 self.UpdateGridLayout() 392 if self._sizesDirty: 393 self.UpdateCellsPositionAndSize() 394 if self._layoutDirty or self._sizesDirty: 395 self.RefreshGridLayout() 396 397 def UpdateAlignment(self, *args, **kwds): 398 if self._layoutDirty: 399 self.UpdateGridLayout() 400 if self._sizesDirty: 401 self.UpdateCellsPositionAndSize() 402 return Container.UpdateAlignment(self, *args, **kwds) 403 404 def UpdateCellsPositionAndSize(self): 405 self._sizesDirty = False 406 rowHeights = {} 407 spreadRows = {} 408 columnWidths = {} 409 spreadColumns = [] 410 scaledCellSpacingX, scaledCellSpacingY = self.cellSpacing 411 for rowIndex, columnData in enumerate(self._layoutData): 412 if columnData and isinstance(columnData[0], LayoutGridRowCell): 413 rowCell = columnData[0] 414 rowGrid = rowCell.GetCellObject() 415 if rowGrid._layoutDirty: 416 rowGrid.UpdateGridLayout() 417 if rowGrid._sizesDirty: 418 rowGrid.UpdateCellsPositionAndSize() 419 columnData = rowGrid._layoutData[0] 420 for columnIndex, cell in enumerate(columnData): 421 if cell is None or cell == CELLUSED or cell == CELLUSED_ROWSPAN: 422 rowHeights.setdefault(rowIndex, []).append(0) 423 continue 424 cW, cH = cell.GetCellSize() 425 cW += scaledCellSpacingX 426 cH += scaledCellSpacingY 427 if cell.rowSpan == 1: 428 rowHeights.setdefault(rowIndex, []).append(cH) 429 else: 430 for r in xrange(cell.rowSpan - 1): 431 rowHeights.setdefault(rowIndex + 1, []).append(0) 432 433 spreadRows[rowIndex] = (cell.rowSpan, cH) 434 colSpan = cell.colSpan 435 if columnIndex + colSpan > self._columns: 436 colSpan = min(self._columns - columnIndex, colSpan) 437 if colSpan == 1: 438 columnWidths.setdefault(columnIndex, []).append(cW) 439 if cell.rowSpan - 1: 440 for r in xrange(cell.rowSpan - 1): 441 columnWidths.setdefault(columnIndex, []).append(0) 442 443 else: 444 for i in xrange(colSpan): 445 for r in xrange(cell.rowSpan): 446 columnWidths.setdefault(columnIndex + i, []).append(0) 447 448 spreadColumns.append((rowIndex, 449 columnIndex, 450 colSpan, 451 cW)) 452 453 if spreadColumns: 454 for rowIndex, columnIndex, colSpan, columnWidth in spreadColumns: 455 spreadToColumns = [] 456 used = 0 457 equalSplitWidth = columnWidth / colSpan 458 for i in xrange(colSpan): 459 currentColumnWidth = max(columnWidths[columnIndex + i]) 460 if currentColumnWidth > equalSplitWidth: 461 used += currentColumnWidth 462 else: 463 spreadToColumns.append(columnIndex + i) 464 465 if spreadToColumns: 466 splitWidth = (columnWidth - used) / len(spreadToColumns) 467 for spreadColumnIndex in spreadToColumns: 468 columnWidths[spreadColumnIndex].append(splitWidth) 469 470 for rowIndex, (rowSpan, spanHeight) in spreadRows.iteritems(): 471 totalHeight = 0 472 for i in xrange(rowSpan - 1): 473 if rowIndex + i in rowHeights: 474 totalHeight += max(rowHeights[rowIndex + i]) 475 476 if rowIndex + rowSpan - 1 in rowHeights: 477 currentHeight = max(rowHeights[rowIndex + rowSpan - 1]) 478 else: 479 currentHeight = 0 480 rowHeights[rowIndex + rowSpan - 1] = [max(currentHeight, spanHeight - totalHeight)] 481 482 colsMaxed = [ (k, max(v)) for k, v in columnWidths.items() ] 483 colsMaxed.sort() 484 rowsMaxed = [ (k, max(v)) for k, v in rowHeights.items() ] 485 rowsMaxed.sort() 486 if getattr(self, 'doPrint', False): 487 print('=' * 30) 488 print('spreadRows', spreadRows) 489 print('spreadColumns', spreadColumns) 490 print('rowHeights', rowHeights) 491 print('columnWidths', columnWidths) 492 print('rowsMaxed', rowsMaxed) 493 print('colsMaxed', colsMaxed) 494 print('scaledCellSpacingY', scaledCellSpacingY) 495 print('scaledCellSpacingX', scaledCellSpacingX) 496 print('=' * 30) 497 ml, mt, mr, mb = self.margin 498 maxScaledHeight = 0 499 maxScaledWidth = 0 500 for rowIndex, columnData in enumerate(self._layoutData): 501 for columnIndex, cell in enumerate(columnData): 502 if cell is None or cell == CELLUSED or cell == CELLUSED_ROWSPAN: 503 continue 504 rowSpan = cell.rowSpan 505 colSpan = cell.colSpan 506 if columnIndex + colSpan > self._columns: 507 colSpan = min(self._columns - columnIndex, colSpan) 508 cellWidth = sum([ colsMaxed[columnIndex + i][1] for i in xrange(colSpan) ]) - scaledCellSpacingX 509 cellHeight = sum([ rowsMaxed[rowIndex + i][1] for i in xrange(rowSpan) ]) - scaledCellSpacingY 510 cellLeft = sum([ w[1] for w in colsMaxed[:columnIndex] ]) 511 cellTop = sum([ h[1] for h in rowsMaxed[:rowIndex] ]) 512 maxScaledWidth = max(maxScaledWidth, cellLeft + cellWidth) 513 maxScaledHeight = max(maxScaledHeight, cellTop + cellHeight) 514 cell.pos = (ml + cellLeft, 515 mt + cellTop, 516 cellWidth, 517 cellHeight) 518 cell.name = 'Row%s_Col%s' % (rowIndex, columnIndex) 519 520 cell = columnData[0] 521 if isinstance(cell, LayoutGridRowCell): 522 rowGrid = cell.GetCellObject() 523 rowColumnData = rowGrid._layoutData[0] 524 for columnIndex, cell in enumerate(rowColumnData): 525 if cell is None or cell == CELLUSED or cell == CELLUSED_ROWSPAN: 526 continue 527 rowSpan = cell.rowSpan 528 colSpan = cell.colSpan 529 if columnIndex + colSpan > self._columns: 530 colSpan = min(self._columns - columnIndex, colSpan) 531 rowCellWidth = sum([ colsMaxed[columnIndex + i][1] for i in xrange(colSpan) ]) - scaledCellSpacingX 532 rowCellHeight = sum([ rowsMaxed[rowIndex + i][1] for i in xrange(rowSpan) ]) - scaledCellSpacingY 533 rowCellLeft = sum([ w[1] for w in colsMaxed[:columnIndex] ]) 534 rowCellTop = 0 535 cell.pos = (rowCellLeft, 536 rowCellTop, 537 rowCellWidth, 538 rowCellHeight) 539 cell.name = 'RowGrid_Row%s_Col%s' % (rowIndex, columnIndex) 540 541 rowGrid.width = cellWidth 542 rowGrid.height = cellHeight 543 rowGrid._sizesDirty = False 544 rowGrid._layoutDirty = False 545 546 if not isinstance(self, LayoutGridRow): 547 self.gridSize = (max(self._fixedGridWidth, maxScaledWidth) + ml + mr, maxScaledHeight + mt + mb) 548 preWidth, preHeight = self.width, self.height 549 if self.align in TOPBOTTOM_ALIGNMENTS: 550 self.width = 0 551 self.height = maxScaledHeight + mt + mb 552 elif self.align in LEFTRIGHT_ALIGNMENTS: 553 self.width = max(self._fixedGridWidth, maxScaledWidth) + ml + mr 554 self.height = 0 555 elif not self.isAffectedByPushAlignment: 556 self.width = max(self._fixedGridWidth, maxScaledWidth) + ml + mr 557 self.height = maxScaledHeight + mt + mb 558 if self.OnGridSizeChanged and (self.width, self.height) != (preWidth, preHeight): 559 self.OnGridSizeChanged(self.width, self.height) 560 561 def UpdateGridLayout(self): 562 rows = [] 563 rowIndex = 0 564 columnIndex = 0 565 taken = [] 566 for cell in self.children: 567 if not cell.display or not cell.GetCellObject().display: 568 continue 569 rowSpan = cell.rowSpan 570 colSpan = cell.colSpan 571 if (rowIndex, columnIndex) in taken: 572 rowIndex, columnIndex = self.GetFirstEmpty(rows) 573 if columnIndex + colSpan > self._columns: 574 colSpan = min(self._columns - columnIndex, colSpan) 575 for columnIndexShift in xrange(colSpan): 576 for rowIndexShift in xrange(rowSpan): 577 while len(rows) <= rowIndex + rowIndexShift: 578 rows.append([None] * self._columns) 579 580 if rows[rowIndex + rowIndexShift][columnIndex + columnIndexShift]: 581 cell.colSpan = columnIndexShift 582 continue 583 if not columnIndexShift: 584 if not rowIndexShift: 585 register = cell 586 else: 587 register = CELLUSED_ROWSPAN 588 else: 589 register = CELLUSED 590 taken.append((rowIndex + rowIndexShift, columnIndex + columnIndexShift)) 591 rows[rowIndex + rowIndexShift][columnIndex + columnIndexShift] = register 592 593 columnIndex = min(self._columns, columnIndex + colSpan) 594 if columnIndex == self._columns: 595 columnIndex = 0 596 rowIndex += 1 597 598 self._nextColumnIndex = columnIndex 599 self._layoutData = rows 600 self._layoutDirty = False 601 self._sizesDirty = True 602 603 def GetFirstEmpty(self, rows): 604 rowIndex = 0 605 for rowData in rows: 606 for columnIndex, cell in enumerate(rowData): 607 if cell is None: 608 return (rowIndex, columnIndex) 609 610 rowIndex += 1 611 612 rows.append([None] * self._columns) 613 return (rowIndex, 0) 614 615 def FillRow(self): 616 self.UpdateGridLayout() 617 if self._nextColumnIndex != 0: 618 self.AddCell() 619 self.FillRow() 620 621 622 class LayoutGridRow(LayoutGrid): 623 624 def ApplyAttributes(self, attributes): 625 self.parentGrid = weakref.ref(attributes.parentGrid) 626 LayoutGrid.ApplyAttributes(self, attributes) 627 628 def FlagCellSizesDirty(self): 629 self._sizesDirty = True 630 if self.parentGrid: 631 parentGrid = self.parentGrid() 632 if parentGrid: 633 parentGrid.FlagCellSizesDirty() 634 635 def FlagGridLayoutDirty(self): 636 self._layoutDirty = True 637 if self.parentGrid: 638 parentGrid = self.parentGrid() 639 if parentGrid: 640 parentGrid.FlagGridLayoutDirty() 641 642 def _InsertChild(self, idx, obj): 643 if len(self.children) == self.columns: 644 raise RuntimeError('The layout grid row is configured for %s columns layout and all columns are taken' % self.columns) 645 return LayoutGrid._InsertChild(self, idx, obj) 646 647 def _SetDisplay(self, value): 648 super(LayoutGridRow, self)._SetDisplay(value) 649 self.FlagCellSizesDirty() 650 651 652 class ListEntryLayoutGridRow(LayoutGridRow): 653 default_state = uiconst.UI_NORMAL 654 655 def __init__(self, **kw): 656 super(LayoutGridRow, self).__init__(**kw) 657 self._construct_underlay() 658 659 def _construct_underlay(self): 660 self.underlay = ListEntryUnderlay(bgParent=self) 661 662 def OnMouseEnter(self, *args): 663 self.underlay.OnMouseEnter(*args) 664 665 def OnMouseExit(self, *args): 666 self.underlay.OnMouseExit(*args)