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 __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 __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 __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 __init__(self, parent): wx.Panel.__init__(self, parent) self.alphaSort = wx.Button(self, label=u'Sort Alphabetically') self.alphaSort.Bind(wx.EVT_BUTTON, self.onSort) self.explanation = wx.StaticText( self, label=u'\n'.join([ _("Change the Category order by dragging-and-dropping the first grey column in the table." ), _("If 'Use Nth Result Only' is True, 'Team N' specifies the top Nth rider's time to use for the team's time (eg. Team TT, scored on 3rd rider's result)" ), _("If 'Use Nth Result Only' if False, 'Team N' specifies the top riders' times to be totaled for the team result (eg. Team Stage Finish, scored on sum of top 3 results for each team)." ), ])) self.headerNames = [ 'Category', 'Ind. Publish', 'Team N', 'Use Nth Result Only', 'Team Publish' ] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) for col in range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) for col in range(self.grid.GetNumberCols()): attr = gridlib.GridCellAttr() if col == self.CategoryCol: attr.SetReadOnly(True) elif col in (self.PublishCol, self.UseNthScoreCol, self.TeamPublishCol): editor = gridlib.GridCellBoolEditor() editor.UseStringValues('1', '0') attr.SetEditor(editor) attr.SetRenderer(gridlib.GridCellBoolRenderer()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) elif col == self.TeamNCol: editor = gridlib.GridCellNumberEditor() attr.SetEditor(editor) attr.SetRenderer(gridlib.GridCellNumberRenderer()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.grid.SetColAttr(col, attr) self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.onGridLeftClick) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.alphaSort, 0, flag=wx.ALL | wx.ALIGN_RIGHT, border=4) sizer.Add(self.explanation, 0, flag=wx.ALL, border=4) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer)
def __init__(self, parent): wx.Panel.__init__(self, parent) font = wx.Font( (0,FontSize), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL ) self.title = wx.StaticText(self, wx.ID_ANY, u"Seeding" + u':') self.title.SetFont( font ) self.communiqueLabel = wx.StaticText( self, label=u'Communiqu\u00E9:' ) self.communiqueLabel.SetFont( font ) self.communiqueNumber = wx.TextCtrl( self, size=(64,-1) ) self.communiqueNumber.SetFont( font ) self.randomizeButton = wx.Button( self, wx.ID_ANY, 'Randomize...' ) self.randomizeButton.Bind( wx.EVT_BUTTON, self.doRandomize ) self.randomizeButton.SetFont( font ) self.importButton = wx.Button( self, wx.ID_ANY, 'Import From Excel' ) self.importButton.Bind( wx.EVT_BUTTON, self.doImportFromExcel ) self.importButton.SetFont( font ) self.headerNames = ['Bib', 'First Name', 'Last Name', 'Team', 'Team Code', 'License'] self.grid = ReorderableGrid( self, style = wx.BORDER_SUNKEN ) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize( 64 ) self.grid.CreateGrid( 200, len(self.headerNames) ) self.setColNames() # 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 == 0: attr.SetRenderer( gridlib.GridCellNumberRenderer() ) attr.SetEditor( gridlib.GridCellNumberEditor() ) self.grid.SetColAttr( col, attr ) hs = wx.BoxSizer( wx.HORIZONTAL ) hs.Add( self.title, 0, flag=wx.ALIGN_CENTRE_VERTICAL|wx.RIGHT, border = 8 ) 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.AddStretchSpacer() hs.Add( self.randomizeButton, 0, flag=wx.ALL, border=4 ) hs.Add( self.importButton, 0, flag=wx.ALL, border=4 ) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add( hs, 0, flag=wx.ALL|wx.EXPAND, border=6 ) sizer.Add( wx.StaticText(self, label=u'Set Bib to 0 to Delete row. Drag-and-drop row numbers to Change Sequence.'), flag=wx.LEFT, border = 8 ) sizer.Add(self.grid, 1, flag=wx.EXPAND|wx.ALL, border=6) self.SetSizer(sizer)
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 __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 __init__(self, parent, id=wx.ID_ANY, size=wx.DefaultSize): super(Prizes, self).__init__(parent, id, size=size) vsOverall = wx.BoxSizer(wx.VERTICAL) self.grid = ReorderableGrid(self) self.grid.CreateGrid(0, 10) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.onCellChange) #--------------------------------------------------------------- vsOverall.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=4) self.SetSizer(vsOverall)
def __init__(self, parent): wx.Panel.__init__(self, parent) self.headerNames = ['Error', 'Race'] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) for col in xrange(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) attr = gridlib.GridCellAttr() 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 __init__( self, parent, id=wx.ID_ANY, size=wx.DefaultSize ): super(TeamResults, self).__init__( parent, id, size=size ) self.state = RaceInputState() vsOverall = wx.BoxSizer( wx.VERTICAL ) #--------------------------------------------------------------- self.colnames = ( _('Pos'), _('Team'), _('Time'), _('Gap'), ) self.grid = ReorderableGrid( self ) self.grid.CreateGrid( 0, len(self.colnames) ) self.grid.SetRowLabelSize( 0 ) self.grid.SetMargins( 0, 0 ) self.grid.AutoSizeColumns( True ) self.grid.DisableDragColSize() self.grid.DisableDragRowSize() self.grid.AutoSizeColumns( False ) self.grid.AutoSizeRows( False ) #--------------------------------------------------------------- self.hbs = wx.BoxSizer(wx.HORIZONTAL) self.categoryLabel = wx.StaticText( self, label = _('Category:') ) self.categoryChoice = wx.Choice( self ) self.Bind(wx.EVT_CHOICE, self.doChooseCategory, self.categoryChoice) self.exportButton = wx.Button( self, label='{} {}/{}'.format(_('Export'), _('Excel'), _('PDF')) ) self.exportButton.Bind( wx.EVT_BUTTON, self.doExport ) self.hbs.Add( self.categoryLabel, flag=wx.TOP|wx.BOTTOM|wx.LEFT|wx.ALIGN_CENTRE_VERTICAL, border=4 ) self.hbs.Add( self.categoryChoice, flag=wx.ALL|wx.ALIGN_CENTRE_VERTICAL, border=4 ) self.hbs.Add( self.exportButton, flag=wx.ALL|wx.ALIGN_CENTRE_VERTICAL, border=4 ) #--------------------------------------------------------------- vsOverall.Add( self.hbs, flag=wx.ALL, border=4 ) vsOverall.Add( self.grid, 1, flag=wx.EXPAND|wx.ALL, border=4 ) self.SetSizer( vsOverall )
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 __init__(self, parent): wx.Panel.__init__(self, parent) #-------------------------------------------------------------------------- box = wx.StaticBox(self, -1, 'Score Competitors by') bsizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.scoreByPoints = wx.RadioButton(self, label='Points', style=wx.RB_GROUP) self.scoreByPoints.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByTime = wx.RadioButton(self, label='Time') self.scoreByTime.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByPercent = wx.RadioButton( self, label='Percent Time (100 * WinnersTime / FinishTime)') self.scoreByPercent.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByTrueSkill = wx.RadioButton(self, label='TrueSkill') self.scoreByTrueSkill.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByPoints.SetValue(True) hb = wx.BoxSizer(wx.HORIZONTAL) hb.Add(self.scoreByPoints) hb.Add(self.scoreByTime, flag=wx.LEFT, border=16) hb.Add(self.scoreByPercent, flag=wx.LEFT, border=16) hb.Add(self.scoreByTrueSkill, flag=wx.LEFT, border=16) bsizer.Add(hb, flag=wx.ALL, border=2) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.considerPrimePointsOrTimeBonus = wx.CheckBox( self, label='Consider Points or Time Bonuses from CrossMgr Primes') self.considerPrimePointsOrTimeBonus.SetValue(True) bsizer.Add(self.considerPrimePointsOrTimeBonus, 0, flag=wx.ALL, border=4) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) maxOptions = 30 self.considerLabel = wx.StaticText(self, label='{}:'.format('Consider')) self.bestResultsToConsider = wx.Choice( self, choices=['All Results', 'Best Result Only'] + [ '{} {} {}'.format('Best', i, 'Results Only') for i in xrange(2, maxOptions + 1) ]) self.participationLabel = wx.StaticText( self, label='{}:'.format('Must have completed')) self.mustHaveCompleted = wx.Choice( self, choices=[ '{} {}'.format(i, 'or more Events') for i in xrange(0, maxOptions + 1) ]) hb = wx.BoxSizer(wx.HORIZONTAL) hb.Add(self.considerLabel, flag=wx.ALIGN_CENTRE_VERTICAL) hb.Add(self.bestResultsToConsider) hb.Add(self.participationLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=16) hb.Add(self.mustHaveCompleted) bsizer.Add(hb, flag=wx.ALL, border=2) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.ifRidersTiedOnPoints = wx.StaticText( self, label='If Riders are Tied on Points:') bsizer.Add(self.ifRidersTiedOnPoints, flag=wx.ALL, border=2) self.mostEventsCompleted = wx.CheckBox( self, label='Consider Number of Events Completed') self.mostEventsCompleted.SetValue(False) bsizer.Add(self.mostEventsCompleted, 0, flag=wx.ALL, border=4) bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.numPlacesTieBreaker = wx.RadioBox( self, majorDimension=3, style=wx.RA_SPECIFY_ROWS, choices=[ 'Do not consider Place Finishes.', 'Number of 1st Place Finishes', 'Number of 1st then 2nd Place Finishes', 'Number of 1st, 2nd then 3rd Place Finishes', 'Number of 1st, 2nd, 3rd then 4th Place Finishes', 'Number of 1st, 2nd, 3rd, 4th then 5th Place Finishes', ]) self.numPlacesTieBreaker.SetLabel( u'If Riders are still Tied on Points:') bsizer.Add(self.numPlacesTieBreaker, 0, flag=wx.ALL | wx.EXPAND, border=2) self.ifRidersAreStillTiedOnPoints = wx.StaticText( self, label=u'If Riders are still Tied on Points, use most Recent Results' ) bsizer.Add(self.ifRidersAreStillTiedOnPoints, flag=wx.ALL, border=4) self.headerNames = [ 'Name', 'OldName', 'Depth', 'Points for Position', 'Participation', 'DNF' ] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(50, len(self.headerNames)) for col in xrange(self.grid.GetNumberCols()): self.grid.SetColLabelValue( col, self.headerNames[col] + (u' ' if self.headerNames[col] == 'DNF' else '')) attr = gridlib.GridCellAttr() attr.SetReadOnly(True) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.grid.SetColAttr(self.DepthCol, attr) attr = gridlib.GridCellAttr() attr.SetEditor(PointsEditor()) self.grid.SetColAttr(self.PointsCol, attr) for c in (self.ParticipationCol, self.DNFCol): attr = gridlib.GridCellAttr() attr.SetRenderer(wx.grid.GridCellNumberRenderer()) attr.SetEditor(wx.grid.GridCellNumberEditor(0, 10000)) self.grid.SetColAttr(c, attr) self.gridAutoSize() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(bsizer, 0, flag=wx.EXPAND | wx.ALL, border=4) self.pointsStructures = wx.StaticText(self, wx.ID_ANY, 'Points Structures:') sizer.Add(self.pointsStructures, 0, flag=wx.ALL, border=4) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) self.scoreByPointsControls = [ self.ifRidersTiedOnPoints, self.mostEventsCompleted, self.numPlacesTieBreaker, self.ifRidersAreStillTiedOnPoints, self.pointsStructures, self.grid, ]
class Races(wx.Panel): #---------------------------------------------------------------------- headerNames = ['Race', 'Grade', 'Points', 'Team Pts', 'Race File'] RaceCol = 0 GradeCol = 1 PointsCol = 2 TeamPointsCol = 3 RaceFileCol = 4 RaceStatusCol = 5 def __init__(self, parent): wx.Panel.__init__(self, parent) self.seriesNameLabel = wx.StaticText(self, label='Series Name:') self.seriesName = wx.TextCtrl(self) self.organizerNameLabel = wx.StaticText(self, label='Organizer:') self.organizerName = wx.TextCtrl(self) self.explanation = wx.StaticText( self, label=u'\n'.join([ _("Add all the races in your Series."), _("Make sure the races are in chronological order."), _("You can change the order by dragging-and-dropping the first grey column in the table." ), u'', _("Configure the Points Structures or Time Scoring parameters on the Scoring Criteria page." ), _("Each race can have its own Points Structure. For example, you could create 'Double Points' for one race." ), u'', _("Race results are shown Last-to-First in the output by default." ), _("You can change this on the Options page."), ])) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) for col in range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.pointsChoiceEditor = gridlib.GridCellChoiceEditor( [], allowOthers=False) attr = gridlib.GridCellAttr() attr.SetEditor(self.pointsChoiceEditor) self.grid.SetColAttr(self.PointsCol, attr) self.teamPointsChoiceEditor = gridlib.GridCellChoiceEditor( [], allowOthers=False) attr = gridlib.GridCellAttr() attr.SetEditor(self.teamPointsChoiceEditor) self.grid.SetColAttr(self.TeamPointsCol, attr) attr = gridlib.GridCellAttr() attr.SetReadOnly(True) self.grid.SetColAttr(self.RaceCol, attr) attr = gridlib.GridCellAttr() attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.grid.SetColAttr(self.GradeCol, attr) ''' attr = gridlib.GridCellAttr() attr.SetReadOnly( True ) self.grid.SetColAttr( self.RaceStatusCol, attr ) ''' attr = gridlib.GridCellAttr() attr.SetReadOnly(True) self.grid.SetColAttr(self.RaceFileCol, attr) self.grid.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.onGridChange) self.gridAutoSize() self.grid.Bind(wx.grid.EVT_GRID_EDITOR_CREATED, self.onGridEditorCreated) self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.onEditRaceFileName) self.addButton = wx.Button(self, wx.ID_ANY, 'Add Races') self.addButton.Bind(wx.EVT_BUTTON, self.doAddRace) self.removeButton = wx.Button(self, wx.ID_ANY, 'Remove Race') self.removeButton.Bind(wx.EVT_BUTTON, self.doRemoveRace) fgs = wx.FlexGridSizer(rows=2, cols=2, vgap=2, hgap=2) fgs.AddGrowableCol(1, proportion=1) fgs.Add(self.seriesNameLabel, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT) fgs.Add(self.seriesName, flag=wx.EXPAND) fgs.Add(self.organizerNameLabel, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT) fgs.Add(self.organizerName, flag=wx.EXPAND) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.addButton, 0, flag=wx.ALL, border=4) hs.Add(self.removeButton, 0, flag=wx.ALL, border=4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(fgs, 0, flag=wx.EXPAND | wx.ALL, border=4) sizer.Add(self.explanation, 0, flag=wx.EXPAND | wx.ALL, border=4) sizer.Add(hs, 0, flag=wx.EXPAND) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) def getGrid(self): return self.grid wildcard = 'CrossMgr or Excel files (*.cmn, *.xlsx, *.xlsm, *.xls)|*.cmn;*.xlsx;*.xlsm;*.xls;' def onEditRaceFileName(self, event): col = event.GetCol() if col != self.RaceFileCol: event.Skip() return row = event.GetRow() dlg = wx.FileDialog(self, message="Choose a CrossMgr or Excel file", defaultFile='', wildcard=self.wildcard, style=wx.FD_OPEN | wx.FD_CHANGE_DIR) ret = dlg.ShowModal() fileName = '' if ret == wx.ID_OK: fileName = dlg.GetPath() self.grid.SetCellValue(row, self.RaceCol, SeriesModel.RaceNameFromPath(fileName)) self.grid.SetCellValue(row, self.RaceFileCol, fileName) dlg.Destroy() self.commit() def doAddRace(self, event): dlg = wx.FileDialog(self, message="Choose a CrossMgr or Excel file", defaultFile='', wildcard=self.wildcard, style=wx.FD_OPEN | wx.FD_CHANGE_DIR | wx.FD_MULTIPLE) ret = dlg.ShowModal() if ret == wx.ID_OK: for fileName in dlg.GetPaths(): SeriesModel.model.addRace(fileName) dlg.Destroy() self.refresh() def doRemoveRace(self, event): row = self.grid.GetGridCursorRow() if row < 0: Utils.MessageOK( self, 'No Selected Race.\nPlease Select a Race to Remove.', 'No Selected Race') return if Utils.MessageOKCancel( self, 'Confirm Remove Race:\n\n {}'.format( self.grid.GetCellValue(row, 0)), 'Remove Race'): self.grid.DeleteRows(row) self.commit() def updatePointsChoices(self): try: comboBox = self.comboBox except AttributeError: return comboBox.SetItems([p.name for p in SeriesModel.model.pointStructures]) def updateTeamPointsChoices(self): try: teamComboBox = self.teamComboBox except AttributeError: return teamComboBox.SetItems( [''] + [p.name for p in SeriesModel.model.pointStructures]) def onGridEditorCreated(self, event): if event.GetCol() == self.PointsCol: self.comboBox = event.GetControl() self.updatePointsChoices() elif event.GetCol() == self.TeamPointsCol: self.teamComboBox = event.GetControl() self.updateTeamPointsChoices() event.Skip() def gridAutoSize(self): self.grid.AutoSize() self.grid.EnableDragGridSize(False) self.grid.EnableDragColSize(False) self.Layout() self.Refresh() def onGridChange(self, event): wx.CallAfter(self.gridAutoSize) def refresh(self): model = SeriesModel.model Utils.AdjustGridSize(self.grid, len(model.races)) for row, race in enumerate(model.races): self.grid.SetCellValue(row, self.RaceCol, race.getRaceName()) self.grid.SetCellValue(row, self.GradeCol, race.grade) self.grid.SetCellValue(row, self.PointsCol, race.pointStructure.name) self.grid.SetCellValue( row, self.TeamPointsCol, race.teamPointStructure.name if race.teamPointStructure else u'') self.grid.SetCellValue(row, self.RaceFileCol, race.fileName) wx.CallAfter(self.gridAutoSize) self.seriesName.SetValue(SeriesModel.model.name) self.organizerName.SetValue(SeriesModel.model.organizer) def commit(self): self.grid.SaveEditControlValue() self.grid.DisableCellEditControl( ) # Make sure the current edit is committed. raceList = [] for row in range(self.grid.GetNumberRows()): race = SeriesModel.model.races[row] fileName = self.grid.GetCellValue(row, self.RaceFileCol).strip() pname = self.grid.GetCellValue(row, self.PointsCol) pteamname = self.grid.GetCellValue(row, self.TeamPointsCol) or None grade = self.grid.GetCellValue(row, self.GradeCol).strip().upper()[:1] if not (grade and ord(u'A') <= ord(grade) <= ord(u'Z')): grade = u'A' if not fileName or not pname: continue raceList.append((fileName, pname, pteamname, grade)) model = SeriesModel.model model.setRaces(raceList) if self.seriesName.GetValue() != model.name: model.name = self.seriesName.GetValue() model.changed = True if self.organizerName.GetValue() != model.organizer: model.organizer = self.organizerName.GetValue() model.changed = True wx.CallAfter(self.refresh)
class Points(wx.Panel): #---------------------------------------------------------------------- NameCol = 0 OldNameCol = 1 DepthCol = 2 PointsCol = 3 ParticipationCol = 4 DNFCol = 5 def __init__(self, parent): wx.Panel.__init__(self, parent) #-------------------------------------------------------------------------- box = wx.StaticBox(self, -1, 'Score Competitors by') bsizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.scoreByPoints = wx.RadioButton(self, label='Points', style=wx.RB_GROUP) self.scoreByPoints.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByTime = wx.RadioButton(self, label='Time') self.scoreByTime.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByPercent = wx.RadioButton( self, label='Percent Time (100 * WinnersTime / FinishTime)') self.scoreByPercent.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByTrueSkill = wx.RadioButton(self, label='TrueSkill') self.scoreByTrueSkill.Bind(wx.EVT_RADIOBUTTON, self.fixEnable) self.scoreByPoints.SetValue(True) hb = wx.BoxSizer(wx.HORIZONTAL) hb.Add(self.scoreByPoints) hb.Add(self.scoreByTime, flag=wx.LEFT, border=16) hb.Add(self.scoreByPercent, flag=wx.LEFT, border=16) hb.Add(self.scoreByTrueSkill, flag=wx.LEFT, border=16) bsizer.Add(hb, flag=wx.ALL, border=2) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.considerPrimePointsOrTimeBonus = wx.CheckBox( self, label='Consider Points or Time Bonuses from CrossMgr Primes') self.considerPrimePointsOrTimeBonus.SetValue(True) bsizer.Add(self.considerPrimePointsOrTimeBonus, 0, flag=wx.ALL, border=4) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) maxOptions = 30 self.considerLabel = wx.StaticText(self, label='{}:'.format('Consider')) self.bestResultsToConsider = wx.Choice( self, choices=['All Results', 'Best Result Only'] + [ '{} {} {}'.format('Best', i, 'Results Only') for i in xrange(2, maxOptions + 1) ]) self.participationLabel = wx.StaticText( self, label='{}:'.format('Must have completed')) self.mustHaveCompleted = wx.Choice( self, choices=[ '{} {}'.format(i, 'or more Events') for i in xrange(0, maxOptions + 1) ]) hb = wx.BoxSizer(wx.HORIZONTAL) hb.Add(self.considerLabel, flag=wx.ALIGN_CENTRE_VERTICAL) hb.Add(self.bestResultsToConsider) hb.Add(self.participationLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=16) hb.Add(self.mustHaveCompleted) bsizer.Add(hb, flag=wx.ALL, border=2) #-------------------------------------------------------------------------- bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.ifRidersTiedOnPoints = wx.StaticText( self, label='If Riders are Tied on Points:') bsizer.Add(self.ifRidersTiedOnPoints, flag=wx.ALL, border=2) self.mostEventsCompleted = wx.CheckBox( self, label='Consider Number of Events Completed') self.mostEventsCompleted.SetValue(False) bsizer.Add(self.mostEventsCompleted, 0, flag=wx.ALL, border=4) bsizer.Add(wx.StaticLine(self), 1, flag=wx.EXPAND | wx.ALL, border=4) self.numPlacesTieBreaker = wx.RadioBox( self, majorDimension=3, style=wx.RA_SPECIFY_ROWS, choices=[ 'Do not consider Place Finishes.', 'Number of 1st Place Finishes', 'Number of 1st then 2nd Place Finishes', 'Number of 1st, 2nd then 3rd Place Finishes', 'Number of 1st, 2nd, 3rd then 4th Place Finishes', 'Number of 1st, 2nd, 3rd, 4th then 5th Place Finishes', ]) self.numPlacesTieBreaker.SetLabel( u'If Riders are still Tied on Points:') bsizer.Add(self.numPlacesTieBreaker, 0, flag=wx.ALL | wx.EXPAND, border=2) self.ifRidersAreStillTiedOnPoints = wx.StaticText( self, label=u'If Riders are still Tied on Points, use most Recent Results' ) bsizer.Add(self.ifRidersAreStillTiedOnPoints, flag=wx.ALL, border=4) self.headerNames = [ 'Name', 'OldName', 'Depth', 'Points for Position', 'Participation', 'DNF' ] self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(50, len(self.headerNames)) for col in xrange(self.grid.GetNumberCols()): self.grid.SetColLabelValue( col, self.headerNames[col] + (u' ' if self.headerNames[col] == 'DNF' else '')) attr = gridlib.GridCellAttr() attr.SetReadOnly(True) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.grid.SetColAttr(self.DepthCol, attr) attr = gridlib.GridCellAttr() attr.SetEditor(PointsEditor()) self.grid.SetColAttr(self.PointsCol, attr) for c in (self.ParticipationCol, self.DNFCol): attr = gridlib.GridCellAttr() attr.SetRenderer(wx.grid.GridCellNumberRenderer()) attr.SetEditor(wx.grid.GridCellNumberEditor(0, 10000)) self.grid.SetColAttr(c, attr) self.gridAutoSize() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(bsizer, 0, flag=wx.EXPAND | wx.ALL, border=4) self.pointsStructures = wx.StaticText(self, wx.ID_ANY, 'Points Structures:') sizer.Add(self.pointsStructures, 0, flag=wx.ALL, border=4) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer) self.scoreByPointsControls = [ self.ifRidersTiedOnPoints, self.mostEventsCompleted, self.numPlacesTieBreaker, self.ifRidersAreStillTiedOnPoints, self.pointsStructures, self.grid, ] def getGrid(self): return self.grid def gridAutoSize(self): self.grid.AutoSize() self.grid.SetColMinimalAcceptableWidth(0) self.grid.SetColMinimalWidth(self.OldNameCol, 0) self.grid.SetColSize(self.OldNameCol, 0) self.grid.EnableDragGridSize(False) self.grid.EnableDragColSize(False) self.Layout() self.Refresh() def updateDepth(self, row): v = self.grid.GetCellValue(row, self.PointsCol).strip() depth = unicode(len(v.split())) if v else u'' self.grid.SetCellValue(row, self.DepthCol, depth) def onGridChange(self, event): row = event.GetRow() if row >= 0: self.updateDepth(row) wx.CallAfter(self.gridAutoSize) def fixEnable(self, event=None): enable = self.scoreByPoints.GetValue() for c in self.scoreByPointsControls: c.Enable(enable) def refresh(self): model = SeriesModel.model for row in xrange(self.grid.GetNumberRows()): for col in xrange(self.grid.GetNumberCols()): self.grid.SetCellValue(row, col, '') for row, ps in enumerate(model.pointStructures): self.grid.SetCellValue(row, self.NameCol, ps.name) self.grid.SetCellValue(row, self.OldNameCol, ps.name) self.grid.SetCellValue(row, self.PointsCol, ps.getStr()) self.grid.SetCellValue(row, self.ParticipationCol, unicode(ps.participationPoints)) self.grid.SetCellValue(row, self.DNFCol, unicode(ps.dnfPoints)) self.updateDepth(row) wx.CallAfter(self.gridAutoSize) self.considerPrimePointsOrTimeBonus.SetValue( model.considerPrimePointsOrTimeBonus) self.bestResultsToConsider.SetSelection(model.bestResultsToConsider) self.mustHaveCompleted.SetSelection(model.mustHaveCompleted) self.mostEventsCompleted.SetValue(model.useMostEventsCompleted) self.numPlacesTieBreaker.SetSelection(model.numPlacesTieBreaker) if model.scoreByTime: self.scoreByTime.SetValue(True) elif model.scoreByPercent: self.scoreByPercent.SetValue(True) elif model.scoreByTrueSkill: self.scoreByTrueSkill.SetValue(True) else: self.scoreByPoints.SetValue(True) self.fixEnable() def commit(self): self.grid.SaveEditControlValue() self.grid.DisableCellEditControl( ) # Make sure the current edit is committed. pointsList = [] for row in xrange(self.grid.GetNumberRows()): if (self.grid.GetCellValue(row, self.NameCol).strip()): pointsList.append(( self.grid.GetCellValue(row, self.NameCol), self.grid.GetCellValue(row, self.OldNameCol), self.grid.GetCellValue(row, self.PointsCol), self.grid.GetCellValue(row, self.ParticipationCol), self.grid.GetCellValue(row, self.DNFCol), )) model = SeriesModel.model model.setPoints(pointsList) modelUpdate = { 'considerPrimePointsOrTimeBonus': self.considerPrimePointsOrTimeBonus.GetValue(), 'bestResultsToConsider': self.bestResultsToConsider.GetSelection(), 'mustHaveCompleted': self.mustHaveCompleted.GetSelection(), 'useMostEventsCompleted': self.mostEventsCompleted.GetValue(), 'numPlacesTieBreaker': self.numPlacesTieBreaker.GetSelection(), 'scoreByTime': self.scoreByTime.GetValue(), 'scoreByPercent': self.scoreByPercent.GetValue(), 'scoreByTrueSkill': self.scoreByTrueSkill.GetValue(), } for attr, value in modelUpdate.iteritems(): if getattr(model, attr) != value: setattr(model, attr, value) model.changed = True
def __init__(self, parent): wx.Panel.__init__(self, parent) self.seriesNameLabel = wx.StaticText(self, label='Series Name:') self.seriesName = wx.TextCtrl(self) self.organizerNameLabel = wx.StaticText(self, label='Organizer:') self.organizerName = wx.TextCtrl(self) self.explanation = wx.StaticText( self, label=u'\n'.join([ _("Add all the races in your Series."), _("Make sure the races are in chronological order."), _("You can change the order by dragging-and-dropping the first grey column in the table." ), u'', _("Configure the Points Structures or Time Scoring parameters on the Scoring Criteria page." ), _("Each race can have its own Points Structure. For example, you could create 'Double Points' for one race." ), u'', _("Race results are shown Last-to-First in the output by default." ), _("You can change this on the Options page."), ])) self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.DisableDragRowSize() self.grid.SetRowLabelSize(64) self.grid.CreateGrid(0, len(self.headerNames)) for col in range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.pointsChoiceEditor = gridlib.GridCellChoiceEditor( [], allowOthers=False) attr = gridlib.GridCellAttr() attr.SetEditor(self.pointsChoiceEditor) self.grid.SetColAttr(self.PointsCol, attr) self.teamPointsChoiceEditor = gridlib.GridCellChoiceEditor( [], allowOthers=False) attr = gridlib.GridCellAttr() attr.SetEditor(self.teamPointsChoiceEditor) self.grid.SetColAttr(self.TeamPointsCol, attr) attr = gridlib.GridCellAttr() attr.SetReadOnly(True) self.grid.SetColAttr(self.RaceCol, attr) attr = gridlib.GridCellAttr() attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.grid.SetColAttr(self.GradeCol, attr) ''' attr = gridlib.GridCellAttr() attr.SetReadOnly( True ) self.grid.SetColAttr( self.RaceStatusCol, attr ) ''' attr = gridlib.GridCellAttr() attr.SetReadOnly(True) self.grid.SetColAttr(self.RaceFileCol, attr) self.grid.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.onGridChange) self.gridAutoSize() self.grid.Bind(wx.grid.EVT_GRID_EDITOR_CREATED, self.onGridEditorCreated) self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.onEditRaceFileName) self.addButton = wx.Button(self, wx.ID_ANY, 'Add Races') self.addButton.Bind(wx.EVT_BUTTON, self.doAddRace) self.removeButton = wx.Button(self, wx.ID_ANY, 'Remove Race') self.removeButton.Bind(wx.EVT_BUTTON, self.doRemoveRace) fgs = wx.FlexGridSizer(rows=2, cols=2, vgap=2, hgap=2) fgs.AddGrowableCol(1, proportion=1) fgs.Add(self.seriesNameLabel, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT) fgs.Add(self.seriesName, flag=wx.EXPAND) fgs.Add(self.organizerNameLabel, flag=wx.ALIGN_CENTRE_VERTICAL | wx.ALIGN_RIGHT) fgs.Add(self.organizerName, flag=wx.EXPAND) hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.addButton, 0, flag=wx.ALL, border=4) hs.Add(self.removeButton, 0, flag=wx.ALL, border=4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(fgs, 0, flag=wx.EXPAND | wx.ALL, border=4) sizer.Add(self.explanation, 0, flag=wx.EXPAND | wx.ALL, border=4) sizer.Add(hs, 0, flag=wx.EXPAND) sizer.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=6) self.SetSizer(sizer)
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)
def __init__(self, parent): EnablePanel.__init__(self, parent) self.box = wx.StaticBox( self, label='Result (right-click to enter Bib numbers from keyboard)') boxSizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) self.event = None self.SetBackgroundColour(wx.WHITE) self.activeBar = EnableBar(self) self.activeBar.SetToolTip( wx.ToolTip('.\n'.join([ 'Record the Finish Order by dragging the row numbers in the table.', 'Record DNF and DQ in the Status column.', 'Then press OK or Cancel.' ]))) vs = wx.BoxSizer(wx.VERTICAL) self.okButton = MakeRoundButton(self, 'OK') self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) vs.Add(self.okButton, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) vs.Add(self.cancelButton, flag=wx.ALL, border=4) self.headerNames = [ 'Bib', 'Name', 'Team', 'Status', 'Warn', 'Rel', 'Time ' ] self.iColStatus = self.headerNames.index('Status') self.iColWarning = self.headerNames.index('Warn') self.iColRelegation = self.headerNames.index('Rel') self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.CreateGrid(4, len(self.headerNames)) self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnClick) self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnRightClick) font = GetFont() self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.grid.SetCellValue( 0, col, self.headerNames[col]) # Add the label as data. attr = gridlib.GridCellAttr() attr.SetFont(font) if self.headerNames[col] == 'Bib': attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) elif self.headerNames[col].startswith('Time'): attr.SetEditor(HighPrecisionTimeEditor()) attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) elif col == 1 or col == 2: attr.SetReadOnly(True) elif col == self.iColStatus: attr.SetEditor( gridlib.GridCellChoiceEditor( choices=['DQ', 'DNF', 'DNS', ''])) elif col == self.iColWarning or col == self.iColRelegation: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) attr.SetEditor(gridlib.GridCellBoolEditor()) attr.SetRenderer(gridlib.GridCellBoolRenderer()) self.grid.SetColAttr(col, attr) self.grid.AutoSizeColumns(False) # Resize to fit the column name. self.grid.AutoSizeRows(False) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellValue(0, col, '') # Remove the labels. boxSizer.Add(self.activeBar, 0, flag=wx.ALL | wx.EXPAND, border=4) boxSizer.Add(vs, 0, flag=wx.ALL, border=4) boxSizer.Add(self.grid, 1, flag=wx.ALL | wx.EXPAND, border=4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(boxSizer, 1, flag=wx.EXPAND) self.SetSizer(sizer)
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 Primes( wx.Panel ): def __init__( self, parent, id=wx.ID_ANY, size=wx.DefaultSize ): super(Primes, self).__init__( parent, id, size=size ) self.state = RaceInputState() vsOverall = wx.BoxSizer( wx.VERTICAL ) #--------------------------------------------------------------- self.colNameFields = ( (_('Prime For'), 'effortType', 's'), (_('or Custom'), 'effortCustom', 's'), (_('Position'), 'position', 'i'), (_('Laps\nTo Go'), 'lapsToGo', 'i'), (_('Sponsor'), 'sponsor', 's'), (_('Cash'), 'cash', 'f'), (_('Merchandise'), 'merchandise', 's'), (_('Points'), 'points', 'i'), (_('Time\nBonus'), 'timeBonus', 't'), (_('Winner\nBib'), 'winnerBib', 'i'), (u'', 'winnerInfo', 's'), ) self.colnames = [colName for colName, fieldName, dataType in self.colNameFields] self.iCol = dict( (fieldName, i) for i, (colName, fieldName, dataType) in enumerate(self.colNameFields) if fieldName ) self.grid = ReorderableGrid( self ) self.grid.CreateGrid( 0, len(self.colNameFields) ) GetTranslation = _ for col, (colName, fieldName, dataType) in enumerate(self.colNameFields): self.grid.SetColLabelValue( col, colName ) attr = wx.grid.GridCellAttr() if fieldName == 'effortType': attr.SetEditor( wx.grid.GridCellChoiceEditor(choices=[GetTranslation(name) for code, name in EffortChoices]) ) attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_TOP ) elif fieldName == 'position': attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_TOP ) elif fieldName == 'winnerInfo': attr.SetReadOnly( True ) elif dataType == 'i': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_TOP ) attr.SetEditor( wx.grid.GridCellFloatEditor(precision=0) ) attr.SetRenderer( wx.grid.GridCellFloatRenderer(precision=0) ) elif dataType == 'f': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_TOP ) attr.SetEditor( wx.grid.GridCellFloatEditor(precision=2) ) attr.SetRenderer( wx.grid.GridCellFloatRenderer(precision=2) ) elif dataType == 't': attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE ) attr.SetEditor( TimeEditor() ) self.grid.SetColAttr( col, attr ) if fieldName == 'lapsToGo': self.lapsToGoCol = col self.grid.Bind( wx.grid.EVT_GRID_CELL_CHANGE, self.onCellChange ) self.grid.AutoSizeColumns( False ) self.grid.AutoSizeRows( False ) #--------------------------------------------------------------- self.photosButton = wx.Button( self, label=u'{}...'.format(_('Photos')) ) self.photosButton.Bind( wx.EVT_BUTTON, self.onPhotos ) self.finishStrip = wx.Button( self, label=u'{}...'.format(_('Finish Strip')) ) self.finishStrip.Bind( wx.EVT_BUTTON, self.onFinishStrip ) self.history = wx.Button( self, label=u'{}...'.format(_('Passings')) ) self.history.Bind( wx.EVT_BUTTON, self.onHistory ) self.newButton = wx.Button( self, id=wx.ID_NEW ) self.newButton.SetToolTip( wx.ToolTip(_('Create a new Prime')) ) self.newButton.Bind( wx.EVT_BUTTON, self.onNew ) self.nextPositionButton = wx.Button( self, label=('Next Position') ) self.nextPositionButton.SetToolTip( wx.ToolTip(_('Create a Prime from an Existing Prime for the Next Position')) ) self.nextPositionButton.Bind( wx.EVT_BUTTON, self.onNextPosition ) self.nextPrimeButton = wx.Button( self, label=('Next Prime') ) self.nextPrimeButton.SetToolTip( wx.ToolTip(_('Create a Prime from an Existing Prime')) ) self.nextPrimeButton.Bind( wx.EVT_BUTTON, self.onNextPrime ) self.deleteButton = wx.Button( self, id=wx.ID_DELETE ) self.deleteButton.SetToolTip( wx.ToolTip(_('Delete a Prime')) ) self.deleteButton.Bind( wx.EVT_BUTTON, self.onDelete ) hsButtons = wx.BoxSizer( wx.HORIZONTAL ) hsButtons.Add( self.photosButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.finishStrip, flag=wx.ALL, border=4 ) hsButtons.Add( self.history, flag=wx.ALL, border=4 ) hsButtons.AddStretchSpacer() hsButtons.Add( self.newButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.nextPositionButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.nextPrimeButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.deleteButton, flag=wx.ALL, border=4 ) #--------------------------------------------------------------- vsOverall.Add( self.grid, 1, flag=wx.EXPAND|wx.ALL, border=4 ) vsOverall.Add( hsButtons, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=4 ) self.SetSizer( vsOverall ) def onCellChange( self, event ): row, col = event.GetRow(), event.GetCol() colName = self.colNameFields[col][1] GetTranslation = _ if colName == 'effortCustom': if self.grid.GetCellValue(row, col).strip(): self.grid.SetCellValue( row, col-1, GetTranslation('Custom') ) elif colName == 'effortType': if self.grid.GetCellValue(row, col) != 'Custom': self.grid.SetCellValue( row, col+1, u'' ) elif colName == 'winnerBib': bib = int( u''.join(c for c in self.grid.GetCellValue(row, col) if c.isdigit()) ) self.grid.SetCellValue( row, col+1, getWinnerInfo(bib) ) wx.CallAfter( self.grid.AutoSizeColumns, False ) def getT( self ): race = Model.race if not race: return 0 row = self.grid.GetGridCursorRow() if row is None or row < 0: return lapsToGo = int( u''.join(c for c in self.grid.GetCellValue(row, self.lapsToGoCol) if c.isdigit()) ) tMax = 0.0 for rr in GetResults(None): try: tMax = min( tMax, rr.raceTimes[-1-lapsToGo] ) except IndexError: pass return tMax def onPhotos( self, event ): mainWin = Utils.getMainWin() if not mainWin: return mainWin.photoDialog.SetT( self.getT() ) mainWin.photoDialog.Show() def onFinishStrip( self, event ): ShowFinishStrip( self, self.getT() ) def onHistory( self, event ): mainWin = Utils.getMainWin() if not mainWin: return mainWin.openMenuWindow( 'Passings' ) def selectGridRow( self, row ): self.grid.SelectRow( row ) self.grid.SetGridCursor( row, 0 ) self.grid.ShowCellEditControl() def onNew( self, event ): race = Model.race if not race: Utils.MessageOK( self, _('You must have a Race to create a Prime.'), _('Missing Race') ) return self.commit() race.primes = getattr(race, 'primes', []) rowNew = len( race.primes ) race.primes.append( {} ) self.updateGrid() self.selectGridRow( rowNew ) def onNextPosition( self, event ): rowNext = self.grid.GetGridCursorRow() if rowNext is None or rowNext < 0: return self.commit() race = Model.race if not race: Utils.MessageOK( self, _('You must have a Race to create a next Prime.'), _('Missing Race') ) return nextPrime = race.primes[rowNext].copy() nextPoints = { (1, 5): 3, (2, 3): 2, (3, 2): 1, }.get( (nextPrime['position'], nextPrime['points']), None ) if nextPoints is not None: nextPrime['points'] = nextPoints try: nextPrime['position'] += 1 except: pass nextPrime['winnerBib'] = None race.primes = race.primes[:rowNext+1] + [nextPrime] + race.primes[rowNext+1:] self.updateGrid() self.selectGridRow( rowNext + 1 ) def onNextPrime( self, event ): rowNext = self.grid.GetGridCursorRow() if rowNext is None or rowNext < 0: return self.commit() race = Model.race if not race: Utils.MessageOK( self, _('You must have a Race to create a next Prime.'), _('Missing Race') ) return nextPrime = race.primes[rowNext].copy() nextPrime['position'] = 1 if nextPrime['points']: nextPrime['points'] = 5 if nextPrime['lapsToGo'] > 0: nextPrime['lapsToGo'] -= 1 nextPrime['winnerBib'] = None race.primes = race.primes[:rowNext+1] + [nextPrime] + race.primes[rowNext+1:] self.updateGrid() self.selectGridRow( rowNext + 1 ) def onDelete( self, event ): rowDelete = self.grid.GetGridCursorRow() if rowDelete is None or rowDelete < 0: return self.commit() race = Model.race if race and Utils.MessageOKCancel( self, u'{}: {} ?'.format(_('Delete Prime'), rowDelete+1), _('Confirm Delete Primes') ): race.primes = getattr(race, 'primes', []) try: del race.primes[rowDelete] except Exception as e: return self.updateGrid() if race.primes: self.grid.SetGridCursor( rowDelete, 0 ) def getSponsors( self ): race = Model.race if not race: return [] sponsors = [prime.get('sponsor', u'') for prime in getattr(race, 'primes', [])] + [race.organizer] sponsors = [s for s in sponsors if s] return sponsors def getMerchandise( self ): race = Model.race if not race: return [] merchandise = [prime.get('merchandise', u'') for prime in getattr(race, 'primes', [])] merchandise = [m for m in merchandise if m] return merchandise def setRow( self, prime, row, updateGrid=True ): GetTranslation = _ data = [] for col, (name, attr, dataType) in enumerate(self.colNameFields): if attr == 'effortType': effortType = prime.get('effortType', 'Pack') v = GetTranslation(effortType) elif attr == 'position': position = prime.get('position', 1) v = u'' if position == 0 else unicode(position) elif attr == 'points': points = prime.get('points', 0) v = u'' if points == 0 else unicode(points) elif attr == 'winnerBib': winnerBib = prime.get('winnerBib', None) v = u'' if not winnerBib else unicode(winnerBib) elif attr == 'winnerInfo': v = getWinnerInfo(winnerBib) elif dataType == 'f': f = prime.get(attr, 0.0) v = u'{:.2f}'.format(f) if f else u'' elif dataType == 't': t = prime.get(attr, 0.0) v = Utils.formatTime(t, forceHours=True, twoDigitHours=True) if t != 0 else u'' else: v = unicode(prime.get(attr, u'')) if updateGrid: self.grid.SetCellValue( row, col, v ) data.append( v ) return data def getRow( self, row ): values = {} for col, (name, attr, dataType) in enumerate(self.colNameFields): v = self.grid.GetCellValue( row, col ).strip() if dataType == 'i': v = u''.join( c for c in v if c.isdigit() ) v = int( v or 0 ) elif dataType == 'f': v = u''.join( c for c in v if c.isdigit() or c == '.') v = float( v or 0.0 ) elif dataType == 't': v = Utils.StrToSeconds( v ) if attr == 'position' and not v: v = 1 values[attr] = v GetTranslation = _ for code, name in EffortChoices: if values['effortType'] == GetTranslation(name): values['effortType'] = name break if values['effortCustom']: values['effortType'] = 'Custom' return values def updateGrid( self ): race = Model.race if not race or not getattr(race, 'primes', None): self.grid.ClearGrid() return Utils.AdjustGridSize( self.grid, len(race.primes) ) for row, prime in enumerate(race.primes): self.setRow( prime, row ) self.grid.AutoSizeColumns( False ) # Resize to fit the column name. self.grid.AutoSizeRows( False ) def refresh( self ): if self.state.changed(): self.updateGrid() def commit( self ): self.grid.SaveEditControlValue() # Make sure the current edit is committed. self.grid.DisableCellEditControl() race = Model.race if not race: return race.primes = [self.getRow(row) for row in xrange(self.grid.GetNumberRows())]
class EventFinishOrder(EnablePanel): def __init__(self, parent): EnablePanel.__init__(self, parent) self.box = wx.StaticBox( self, label='Result (right-click to enter Bib numbers from keyboard)') boxSizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) self.event = None self.SetBackgroundColour(wx.WHITE) self.activeBar = EnableBar(self) self.activeBar.SetToolTip( wx.ToolTip('.\n'.join([ 'Record the Finish Order by dragging the row numbers in the table.', 'Record DNF and DQ in the Status column.', 'Then press OK or Cancel.' ]))) vs = wx.BoxSizer(wx.VERTICAL) self.okButton = MakeRoundButton(self, 'OK') self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) vs.Add(self.okButton, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) vs.Add(self.cancelButton, flag=wx.ALL, border=4) self.headerNames = [ 'Bib', 'Name', 'Team', 'Status', 'Warn', 'Rel', 'Time ' ] self.iColStatus = self.headerNames.index('Status') self.iColWarning = self.headerNames.index('Warn') self.iColRelegation = self.headerNames.index('Rel') self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.CreateGrid(4, len(self.headerNames)) self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnClick) self.grid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnRightClick) font = GetFont() self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.grid.SetCellValue( 0, col, self.headerNames[col]) # Add the label as data. attr = gridlib.GridCellAttr() attr.SetFont(font) if self.headerNames[col] == 'Bib': attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) attr.SetReadOnly(True) elif self.headerNames[col].startswith('Time'): attr.SetEditor(HighPrecisionTimeEditor()) attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) elif col == 1 or col == 2: attr.SetReadOnly(True) elif col == self.iColStatus: attr.SetEditor( gridlib.GridCellChoiceEditor( choices=['DQ', 'DNF', 'DNS', ''])) elif col == self.iColWarning or col == self.iColRelegation: attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) attr.SetEditor(gridlib.GridCellBoolEditor()) attr.SetRenderer(gridlib.GridCellBoolRenderer()) self.grid.SetColAttr(col, attr) self.grid.AutoSizeColumns(False) # Resize to fit the column name. self.grid.AutoSizeRows(False) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellValue(0, col, '') # Remove the labels. boxSizer.Add(self.activeBar, 0, flag=wx.ALL | wx.EXPAND, border=4) boxSizer.Add(vs, 0, flag=wx.ALL, border=4) boxSizer.Add(self.grid, 1, flag=wx.ALL | wx.EXPAND, 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.okButton, isSelect), (self.cancelButton, isCancel)]: EnableRoundButton(b, enable, t) self.activeBar.SetBackgroundColour( wx.Colour(0, 128, 0) if enable else wx.WHITE) self.Refresh() def OnClick(self, event): row = event.GetRow() col = event.GetCol() if col == self.iColWarning or col == self.iColRelegation: self.grid.SetCellValue( row, col, u'0' if (self.grid.GetCellValue(row, col) or u'0')[:1] in u'1TtYy' else u'1') else: event.Skip() def OnRightClick(self, event): ted = wx.TextEntryDialog( self, 'Enter Bib Numbers separated by space or comma', 'Enter Bibs') ret = ted.ShowModal() v = ted.GetValue() ted.Destroy() if ret != wx.ID_OK: return oldBibOrder = [ int(self.grid.GetCellValue(row, 0)) for row in six.moves.range(self.grid.GetNumberRows()) ] oldBibs = set(oldBibOrder) v = re.sub(r'[^\d]', u' ', v) newBibOrder = [int(f) for f in v.split()] newBibOrder = [b for b in newBibOrder if b in oldBibs] newBibs = set(newBibOrder) newBibOrder.extend(b for b in oldBibOrder if b not in newBibs) for row, bib in enumerate(newBibOrder): if oldBibOrder[row] != bib: i = oldBibOrder.index(bib) oldBibOrder[i], oldBibOrder[row] = oldBibOrder[ row], oldBibOrder[i] Utils.SwapGridRows(self.grid, row, i) def setEvent(self, event): self.event = event def refresh(self): if not self.event: self.grid.ClearGrid() return # Propose finish order by qualifying time. state = self.event.competition.state finishPositions = sorted(self.event.starts[-1].startPositions, key=lambda r: state.labels[r].qualifyingTime) Utils.AdjustGridSize(self.grid, rowsRequired=len(finishPositions)) state = self.event.competition.state row = 0 # List DNS starters at the end. for b in [False, True]: for p in finishPositions: rider = state.labels[p] if (rider.bib in CacheDNSs) == b: for col, v in enumerate([ rider.bib, rider.full_name, rider.team, 'DNS' if rider.bib in CacheDNSs else '', '' ]): self.grid.SetCellValue(row, col, u' {}'.format(v)) row += 1 self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def commit(self): self.grid.SaveEditControlValue() if not self.event: self.grid.ClearGrid() return iColTime = self.grid.GetNumberCols() - 1 places = [] times = [] for row in six.moves.range(self.grid.GetNumberRows()): bib = self.grid.GetCellValue(row, 0) try: bib = int(bib) except: continue 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)) try: t = Utils.StrToSeconds(self.grid.GetCellValue(row, iColTime)) except ValueError: continue times.append((row + 1, t)) start = self.event.starts[-1] start.setPlaces(places) start.setTimes(times) self.event.propagate() Model.model.setChanged(True) Model.model.competition.propagate() Utils.setTitle()
def __init__(self, parent): EnablePanel.__init__(self, parent) self.box = wx.StaticBox(self, label='Start Positions') boxSizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) self.SetBackgroundColour(wx.WHITE) self.event = None self.drawLotsBitmap = wx.Bitmap( os.path.join(Utils.getImageFolder(), 'dice.png'), wx.BITMAP_TYPE_PNG) self.drawLotsGreyBitmap = wx.Bitmap( os.path.join(Utils.getImageFolder(), 'dice_grey.png'), wx.BITMAP_TYPE_PNG) self.emptyBitmap = wx.Bitmap(self.drawLotsBitmap.GetWidth(), self.drawLotsBitmap.GetHeight(), self.drawLotsBitmap.GetDepth()) dc = wx.MemoryDC() dc.SelectObject(self.emptyBitmap) dc.SetBrush(wx.WHITE_BRUSH) dc.Clear() dc.SelectObject(wx.NullBitmap) self.activeBar = EnableBar(self) self.activeBar.SetToolTip( wx.ToolTip(u'\n'.join([ u'Record the Start Positions by dragging the row numbers in the table.', u'Set any DNS in the Status column.', u'Then press Start or Cancel.', ]))) vs = wx.BoxSizer(wx.VERTICAL) self.startButton = MakeRoundButton(self, 'Start') self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) vs.Add(self.startButton, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) vs.Add(self.cancelButton, flag=wx.ALL, border=4) self.headerNames = ['Bib', 'Name', 'Team', 'Status'] self.iColStatus = 3 self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.CreateGrid(4, len(self.headerNames)) font = wx.Font((0, FontSize), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.grid.SetCellValue( 0, col, self.headerNames[col]) # Add the label as data. attr = gridlib.GridCellAttr() attr.SetFont(font) attr.SetReadOnly(True) if self.headerNames[col].startswith('Bib'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) elif self.headerNames[col].startswith('Status'): attr.SetEditor( gridlib.GridCellChoiceEditor(choices=['DNS', ''])) attr.SetReadOnly(False) self.grid.SetColAttr(col, attr) self.grid.AutoSizeColumns(False) # Resize to fit the column name. self.grid.AutoSizeRows(False) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellValue(0, col, '') # Remove the labels. self.drawLotsDisplay = wx.StaticBitmap(self, wx.ID_ANY, self.drawLotsBitmap) self.drawLotsDisplay.SetToolTip( wx.ToolTip(u'\n'.join([ u"Dice are active when riders need to draw lots to select their positions.", u"Dice are inactive when riders' start positions are known.", ]))) boxSizer.Add(self.activeBar, 0, flag=wx.ALL | wx.EXPAND, 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.drawLotsDisplay, 0, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, border=4) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(boxSizer, 1, flag=wx.EXPAND) self.SetSizer(sizer)
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)
def __init__( self, parent, id=wx.ID_ANY, size=wx.DefaultSize ): super(Primes, self).__init__( parent, id, size=size ) self.state = RaceInputState() vsOverall = wx.BoxSizer( wx.VERTICAL ) #--------------------------------------------------------------- self.colNameFields = ( (_('Prime For'), 'effortType', 's'), (_('or Custom'), 'effortCustom', 's'), (_('Position'), 'position', 'i'), (_('Laps\nTo Go'), 'lapsToGo', 'i'), (_('Sponsor'), 'sponsor', 's'), (_('Cash'), 'cash', 'f'), (_('Merchandise'), 'merchandise', 's'), (_('Points'), 'points', 'i'), (_('Time\nBonus'), 'timeBonus', 't'), (_('Winner\nBib'), 'winnerBib', 'i'), (u'', 'winnerInfo', 's'), ) self.colnames = [colName for colName, fieldName, dataType in self.colNameFields] self.iCol = dict( (fieldName, i) for i, (colName, fieldName, dataType) in enumerate(self.colNameFields) if fieldName ) self.grid = ReorderableGrid( self ) self.grid.CreateGrid( 0, len(self.colNameFields) ) GetTranslation = _ for col, (colName, fieldName, dataType) in enumerate(self.colNameFields): self.grid.SetColLabelValue( col, colName ) attr = wx.grid.GridCellAttr() if fieldName == 'effortType': attr.SetEditor( wx.grid.GridCellChoiceEditor(choices=[GetTranslation(name) for code, name in EffortChoices]) ) attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_TOP ) elif fieldName == 'position': attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_TOP ) elif fieldName == 'winnerInfo': attr.SetReadOnly( True ) elif dataType == 'i': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_TOP ) attr.SetEditor( wx.grid.GridCellFloatEditor(precision=0) ) attr.SetRenderer( wx.grid.GridCellFloatRenderer(precision=0) ) elif dataType == 'f': attr.SetAlignment( wx.ALIGN_RIGHT, wx.ALIGN_TOP ) attr.SetEditor( wx.grid.GridCellFloatEditor(precision=2) ) attr.SetRenderer( wx.grid.GridCellFloatRenderer(precision=2) ) elif dataType == 't': attr.SetAlignment( wx.ALIGN_CENTRE, wx.ALIGN_CENTRE ) attr.SetEditor( TimeEditor() ) self.grid.SetColAttr( col, attr ) if fieldName == 'lapsToGo': self.lapsToGoCol = col self.grid.Bind( wx.grid.EVT_GRID_CELL_CHANGE, self.onCellChange ) self.grid.AutoSizeColumns( False ) self.grid.AutoSizeRows( False ) #--------------------------------------------------------------- self.photosButton = wx.Button( self, label=u'{}...'.format(_('Photos')) ) self.photosButton.Bind( wx.EVT_BUTTON, self.onPhotos ) self.finishStrip = wx.Button( self, label=u'{}...'.format(_('Finish Strip')) ) self.finishStrip.Bind( wx.EVT_BUTTON, self.onFinishStrip ) self.history = wx.Button( self, label=u'{}...'.format(_('Passings')) ) self.history.Bind( wx.EVT_BUTTON, self.onHistory ) self.newButton = wx.Button( self, id=wx.ID_NEW ) self.newButton.SetToolTip( wx.ToolTip(_('Create a new Prime')) ) self.newButton.Bind( wx.EVT_BUTTON, self.onNew ) self.nextPositionButton = wx.Button( self, label=('Next Position') ) self.nextPositionButton.SetToolTip( wx.ToolTip(_('Create a Prime from an Existing Prime for the Next Position')) ) self.nextPositionButton.Bind( wx.EVT_BUTTON, self.onNextPosition ) self.nextPrimeButton = wx.Button( self, label=('Next Prime') ) self.nextPrimeButton.SetToolTip( wx.ToolTip(_('Create a Prime from an Existing Prime')) ) self.nextPrimeButton.Bind( wx.EVT_BUTTON, self.onNextPrime ) self.deleteButton = wx.Button( self, id=wx.ID_DELETE ) self.deleteButton.SetToolTip( wx.ToolTip(_('Delete a Prime')) ) self.deleteButton.Bind( wx.EVT_BUTTON, self.onDelete ) hsButtons = wx.BoxSizer( wx.HORIZONTAL ) hsButtons.Add( self.photosButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.finishStrip, flag=wx.ALL, border=4 ) hsButtons.Add( self.history, flag=wx.ALL, border=4 ) hsButtons.AddStretchSpacer() hsButtons.Add( self.newButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.nextPositionButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.nextPrimeButton, flag=wx.ALL, border=4 ) hsButtons.Add( self.deleteButton, flag=wx.ALL, border=4 ) #--------------------------------------------------------------- vsOverall.Add( self.grid, 1, flag=wx.EXPAND|wx.ALL, border=4 ) vsOverall.Add( hsButtons, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, border=4 ) self.SetSizer( vsOverall )
class Categories(wx.Panel): CategoryTypeChoices = [ _('Start Wave'), u' ' + _('Component'), _('Custom') ] DistanceTypeChoices = [_('Lap'), _('Race')] def __init__(self, parent, id=wx.ID_ANY): wx.Panel.__init__(self, parent, id) self.state = RaceInputState() vs = wx.BoxSizer(wx.VERTICAL) self.ignoreColour = wx.Colour(80, 80, 80) self.inactiveColour = wx.Colour(200, 200, 200) border = 4 flag = wx.ALL hs = wx.BoxSizer(wx.HORIZONTAL) self.activateAllButton = wx.Button(self, label=_('Activate All'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onActivateAll, self.activateAllButton) hs.Add(self.activateAllButton, 0, border=border, flag=flag) hs.AddSpacer(6) self.newCategoryButton = wx.Button(self, label=_('New'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onNewCategory, self.newCategoryButton) hs.Add(self.newCategoryButton, 0, border=border, flag=flag) self.delCategoryButton = wx.Button(self, label=_('Delete'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onDelCategory, self.delCategoryButton) hs.Add(self.delCategoryButton, 0, border=border, flag=(flag & ~wx.LEFT)) hs.AddSpacer(6) self.upCategoryButton = wx.Button(self, label=u'\u2191', style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onUpCategory, self.upCategoryButton) hs.Add(self.upCategoryButton, 0, border=border, flag=flag) self.downCategoryButton = wx.Button(self, label=u'\u2193', style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onDownCategory, self.downCategoryButton) hs.Add(self.downCategoryButton, 0, border=border, flag=(flag & ~wx.LEFT)) hs.AddSpacer(6) self.setGpxDistanceButton = wx.Button(self, label=_('Set Gpx Distance'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onSetGpxDistance, self.setGpxDistanceButton) hs.Add(self.setGpxDistanceButton, 0, border=border, flag=flag) hs.AddSpacer(6) self.addExceptionsButton = wx.Button(self, label=_('Bib Exceptions'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onAddExceptions, self.addExceptionsButton) hs.Add(self.addExceptionsButton, 0, border=border, flag=flag) hs.AddSpacer(6) ''' self.updateStartWaveNumbersButton = wx.Button(self, label=_('Update Start Wave Bibs'), style=wx.BU_EXACTFIT) self.Bind( wx.EVT_BUTTON, self.onUpdateStartWaveNumbers, self.updateStartWaveNumbersButton ) hs.Add( self.updateStartWaveNumbersButton, 0, border = border, flag = flag ) ''' self.normalizeButton = wx.Button(self, label=_('Normalize'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onNormalize, self.normalizeButton) hs.Add(self.normalizeButton, 0, border=border, flag=flag) hs.AddStretchSpacer() self.printButton = wx.Button(self, label=u'{}...'.format(_('Print')), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onPrint, self.printButton) hs.Add(self.printButton, 0, border=border, flag=flag) self.excelButton = wx.Button(self, label=u'{}...'.format(_('Excel')), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onExcel, self.excelButton) hs.Add(self.excelButton, 0, border=border, flag=flag) self.grid = ReorderableGrid(self) self.colNameFields = [ (u'', None), (_('Category Type'), 'catType'), (_('Active'), 'active'), (_('Name'), 'name'), (_('Gender'), 'gender'), (_('Numbers'), 'catStr'), (_('Start\nOffset'), 'startOffset'), (_('Race\nLaps'), 'numLaps'), (_('Race\nMinutes'), 'raceMinutes'), (_('Lapped\nRiders\nContinue'), 'lappedRidersMustContinue'), (_('Distance'), 'distance'), (_('Dist.\nBy'), 'distanceType'), (_('First\nLap\nDist.'), 'firstLapDistance'), (_('80%\nLap\nTime'), 'rule80Time'), (_('CrossMgr\nEstimated\nLaps'), 'suggestedLaps'), (_('Publish'), 'publishFlag'), (_('Upload'), 'uploadFlag'), (_('Series'), 'seriesFlag'), ] self.computedFields = {'rule80Time', 'suggestedLaps'} self.colnames = [ colName if not colName.startswith('_') else _('Name Copy') for colName, fieldName in self.colNameFields ] self.iCol = { fieldName: i for i, (colName, fieldName) in enumerate(self.colNameFields) if fieldName and not colName.startswith('_') } self.activeColumn = self.iCol['active'] self.genderColumn = self.iCol['gender'] self.numbersColumn = self.iCol['catStr'] self.grid.CreateGrid(0, len(self.colnames)) self.grid.SetRowLabelSize(32) self.grid.SetMargins(0, 0) for col, name in enumerate(self.colnames): self.grid.SetColLabelValue(col, name) self.cb = None self.boolCols = set() self.choiceCols = set() self.readOnlyCols = set() self.dependentCols = set() # Set column attributes for the table. for col, (colName, fieldName) in enumerate(self.colNameFields): attr = gridlib.GridCellAttr() if fieldName is None: attr.SetRenderer(CategoryIconRenderer()) attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) attr.SetReadOnly(True) self.readOnlyCols.add(col) elif fieldName == 'catType': self.catTypeWidth = 64 attr.SetEditor( gridlib.GridCellChoiceEditor(self.CategoryTypeChoices, False)) attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) self.choiceCols.add(col) elif fieldName in { 'active', 'lappedRidersMustContinue', 'publishFlag', 'uploadFlag', 'seriesFlag' }: boolEditor = gridlib.GridCellBoolEditor() boolEditor.UseStringValues('1', '0') attr.SetEditor(boolEditor) attr.SetRenderer(gridlib.GridCellBoolRenderer()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.boolCols.add(col) if fieldName == 'lappedRidersMustContinue': self.dependentCols.add(col) elif fieldName == 'gender': attr.SetEditor( gridlib.GridCellChoiceEditor( [_('Open'), _('Men'), _('Women')], False)) self.choiceCols.add(col) elif fieldName == 'startOffset': attr.SetEditor(TimeEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'numLaps': attr.SetEditor(wx.grid.GridCellNumberEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'raceMinutes': attr.SetEditor(wx.grid.GridCellNumberEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName in ['rule80Time', 'suggestedLaps']: attr.SetReadOnly(True) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.readOnlyCols.add(col) self.dependentCols.add(col) elif fieldName in ['distance', 'firstLapDistance']: attr.SetEditor(gridlib.GridCellFloatEditor(7, 3)) attr.SetRenderer(gridlib.GridCellFloatRenderer(7, 3)) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'distanceType': attr.SetEditor( gridlib.GridCellChoiceEditor(self.DistanceTypeChoices, False)) attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) self.choiceCols.add(col) self.dependentCols.add(col) elif colName == '_name2': attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) attr.SetBackgroundColour(wx.Colour(240, 240, 240)) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.onGridLeftClick) self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.onCellSelected) self.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.onCellChanged) self.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.onEditorCreated) vs.Add(hs, 0, flag=wx.EXPAND | wx.ALL, border=4) vs.Add(self.grid, 1, flag=wx.GROW | wx.ALL | wx.EXPAND) self.rowCur = 0 self.colCur = 0 self.SetSizer(vs) def onPrint(self, event): self.commit() PrintCategories() def onExcel(self, event): self.commit() export = getExportGrid() xlFName = Utils.getMainWin().getFormatFilename('excel') xlFName = os.path.splitext( xlFName)[0] + '-Categories' + os.path.splitext(xlFName)[1] wb = xlwt.Workbook() sheetCur = wb.add_sheet(_('Categories')) export.toExcelSheet(sheetCur) try: wb.save(xlFName) if Utils.getMainWin().launchExcelAfterPublishingResults: Utils.LaunchApplication(xlFName) Utils.MessageOK( self, u'{}:\n\n {}'.format(_('Excel file written to'), xlFName), _('Excel Write')) except IOError: Utils.MessageOK( self, u'{} "{}"\n\n{}\n{}'.format( _('Cannot write'), xlFName, _('Check if this spreadsheet is already open.'), _('If so, close it, and try again.')), _('Excel File Error'), iconMask=wx.ICON_ERROR) def onSetGpxDistance(self, event): race = Model.race geoTrack = getattr(race, 'geoTrack', None) if not geoTrack: return if not Utils.MessageOK(self, _('Set the GPX distance for all Categories?'), _('Set GPX Distance'), wx.ICON_QUESTION): return distance = geoTrack.lengthKm if race.distanceUnit == Model.Race.UnitKm else geoTrack.lengthMiles for category in race.getCategories(): category.distance = distance race.setChanged() self.refresh(forceRefresh=True) def onNormalize(self, event): self.commit() if Model.race: Model.race.normalizeCategories() self.state.reset() self.refresh() #------------------------------------------ def onGridLeftClick(self, event): if event.GetCol() in self.boolCols: r, c = event.GetRow(), event.GetCol() if c == self.iCol['active']: active = (self.grid.GetCellValue(r, self.iCol['active']) == u'1') wx.CallAfter( self.fixRow, r, self.CategoryTypeChoices.index( self.grid.GetCellValue(r, self.iCol['catType'])), not active) self.grid.SetCellValue( r, c, '1' if self.grid.GetCellValue(r, c)[:1] != '1' else '0') event.Skip() def onCellSelected(self, event): self.rowCur = event.GetRow() self.colCur = event.GetCol() if self.colCur in self.choiceCols or self.colCur in self.boolCols: wx.CallAfter(self.grid.EnableCellEditControl) event.Skip() def onCellChanged(self, event): self.rowCur = event.GetRow() self.colCur = event.GetCol() if self.colCur in [1, 2]: wx.CallAfter(self.fixCells) event.Skip() def onEditorCreated(self, event): if event.GetCol() == self.numbersColumn: ctrl = event.GetControl() ctrl.Bind(wx.EVT_KEY_DOWN, self.onNumbersKeyEvent) ctrl.Bind(wx.EVT_TEXT_PASTE, self.onPaste) event.Skip() def getCleanClipboardText(self): if wx.TheClipboard.Open(): data = wx.TextDataObject() if wx.TheClipboard.GetData(data): txt = data.GetText() txt = re.sub('[^0-9,-]+', ',', txt) wx.TheClipboard.Close() return txt return None def isExternalChange(self): if not Model.race: return False categories = Model.race.getAllCategories() for cat in categories: try: cat.distance = float(cat.distance) except: cat.distance = None try: cat.firstLapDistance = float(cat.firstLapDistance) except: cat.firstLapDistance = None if self.grid.GetNumberRows() != len(categories): return True def distanceMatches(distance, cellValue): try: value = float(cellValue) except ValueError: value = None if not distance and not value: return True return u'{:.3f}'.format(distance or 0.0) == cellValue def numLapsMatches(numLaps, cellValue): v = u'{}'.format(numLaps if numLaps is not None else '') return v == cellValue return any(( cat.name != self.grid.GetCellValue(r, self.iCol['name']) or cat.catStr != self.grid.GetCellValue(r, self.iCol['catStr']) or not distanceMatches( cat.distance, self.grid.GetCellValue(r, self.iCol['distance'])) or not distanceMatches( cat.firstLapDistance, self.grid.GetCellValue(r, self.iCol['firstLapDistance'])) or not numLapsMatches( cat.numLaps, self.grid.GetCellValue(r, self.iCol['numLaps']))) for r, cat in enumerate(categories)) def pasteFromClipboard(self, event): txt = self.getCleanClipboardText() if txt: event.GetEventObject().WriteText(txt) return True return False def onNumbersKeyEvent(self, event): # Handle column pastes from Excel when there are newlines. if event.GetModifiers() == wx.MOD_CONTROL and event.GetKeyCode() == 86: if self.pasteFromClipboard(event): return event.Skip() def onPaste(self, event): self.pasteFromClipboard(event) event.Skip() #------------------------------------------ def onUpdateStartWaveNumbers(self, event): self.commit() undo.pushState() with Model.LockRace() as race: race.adjustAllCategoryWaveNumbers() self.state.reset() wx.CallAfter(self.refresh) wx.CallAfter(Utils.refreshForecastHistory) def onAddExceptions(self, event): with Model.LockRace() as race: if not race or not race.getAllCategories(): return r = self.grid.GetGridCursorRow() if r is None or r < 0: Utils.MessageOK(self, _('You must select a Category first'), _('Select a Category')) return with Model.LockRace() as race: categories = race.getAllCategories() category = categories[r] dlg = wx.TextEntryDialog( self, u'{}: {}'.format( category.name, _('''Add Bib Exceptions (comma separated). This will add the given list of Bibs to this category, and remove them from other categories.'''), ), _('Add Bib Exceptions')) good = (dlg.ShowModal() == wx.ID_OK) if good: response = dlg.GetValue() dlg.Destroy() if not good: return undo.pushState() response = re.sub('[^0-9,]', '', response.replace(' ', ',')) with Model.LockRace() as race: for numException in response.split(','): race.addCategoryException(category, numException) self.state.reset() self.refresh() def _setRow( self, r, active, name, catStr, startOffset='00:00:00', numLaps=None, raceMinutes=None, lappedRidersMustContinue=False, distance=None, distanceType=None, firstLapDistance=None, gender=None, catType=Model.Category.CatWave, publishFlag=True, uploadFlag=True, seriesFlag=True, ): if len(startOffset) < len('00:00:00'): startOffset = '00:' + startOffset GetTranslation = _ gender = gender if gender in ['Men', 'Women'] else 'Open' self.grid.SetRowLabelValue(r, u'') self.grid.SetCellValue(r, self.iCol['active'], u'1' if active else u'0') self.grid.SetCellValue(r, self.iCol['catType'], self.CategoryTypeChoices[catType]) self.grid.SetCellValue(r, self.iCol['name'], name) self.grid.SetCellValue(r, self.iCol['gender'], GetTranslation(gender)) self.grid.SetCellValue(r, self.iCol['catStr'], catStr) self.grid.SetCellValue(r, self.iCol['startOffset'], startOffset) self.grid.SetCellValue(r, self.iCol['numLaps'], u'{}'.format(numLaps) if numLaps else u'') self.grid.SetCellValue( r, self.iCol['raceMinutes'], u'{}'.format(raceMinutes) if raceMinutes else u'') self.grid.SetCellValue(r, self.iCol['lappedRidersMustContinue'], u'1' if lappedRidersMustContinue else u'0') self.grid.SetCellValue(r, self.iCol['rule80Time'], u'') self.grid.SetCellValue(r, self.iCol['suggestedLaps'], u'') self.grid.SetCellValue(r, self.iCol['distance'], ('%.3f' % distance) if distance else u'') self.grid.SetCellValue( r, self.iCol['distanceType'], self.DistanceTypeChoices[distanceType if distanceType else 0]) self.grid.SetCellValue(r, self.iCol['firstLapDistance'], ('%.3f' % firstLapDistance) if firstLapDistance else '') self.grid.SetCellValue(r, self.iCol['publishFlag'], u'1' if publishFlag else u'0') self.grid.SetCellValue(r, self.iCol['uploadFlag'], u'1' if uploadFlag else u'0') self.grid.SetCellValue(r, self.iCol['seriesFlag'], u'1' if seriesFlag else u'0') race = Model.race category = race.categories.get(u'{} ({})'.format(name.strip(), gender), None) if race else None if not category or category.catType != Model.Category.CatWave: return # Get the 80% time cutoff. if not active or not Model.race: return rule80Time = race.getRule80CountdownTime(category) if race else None if rule80Time: self.grid.SetCellValue(r, self.iCol['rule80Time'], Utils.formatTime(rule80Time)) laps = race.getCategoryRaceLaps().get(category, 0) if race else None if laps: self.grid.SetCellValue(r, self.iCol['suggestedLaps'], u'{}'.format(laps)) def fixRow(self, row, catType, active): activeColour = wx.WHITE if active else self.inactiveColour colour = activeColour if catType == Model.Category.CatWave else self.ignoreColour for colName, fieldName in self.colNameFields: if not fieldName: continue col = self.iCol[fieldName] self.grid.SetCellBackgroundColour( row, col, colour if col in self.dependentCols else activeColour) def fixCells(self, event=None): for row in xrange(self.grid.GetNumberRows()): active = self.grid.GetCellValue(row, self.iCol['active'])[:1] in 'TtYy1' catType = self.CategoryTypeChoices.index( self.grid.GetCellValue(row, self.iCol['catType'])) self.fixRow(row, catType, active) def onActivateAll(self, event): self.commit() if Model.race: for c in Model.race.getAllCategories(): if not c.active: c.active = True Model.race.setChanged() self.state.reset() wx.CallAfter(self.refresh) def onDeactivateAll(self, event): self.commit() if Model.race: for c in Model.race.getAllCategories(): if c.active: c.active = False Model.race.setChanged() self.state.reset() wx.CallAfter(self.refresh) def doAutosize(self): self.grid.AutoSizeColumns(False) colWidth = self.grid.GetColSize(self.iCol['catStr']) maxWidth = wx.GetDisplaySize().width / 3 if colWidth > maxWidth: self.grid.SetColSize(self.iCol['catStr'], maxWidth) self.grid.ForceRefresh() def onNewCategory(self, event): self.grid.AppendRows(1) self._setRow(r=self.grid.GetNumberRows() - 1, active=True, name=u'<{}> '.format(_('CategoryName')), catStr='100-199,504,-128') self.doAutosize() def onDelCategory(self, event): r = self.grid.GetGridCursorRow() if r is None or r < 0: return if Utils.MessageOKCancel( self, u'{} "{} ({})"?'.format( _('Delete Category'), self.grid.GetCellValue(r, 3).strip(), self.grid.GetCellValue(r, 4).strip(), ), _('Delete Category')): self.grid.DeleteRows(r, 1, True) def onUpCategory(self, event): self.grid.SaveEditControlValue() self.grid.DisableCellEditControl() r = self.grid.GetGridCursorRow() Utils.SwapGridRows(self.grid, r, r - 1) if r - 1 >= 0: self.grid.MoveCursorUp(False) self.grid.ClearSelection() self.grid.SelectRow(max(r - 1, 0), True) def onDownCategory(self, event): self.grid.SaveEditControlValue() self.grid.DisableCellEditControl() r = self.grid.GetGridCursorRow() Utils.SwapGridRows(self.grid, r, r + 1) if r + 1 < self.grid.GetNumberRows(): self.grid.MoveCursorDown(False) self.grid.ClearSelection() self.grid.SelectRow(min(r + 1, self.grid.GetNumberRows() - 1), True) def refresh(self, forceRefresh=False): self.setGpxDistanceButton.Enable(hasattr(Model.race, 'geoTrack')) if not (forceRefresh or self.isExternalChange() or self.state.changed()): return # Fix the height of the column labels. dc = wx.WindowDC(self.grid) dc.SetFont(self.grid.GetLabelFont()) textHeight = dc.GetTextExtent('Label')[1] self.colLabelHeight = textHeight * max( name.count('\n') + 1 for name in self.colnames) + textHeight // 4 self.grid.SetColLabelSize(self.colLabelHeight) with Model.LockRace() as race: self.grid.ClearGrid() if race is None: return for c in xrange(self.grid.GetNumberCols()): if self.grid.GetColLabelValue(c).startswith(_('Distance')): self.grid.SetColLabelValue( c, u'{}\n({})'.format(_('Distance'), ['km', 'miles' ][getattr(race, 'distanceUnit', 0)])) break categories = race.getAllCategories() if self.grid.GetNumberRows() > 0: self.grid.DeleteRows(0, self.grid.GetNumberRows()) self.grid.AppendRows(len(categories)) for r, cat in enumerate(categories): self._setRow( r=r, active=cat.active, name=cat.name, gender=getattr(cat, 'gender', None), catStr=cat.catStr, catType=cat.catType, startOffset=cat.startOffset, numLaps=cat._numLaps, raceMinutes=cat.raceMinutes, lappedRidersMustContinue=getattr( cat, 'lappedRidersMustContinue', False), distance=getattr(cat, 'distance', None), distanceType=getattr(cat, 'distanceType', Model.Category.DistanceByLap), firstLapDistance=getattr(cat, 'firstLapDistance', None), publishFlag=cat.publishFlag, uploadFlag=cat.uploadFlag, seriesFlag=cat.seriesFlag, ) self.doAutosize() self.fixCells() # Force the grid to the correct size. self.grid.FitInside() self.GetSizer().Layout() def commit(self): undo.pushState() with Model.LockRace() as race: self.grid.SaveEditControlValue() self.grid.DisableCellEditControl( ) # Make sure the current edit is committed. if race is None: return numStrTuples = [] for r in xrange(self.grid.GetNumberRows()): values = { name: self.grid.GetCellValue(r, c) for name, c in self.iCol.iteritems() if name not in self.computedFields } values['catType'] = self.CategoryTypeChoices.index( values['catType']) values['distanceType'] = self.DistanceTypeChoices.index( values['distanceType']) numStrTuples.append(values) race.setCategories(numStrTuples) race.adjustAllCategoryWaveNumbers() wx.CallAfter(Utils.refreshForecastHistory)
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)
def __init__(self, parent, id=wx.ID_ANY, size=wx.DefaultSize): super(Pulled, self).__init__(parent, id, size=size) self.state = RaceInputState() vsOverall = wx.BoxSizer(wx.VERTICAL) self.hbs = wx.BoxSizer(wx.HORIZONTAL) self.showingCategoryLabel = wx.StaticText(self, label=u'{}:'.format( _('Start Wave'))) self.showingCategory = wx.StaticText(self) self.showingCategory.SetFont(self.showingCategory.GetFont().Bold()) self.categoryLabel = wx.StaticText(self, label=_('Category:')) self.categoryChoice = wx.Choice(self) self.Bind(wx.EVT_CHOICE, self.doChooseCategory, self.categoryChoice) self.useTableToPullRidersCkBox = wx.CheckBox( self, label=_('Use this Table to Pull Riders')) self.useTableToPullRidersCkBox.SetToolTip( wx.ToolTip( _('Also requires Laps to be set in Categories screen.'))) self.commitBtn = wx.Button(self, label=_('Commit')) self.commitBtn.Bind(wx.EVT_BUTTON, self.doCommit) self.hbs.Add(self.showingCategoryLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=0) self.hbs.Add(self.showingCategory, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=2) self.hbs.Add(self.categoryLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=18) self.hbs.Add(self.categoryChoice, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=2) self.hbs.Add(self.useTableToPullRidersCkBox, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=18) self.hbs.Add(self.commitBtn, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=32) #--------------------------------------------------------------- self.colNameFields = ( (_('Laps to Go'), 'lapsToGo', 'i'), (u' ' + _('Bib'), 'pulledBib', 'i'), (u'Name', 'pulledName', 's'), (u'Team', 'pulledTeam', 's'), (u'Component', 'pulledComponent', 's'), (u'Error', 'pulledError', 's'), ) self.colnames = [ colName for colName, fieldName, dataType in self.colNameFields ] self.iCol = dict((fieldName, i) for i, (colName, fieldName, dataType) in enumerate(self.colNameFields) if fieldName) self.grid = ReorderableGrid(self) self.grid.CreateGrid(0, len(self.colNameFields)) GetTranslation = _ for col, (colName, fieldName, dataType) in enumerate(self.colNameFields): self.grid.SetColLabelValue(col, colName) attr = wx.grid.GridCellAttr() if dataType == 'i': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) attr.SetEditor(wx.grid.GridCellFloatEditor(precision=0)) attr.SetRenderer(wx.grid.GridCellFloatRenderer(precision=0)) elif dataType == 'f': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) attr.SetEditor(wx.grid.GridCellFloatEditor(precision=2)) attr.SetRenderer(wx.grid.GridCellFloatRenderer(precision=2)) elif dataType == 't': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) attr.SetEditor(TimeEditor()) self.grid.SetColAttr(col, attr) self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.onCellChange) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) #--------------------------------------------------------------- vsOverall.Add(self.hbs, 0, flag=wx.EXPAND | wx.ALL, border=4) vsOverall.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=4) self.SetSizer(vsOverall)
class Pulled(wx.Panel): def __init__(self, parent, id=wx.ID_ANY, size=wx.DefaultSize): super(Pulled, self).__init__(parent, id, size=size) self.state = RaceInputState() vsOverall = wx.BoxSizer(wx.VERTICAL) self.hbs = wx.BoxSizer(wx.HORIZONTAL) self.showingCategoryLabel = wx.StaticText(self, label=u'{}:'.format( _('Start Wave'))) self.showingCategory = wx.StaticText(self) self.showingCategory.SetFont(self.showingCategory.GetFont().Bold()) self.categoryLabel = wx.StaticText(self, label=_('Category:')) self.categoryChoice = wx.Choice(self) self.Bind(wx.EVT_CHOICE, self.doChooseCategory, self.categoryChoice) self.useTableToPullRidersCkBox = wx.CheckBox( self, label=_('Use this Table to Pull Riders')) self.useTableToPullRidersCkBox.SetToolTip( wx.ToolTip( _('Also requires Laps to be set in Categories screen.'))) self.commitBtn = wx.Button(self, label=_('Commit')) self.commitBtn.Bind(wx.EVT_BUTTON, self.doCommit) self.hbs.Add(self.showingCategoryLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=0) self.hbs.Add(self.showingCategory, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=2) self.hbs.Add(self.categoryLabel, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=18) self.hbs.Add(self.categoryChoice, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=2) self.hbs.Add(self.useTableToPullRidersCkBox, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=18) self.hbs.Add(self.commitBtn, flag=wx.LEFT | wx.ALIGN_CENTRE_VERTICAL, border=32) #--------------------------------------------------------------- self.colNameFields = ( (_('Laps to Go'), 'lapsToGo', 'i'), (u' ' + _('Bib'), 'pulledBib', 'i'), (u'Name', 'pulledName', 's'), (u'Team', 'pulledTeam', 's'), (u'Component', 'pulledComponent', 's'), (u'Error', 'pulledError', 's'), ) self.colnames = [ colName for colName, fieldName, dataType in self.colNameFields ] self.iCol = dict((fieldName, i) for i, (colName, fieldName, dataType) in enumerate(self.colNameFields) if fieldName) self.grid = ReorderableGrid(self) self.grid.CreateGrid(0, len(self.colNameFields)) GetTranslation = _ for col, (colName, fieldName, dataType) in enumerate(self.colNameFields): self.grid.SetColLabelValue(col, colName) attr = wx.grid.GridCellAttr() if dataType == 'i': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) attr.SetEditor(wx.grid.GridCellFloatEditor(precision=0)) attr.SetRenderer(wx.grid.GridCellFloatRenderer(precision=0)) elif dataType == 'f': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_TOP) attr.SetEditor(wx.grid.GridCellFloatEditor(precision=2)) attr.SetRenderer(wx.grid.GridCellFloatRenderer(precision=2)) elif dataType == 't': attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) attr.SetEditor(TimeEditor()) self.grid.SetColAttr(col, attr) self.grid.Bind(wx.grid.EVT_GRID_CELL_CHANGED, self.onCellChange) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) #--------------------------------------------------------------- vsOverall.Add(self.hbs, 0, flag=wx.EXPAND | wx.ALL, border=4) vsOverall.Add(self.grid, 1, flag=wx.EXPAND | wx.ALL, border=4) self.SetSizer(vsOverall) def setCategory(self, category): for i, c in enumerate( Model.race.getCategories( startWaveOnly=False) if Model.race else [], 1): if c == category: SetCategory(self.categoryChoice, c) Model.setCategoryChoice(i, 'resultsCategory') return SetCategory(self.categoryChoice, None) Model.setCategoryChoice(0, 'resultsCategory') def doChooseCategory(self, event): Model.setCategoryChoice(self.categoryChoice.GetSelection(), 'resultsCategory') self.refresh() def doCommit(self, event): self.commit() self.refresh() def getCategory(self): race = Model.race if not race: category = None else: category = race.getCategoryStartWave( FixCategories(self.categoryChoice, getattr(race, 'resultsCategory', 0))) categoryName = category.fullname if category else u'' if categoryName != self.showingCategory.GetLabel(): self.showingCategory.SetLabel(categoryName) self.hbs.Layout() return category def getRaceInfo(self): race = Model.race if not race: return False, [] category = self.getCategory() if not category: return False, [] results = GetResults(category) if not results or not results[0].lapTimes: return False, [] return True, [race, category, results, len(results[0].lapTimes)] def getError(self, bib, lapsToGo, laps): if not bib: return u'' if not lapsToGo: lapsToGo = 1 success, info = self.getRaceInfo() if not success: return u'' race, category, results, laps = info if bib not in race.riders: return _(u'Bib not in Race') if race.getCategory(bib) != category: return _(u'Bib not in Category') rider = race.riders[bib] if rider.status not in (Model.Rider.Pulled, Model.Rider.Finisher): return u'{}: {}'.format(_('Bib has non-Finisher Status'), Model.Rider.statusNames[rider.status]) if lapsToGo >= laps: return u'{}: {}'.format(_('Laps To Go exceeds for Race Laps'), laps) if lapsToGo <= 0: return u'{}'.format(_('Laps To Go must be >= 0')) return u'' def onCellChange(self, event): row, col = event.GetRow(), event.GetCol() colName = self.colNameFields[col][1] GetTranslation = _ if colName == 'pulledBib' or colName == 'lapsToGo': bib = int( '0' + re.sub('[^0-9]', '', self.grid.GetCellValue(row, self.iCol['pulledBib']))) for r in range(row, -1, -1): lapsToGo = int( '0' + self.grid.GetCellValue(r, self.iCol['lapsToGo'])) if lapsToGo: break if not lapsToGo: lapsToGo = 1 success, info = self.getRaceInfo() if not success: return race, category, results, laps = info name, team, component = getRiderInfo(bib) self.grid.SetCellValue(row, self.iCol['pulledName'], name) self.grid.SetCellValue(row, self.iCol['pulledTeam'], team) self.grid.SetCellValue(row, self.iCol['pulledComponent'], component) self.grid.SetCellValue(row, self.iCol['pulledError'], self.getError(bib, lapsToGo, laps)) wx.CallAfter(self.grid.AutoSizeColumns, False) def setRow(self, bib, lapsToGo, laps, row, updateGrid=True): name, team, component = getRiderInfo(bib) values = { 'pulledBib': bib, 'pulledName': name, 'pulledTeam': team, 'pulledComponent': component, 'pulledError': self.getError(bib, lapsToGo, laps), 'lapsToGo': lapsToGo } for col, (name, attr, valuesType) in enumerate(self.colNameFields): self.grid.SetCellValue(row, col, str(values[attr])) return values def getRow(self, row): values = {'row': row} for col, (name, attr, dataType) in enumerate(self.colNameFields): v = self.grid.GetCellValue(row, col).strip() if dataType == 'i': v = u''.join(c for c in v if c.isdigit()) v = int(v or 0) elif dataType == 'f': v = u''.join(c for c in v if c.isdigit() or c == '.') v = float(v or 0.0) elif dataType == 't': v = Utils.StrToSeconds(v or '') values[attr] = v return values def updateGrid(self): self.grid.ClearGrid() success, info = self.getRaceInfo() if not success: return race, category, results, laps = info if race.isTimeTrial: return Pulled = Model.Rider.Pulled pulled = [] for rr in results: if race.riders[rr.num].status == Pulled: pulled.append( getPulledCmpTuple(rr, race.riders[rr.num], laps, False)) pulled.sort() bibLapsToGo = {p[-1].num: abs(p[0]) for p in pulled} pulled = [p[-1] for p in pulled] Utils.AdjustGridSize(self.grid, len(pulled) + 20) for row, rr in enumerate(pulled): self.setRow(rr.num, bibLapsToGo[rr.num], laps, row) # Remove repeated lapsToGo entries. col = self.iCol['lapsToGo'] for row in range(self.grid.GetNumberRows() - 1, 0, -1): if self.grid.GetCellValue(row, col) == self.grid.GetCellValue( row - 1, col): self.grid.SetCellValue(row, col, u'') self.grid.AutoSizeColumns(False) # Resize to fit the column name. self.grid.AutoSizeRows(False) def refresh(self): success, info = self.getRaceInfo() if not success: return self.updateGrid() race, category, results, laps = info if race.isTimeTrial: self.grid.SaveEditControlValue( ) # Make sure the current edit is committed. self.grid.DisableCellEditControl() self.grid.ClearGrid() return col = self.iCol['pulledBib'] tableBibs = set( int(u'0' + self.grid.GetCellValue(row, col)) for row in range(self.grid.GetNumberRows())) tableBibs.discard(0) if not tableBibs: return self.updateGrid() Pulled = Model.Rider.Pulled allBibs = set(rr.num for rr in results) if not allBibs >= tableBibs: return self.updateGrid() pulledBibs = set(rr.num for rr in results if race.riders[rr.num].status == Pulled) if not tableBibs >= pulledBibs: return self.updateGrid() def commit(self): self.grid.SaveEditControlValue( ) # Make sure the current edit is committed. self.grid.DisableCellEditControl() race = Model.race if not race: return race.useTableToPullRiders = self.useTableToPullRidersCkBox.GetValue() if not race.useTableToPullRiders: self.grid.ClearGrid() Utils.AdjustGridSize(self.grid, 20) return rows = [self.getRow(r) for r in range(self.grid.GetNumberRows())] rows = [rv for rv in rows if rv['pulledBib']] # Fix any missing data lapsToGo in the table. lapsToGoLast = 1 for rv in rows: if not rv['lapsToGo']: rv['lapsToGo'] = lapsToGoLast lapsToGoLast = rv['lapsToGo'] success, info = self.getRaceInfo() if not success: return False race, category, results, laps = info rule80LapTime = race.getRule80LapTime(category) changed = False Finisher, Pulled = Model.Rider.Finisher, Model.Rider.Pulled for rr in results: rider = race.riders.get(rr.num, None) if not rider or race.getCategory(rr.num) != category: continue if rider.status == Pulled: rider.status = Finisher changed = True lapsToGoPulled = defaultdict(list) for rv in rows: lapsToGoPulled[rv['lapsToGo']].append(rv['pulledBib']) for lapsToGo, bibs in lapsToGoPulled.items(): if lapsToGo <= 0: continue for seq, bib in enumerate(bibs): try: rider = race.riders[bib] except KeyError: continue rider.status = Pulled rider.pulledLapsToGo = lapsToGo rider.pulledSequence = seq changed = True if changed: race.setChanged() self.updateGrid()
def __init__(self, parent, id=wx.ID_ANY): wx.Panel.__init__(self, parent, id) self.state = RaceInputState() vs = wx.BoxSizer(wx.VERTICAL) self.ignoreColour = wx.Colour(80, 80, 80) self.inactiveColour = wx.Colour(200, 200, 200) border = 4 flag = wx.ALL hs = wx.BoxSizer(wx.HORIZONTAL) self.activateAllButton = wx.Button(self, label=_('Activate All'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onActivateAll, self.activateAllButton) hs.Add(self.activateAllButton, 0, border=border, flag=flag) hs.AddSpacer(6) self.newCategoryButton = wx.Button(self, label=_('New'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onNewCategory, self.newCategoryButton) hs.Add(self.newCategoryButton, 0, border=border, flag=flag) self.delCategoryButton = wx.Button(self, label=_('Delete'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onDelCategory, self.delCategoryButton) hs.Add(self.delCategoryButton, 0, border=border, flag=(flag & ~wx.LEFT)) hs.AddSpacer(6) self.upCategoryButton = wx.Button(self, label=u'\u2191', style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onUpCategory, self.upCategoryButton) hs.Add(self.upCategoryButton, 0, border=border, flag=flag) self.downCategoryButton = wx.Button(self, label=u'\u2193', style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onDownCategory, self.downCategoryButton) hs.Add(self.downCategoryButton, 0, border=border, flag=(flag & ~wx.LEFT)) hs.AddSpacer(6) self.setGpxDistanceButton = wx.Button(self, label=_('Set Gpx Distance'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onSetGpxDistance, self.setGpxDistanceButton) hs.Add(self.setGpxDistanceButton, 0, border=border, flag=flag) hs.AddSpacer(6) self.addExceptionsButton = wx.Button(self, label=_('Bib Exceptions'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onAddExceptions, self.addExceptionsButton) hs.Add(self.addExceptionsButton, 0, border=border, flag=flag) hs.AddSpacer(6) ''' self.updateStartWaveNumbersButton = wx.Button(self, label=_('Update Start Wave Bibs'), style=wx.BU_EXACTFIT) self.Bind( wx.EVT_BUTTON, self.onUpdateStartWaveNumbers, self.updateStartWaveNumbersButton ) hs.Add( self.updateStartWaveNumbersButton, 0, border = border, flag = flag ) ''' self.normalizeButton = wx.Button(self, label=_('Normalize'), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onNormalize, self.normalizeButton) hs.Add(self.normalizeButton, 0, border=border, flag=flag) hs.AddStretchSpacer() self.printButton = wx.Button(self, label=u'{}...'.format(_('Print')), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onPrint, self.printButton) hs.Add(self.printButton, 0, border=border, flag=flag) self.excelButton = wx.Button(self, label=u'{}...'.format(_('Excel')), style=wx.BU_EXACTFIT) self.Bind(wx.EVT_BUTTON, self.onExcel, self.excelButton) hs.Add(self.excelButton, 0, border=border, flag=flag) self.grid = ReorderableGrid(self) self.colNameFields = [ (u'', None), (_('Category Type'), 'catType'), (_('Active'), 'active'), (_('Name'), 'name'), (_('Gender'), 'gender'), (_('Numbers'), 'catStr'), (_('Start\nOffset'), 'startOffset'), (_('Race\nLaps'), 'numLaps'), (_('Race\nMinutes'), 'raceMinutes'), (_('Lapped\nRiders\nContinue'), 'lappedRidersMustContinue'), (_('Distance'), 'distance'), (_('Dist.\nBy'), 'distanceType'), (_('First\nLap\nDist.'), 'firstLapDistance'), (_('80%\nLap\nTime'), 'rule80Time'), (_('CrossMgr\nEstimated\nLaps'), 'suggestedLaps'), (_('Publish'), 'publishFlag'), (_('Upload'), 'uploadFlag'), (_('Series'), 'seriesFlag'), ] self.computedFields = {'rule80Time', 'suggestedLaps'} self.colnames = [ colName if not colName.startswith('_') else _('Name Copy') for colName, fieldName in self.colNameFields ] self.iCol = { fieldName: i for i, (colName, fieldName) in enumerate(self.colNameFields) if fieldName and not colName.startswith('_') } self.activeColumn = self.iCol['active'] self.genderColumn = self.iCol['gender'] self.numbersColumn = self.iCol['catStr'] self.grid.CreateGrid(0, len(self.colnames)) self.grid.SetRowLabelSize(32) self.grid.SetMargins(0, 0) for col, name in enumerate(self.colnames): self.grid.SetColLabelValue(col, name) self.cb = None self.boolCols = set() self.choiceCols = set() self.readOnlyCols = set() self.dependentCols = set() # Set column attributes for the table. for col, (colName, fieldName) in enumerate(self.colNameFields): attr = gridlib.GridCellAttr() if fieldName is None: attr.SetRenderer(CategoryIconRenderer()) attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) attr.SetReadOnly(True) self.readOnlyCols.add(col) elif fieldName == 'catType': self.catTypeWidth = 64 attr.SetEditor( gridlib.GridCellChoiceEditor(self.CategoryTypeChoices, False)) attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) self.choiceCols.add(col) elif fieldName in { 'active', 'lappedRidersMustContinue', 'publishFlag', 'uploadFlag', 'seriesFlag' }: boolEditor = gridlib.GridCellBoolEditor() boolEditor.UseStringValues('1', '0') attr.SetEditor(boolEditor) attr.SetRenderer(gridlib.GridCellBoolRenderer()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.boolCols.add(col) if fieldName == 'lappedRidersMustContinue': self.dependentCols.add(col) elif fieldName == 'gender': attr.SetEditor( gridlib.GridCellChoiceEditor( [_('Open'), _('Men'), _('Women')], False)) self.choiceCols.add(col) elif fieldName == 'startOffset': attr.SetEditor(TimeEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'numLaps': attr.SetEditor(wx.grid.GridCellNumberEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'raceMinutes': attr.SetEditor(wx.grid.GridCellNumberEditor()) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName in ['rule80Time', 'suggestedLaps']: attr.SetReadOnly(True) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.readOnlyCols.add(col) self.dependentCols.add(col) elif fieldName in ['distance', 'firstLapDistance']: attr.SetEditor(gridlib.GridCellFloatEditor(7, 3)) attr.SetRenderer(gridlib.GridCellFloatRenderer(7, 3)) attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE) self.dependentCols.add(col) elif fieldName == 'distanceType': attr.SetEditor( gridlib.GridCellChoiceEditor(self.DistanceTypeChoices, False)) attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTRE) self.choiceCols.add(col) self.dependentCols.add(col) elif colName == '_name2': attr.SetAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTRE) attr.SetBackgroundColour(wx.Colour(240, 240, 240)) attr.SetReadOnly(True) self.grid.SetColAttr(col, attr) self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.onGridLeftClick) self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.onCellSelected) self.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.onCellChanged) self.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.onEditorCreated) vs.Add(hs, 0, flag=wx.EXPAND | wx.ALL, border=4) vs.Add(self.grid, 1, flag=wx.GROW | wx.ALL | wx.EXPAND) self.rowCur = 0 self.colCur = 0 self.SetSizer(vs)
class EventPosition(EnablePanel): def __init__(self, parent): EnablePanel.__init__(self, parent) self.box = wx.StaticBox(self, label='Start Positions') boxSizer = wx.StaticBoxSizer(self.box, wx.HORIZONTAL) self.SetBackgroundColour(wx.WHITE) self.event = None self.drawLotsBitmap = wx.Bitmap( os.path.join(Utils.getImageFolder(), 'dice.png'), wx.BITMAP_TYPE_PNG) self.drawLotsGreyBitmap = wx.Bitmap( os.path.join(Utils.getImageFolder(), 'dice_grey.png'), wx.BITMAP_TYPE_PNG) self.emptyBitmap = wx.Bitmap(self.drawLotsBitmap.GetWidth(), self.drawLotsBitmap.GetHeight(), self.drawLotsBitmap.GetDepth()) dc = wx.MemoryDC() dc.SelectObject(self.emptyBitmap) dc.SetBrush(wx.WHITE_BRUSH) dc.Clear() dc.SelectObject(wx.NullBitmap) self.activeBar = EnableBar(self) self.activeBar.SetToolTip( wx.ToolTip(u'\n'.join([ u'Record the Start Positions by dragging the row numbers in the table.', u'Set any DNS in the Status column.', u'Then press Start or Cancel.', ]))) vs = wx.BoxSizer(wx.VERTICAL) self.startButton = MakeRoundButton(self, 'Start') self.cancelButton = MakeRoundButton(self, 'Cancel', isCancel) vs.Add(self.startButton, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) vs.Add(self.cancelButton, flag=wx.ALL, border=4) self.headerNames = ['Bib', 'Name', 'Team', 'Status'] self.iColStatus = 3 self.grid = ReorderableGrid(self, style=wx.BORDER_SUNKEN) self.grid.CreateGrid(4, len(self.headerNames)) font = wx.Font((0, FontSize), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) self.grid.SetLabelFont(font) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetColLabelValue(col, self.headerNames[col]) self.grid.SetCellValue( 0, col, self.headerNames[col]) # Add the label as data. attr = gridlib.GridCellAttr() attr.SetFont(font) attr.SetReadOnly(True) if self.headerNames[col].startswith('Bib'): attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_TOP) elif self.headerNames[col].startswith('Status'): attr.SetEditor( gridlib.GridCellChoiceEditor(choices=['DNS', ''])) attr.SetReadOnly(False) self.grid.SetColAttr(col, attr) self.grid.AutoSizeColumns(False) # Resize to fit the column name. self.grid.AutoSizeRows(False) for col in six.moves.range(self.grid.GetNumberCols()): self.grid.SetCellValue(0, col, '') # Remove the labels. self.drawLotsDisplay = wx.StaticBitmap(self, wx.ID_ANY, self.drawLotsBitmap) self.drawLotsDisplay.SetToolTip( wx.ToolTip(u'\n'.join([ u"Dice are active when riders need to draw lots to select their positions.", u"Dice are inactive when riders' start positions are known.", ]))) boxSizer.Add(self.activeBar, 0, flag=wx.ALL | wx.EXPAND, 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.drawLotsDisplay, 0, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL, 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.startButton, isSelect), (self.cancelButton, isCancel)]: EnableRoundButton(b, enable, t) self.activeBar.SetBackgroundColour( wx.Colour(0, 128, 0) if enable else wx.WHITE) self.Refresh() def setEvent(self, event): self.event = event def refresh(self): if not self.event: self.grid.ClearGrid() self.drawLotsDisplay.SetBitmap(self.emptyBitmap) return self.drawLotsDisplay.Show(not Model.model.competition.isMTB) DQs, DNSs, DNFs = Model.model.competition.getRiderStates() start = self.event.starts[-1] if self.startButton.IsEnabled(): self.drawLotsDisplay.SetBitmap( self.drawLotsBitmap if start.canDrawLots else self.emptyBitmap) else: self.drawLotsDisplay.SetBitmap(self.drawLotsGreyBitmap if start. canDrawLots else self.emptyBitmap) startPositions = start.startPositions Utils.AdjustGridSize(self.grid, rowsRequired=len(startPositions)) state = self.event.competition.state for row, p in enumerate(startPositions): rider = state.labels[p] for col, v in enumerate([ rider.bib, rider.full_name, rider.team, 'DNS' if (rider in DNSs or rider.bib in CacheDNSs) else '' ]): self.grid.SetCellValue(row, col, u' {}'.format(v)) self.grid.AutoSizeColumns(False) self.grid.AutoSizeRows(False) def commit(self): self.grid.SaveEditControlValue() self.grid.HideCellEditControl() if not self.event: self.grid.ClearGrid() return startPositions = [] for row in six.moves.range(self.grid.GetNumberRows()): bib = self.grid.GetCellValue(row, 0) try: bib = int(bib) except: continue if self.grid.GetCellValue(row, self.iColStatus).strip(): CacheDNSs.add(bib) else: CacheDNSs.discard(bib) startPositions.append((bib, '')) start = self.event.starts[-1] start.setStartPositions(startPositions) Model.model.setChanged(True) Utils.setTitle()