NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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)