Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
	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)
Beispiel #4
0
    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)
Beispiel #6
0
	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)
Beispiel #7
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
    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)
Beispiel #10
0
    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)
Beispiel #11
0
	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 )
Beispiel #12
0
    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)
Beispiel #13
0
    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,
        ]
Beispiel #14
0
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)
Beispiel #15
0
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
Beispiel #16
0
    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)
Beispiel #17
0
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)
Beispiel #18
0
    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)
Beispiel #19
0
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)
Beispiel #20
0
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())]
Beispiel #21
0
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()
Beispiel #22
0
    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)
Beispiel #23
0
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)
Beispiel #24
0
	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 )
Beispiel #25
0
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)
Beispiel #26
0
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)
Beispiel #27
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)
Beispiel #28
0
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()
Beispiel #29
0
    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)
Beispiel #30
0
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()