def getGrid(self): headerNames = [u'', u''] grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) grid.DisableDragRowSize() grid.SetRowLabelSize(0) grid.EnableReorderRows(False) grid.CreateGrid(len(self.modelFields) + 1, len(headerNames)) for col, h in enumerate(headerNames): grid.SetColLabelValue(col, h) grid.Show(False) for row, fd in enumerate(self.modelFields): grid.SetCellValue(row, 0, fd.name) grid.SetCellAlignment(row, 0, wx.ALIGN_RIGHT, wx.ALIGN_BOTTOM) grid.SetCellValue(row, 1, fd.getText()) row = len(self.modelFields) grid.SetCellValue(row, 0, _('Competition Format')) grid.SetCellAlignment(row, 0, wx.ALIGN_RIGHT, wx.ALIGN_BOTTOM) grid.SetCellValue( row, 1, self.competitionFormatCtrl.GetStringSelection().split( u'.', 1)[1].strip()) return grid
def writeKOMGC(): if not model.kom_gc: return riderFields = set( model.registration.getFieldsInUse() ) headers = ( ['place', 'bib', 'last_name', 'first_name', 'team'] + (['uci_id'] if 'uci_id' in riderFields else []) + (['license'] if 'license' in riderFields else []) + ['KOM Total', 'HC Wins', 'C1 Wins', 'C2 Wins', 'C3 Wins', 'C4 Wins', 'GC'] ) grid = ReorderableGrid( notebook ) grid.CreateGrid( len(model.kom_gc), len(headers) ) grid.EnableReorderRows( False ) for col, h in enumerate(headers): attr = gridlib.GridCellAttr() attr.SetReadOnly() if h in Model.Result.NumericFields or h in {'KOM Total', 'HC Wins', 'C1 Wins', 'C2 Wins', 'C3 Wins', 'C4 Wins', 'GC'}: attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_CENTRE ) grid.SetColAttr( col, attr ) grid.SetColLabelValue( col, Utils.fieldToHeader(h, True) ) rowNum = 0 for place, r in enumerate(model.kom_gc, 1): try: rider = model.registration.bibToRider[r[-1]] except KeyError: continue col = 0 grid.SetCellValue( rowNum, col, unicode(place) ); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.bib) ); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.last_name).upper()); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.first_name) ); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.team) ); col += 1 if 'uci_id' in riderFields: grid.SetCellValue( rowNum, col, unicode(rider.uci_id) ); col += 1 if 'license' in riderFields: grid.SetCellValue( rowNum, col, unicode(rider.license) ); col += 1 for v in r[:-1]: grid.SetCellValue( rowNum, col, unicode(v) if v else u'' ); col += 1 rowNum +=1 grid.AutoSize() return grid
def writeTeamClass( stage ): headers = ['Place', 'Team', 'Gap', 'Combined\nTimes', 'Combined\nPlaces', 'Best\nRider GC'] grid = ReorderableGrid( notebook ) grid.CreateGrid( len(stage.team_classification), len(headers) ) grid.EnableReorderRows( False ) for col, h in enumerate(headers): attr = gridlib.GridCellAttr() attr.SetReadOnly() if h != 'Team': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_CENTRE ) grid.SetColAttr( col, attr ) grid.SetColLabelValue( col, h ) rowNum = 0 gapLast = None timeLast = None for place, tc in enumerate(stage.team_classification, 1): col = 0 grid.SetCellValue( rowNum, col, unicode(place) ); col += 1 grid.SetCellValue( rowNum, col, tc.team ); col += 1 grid.SetCellValue( rowNum, col, Utils.formatTime(tc.gap, twoDigitHours=True) if tc.gap != gapLast else sameGap ) gapLast = tc.gap col += 1 timeCur = tc.sum_best_top_times.value grid.SetCellValue( rowNum, col, Utils.formatTime(timeCur, forceHours=True) if timeCur != timeLast else sameTime ) timeLast = timeCur setComment( rowNum, col, formatContext(tc.sum_best_top_times.context), {'width':256} ) col += 1 grid.SetCellValue( rowNum, col, unicode(tc.sum_best_top_places.value) ) setComment( rowNum, col, formatContext(tc.sum_best_top_places.context), {'width':256} ) col += 1 grid.SetCellValue( rowNum, col, unicode(tc.best_place.value) ) setComment( rowNum, col, formatContext(tc.best_place.context), {'width':256} ) col += 1 rowNum +=1 grid.GetGridWindow().Bind(wx.EVT_MOTION, getCommentCallback(grid)) grid.AutoSize() return grid
class Qualifiers(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) font = GetFont() self.title = wx.StaticText( self, wx.ID_ANY, "Enter each rider's qualifying time in hh:mm:ss.ddd format. Use a colon ':' a space, or a dash '-' to separate hour, minute and seconds." ) self.title.SetFont(font) self.renumberButton = wx.Button(self, wx.ID_ANY, 'Renumber Bibs by Time') self.renumberButton.SetFont(font) self.renumberButton.Bind(wx.EVT_BUTTON, self.doRenumber) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.title, 0, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=6) hs.AddStretchSpacer() hs.Add(self.renumberButton, 0, flag=wx.ALL, border=6) self.headerNames = ['Bib', 'Name', 'Team', 'Time', 'Status'] self.iTime = next(i for i, n in enumerate(self.headerNames) if n.startswith('Time')) self.iStatus = next(i for i, n in enumerate(self.headerNames) if n.startswith('Status')) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) self.setColNames() self.grid.EnableReorderRows(False) # Set specialized editors for appropriate columns. self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): attr = gridlib.GridCellAttr() attr.SetFont(font) if col == self.iTime: attr.SetEditor(HighPrecisionTimeEditor()) attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) elif col == self.iStatus: attr.SetEditor( gridlib.GridCellChoiceEditor(choices=['', 'DNQ'])) attr.SetReadOnly(False) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) else: if col == 0: attr.SetRenderer(gridlib.GridCellNumberRenderer()) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(hs, 0, flag=wx.ALL | wx.EXPAND, border=6) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) def getGrid(self): return self.grid def setColNames(self): for col, headerName in enumerate(self.headerNames): self.grid.SetColLabelValue(col, headerName) def setTestData(self): self.grid.ClearGrid() testData = TestData.getTestData() Utils.AdjustGridSize(self.grid, rowsRequired=len(testData)) for row, data in enumerate(testData): bib = data[0] name = data[1] + ' ' + data[2] team = data[3] time = data[-1] for col, d in enumerate([bib, name, team, time]): self.grid.SetCellValue(row, col, u' {}'.format(d)) # Fix up the column and row sizes. self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def refresh(self): model = Model.model riders = model.riders self.renumberButton.Show(model.competition.isMTB) Utils.AdjustGridSize(self.grid, rowsRequired=len(riders)) for row, r in enumerate(riders): for col, value in enumerate([ u'{}'.format(r.bib), r.full_name, r.team, r.qualifyingTimeText ]): self.grid.SetCellValue(row, col, value) # Fix up the column and row sizes. self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) self.grid.SetColSize(self.grid.GetNumberCols() - 1, 96) self.Layout() self.Refresh() def setQT(self): # The qualifying times can be changed at any time, however, if the competition is under way, the events cannot # be adjusted. model = Model.model riders = model.riders self.grid.SaveEditControlValue() for row in six.moves.range(self.grid.GetNumberRows()): v = self.grid.GetCellValue(row, self.iTime).strip() if v: qt = Utils.StrToSeconds(v) else: qt = Model.QualifyingTimeDefault qt = min(qt, Model.QualifyingTimeDefault) status = self.grid.GetCellValue(row, self.iStatus).strip() rider = riders[row] if rider.qualifyingTime != qt or rider.status != status: rider.qualifyingTime = qt rider.status = status model.setChanged(True) def commit(self): # The qualifying times can be changed at any time, however, if the competition is underway, the events cannot # be adusted. model = Model.model riders = model.riders self.setQT() if model.canReassignStarters(): model.setQualifyingTimes() Utils.getMainWin().resetEvents() def doRenumber(self, event): if not Utils.MessageOKCancel( self, 'Sequence Bib numbers in Increasing Order by Qualifying Time.\n\nContinue?', 'Renumber Riders'): return self.setQT() model = Model.model riders = sorted(model.riders, key=lambda x: x.keyQualifying()) for r, rider in enumerate(riders, 1): rider.bib = r wx.CallAfter(self.refresh)
class RestartDialog(wx.Dialog): def __init__(self, parent, id=wx.ID_ANY): wx.Dialog.__init__(self, parent, id, "Restart", style=wx.DEFAULT_DIALOG_STYLE | wx.TAB_TRAVERSAL) font = GetFont() sizer = wx.BoxSizer(wx.VERTICAL) self.SetBackgroundColour(wx.WHITE) bitmap = wx.Bitmap(os.path.join(Utils.getImageFolder(), 'refresh.png'), wx.BITMAP_TYPE_PNG) restartBitmap = wx.StaticBitmap(self, wx.ID_ANY, bitmap) title = wx.StaticText(self, label='Restart Status Changes') title.SetFont(font) self.titleText = title hsTitle = wx.BoxSizer(wx.HORIZONTAL) hsTitle.Add(restartBitmap, 0, flag=wx.EXPAND | wx.ALL, border=4) hsTitle.Add(title, 0, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) sizer.Add(hsTitle, flag=wx.EXPAND) self.headerNames = ['Bib', 'Name', 'Team', 'Status '] self.iColStatus = len(self.headerNames) - 1 self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.EnableReorderRows(False) self.grid.SetRowLabelSize(0) self.grid.CreateGrid(0, len(self.headerNames)) sizer.Add(self.grid, 1, flag=wx.ALL | wx.EXPAND, border=4) hs = wx.BoxSizer(wx.HORIZONTAL) self.okButton = MakeRoundButton(self, 'OK') self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) hs.Add(self.cancelButton, flag=wx.ALL, border=4) hs.AddStretchSpacer() hs.Add(self.okButton, flag=wx.ALL, border=4) self.okButton.Bind(wx.EVT_BUTTON, self.onOK) self.cancelButton.Bind(wx.EVT_BUTTON, self.onCancel) sizer.Add(hs, 0, flag=wx.EXPAND) self.SetSizer(sizer) def refresh(self, event): self.event = event start = event.starts[-1] state = event.competition.state font = GetFont() startPositions = start.startPositions Utils.AdjustGridSize(self.grid, rowsRequired=len(startPositions)) self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) attr = gridlib.GridCellAttr() attr.SetFont(font) if self.headerNames[col] == 'Bib': attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) elif col == 1 or col == 2: attr.SetReadOnly(True) elif self.headerNames[col].startswith('Status'): if len(start.getRemainingComposition()) > 2: choices = ['DQ', 'DNF', ''] self.titleText.SetLabel(u'Restart Status Change') else: choices = ['Inside', ''] self.titleText.SetLabel(u'Restart Position Change') attr.SetEditor(gridlib.GridCellChoiceEditor(choices=choices)) self.grid.SetColAttr(col, attr) for row, p in enumerate(startPositions): rider = state.labels[p] for col, v in enumerate( [rider.bib, rider.full_name, rider.team, '']): self.grid.SetCellValue(row, col, u' {}'.format(v)) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) self.GetSizer().Layout() self.GetSizer().Fit(self) self.CentreOnParent(wx.BOTH) self.SetFocus() def commit(self): places = [] for row in six.moves.range(self.grid.GetNumberRows()): bib = self.grid.GetCellValue(row, 0) status = self.grid.GetCellValue(row, self.iColStatus) warning = self.grid.GetCellValue(row, self.iColWarning) relegation = self.grid.GetCellValue(row, self.iColRelegation) places.append((bib, status, warning, relegation)) start = self.event.starts[-1] start.setPlaces(places) start.restartRequired = True self.event.propagate() Model.model.competition.propagate() Model.model.setChanged(True) Utils.setTitle() def onOK(self, event): self.commit() self.EndModal(wx.ID_OK) def onCancel(self, event): self.EndModal(wx.ID_CANCEL)
class EventFinishOrderConfirmDialog(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent) self.SetBackgroundColour(wx.WHITE) vs = wx.BoxSizer(wx.VERTICAL) font = GetFont() bitmap = wx.Bitmap( os.path.join(Utils.getImageFolder(), 'checkered_flag_wavy.png'), wx.BITMAP_TYPE_PNG) flagBitmap = wx.StaticBitmap(self, wx.ID_ANY, bitmap) title = wx.StaticText(self, label='Confirm Event Result') title.SetFont( wx.Font((0, int(FontSize * 1.5)), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) hsTitle = wx.BoxSizer(wx.HORIZONTAL) hsTitle.Add(flagBitmap, 0, flag=wx.EXPAND | wx.ALL, border=4) hsTitle.Add(title, 0, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) vs.Add(hsTitle, flag=wx.EXPAND) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.EnableReorderRows(False) self.grid.CreateGrid(2, 6) self.grid.SetRowLabelSize(0) self.grid.SetLabelFont(font) vs.Add(self.grid, 1, flag=wx.ALL | wx.EXPAND, border=4) self.okButton = MakeRoundButton(self, 'OK') self.okButton.Bind(wx.EVT_BUTTON, self.onOK) self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) self.cancelButton.Bind(wx.EVT_BUTTON, self.onCancel) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.okButton, 0, flag=wx.ALL | wx.EXPAND, border=4) hs.AddStretchSpacer() hs.Add(self.cancelButton, 0, flag=wx.ALL | wx.EXPAND, border=4) vs.Add(hs, 0, flag=wx.ALL | wx.EXPAND, border=4) self.SetSizer(vs) def refresh(self, grid): font = GetFont() Utils.AdjustGridSize(self.grid, rowsRequired=grid.GetNumberRows(), colsRequired=grid.GetNumberCols() + 1) self.grid.SetColLabelValue(0, 'Pos') attr = gridlib.GridCellAttr() attr.SetFont(font) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) self.grid.SetColAttr(0, attr) iColStatus = None for col in six.moves.range(grid.GetNumberCols()): headerName = grid.GetColLabelValue(col) self.grid.SetColLabelValue(col + 1, headerName) attr = gridlib.GridCellAttr() attr.SetFont(font) if headerName == 'Bib': attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) elif headerName.startswith('Time'): attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) elif headerName.startswith('Status'): iColStatus = col elif headerName.startswith('Warn'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) attr.SetRenderer(gridlib.GridCellBoolRenderer()) elif headerName.startswith('Rel'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) attr.SetRenderer(gridlib.GridCellBoolRenderer()) attr.SetReadOnly(True) self.grid.SetColAttr(col + 1, attr) results = [[ grid.GetCellValue(row, col) for col in six.moves.range(grid.GetNumberCols()) ] for row in six.moves.range(grid.GetNumberRows())] results.sort(key=lambda x: x[iColStatus]) for row in six.moves.range(grid.GetNumberRows()): self.grid.SetCellValue(row, 0, u'{}'.format(row + 1)) for col in six.moves.range(grid.GetNumberCols()): v = results[row][col] self.grid.SetCellValue(row, col + 1, v if v != '0.000' else '') self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) self.GetSizer().Layout() self.GetSizer().Fit(self) self.CentreOnParent(wx.BOTH) self.SetFocus() def onOK(self, event): self.EndModal(wx.ID_OK) def onCancel(self, event): self.EndModal(wx.ID_CANCEL)
class EventSelect(EnablePanel): def __init__(self, parent): EnablePanel.__init__(self, parent) self.box = wx.StaticBox(self, label=u'Available Events') boxSizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) self.SetBackgroundColour(wx.WHITE) self.events = [] self.event = None self.activeBar = EnableBar(self) self.activeBar.SetToolTip( wx.ToolTip(u'\n'.join([ u'Click on an available Event in the table.', u'Then press Select.', ]))) self.selectButton = MakeRoundButton(self, 'Select', isSelect) self.headerNames = ['Event', 'Bib', 'Name', 'Team', 'In', 'Out'] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.CreateGrid(0, len(self.headerNames)) self.grid.EnableReorderRows(False) self.grid.SetRowLabelSize(40) self.grid.SetSelectionMode(gridlib.Grid.SelectRows) font = GetFont() self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) attr = gridlib.GridCellAttr() attr.SetFont(font) attr.SetRenderer(GridCellMultiLineStringRenderer()) attr.SetReadOnly(True) if self.headerNames[col] == 'Bib': attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) self.grid.SetColAttr(col, attr) self.clock = Clock(self, size=(128, 128)) self.clock.SetBackgroundColour(wx.WHITE) boxSizer.Add(self.activeBar, 0, flag=wx.ALL | wx.EXPAND, border=4) vs = wx.BoxSizer(wx.VERTICAL) vs.AddSpacer( int(self.grid.GetColLabelSize() + FontSize * 1.15 - RoundButtonSize / 2)) vs.Add(self.selectButton, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) boxSizer.Add(vs, 0, flag=wx.ALL, border=4) boxSizer.Add(self.grid, 1, flag=wx.ALL | wx.EXPAND, border=4) boxSizer.Add(self.clock, 0, flag=wx.ALL, border=4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(boxSizer, 1, flag=wx.EXPAND) self.SetSizer(sizer) def SetEnable(self, enable): EnablePanel.SetEnable(self, enable) for b, t in [(self.selectButton, isSelect)]: EnableRoundButton(b, enable, t) self.activeBar.SetBackgroundColour( wx.Colour(0, 128, 0) if enable else wx.WHITE) self.Refresh() def refresh(self): self.grid.ClearGrid() model = Model.model if not model: return self.events = [e for t, s, e in model.competition.getCanStart()] self.events.sort( key=lambda e: (0 if e == self.event else 1, e.tournament.i, e. system.i, e.getHeat(), e.i)) Utils.AdjustGridSize(self.grid, rowsRequired=len(self.events)) for row, e in enumerate(self.events): for col, v in enumerate([ e.multi_line_name, e.multi_line_bibs, e.multi_line_rider_names, e.multi_line_rider_teams, e.multi_line_inlabels, e.multi_line_outlabels ]): self.grid.SetCellValue(row, col, u' {}'.format(v)) if e.system != self.events[0].system: for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellBackgroundColour( row, col, InactiveBackgroundColour) else: for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellBackgroundColour(row, col, wx.WHITE) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) if self.events: self.grid.SelectRow(0)
class TimeTrialRecord( wx.Panel ): def __init__( self, parent, controller, id = wx.ID_ANY ): wx.Panel.__init__(self, parent, id) self.SetBackgroundColour( wx.WHITE ) self.controller = controller self.headerNames = [_('Time'), _('Bib')] self.maxRows = 10 fontSize = 18 self.font = wx.FontFromPixelSize( wx.Size(0,fontSize), wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL ) self.bigFont = wx.FontFromPixelSize( wx.Size(0,int(fontSize*1.3)), wx.FONTFAMILY_SWISS, wx.NORMAL, wx.FONTWEIGHT_NORMAL ) self.vbs = wx.BoxSizer(wx.VERTICAL) tapForTimeLabel = _('Tap for Time') if 'WXMAC' in wx.Platform: self.recordTimeButton = wx.lib.buttons.ThemedGenButton( self, label=tapForTimeLabel ) self.recordTimeButton.Bind( wx.EVT_BUTTON, self.doRecordTime ) else: self.recordTimeButton = wx.Button( self, label=tapForTimeLabel ) self.recordTimeButton.Bind( wx.EVT_LEFT_DOWN, self.doRecordTime ) self.recordTimeButton.SetFont( self.bigFont ) self.recordTimeButton.SetToolTip(wx.ToolTip(u'\n'.join( [_('Tap to Record Times (or press the "t" key).'), _('Then enter the Bib numbers and Save as soon as possible.')]) )) hbs = wx.BoxSizer( wx.HORIZONTAL ) hbs.Add( self.recordTimeButton, 0 ) self.grid = ReorderableGrid( self, style = wx.BORDER_SUNKEN ) self.grid.SetFont( self.font ) self.grid.EnableReorderRows( False ) dc = wx.WindowDC( self.grid ) dc.SetFont( self.font ) width, height = dc.GetTextExtent(" 999 ") self.rowLabelSize = width self.grid.SetRowLabelSize( self.rowLabelSize ) self.grid.CreateGrid( self.maxRows, len(self.headerNames) ) self.grid.Bind( gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.doClickLabel ) for col, name in enumerate(self.headerNames): self.grid.SetColLabelValue( col, name ) self.grid.SetLabelFont( self.font ) for col in xrange(self.grid.GetNumberCols()): attr = gridlib.GridCellAttr() attr.SetFont( self.font ) if col == 0: attr.SetEditor( HighPrecisionTimeEditor() ) elif col == 1: attr.SetRenderer( gridlib.GridCellNumberRenderer() ) attr.SetEditor( gridlib.GridCellNumberEditor() ) self.grid.SetColAttr( col, attr ) saveLabel = _('Save') if 'WXMAC' in wx.Platform: self.commitButton = wx.lib.buttons.ThemedGenButton( self, label=saveLabel ) else: self.commitButton = wx.Button( self, label=saveLabel ) self.commitButton.Bind( wx.EVT_BUTTON, self.doCommit ) self.commitButton.SetFont( self.bigFont ) self.commitButton.SetToolTip(wx.ToolTip(_('Save Entries (or press the "s" key)'))) self.vbs.Add( hbs, 0, flag=wx.ALL|wx.EXPAND, border = 4 ) self.vbs.Add( self.grid, 1, flag=wx.ALL|wx.EXPAND, border = 4 ) self.vbs.Add( self.commitButton, flag=wx.ALL|wx.ALIGN_RIGHT, border = 4 ) idRecordAcceleratorId, idCommitAccelleratorId = wx.NewId(), wx.NewId() self.Bind(wx.EVT_MENU, self.doRecordTime, id=idRecordAcceleratorId) self.Bind(wx.EVT_MENU, self.doCommit, id=idCommitAccelleratorId) accel_tbl = wx.AcceleratorTable([ (wx.ACCEL_NORMAL, ord('T'), idRecordAcceleratorId), (wx.ACCEL_NORMAL, ord('S'), idCommitAccelleratorId), ]) self.SetAcceleratorTable(accel_tbl) self.SetSizer(self.vbs) self.Fit() def doClickLabel( self, event ): if event.GetCol() == 0: self.doRecordTime( event ) def doRecordTime( self, event ): t = Model.race.curRaceTime() # Trigger the camera. with Model.LockRace() as race: if not race: return if race.enableUSBCamera: race.photoCount += TakePhoto( 0, StrToSeconds(formatTime(t)) ) # Find the last row without a time. self.grid.SetGridCursor( 0, 0, ) emptyRow = self.grid.GetNumberRows() + 1 success = False for i in xrange(2): for row in xrange(self.grid.GetNumberRows()): if not self.grid.GetCellValue(row, 0): emptyRow = row break if emptyRow >= self.grid.GetNumberRows(): self.doCommit( event ) else: success = True break if not success: Utils.MessageOK( self, u'\n'.join([ _('Insufficient space to Record Time.'), _('Enter Bib numbers and press Commit.'), _('Or delete some entries')]), _('Record Time Failed.') ) return self.grid.SetCellValue( emptyRow, 0, formatTime(t) ) # Set the edit cursor at the first empty bib position. for row in xrange(self.grid.GetNumberRows()): text = self.grid.GetCellValue(row, 1) if not text or text == '0': self.grid.SetGridCursor( row, 1 ) break def doCommit( self, event ): self.grid.SetGridCursor( 0, 0, ) # Find the last row without a time. timesBibs = [] timesNoBibs = [] for row in xrange(self.grid.GetNumberRows()): tStr = self.grid.GetCellValue(row, 0).strip() if not tStr: continue bib = self.grid.GetCellValue(row, 1).strip() try: bib = int(bib) except (TypeError, ValueError): bib = 0 if bib: timesBibs.append( (tStr, bib) ) else: timesNoBibs.append( tStr ) for row in xrange(self.grid.GetNumberRows()): for column in xrange(self.grid.GetNumberCols()): self.grid.SetCellValue(row, column, '' ) ''' for row, tStr in enumerate(timesNoBibs): self.grid.SetCellValue( row, 0, tStr ) ''' self.grid.SetGridCursor( 0, 1 ) if timesBibs and Model.race: with Model.LockRace() as race: bibRaceSeconds = [] for tStr, bib in timesBibs: raceSeconds = StrToSeconds(tStr) race.addTime( bib, raceSeconds ) OutputStreamer.writeNumTime( bib, raceSeconds ) bibRaceSeconds.append( (bib, raceSeconds) ) wx.CallAfter( Utils.refresh ) self.grid.SetGridCursor( 0, 1 ) def refresh( self ): self.grid.AutoSizeRows( False ) dc = wx.WindowDC( self.grid ) dc.SetFont( self.font ) widthTotal = self.rowLabelSize width, height = dc.GetTextExtent(" 00:00:00.000 ") self.grid.SetColSize( 0, width ) widthTotal += width width, height = dc.GetTextExtent(" 9999 ") self.grid.SetColSize( 1, width ) widthTotal += width scrollBarWidth = 48 self.grid.SetSize( (widthTotal + scrollBarWidth, -1) ) self.GetSizer().SetMinSize( (widthTotal + scrollBarWidth, -1) ) self.grid.ForceRefresh() self.Fit() wx.CallAfter( self.recordTimeButton.SetFocus ) def commit( self ): pass
class TeamResults(wx.Panel): #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) self.categoryLabel = wx.StaticText(self, label='Category:') self.categoryChoice = wx.Choice(self, choices=['No Categories']) self.categoryChoice.SetSelection(0) self.categoryChoice.Bind(wx.EVT_CHOICE, self.onCategoryChoice) self.statsLabel = wx.StaticText(self, label=' / ') self.refreshButton = wx.Button(self, label='Refresh') self.refreshButton.Bind(wx.EVT_BUTTON, self.onRefresh) self.publishToHtml = wx.Button(self, label='Publish to Html') self.publishToHtml.Bind(wx.EVT_BUTTON, self.onPublishToHtml) self.publishToFtp = wx.Button(self, label='Publish to Html with FTP') self.publishToFtp.Bind(wx.EVT_BUTTON, self.onPublishToFtp) self.publishToExcel = wx.Button(self, label='Publish to Excel') self.publishToExcel.Bind(wx.EVT_BUTTON, self.onPublishToExcel) self.postPublishCmdLabel = wx.StaticText(self, label='Post Publish Cmd:') self.postPublishCmd = wx.TextCtrl(self, size=(300, -1)) self.postPublishExplain = wx.StaticText( self, label= 'Command to run after publish. Use %* for all filenames (eg. "copy %* dirname")' ) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.categoryLabel, flag=wx.TOP, border=4) hs.Add(self.categoryChoice) hs.AddSpacer(4) hs.Add(self.statsLabel, flag=wx.TOP | wx.LEFT | wx.RIGHT, border=4) hs.AddStretchSpacer() hs.Add(self.refreshButton) hs.Add(self.publishToHtml, flag=wx.LEFT, border=48) hs.Add(self.publishToFtp, flag=wx.LEFT, border=4) hs.Add(self.publishToExcel, flag=wx.LEFT, border=4) hs2 = wx.BoxSizer(wx.HORIZONTAL) hs2.Add(self.postPublishCmdLabel, flag=wx.ALIGN_CENTRE_VERTICAL) hs2.Add(self.postPublishCmd, flag=wx.ALIGN_CENTRE_VERTICAL) hs2.Add(self.postPublishExplain, flag=wx.ALIGN_CENTRE_VERTICAL | wx.LEFT, border=4) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(HeaderNamesTemplate) + 1) self.grid.SetRowLabelSize(0) self.grid.EnableReorderRows(False) self.grid.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.doLabelClick) self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.doCellClick) self.sortCol = None self.setColNames(getHeaderNames()) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(hs, flag=wx.TOP | wx.LEFT | wx.RIGHT, border=4) sizer.Add(hs2, flag=wx.ALIGN_RIGHT | wx.TOP | wx.LEFT | wx.RIGHT, border=4) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.TOP | wx.ALL, border=4) self.SetSizer(sizer) def onRefresh(self, event): SeriesModel.model.clearCache() self.refresh() def onCategoryChoice(self, event): wx.CallAfter(self.refresh) def readReset(self): self.sortCol = None def doLabelClick(self, event): col = event.GetCol() label = self.grid.GetColLabelValue(col) if self.sortCol == col: self.sortCol = -self.sortCol elif self.sortCol == -col: self.sortCol = None else: self.sortCol = col if not self.sortCol: self.sortCol = None wx.CallAfter(self.refresh) def doCellClick(self, event): if not hasattr(self, 'popupInfo'): self.popupInfo = [ (u'{}...'.format(_('Copy Team to Clipboard')), wx.NewId(), self.onCopyTeam), ] for p in self.popupInfo: if p[2]: self.Bind(wx.EVT_MENU, p[2], id=p[1]) menu = wx.Menu() for i, p in enumerate(self.popupInfo): if p[2]: menu.Append(p[1], p[0]) else: menu.AppendSeparator() self.rowCur, self.colCur = event.GetRow(), event.GetCol() self.PopupMenu(menu) menu.Destroy() def copyCellToClipboard(self, r, c): if wx.TheClipboard.Open(): # Create a wx.TextDataObject do = wx.TextDataObject() do.SetText(self.grid.GetCellValue(r, c)) # Add the data to the clipboard wx.TheClipboard.SetData(do) # Close the clipboard wx.TheClipboard.Close() else: wx.MessageBox(u"Unable to open the clipboard", u"Error") def onCopyTeam(self, event): self.copyCellToClipboard(self.rowCur, 1) def setColNames(self, headerNames): for col, headerName in enumerate(headerNames): self.grid.SetColLabelValue(col, headerName) attr = gridlib.GridCellAttr() if headerName in ('Team', ): attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_TOP) elif headerName in ('Pos', 'Points', 'Gap'): attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) else: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) def getGrid(self): return self.grid def getTitle(self): return self.showResults.GetStringSelection() + ' Series Results' def fixCategories(self): model = SeriesModel.model categoryNames = model.getCategoryNamesSortedTeamPublish() lastSelection = self.categoryChoice.GetStringSelection() self.categoryChoice.SetItems(categoryNames) iCurSelection = 0 for i, n in enumerate(categoryNames): if n == lastSelection: iCurSelection = i break self.categoryChoice.SetSelection(iCurSelection) self.GetSizer().Layout() def refresh(self): model = SeriesModel.model HeaderNames = getHeaderNames() scoreByPoints = model.scoreByPoints scoreByTime = model.scoreByTime self.postPublishCmd.SetValue(model.postPublishCmd) wait = wx.BusyCursor() self.raceResults = model.extractAllRaceResults(False) del wait self.fixCategories() categoryName = self.categoryChoice.GetStringSelection() if not categoryName or not (scoreByPoints or scoreByTime): Utils.AdjustGridSize(self.grid, 0, 0) return self.grid.ClearGrid() pointsForRank = { r.getFileName(): r.pointStructure for r in model.races } results, races = GetModelInfo.GetCategoryResultsTeam( categoryName, self.raceResults, pointsForRank, useMostEventsCompleted=model.useMostEventsCompleted, numPlacesTieBreaker=model.numPlacesTieBreaker, ) results = [rr for rr in results if rr[1] > 0] headerNames = HeaderNames + [ u'{}\n{}'.format(r[1], r[0].strftime('%Y-%m-%d') if r[0] else u'') for r in races ] Utils.AdjustGridSize(self.grid, len(results), len(headerNames)) self.setColNames(headerNames) for row, (team, points, gap, rrs) in enumerate(results): self.grid.SetCellValue(row, 0, unicode(row + 1)) self.grid.SetCellValue(row, 1, unicode(team)) self.grid.SetCellValue(row, 2, unicode(points)) self.grid.SetCellValue(row, 3, unicode(gap)) for q, rt in enumerate(rrs): self.grid.SetCellValue(row, 4 + q, formatTeamResults(scoreByPoints, rt)) for c in xrange(0, len(headerNames)): self.grid.SetCellBackgroundColour(row, c, wx.WHITE) self.grid.SetCellTextColour(row, c, wx.BLACK) if self.sortCol is not None: def getBracketedNumber(v): numberMax = 99999 if not v: return numberMax try: return int(reNoDigits.sub('', v.split('(')[1])) except (IndexError, ValueError): return numberMax data = [] for r in xrange(0, self.grid.GetNumberRows()): rowOrig = [ self.grid.GetCellValue(r, c) for c in xrange(0, self.grid.GetNumberCols()) ] rowCmp = rowOrig[:] rowCmp[0] = int(rowCmp[0]) rowCmp[4] = Utils.StrToSeconds(rowCmp[4]) rowCmp[5:] = [getBracketedNumber(v) for v in rowCmp[5:]] rowCmp.extend(rowOrig) data.append(rowCmp) if self.sortCol > 0: fg = wx.WHITE bg = wx.Colour(0, 100, 0) else: fg = wx.BLACK bg = wx.Colour(255, 165, 0) iCol = abs(self.sortCol) data.sort(key=lambda x: x[iCol], reverse=(self.sortCol < 0)) for r, row in enumerate(data): for c, v in enumerate(row[self.grid.GetNumberCols():]): self.grid.SetCellValue(r, c, v) if c == iCol: self.grid.SetCellTextColour(r, c, fg) self.grid.SetCellBackgroundColour(r, c, bg) if c < 4: halign = wx.ALIGN_LEFT elif c == 4 or c == 5: halign = wx.ALIGN_RIGHT else: halign = wx.ALIGN_CENTRE self.grid.SetCellAlignment(r, c, halign, wx.ALIGN_TOP) self.statsLabel.SetLabel('{} / {}'.format( self.grid.GetNumberRows(), GetModelInfo.GetTotalUniqueTeams(self.raceResults))) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) self.GetSizer().Layout() def onPublishToExcel(self, event): model = SeriesModel.model scoreByPoints = model.scoreByPoints scoreByTime = model.scoreByTime scoreByPercent = model.scoreByPercent scoreByTrueSkill = model.scoreByTrueSkill HeaderNames = getHeaderNames() if Utils.mainWin: if not Utils.mainWin.fileName: Utils.MessageOK(self, 'You must save your Series to a file first.', 'Save Series') return self.raceResults = model.extractAllRaceResults(False) categoryNames = model.getCategoryNamesSortedTeamPublish() if not categoryNames: return pointsForRank = { r.getFileName(): r.pointStructure for r in model.races } wb = xlwt.Workbook() for categoryName in categoryNames: results, races = GetModelInfo.GetCategoryResultsTeam( categoryName, self.raceResults, pointsForRank, useMostEventsCompleted=model.useMostEventsCompleted, numPlacesTieBreaker=model.numPlacesTieBreaker, ) results = [rr for rr in results if rr[1] > 0] headerNames = HeaderNames + [r[1] for r in races] ws = wb.add_sheet(re.sub('[:\\/?*\[\]]', ' ', categoryName)) wsFit = FitSheetWrapper(ws) fnt = xlwt.Font() fnt.name = 'Arial' fnt.bold = True fnt.height = int(fnt.height * 1.5) headerStyle = xlwt.XFStyle() headerStyle.font = fnt rowCur = 0 ws.write_merge(rowCur, rowCur, 0, 8, model.name, headerStyle) rowCur += 1 if model.organizer: ws.write_merge(rowCur, rowCur, 0, 8, u'by {}'.format(model.organizer), headerStyle) rowCur += 1 rowCur += 1 colCur = 0 ws.write_merge(rowCur, rowCur, colCur, colCur + 4, categoryName, xlwt.easyxf("font: name Arial, bold on;")) rowCur += 2 for c, headerName in enumerate(headerNames): wsFit.write(rowCur, c, headerName, labelStyle, bold=True) rowCur += 1 for pos, (team, points, gap, rrs) in enumerate(results): wsFit.write(rowCur, 0, pos + 1, numberStyle) wsFit.write(rowCur, 1, team, textStyle) wsFit.write(rowCur, 2, points, numberStyle) wsFit.write(rowCur, 3, gap, numberStyle) for q, rt in enumerate(rrs): wsFit.write(rowCur, 4 + q, formatTeamResults(scoreByPoints, rt), centerStyle) rowCur += 1 # Add branding at the bottom of the sheet. style = xlwt.XFStyle() style.alignment.horz = xlwt.Alignment.HORZ_LEFT ws.write(rowCur + 2, 0, brandText, style) if Utils.mainWin: xlfileName = os.path.splitext( Utils.mainWin.fileName)[0] + 'Team.xls' else: xlfileName = 'ResultsTestTeam.xls' try: wb.save(xlfileName) webbrowser.open(xlfileName, new=2, autoraise=True) Utils.MessageOK( self, 'Excel file written to:\n\n {}'.format(xlfileName), 'Excel Write') self.callPostPublishCmd(xlfileName) except IOError: Utils.MessageOK( self, 'Cannot write "{}".\n\nCheck if this spreadsheet is open.\nIf so, close it, and try again.' .format(xlfileName), 'Excel File Error', iconMask=wx.ICON_ERROR) def onPublishToHtml(self, event): if Utils.mainWin: if not Utils.mainWin.fileName: Utils.MessageOK(self, 'You must save your Series to a file first.', 'Save Series') return htmlfileName = getHtmlFileName() model = SeriesModel.model model.postPublishCmd = self.postPublishCmd.GetValue().strip() try: getHtml(htmlfileName) webbrowser.open(htmlfileName, new=2, autoraise=True) Utils.MessageOK( self, u'Html file written to:\n\n {}'.format(htmlfileName), 'html Write') except IOError: Utils.MessageOK( self, 'Cannot write "%s".\n\nCheck if this file is open.\nIf so, close it, and try again.' % htmlfileName, 'Html File Error', iconMask=wx.ICON_ERROR) self.callPostPublishCmd(htmlfileName) def onPublishToFtp(self, event): if Utils.mainWin: if not Utils.mainWin.fileName: Utils.MessageOK(self, 'You must save your Series to a file first.', 'Save Series') return htmlfileName = getHtmlFileName() try: getHtml(htmlfileName) except IOError: return html = io.open(htmlfileName, 'r', encoding='utf-8', newline='').read() with FtpWriteFile.FtpPublishDialog(self, html=html) as dlg: dlg.ShowModal() self.callPostPublishCmd(htmlfileName) def commit(self): model = SeriesModel.model if model.postPublishCmd != self.postPublishCmd.GetValue().strip(): model.postPublishCmd = self.postPublishCmd.GetValue().strip() model.setChanged() def callPostPublishCmd(self, fname): self.commit() postPublishCmd = SeriesModel.model.postPublishCmd if postPublishCmd and fname: allFiles = [fname] if platform.system() == 'Windows': files = ' '.join('""{}""'.format(f) for f in allFiles) else: files = ' '.join('"{}"'.format(f) for f in allFiles) if '%*' in postPublishCmd: cmd = postPublishCmd.replace('%*', files) else: cmd = ' '.join([postPublishCmd, files]) try: subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError as e: Utils.MessageOK( self, u'{}\n\n {}\n{}: {}'.format('Post Publish Cmd Error', e, 'return code', e.returncode), _('Post Publish Cmd Error')) except Exception as e: Utils.MessageOK( self, u'{}\n\n {}'.format('Post Publish Cmd Error', e), 'Post Publish Cmd Error')
def writeIC( stage ): ic_fields = ['gap'] + list(Model.IndividualClassification._fields[1:-1]) riderFields = set( model.registration.getFieldsInUse() ) headers = ( ['place', 'bib', 'last_name', 'first_name', 'team'] + (['uci_id'] if 'uci_id' in riderFields else []) + (['license'] if 'license' in riderFields else []) + list(ic_fields) ) grid = ReorderableGrid( notebook ) grid.CreateGrid( len(getattr(stage, 'individual_gc', [])), len(headers) ) grid.EnableReorderRows( False ) for col, h in enumerate(headers): attr = gridlib.GridCellAttr() attr.SetReadOnly() if h in Model.Result.NumericFields or any(t in h for t in ('place', 'time')): attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_CENTRE ) grid.SetColAttr( col, attr ) grid.SetColLabelValue( col, Utils.fieldToHeader(h, True) ) rowNum = 0 gapLast = None timeLast = None for place, r in enumerate(stage.individual_gc, 1): try: rider = model.registration.bibToRider[r.bib] except KeyError: continue col = 0 if r.retired_stage > 0: grid.SetCellValue( rowNum, col, u'AB' ); col += 1 else: grid.SetCellValue( rowNum, col, unicode(place) ); col += 1 grid.SetCellValue( rowNum, col, unicode(r.bib) ); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.last_name).upper()); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.first_name) ); col += 1 grid.SetCellValue( rowNum, col, unicode(rider.team) ); col += 1 if 'uci_id' in riderFields: grid.SetCellValue( rowNum, col, unicode(rider.uci_id) ); col += 1 if 'license' in riderFields: grid.SetCellValue( rowNum, col, unicode(rider.license) ); col += 1 if r.retired_stage == 0: grid.SetCellValue( rowNum, col, Utils.formatTime(r.gap, twoDigitHours=True) if gapLast != r.gap else sameGap ) gapLast = r.gap col += 1 timeCur = r.total_time_with_bonus_plus_penalty grid.SetCellValue( rowNum, col, Utils.formatTime(timeCur, twoDigitHours=True) if timeCur != timeLast else sameTime ) timeLast = timeCur col += 1 grid.SetCellValue( rowNum, col, Utils.formatTime(r.total_time_with_bonus_plus_penalty_plus_second_fraction, twoDigitHours=True, extraPrecision=True) ); col += 1 grid.SetCellValue( rowNum, col, unicode(r.sum_of_places) ); col += 1 grid.SetCellValue( rowNum, col, unicode(r.last_stage_place) ); col += 1 rowNum +=1 grid.GetGridWindow().Bind(wx.EVT_MOTION, getCommentCallback(grid)) grid.AutoSize() return grid
def writeTeamGC(): headers = ( ['Place', 'Team', 'Gap', 'Combined\nTime'] + ['{}s'.format(Utils.ordinal(i+1)) for i in xrange(len(model.all_teams))] + ['Best\nRider GC'] ) grid = ReorderableGrid( notebook ) grid.CreateGrid( len(model.team_gc) + len(model.unranked_teams), len(headers) ) grid.EnableReorderRows( False ) for col, h in enumerate(headers): attr = gridlib.GridCellAttr() attr.SetReadOnly() if h != 'Team': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_CENTRE ) grid.SetColAttr( col, attr ) grid.SetColLabelValue( col, h ) rowNum = 0 leaderTime = None gapLast = None timeLast = None for place, tgc in enumerate(model.team_gc, 1): col = 0 grid.SetCellValue( rowNum, col, unicode(place) ); col += 1 grid.SetCellValue( rowNum, col, unicode(tgc[-1]) ); col += 1 combinedTime = tgc[0].value if leaderTime is None: leaderTime = combinedTime gap = combinedTime - leaderTime grid.SetCellValue( rowNum, col, Utils.formatTime(gap, twoDigitHours=True) if gap != gapLast else sameGap ); col += 1 gapLast = gap grid.SetCellValue( rowNum, col, Utils.formatTime(combinedTime, forceHours=True) if combinedTime != timeLast else sameTime) timeLast = combinedTime setComment( rowNum, col, formatContextList(tgc[0].context), {'width':512} ) col += 1 for i in xrange(1, len(tgc)-2): if tgc[i].value: grid.SetCellValue( rowNum, col, unicode(tgc[i].value) ) setComment( rowNum, col, u'\n'.join(tgc[i].context), {'width':128} ) col += 1 grid.SetCellValue( rowNum, col, unicode(tgc[-2].value) ) setComment( rowNum, col, formatContext(tgc[-2].context), {'width':256} ) col += 1 rowNum +=1 for team in model.unranked_teams: col = 0 grid.SetCellValue( rowNum, col, 'DNF' ); col += 1 grid.SetCellValue( rowNum, col, team ); col += 1 rowNum +=1 grid.GetGridWindow().Bind(wx.EVT_MOTION, getCommentCallback(grid)) grid.AutoSize() return grid
class Chart(wx.Panel): """""" #---------------------------------------------------------------------- def __init__(self, parent): wx.Panel.__init__(self, parent) font = GetFont() self.title = wx.StaticText(self, wx.ID_ANY, "Competition Table:") self.title.SetFont(font) self.showNames = wx.ToggleButton(self, wx.ID_ANY, 'Show Names') self.showNames.SetFont(font) self.showNames.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleShow) self.showTeams = wx.ToggleButton(self, wx.ID_ANY, 'Show Teams') self.showTeams.SetFont(font) self.showTeams.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleShow) self.headerNames = [ '', 'System', 'Event', 'Heats', 'In', 'Bib', 'Name', 'Team', 'H1', 'H2', 'H3', 'Out', 'Bib', 'Name', 'Team' ] self.numericFields = set(['Event', 'Heats', 'Bib', 'In', 'Out']) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(0) self.grid.EnableReorderRows(False) self.grid.CreateGrid(0, len(self.headerNames)) self.setColNames() # Set a larger font for the table. # Set specialized editors for appropriate columns. self.grid.SetLabelFont(font) sizer = wx.BoxSizer(wx.VERTICAL) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.title, 0, flag=wx.ALL | wx.ALIGN_CENTRE_VERTICAL, border=4) hs.Add(self.showNames, 0, flag=wx.ALL, border=4) hs.Add(self.showTeams, 0, flag=wx.ALL, border=4) sizer.Add(hs, flag=wx.ALL, border=4) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) def onToggleShow(self, e): model = Model.model model.chartShowNames = self.showNames.GetValue() model.chartShowTeams = self.showTeams.GetValue() self.refresh() def getHideCols(self, headerNames): model = Model.model toHide = set() for col, h in enumerate(headerNames): if h == 'Name' and not getattr(model, 'chartShowNames', True): toHide.add(col) elif h == 'Team' and not getattr(model, 'chartShowTeams', True): toHide.add(col) return toHide def setColNames(self): for col, headerName in enumerate(self.headerNames): self.grid.SetColLabelValue(col, headerName) def getGrid(self): return self.grid def refresh(self): model = Model.model competition = model.competition state = competition.state self.showNames.SetValue(getattr(model, 'chartShowNames', True)) self.showTeams.SetValue(getattr(model, 'chartShowTeams', True)) font = GetFont() self.headerNames = [ '', 'System', 'Event', 'Heats', 'In', 'Bib', 'Name', 'Team', 'H1', 'H2', 'H3', 'Out', 'Bib', 'Name', 'Team' ] hideCols = self.getHideCols(self.headerNames) self.headerNames = [ h for c, h in enumerate(self.headerNames) if c not in hideCols ] Utils.AdjustGridSize(self.grid, rowsRequired=sum( 1 for t, s, e in competition.allEvents()), colsRequired=len(self.headerNames)) self.grid.ClearGrid() self.setColNames() for col in six.moves.range(self.grid.GetNumberCols()): attr = gridlib.GridCellAttr() attr.SetFont(font) attr.SetReadOnly(True) if col >= 4: attr.SetRenderer(GridCellMultiLineStringRenderer()) if self.headerNames[col] in self.numericFields: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) elif self.headerNames[col].startswith('H'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) self.grid.SetColAttr(col, attr) row = 0 for tournament in competition.tournaments: self.grid.SetCellValue(row, 0, tournament.name) for system in tournament.systems: self.grid.SetCellValue(row, 1, system.name) for i, event in enumerate(system.events): writeCell = WriteCell(self.grid, row, 2) writeCell(u'{}'.format(i + 1)) writeCell(u' {}'.format(event.heatsMax)) writeCell(u'\n'.join(event.composition).replace( u'\n', u' ({})\n'.format(len(event.composition)), 1)) riders = [ state.labels.get(c, None) for c in event.composition ] writeCell(u'\n'.join([ u'{}'.format(rider.bib if rider.bib else u'') if rider else '' for rider in riders ])) if getattr(model, 'chartShowNames', True): writeCell(u'\n'.join([ rider.full_name if rider else u'' for rider in riders ])) if getattr(model, 'chartShowTeams', True): writeCell(u'\n'.join([ rider.team if rider else u'' for rider in riders ])) for heat in six.moves.range(3): if event.heatsMax > 1: writeCell(u'\n'.join(event.getHeatPlaces(heat + 1))) else: writeCell(u'') out = [event.winner] + event.others writeCell(u'\n'.join(out).replace( u'\n', u' ({})\n'.format(len(out)), 1)) riders = [state.labels.get(c, None) for c in out] writeCell(u'\n'.join([ u'{}'.format(rider.bib if rider.bib else '') if rider else '' for rider in riders ])) if getattr(model, 'chartShowNames', True): writeCell('\n'.join([ rider.full_name if rider else '' for rider in riders ])) if getattr(model, 'chartShowTeams', True): writeCell('\n'.join( [rider.team if rider else '' for rider in riders])) row += 1 self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def commit(self): pass
class Results(wx.Panel): #---------------------------------------------------------------------- def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent) self.font = wx.Font((0, FontSize), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) self.showResultsLabel = wx.StaticText(self, wx.ID_ANY, u'Show:') self.showResultsLabel.SetFont(self.font) self.showResults = wx.Choice(self, wx.ID_ANY, choices=['Qualifiers']) self.showResults.SetFont(self.font) self.showResults.SetSelection(0) self.communiqueLabel = wx.StaticText(self, wx.ID_ANY, u'Communiqu\u00E9:') self.communiqueLabel.SetFont(self.font) self.communiqueNumber = wx.TextCtrl(self, wx.ID_ANY, '', size=(80, -1)) self.communiqueNumber.SetFont(self.font) self.showResults.Bind(wx.EVT_LEFT_DOWN, self.onClickResults) self.showResults.Bind(wx.EVT_CHOICE, self.onShowResults) self.showNames = wx.ToggleButton(self, wx.ID_ANY, u'Show Names') self.showNames.SetFont(self.font) self.showNames.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleShow) self.showTeams = wx.ToggleButton(self, wx.ID_ANY, u'Show Teams') self.showTeams.SetFont(self.font) self.showTeams.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleShow) self.competitionTime = wx.StaticText(self) self.headerNames = ['uPos', u'Bib', u'Rider', u'Team', u'License'] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) self.grid.SetRowLabelSize(0) self.grid.EnableReorderRows(False) self.setColNames() sizer = wx.BoxSizer(wx.VERTICAL) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.showResultsLabel, 0, flag=wx.ALIGN_CENTRE_VERTICAL, border=4) hs.Add(self.showResults, 0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) hs.Add(self.communiqueLabel, 0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) hs.Add(self.communiqueNumber, 0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, border=4) hs.Add(self.showNames, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) hs.Add(self.showTeams, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) hs.Add(self.competitionTime, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=4) sizer.Add(hs, 0, flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=6) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) def onToggleShow(self, e): model = Model.model model.resultsShowNames = self.showNames.GetValue() model.resultsShowTeams = self.showTeams.GetValue() self.refresh() def setColNames(self): self.grid.SetLabelFont(self.font) for col, headerName in enumerate(self.headerNames): self.grid.SetColLabelValue(col, headerName) attr = gridlib.GridCellAttr() attr.SetFont(self.font) if self.headerNames[col] in {u'Bib', u'Event'}: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) elif u'Time' in self.headerNames[col]: attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) elif self.headerNames[col] == u'Pos': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) elif Arrow in self.headerNames[col]: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_VERTICAL_CENTRE) elif self.headerNames[col].startswith(u'H'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) def getResultChoices(self): model = Model.model competition = model.competition choices = [u'Qualifiers'] for tournament in competition.tournaments: for system in tournament.systems: name = ('%s: ' % tournament.name if tournament.name else '') + system.name choices.append(name) choices.append(u'Final Classification') return choices def fixShowResults(self): model = Model.model competition = model.competition choices = self.getResultChoices() self.showResults.SetItems(choices) if model.showResults >= len(choices): model.showResults = 0 self.showResults.SetSelection(model.showResults) def getHideCols(self, headerNames): model = Model.model toHide = set() for col, h in enumerate(headerNames): if h == u'Name' and not getattr(model, 'resultsShowNames', True): toHide.add(col) elif h == u'Team' and not getattr(model, 'resultsShowTeams', True): toHide.add(col) return toHide def getGrid(self): return self.grid def getPhase(self, num=None): if num is None: num = self.showResults.GetSelection() choices = self.getResultChoices() return choices[num] def getTitle(self): phase = self.getPhase() title = u'Communiqu\u00E9: {}\n{} {} '.format( self.communiqueNumber.GetValue(), phase, '' if phase.startswith(u'Final') or phase.startswith('Time') else u'Draw Sheet/Intermediate Results') return title def onClickResults(self, event): self.commit() event.Skip() def onShowResults(self, event): Model.model.showResults = self.showResults.GetSelection() self.refresh() def refresh(self): self.fixShowResults() self.grid.ClearGrid() model = Model.model competition = model.competition self.showNames.SetValue(getattr(model, 'resultsShowNames', True)) self.showTeams.SetValue(getattr(model, 'resultsShowTeams', True)) self.communiqueNumber.SetValue( model.communique_number.get(self.getPhase(), '')) resultName = self.showResults.GetStringSelection() if 'Qualifiers' in resultName: starters = competition.starters self.headerNames = [u'Pos', u'Bib', u'Name', u'Team', u'Time'] hideCols = self.getHideCols(self.headerNames) self.headerNames = [ h for c, h in enumerate(self.headerNames) if c not in hideCols ] riders = sorted(model.riders, key=lambda r: r.keyQualifying()) for row, r in enumerate(riders): if row >= starters or r.status == 'DNQ': riders[row:] = sorted(riders[row:], key=lambda r: r.keyQualifying()[1:]) break Utils.AdjustGridSize(self.grid, rowsRequired=len(riders), colsRequired=len(self.headerNames)) Utils.SetGridCellBackgroundColour(self.grid, wx.WHITE) self.setColNames() for row, r in enumerate(riders): if row < starters and r.status != 'DNQ': pos = u'{}'.format(row + 1) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellBackgroundColour(row, col, wx.WHITE) else: pos = 'DNQ' for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellBackgroundColour( row, col, wx.Colour(200, 200, 200)) writeCell = WriteCell(self.grid, row) for col, value in enumerate([ pos, u' {}'.format(r.bib), r.full_name, r.team, r.qualifyingTimeText ]): if col not in hideCols: writeCell(value) competitionTime = model.qualifyingCompetitionTime self.competitionTime.SetLabel(u'{}: {}'.format( _('Est. Competition Time'), Utils.formatTime(competitionTime) ) if competitionTime else u'') elif 'Final Classification' in resultName: self.headerNames = [u'Pos', u'Bib', u'Name', u'Team', u'License'] hideCols = self.getHideCols(self.headerNames) self.headerNames = [ h for c, h in enumerate(self.headerNames) if c not in hideCols ] results, dnfs, dqs = competition.getResults() Utils.AdjustGridSize(self.grid, rowsRequired=len(model.riders), colsRequired=len(self.headerNames)) Utils.SetGridCellBackgroundColour(self.grid, wx.WHITE) self.setColNames() for row, (classification, r) in enumerate(results): writeCell = WriteCell(self.grid, row) if not r: for col in six.moves.range(self.grid.GetNumberCols()): writeCell('') else: for col, value in enumerate([ classification, r.bib if r.bib else '', r.full_name, r.team, r.license ]): if col not in hideCols: writeCell(u' {}'.format(value)) self.competitionTime.SetLabel(u'') else: # Find the Tournament and System selected. keepGoing = True for tournament in competition.tournaments: for system in tournament.systems: name = (u'%s: ' % tournament.name if tournament.name else '') + system.name if name == resultName: keepGoing = False break if not keepGoing: break heatsMax = max(event.heatsMax for event in system.events) if heatsMax == 1: self.headerNames = [ u'Event', u'Bib', u'Name', u'Note', u'Team', u' ', u'Pos', u'Bib', u'Name', u'Note', u'Team', u'Time' ] else: self.headerNames = [ u'Event', u'Bib', u'Name', u'Note', u'Team', u'H1', u'H2', u'H3', u' ', u'Pos', u'Bib', u'Name', u'Note', u'Team', u'Time' ] hideCols = self.getHideCols(self.headerNames) self.headerNames = [ h for c, h in enumerate(self.headerNames) if c not in hideCols ] Utils.AdjustGridSize(self.grid, rowsRequired=len(system.events), colsRequired=len(self.headerNames)) Utils.SetGridCellBackgroundColour(self.grid, wx.WHITE) self.setColNames() state = competition.state for row, event in enumerate(system.events): writeCell = WriteCell(self.grid, row) writeCell(u'{}'.format(row + 1)) riders = [state.labels.get(c, None) for c in event.composition] writeCell(u'\n'.join([ u'{}'.format(rider.bib) if rider and rider.bib else '' for rider in riders ])) if getattr(model, 'resultsShowNames', True): writeCell(u'\n'.join([ rider.full_name if rider else u'' for rider in riders ])) writeCell(u'\n'.join([ competition.getRelegationsWarningsStr( rider.bib, event, True) if rider else u'' for rider in riders ])) if getattr(model, 'resultsShowTeams', True): writeCell(u'\n'.join( [rider.team if rider else '' for rider in riders])) if heatsMax != 1: for heat in six.moves.range(heatsMax): if event.heatsMax != 1: writeCell(u'\n'.join(event.getHeatPlaces(heat + 1))) else: writeCell(u'') #writeCell( u' ===> ', vert=wx.ALIGN_CENTRE ) writeCell(' '.join(['', Arrow, '']), vert=wx.ALIGN_CENTRE) out = [event.winner] + event.others riders = [state.labels.get(c, None) for c in out] writeCell(u'\n'.join(u'{}'.format(i + 1) for i in six.moves.range(len(riders)))) writeCell(u'\n'.join([ u'{}'.format(rider.bib if rider.bib else '') if rider else '' for rider in riders ])) if getattr(model, 'resultsShowNames', True): writeCell(u'\n'.join([ rider.full_name if rider else '' for rider in riders ])) writeCell(u'\n'.join([ competition.getRelegationsWarningsStr( rider.bib, event, False) if rider else u'' for rider in riders ])) if getattr(model, 'resultsShowTeams', True): writeCell(u'\n'.join( [rider.team if rider else '' for rider in riders])) if event.winner in state.labels: try: value = u'%.3f' % event.starts[-1].times[1] except (KeyError, IndexError, ValueError): value = '' writeCell(value) competitionTime = system.competitionTime self.competitionTime.SetLabel(u'{}: {}'.format( _('Est. Competition Time'), Utils.formatTime(competitionTime) ) if competitionTime else u'') self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def commit(self): model = Model.model phase = self.getPhase() cn = self.communiqueNumber.GetValue() if cn != model.communique_number.get(phase, u''): model.communique_number[phase] = cn model.setChanged()
class TTResults(wx.Panel): #---------------------------------------------------------------------- def __init__(self, parent): wx.Panel.__init__(self, parent) self.headerNames = ['Pos', 'Bib', 'Name', 'Team', 'Time'] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(0) self.grid.CreateGrid(0, len(self.headerNames)) self.setColNames() self.grid.EnableReorderRows(False) # Set a larger font for the table. # Set specialized editors for appropriate columns. font = GetFont() self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): attr = gridlib.GridCellAttr() attr.SetFont(font) if col == self.grid.GetNumberCols() - 1: attr.SetRenderer(gridlib.GridCellFloatRenderer(-1, 3)) attr.SetEditor(gridlib.GridCellFloatEditor(-1, 3)) else: if col in (0, 1): attr.SetRenderer(gridlib.GridCellNumberRenderer()) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) def setColNames(self): for col, headerName in enumerate(self.headerNames): self.grid.SetColLabelValue(col, headerName) def getGrid(self): return self.grid def refresh(self): riders = sorted(Model.model.riders, key=lambda r: r.qualifyingTime) starters = Model.model.competition.starters Utils.AdjustGridSize(self.grid, rowsRequired=len(riders)) for row, r in enumerate(riders): if row < starters: pos = u'{}'.format(row + 1) else: pos = 'DNQ' for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellBackgroundColour(row, col, wx.Colour(200, 200, 200)) for col, value in enumerate([ pos, u' {}'.format(r.bib), r.full_name, r.team, '%.3f' % r.qualifyingTime ]): self.grid.SetCellValue(row, col, value) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def commit(self): pass