Esempio n. 1
0
 def Create(self, parent, id=wx.ID_ANY, evtHandler=None):
     self._tc = HighPrecisionTimeEdit(parent,
                                      id,
                                      allow_none=False,
                                      style=wx.TE_PROCESS_ENTER)
     self.SetControl(self._tc)
     if evtHandler:
         self._tc.PushEventHandler(evtHandler)
Esempio n. 2
0
 def Create(self, parent, id=wx.ID_ANY, evtHandler=None):
     self._tc = HighPrecisionTimeEdit(parent,
                                      id,
                                      style=wx.TE_CENTRE,
                                      value=self.defaultValue,
                                      display_milliseconds=False)
     self.SetControl(self._tc)
     if evtHandler:
         self._tc.PushEventHandler(evtHandler)
Esempio n. 3
0
	def __init__( self, parent, entry, id = wx.ID_ANY ):
		wx.Dialog.__init__( self, parent, id, "Shift Time",
						style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.TAB_TRAVERSAL )
						
		self.entry = entry
		bs = wx.GridBagSizer(vgap=5, hgap=5)
		self.numEdit = wx.lib.intctrl.IntCtrl( self, size=(40, -1),
			style=wx.TE_RIGHT | wx.TE_PROCESS_ENTER,
			value=int(self.entry.num),
			allow_none=False, min=1, max=9999 )
		
		self.timeMsEdit = HighPrecisionTimeEdit( self )
		self.timeMsEdit.Bind( wx.EVT_TEXT, self.updateNewTime )
		self.newTime = wx.StaticText( self, label = u"00:00:00")
		
		shiftOptions = [_('Earlier'), _('Later')]
		self.shiftBox = wx.RadioBox( self, wx.ID_ANY,
			_('Shift Direction'),
			wx.DefaultPosition, wx.DefaultSize,
			shiftOptions, 2, wx.RA_SPECIFY_COLS )
		self.Bind(wx.EVT_RADIOBOX, self.updateNewTime, self.shiftBox)
				
		self.okBtn = wx.Button( self, wx.ID_OK )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		border = 8
		bs.Add( wx.StaticText( self, label = u'{}: {}   {}: {}'.format(
			_('Rider Lap'), self.entry.lap,
			_('Race Time'), Utils.formatTime(self.entry.t,True)) ),
			pos=(0,0), span=(1,2), border = border, flag=wx.GROW|wx.ALL )
		bs.Add( wx.StaticText( self, label = u'{}:'.format(_("Rider"))),  pos=(1,0), span=(1,1), border = border, flag=wx.LEFT|wx.TOP|wx.ALIGN_RIGHT )
		bs.Add( self.numEdit, pos=(1,1), span=(1,2), border = border, flag=wx.GROW|wx.RIGHT|wx.TOP )
		bs.Add( self.shiftBox, pos=(2, 0), span=(1, 2), border = border, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM )
		bs.Add( wx.StaticText( self, label = u'{}:'.format(_("Shift Time"))),  pos=(3,0), span=(1,1), border = border, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT|wx.BOTTOM )
		bs.Add( self.timeMsEdit, pos=(3,1), span=(1,1), border = border, flag=wx.GROW|wx.LEFT|wx.RIGHT )
		bs.Add( self.newTime, pos=(4,0), span=(1,2), border = border, flag=wx.GROW|wx.LEFT|wx.RIGHT )
		
		bs.Add( self.okBtn, pos=(5, 0), span=(1,1), border = border, flag=wx.ALL )
		self.okBtn.SetDefault()
		bs.Add( self.cancelBtn, pos=(5, 1), span=(1,1), border = border, flag=wx.ALL )
		
		self.SetSizerAndFit(bs)
		bs.Fit( self )
		
		wx.CallAfter( self.updateNewTime )
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )
Esempio n. 4
0
	def __init__( self, parent, entry, id = wx.ID_ANY ):
		wx.Dialog.__init__( self, parent, id, "Correct Number",
						style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.TAB_TRAVERSAL )
						
		self.entry = entry
		bs = wx.GridBagSizer(vgap=5, hgap=5)
		self.numEdit = wx.lib.intctrl.IntCtrl( self, size=(64,-1), style=wx.TE_RIGHT | wx.TE_PROCESS_ENTER, value=int(self.entry.num), allow_none=False, min=1, max=9999 )
		
		self.timeMsEdit = HighPrecisionTimeEdit( self, seconds=entry.t, size=(120, -1) )
				
		self.okBtn = wx.Button( self, wx.ID_OK )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		border = 8
		bs.Add( wx.StaticText( self, label = u'{}: {}   {}: {}'.format(
				_('Rider Lap'), self.entry.lap,
				_('Race Time'), Utils.formatTime(self.entry.t, True)
			)),
			pos=(0,0), span=(1,2), border = border, flag=wx.GROW|wx.ALL )
		bs.Add( wx.StaticText( self, label = u'{}:'.format(_("Rider"))),  pos=(1,0), span=(1,1), border = border, flag=wx.LEFT|wx.TOP|wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL )
		bs.Add( self.numEdit, pos=(1,1), span=(1,2), border = border, flag=wx.RIGHT|wx.TOP|wx.ALIGN_LEFT )
		choices = [u'{}:'.format(_("Race Time"))]
		if Model.race and Model.race.startTime:
			choices.append( _("24 hr Clock Time:") )
		self.timeChoice = wx.Choice( self, -1, choices = choices )
		self.timeChoiceLastSelection = 0
		self.timeChoice.SetSelection( self.timeChoiceLastSelection )
		self.timeChoice.Bind( wx.EVT_CHOICE, self.doTimeChoice, self.timeChoice )
		bs.Add( self.timeChoice,  pos=(2,0), span=(1,1), border = border, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.BOTTOM|wx.ALIGN_CENTRE_VERTICAL )
		bs.Add( self.timeMsEdit, pos=(2,1), span=(1,1), border = border, flag=wx.RIGHT|wx.BOTTOM|wx.ALIGN_LEFT )
		
		bs.Add( self.okBtn, pos=(3, 0), span=(1,1), border = border, flag=wx.ALL )
		self.okBtn.SetDefault()
		bs.Add( self.cancelBtn, pos=(3, 1), span=(1,1), border = border, flag=wx.ALL )
		
		self.SetSizerAndFit(bs)
		bs.Fit( self )
		
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )
Esempio n. 5
0
	def __init__( self, parent, id = wx.ID_ANY ):
		wx.Dialog.__init__( self, parent, id, "Change Race Start Time",
						style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.TAB_TRAVERSAL )
						
		race = Model.race
		if not race:
			return
		bs = wx.GridBagSizer(vgap=5, hgap=5)
		
		seconds = (race.startTime - race.startTime.replace(hour=0, minute=0, second=0)).total_seconds()
		self.timeMsEdit = HighPrecisionTimeEdit( self, seconds = seconds, size=(80,-1) )
		self.timeMsEdit.SetMinSize( (80, -1) )
		
		self.setTimeNow = wx.Button( self, label=_('Tap for NOW') )
		self.setTimeNow.Bind( wx.EVT_LEFT_DOWN, self.onSetTimeNow )
				
		self.okBtn = wx.Button( self, wx.ID_OK )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		border = 8
		self.timeLabel = wx.StaticText( self, label = _('New Race Start Time (24hr clock):') )
		bs.Add( self.timeLabel,  pos=(0,0), span=(1,1), border = border, flag=wx.ALIGN_RIGHT|wx.LEFT|wx.BOTTOM|wx.TOP|wx.ALIGN_CENTRE_VERTICAL )
		bs.Add( self.timeMsEdit, pos=(0,1), span=(1,1), border = border, flag=wx.RIGHT|wx.BOTTOM|wx.TOP|wx.ALIGN_LEFT )
		bs.Add( self.setTimeNow, pos=(0,2), span=(1,1), border = border, flag=wx.ALL )
		
		bs.Add( self.okBtn, pos=(1, 1), span=(1,1), border = border, flag=wx.ALL )
		self.okBtn.SetDefault()
		bs.Add( self.cancelBtn, pos=(1, 2), span=(1,1), border = border, flag=wx.ALL )
		
		self.SetSizerAndFit(bs)
		bs.Fit( self )
		
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )
class HighPrecisionTimeEditor(gridlib.GridCellEditor):
	Empty = '00:00:00.000'
	def __init__(self):
		self._tc = None
		self.startValue = self.Empty
		gridlib.GridCellEditor.__init__(self)
		
	def Create( self, parent, id=wx.ID_ANY, evtHandler=None ):
		self._tc = HighPrecisionTimeEdit(parent, id, allow_none=False, style=wx.TE_PROCESS_ENTER)
		self.SetControl( self._tc )
		if evtHandler:
			self._tc.PushEventHandler( evtHandler )
	
	def SetSize( self, rect ):
		self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2, wx.SIZE_ALLOW_MINUS_ONE )
	
	def BeginEdit( self, row, col, grid ):
		self.startValue = grid.GetTable().GetValue(row, col).strip()
		v = self.startValue
		v = Utils.SecondsToStr( Utils.StrToSeconds(v), full=True )
		self._tc.SetValue( v )
		self._tc.SetSelection(-1,-1)
		wx.CallAfter( self._tc.SetFocus )
		
	def EndEdit( self, row, col, grid, value = None ):
		changed = False
		v = self._tc.GetValue()
		v = Utils.SecondsToStr( Utils.StrToSeconds(v), full=True )
		if v != self.startValue:
			if v == self.Empty:
				v = ''
			else:
				v = Utils.SecondsToStr( Utils.StrToSeconds(v), full=False )
			changed = True
			grid.GetTable().SetValue( row, col, v )
		self.startValue = self.Empty
		self._tc.SetValue( self.startValue )
		
	def Reset( self ):
		self._tc.SetValue( self.startValue )
		
	def Clone( self ):
		return HighPrecisionTimeEditor()
Esempio n. 7
0
class HighPrecisionTimeEditor(gridlib.GridCellEditor):
    Empty = '00:00:00.000'

    def __init__(self):
        self._tc = None
        self.startValue = self.Empty
        gridlib.GridCellEditor.__init__(self)

    def Create(self, parent, id=wx.ID_ANY, evtHandler=None):
        self._tc = HighPrecisionTimeEdit(parent,
                                         id,
                                         allow_none=False,
                                         style=wx.TE_PROCESS_ENTER)
        self.SetControl(self._tc)
        if evtHandler:
            self._tc.PushEventHandler(evtHandler)

    def SetSize(self, rect):
        self._tc.SetSize(rect.x, rect.y, rect.width + 2, rect.height + 2,
                         wx.SIZE_ALLOW_MINUS_ONE)

    def BeginEdit(self, row, col, grid):
        self.startValue = grid.GetTable().GetValue(row, col).strip()
        self._tc.SetValue(self.startValue)
        self._tc.SetFocus()

    def EndEdit(self, row, col, grid, value=None):
        changed = False
        val = self._tc.GetValue()
        if val != self.startValue:
            if val == self.Empty:
                val = ''
            changed = True
            grid.GetTable().SetValue(row, col, val)
        self.startValue = self.Empty
        self._tc.SetValue(self.startValue)

    def Reset(self):
        self._tc.SetValue(self.startValue)

    def Clone(self):
        return HighPrecisionTimeEditor()
Esempio n. 8
0
class TimeEditor(gridlib.GridCellEditor):
    defaultValue = '00:00:00'

    def __init__(self):
        self._tc = None
        self.startValue = self.defaultValue
        gridlib.GridCellEditor.__init__(self)

    def Create(self, parent, id=wx.ID_ANY, evtHandler=None):
        self._tc = HighPrecisionTimeEdit(parent,
                                         id,
                                         style=wx.TE_CENTRE,
                                         value=self.defaultValue,
                                         display_milliseconds=False)
        self.SetControl(self._tc)
        if evtHandler:
            self._tc.PushEventHandler(evtHandler)

    def SetSize(self, rect):
        self._tc.SetSize(rect.x, rect.y, rect.width + 2, rect.height + 2,
                         wx.SIZE_ALLOW_MINUS_ONE)

    def BeginEdit(self, row, col, grid):
        self.startValue = grid.GetTable().GetValue(row, col)
        self._tc.SetValue(self.startValue or self.defaultValue)
        self._tc.SetFocus()

    def EndEdit(self, row, col, grid, value=None):
        val = self._tc.GetValue()
        grid.GetTable().SetValue(row, col, val)

    def Reset(self):
        self._tc.SetValue(self.startValue)

    def Clone(self):
        return TimeEditor()
Esempio n. 9
0
class ShiftNumberDialog(wx.Dialog):
    def __init__(self, parent, entry, id=wx.ID_ANY):
        wx.Dialog.__init__(self,
                           parent,
                           id,
                           "Shift Time",
                           style=wx.DEFAULT_DIALOG_STYLE | wx.TAB_TRAVERSAL)

        self.entry = entry
        bs = wx.GridBagSizer(vgap=5, hgap=5)
        self.numEdit = wx.lib.intctrl.IntCtrl(self,
                                              size=(40, -1),
                                              style=wx.TE_RIGHT,
                                              value=int(self.entry.num),
                                              allow_none=False,
                                              min=1,
                                              max=9999)

        shiftOptions = [_('Earlier'), _('Later')]
        self.shiftBox = wx.RadioBox(self, wx.ID_ANY, _('Shift Direction'),
                                    wx.DefaultPosition, wx.DefaultSize,
                                    shiftOptions, 2, wx.RA_SPECIFY_COLS)
        self.Bind(wx.EVT_RADIOBOX, self.updateNewTime, self.shiftBox)

        self.timeMsEdit = HighPrecisionTimeEdit(self)
        self.timeMsEdit.Bind(wx.EVT_TEXT, self.updateNewTime)
        self.newTime = wx.StaticText(self, label=u"00:00:00")

        border = 8
        bs.Add(wx.StaticText(self,
                             label=u'{}: {}   {}: {}'.format(
                                 _('Rider Lap'), self.entry.lap,
                                 _('Race Time'),
                                 Utils.formatTime(self.entry.t, True))),
               pos=(0, 0),
               span=(1, 2),
               border=border,
               flag=wx.GROW | wx.ALL)
        bs.Add(wx.StaticText(self, label=u'{}:'.format(_("Rider"))),
               pos=(1, 0),
               span=(1, 1),
               border=border,
               flag=wx.LEFT | wx.TOP | wx.ALIGN_RIGHT)
        bs.Add(self.numEdit,
               pos=(1, 1),
               span=(1, 2),
               border=border,
               flag=wx.GROW | wx.RIGHT | wx.TOP)
        bs.Add(self.shiftBox,
               pos=(2, 0),
               span=(1, 2),
               border=border,
               flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM)
        bs.Add(wx.StaticText(self, label=u'{}:'.format(_("Shift Time"))),
               pos=(3, 0),
               span=(1, 1),
               border=border,
               flag=wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.BOTTOM)
        bs.Add(self.timeMsEdit,
               pos=(3, 1),
               span=(1, 1),
               border=border,
               flag=wx.GROW | wx.LEFT | wx.RIGHT)
        bs.Add(self.newTime,
               pos=(4, 0),
               span=(1, 2),
               border=border,
               flag=wx.GROW | wx.LEFT | wx.RIGHT)

        self.okBtn = wx.Button(self, wx.ID_OK)
        self.Bind(wx.EVT_BUTTON, self.onOK, self.okBtn)

        self.cancelBtn = wx.Button(self, wx.ID_CANCEL)
        self.Bind(wx.EVT_BUTTON, self.onCancel, self.cancelBtn)

        bs.Add(self.okBtn, pos=(5, 0), span=(1, 1), border=border, flag=wx.ALL)
        self.okBtn.SetDefault()
        bs.Add(self.cancelBtn,
               pos=(5, 1),
               span=(1, 1),
               border=border,
               flag=wx.ALL)

        self.SetSizerAndFit(bs)
        bs.Fit(self)

        wx.CallAfter(self.updateNewTime)
        self.CentreOnParent(wx.BOTH)
        wx.CallAfter(self.SetFocus)

    def getNewTime(self):
        tAdjust = self.timeMsEdit.GetSeconds() * (
            -1 if self.shiftBox.GetSelection() == 0 else 1)
        return self.entry.t + tAdjust

    def onOK(self, event):
        num = self.numEdit.GetValue()
        t = self.getNewTime()
        if self.entry.num != num or self.entry.t != t:
            undo.pushState()
            with Model.LockRace() as race:
                rider = race.getRider(num)
                if self.entry.lap != 0:
                    race.numTimeInfo.change(self.entry.num, self.entry.t, t)
                    race.deleteTime(self.entry.num, self.entry.t)
                    race.addTime(
                        num, t + ((rider.firstTime or 0.0)
                                  if race.isTimeTrial else 0.0))
                else:
                    race.numTimeInfo.change(self.entry.num, rider.firstTime, t)
                    rider.firstTime = t
                    race.setChanged()
            Utils.refresh()
        self.EndModal(wx.ID_OK)

    def onCancel(self, event):
        self.EndModal(wx.ID_CANCEL)

    def updateNewTime(self, event=None):
        s = u'{}: {}  {}: {}'.format(_('Was'),
                                     Utils.formatTime(self.entry.t, True),
                                     _('Now'),
                                     Utils.formatTime(self.getNewTime(), True))
        self.newTime.SetLabel(s)
Esempio n. 10
0
class CorrectNumberDialog(wx.Dialog):
    def __init__(self, parent, entry, id=wx.ID_ANY):
        wx.Dialog.__init__(self,
                           parent,
                           id,
                           "Correct Number",
                           style=wx.DEFAULT_DIALOG_STYLE | wx.TAB_TRAVERSAL)

        self.entry = entry
        bs = wx.GridBagSizer(vgap=5, hgap=5)
        self.numEdit = wx.lib.intctrl.IntCtrl(self,
                                              size=(64, -1),
                                              style=wx.TE_RIGHT,
                                              value=int(self.entry.num),
                                              allow_none=False,
                                              min=1,
                                              max=9999)

        border = 4
        bs.Add(wx.StaticText(self,
                             label=u'{}: {}   {}: {}'.format(
                                 _('Rider Lap'), self.entry.lap,
                                 _('Race Time'),
                                 Utils.formatTime(self.entry.t, True))),
               pos=(0, 0),
               span=(1, 2),
               border=border,
               flag=wx.GROW | wx.ALL)
        bs.Add(wx.StaticText(self, label=u'{}:'.format(_("Rider"))),
               pos=(1, 0),
               span=(1, 1),
               border=border,
               flag=wx.LEFT | wx.TOP | wx.ALIGN_RIGHT
               | wx.ALIGN_CENTRE_VERTICAL)
        bs.Add(self.numEdit,
               pos=(1, 1),
               span=(1, 2),
               border=border,
               flag=wx.RIGHT | wx.TOP | wx.ALIGN_LEFT)
        choices = [u'{}:'.format(_("Race Time"))]
        race = Model.race
        if race and race.startTime:
            choices.append(_("24 hr Clock Time:"))
        self.timeChoice = wx.Choice(self, -1, choices=choices)
        self.timeChoiceLastSelection = 0
        self.timeChoice.SetSelection(self.timeChoiceLastSelection)
        self.timeChoice.Bind(wx.EVT_CHOICE, self.doTimeChoice, self.timeChoice)
        self.timeMsEdit = HighPrecisionTimeEdit(self,
                                                seconds=entry.t,
                                                size=(120, -1))

        bs.Add(self.timeChoice,
               pos=(2, 0),
               span=(1, 1),
               border=border,
               flag=wx.ALIGN_RIGHT | wx.LEFT | wx.BOTTOM
               | wx.ALIGN_CENTRE_VERTICAL)
        bs.Add(self.timeMsEdit,
               pos=(2, 1),
               span=(1, 1),
               border=border,
               flag=wx.RIGHT | wx.BOTTOM | wx.ALIGN_LEFT)

        bs.Add(wx.StaticText(self, label=u'{}:'.format(_("Lap Note"))),
               pos=(3, 0),
               span=(1, 1),
               border=border,
               flag=wx.LEFT | wx.TOP | wx.ALIGN_RIGHT
               | wx.ALIGN_CENTRE_VERTICAL)
        self.noteEdit = wx.TextCtrl(self, size=(250, -1))
        if race:
            self.noteEdit.SetValue(
                getattr(race, 'lapNote', {}).get(
                    (self.entry.num, self.entry.lap), u''))
        bs.Add(self.noteEdit,
               pos=(3, 1),
               span=(1, 2),
               border=border,
               flag=wx.RIGHT | wx.TOP | wx.ALIGN_LEFT)

        self.okBtn = wx.Button(self, wx.ID_OK)
        self.Bind(wx.EVT_BUTTON, self.onOK, self.okBtn)

        self.cancelBtn = wx.Button(self, wx.ID_CANCEL)
        self.Bind(wx.EVT_BUTTON, self.onCancel, self.cancelBtn)

        border = 4
        bs.Add(self.okBtn, pos=(4, 0), span=(1, 1), border=border, flag=wx.ALL)
        self.okBtn.SetDefault()
        bs.Add(self.cancelBtn,
               pos=(4, 1),
               span=(1, 1),
               border=border,
               flag=wx.ALL)

        self.SetSizerAndFit(bs)
        bs.Fit(self)

        self.CentreOnParent(wx.BOTH)
        wx.CallAfter(self.SetFocus)

    def doTimeChoice(self, event):
        iSelection = event.GetSelection()
        if iSelection == self.timeChoiceLastSelection:
            return
        if not (Model.race and Model.race.startTime):
            return

        dtStart = Model.race.startTime
        t = self.timeMsEdit.GetSeconds()
        if iSelection == 0:
            # Clock time to race time.
            dtInput = datetime.datetime(
                dtStart.year, dtStart.month,
                dtStart.day) + datetime.timedelta(seconds=t)
            t = (dtInput - dtStart).total_seconds()
        else:
            # Race time to clock time.
            dtInput = dtStart + datetime.timedelta(seconds=t)
            t = (dtInput - datetime.datetime(dtStart.year, dtStart.month,
                                             dtStart.day)).total_seconds()

        self.timeMsEdit.SetSeconds(t)
        self.timeChoiceLastSelection = iSelection

    def onOK(self, event):
        num = self.numEdit.GetValue()
        t = self.timeMsEdit.GetSeconds()

        if self.timeChoice.GetSelection(
        ) == 1 and Model.race and Model.race.startTime:
            dtStart = Model.race.startTime
            dtInput = datetime.datetime(
                dtStart.year, dtStart.month,
                dtStart.day) + datetime.timedelta(seconds=t)
            if dtInput < dtStart:
                Utils.MessageOK(
                    self,
                    u'\n\n'.join([
                        _('Cannot Enter Clock Time Before Race Start.'),
                        _('(reminder: clock time is in 24-hour format)')
                    ]),
                    _('Time Entry Error'),
                    iconMask=wx.ICON_ERROR)
                return
            t = (dtInput - dtStart).total_seconds()

        race = Model.race
        offset = race.getStartOffset(num)
        if t <= offset:
            Utils.MessageOK(
                self,
                u'{}: {}\n\n{}\n{}'.format(
                    _('Cannot enter a time that is before the Category Start Offset'
                      ), Utils.formatTime(offset, highPrecision=True),
                    _('All times earlier than the Start Offset are ignored.'),
                    _('Please enter a time after the Start Offset.')),
                _('Time Entry Error'),
                iconMask=wx.ICON_ERROR)
            return

        race.lapNote = getattr(race, 'lapNote', {})
        if self.noteEdit.GetValue() != race.lapNote.get(
            (self.entry.num, self.entry.lap),
                u'') or self.entry.num != num or self.entry.t != t:
            undo.pushState()

            note = self.noteEdit.GetValue().strip()
            if not note:
                race.lapNote.pop((self.entry.num, self.entry.lap), None)
            else:
                race.lapNote[(self.entry.num, self.entry.lap)] = note

            if self.entry.num != num or self.entry.t != t:
                rider = race.getRider(num)
                if self.entry.lap != 0:
                    race.numTimeInfo.change(self.entry.num, self.entry.t, t)
                    race.deleteTime(self.entry.num, self.entry.t)
                    race.addTime(
                        num, t + ((rider.firstTime or 0.0)
                                  if race.isTimeTrial else 0.0))
                else:
                    race.numTimeInfo.change(self.entry.num, rider.firstTime, t)
                    rider.firstTime = t

            race.setChanged()
            Utils.refresh()

        self.EndModal(wx.ID_OK)

    def onCancel(self, event):
        self.EndModal(wx.ID_CANCEL)
Esempio n. 11
0
	def __init__( self, chipName, parseTagTime, parent, id = wx.ID_ANY, fileSuffix = 'txt' ):
		wx.Dialog.__init__( self, parent, id, u'{} {}'.format(chipName, _('Import')),
						style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.TAB_TRAVERSAL )
		
		self.chipName = chipName
		self.parseTagTime = parseTagTime
		self.fileSuffix = fileSuffix
		todoList = [
			u'{} {}'.format(chipName, _('Import Data File')),
			u'',
			_('You must first "New" a race and fill in the details.'),
			_('You must also configure a "Tag" field in your Sign-On Excel Sheet and link the sheet to the race.'),
			_('This is required so CrossMgr can link the tags in the import file back to rider numbers and info.'),
			u'',
			_('Race Data:'),
			_('If the first chip read is NOT the start of the race, you will need to enter the start time manually.'),
			_('Otherwise the import will use the first chip read as the race start.'),
			u'',
			_('TimeTrial Data:'),
			_("The first chip read for each rider will be interpreted as the rider's start time."),
			u'',
			_('Warning: Importing from chip data could replace all the data in this race.'),
			_('Proceed with caution.'),
		]
		intro = u'\n'.join(todoList)
		
		gs = wx.FlexGridSizer( rows=0, cols=3, vgap=10, hgap=5 )
		gs.Add( wx.StaticText(self, label = u'{} {}:'.format(chipName, _('Data File'))), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.chipDataFile = wx.TextCtrl( self, -1, '', size=(450,-1) )
		defaultPath = Utils.getFileName()
		if not defaultPath:
			defaultPath = Utils.getDocumentsDir()
		else:
			defaultPath = os.path.join( os.path.split(defaultPath)[0], '' )
		self.chipDataFile.SetValue( defaultPath )
		gs.Add( self.chipDataFile, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.GROW)

		btn = wx.Button( self, label=_('Browse') + u'...' )
		btn.Bind( wx.EVT_BUTTON, self.onBrowseChipReaderDataFile )
		gs.Add( btn, 0, wx.ALIGN_CENTER_VERTICAL )
		
		gs.AddSpacer(1)
		self.dataType = wx.StaticText( self, label = _("Data Is:") )
		gs.Add( self.dataType, 1, wx.ALIGN_LEFT )
		gs.AddSpacer(1)

		gs.Add( wx.StaticText(self, label = _('Data Policy:') ), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.importPolicy = wx.Choice( self, choices = [
				_('Clear All Existing Data Before Import'),
				_('Merge New Data with Existing')
			] )
		self.importPolicy.SetSelection( 0 )
		gs.Add( self.importPolicy, 1, wx.ALIGN_LEFT )
		gs.AddSpacer(1)
        
		gs.Add( wx.StaticText(self, label = _('Import Data Time Adjustment:') ), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.timeAdjustment = HighPrecisionTimeEdit( self, size=(120,-1) )
		self.behindAhead = wx.Choice( self, choices=[_('Behind'), _('Ahead')] )
		if JChip.readerComputerTimeDiff:
			rtAdjust = JChip.readerComputerTimeDiff.total_seconds()
			if rtAdjust >= 0.0:
				self.behindAhead.SetSelection( 0 )
			else:
				self.behindAhead.SetSelection( 1 )
				rtAdjust *= -1.0
			self.timeAdjustment.SetSeconds( rtAdjust )
		else:
			self.behindAhead.SetSelection( 0 )
		hb = wx.BoxSizer()
		hb.Add( self.behindAhead, flag=wx.ALIGN_BOTTOM|wx.BOTTOM, border=4 )
		hb.Add( self.timeAdjustment, flag=wx.ALL, border=4 )
		gs.Add( hb, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT )
		gs.AddSpacer(1)
		
		self.manualStartTime = wx.CheckBox(self, label = _('Race Start Time (if NOT first recorded time):') )
		self.Bind( wx.EVT_CHECKBOX, self.onChangeManualStartTime, self.manualStartTime )
		gs.Add( self.manualStartTime, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.raceStartTime = masked.TimeCtrl( self, fmt24hr=True, value="10:00:00" )
		self.raceStartTime.Enable( False )
		gs.Add( self.raceStartTime, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
		gs.AddSpacer(1)
		
		with Model.LockRace() as race:
			isTimeTrial = getattr(race, 'isTimeTrial', False) if race else False

		if isTimeTrial:
			self.manualStartTime.Enable( False )
			self.manualStartTime.Show( False )
			self.raceStartTime.Enable( False )
			self.raceStartTime.Show( False )
			self.dataType.SetLabel( _('Data will be imported for a Time Trial') )
		else:
			self.dataType.SetLabel( _('Data will be imported for a Race') )
			
		self.okBtn = wx.Button( self, wx.ID_OK )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		bs = wx.BoxSizer( wx.VERTICAL )
		
		border = 4
		
		hs = wx.BoxSizer( wx.HORIZONTAL )
		
		try:
			image = wx.Image( os.path.join(Utils.getImageFolder(), '{}Logo.png'.format(chipName)), wx.BITMAP_TYPE_PNG )
		except Exception as e:
			image = wx.EmptyImage( 32, 32, True )
		hs.Add( wx.StaticBitmap(self, bitmap = image.ConvertToBitmap()), 0 )
		hs.Add( wx.StaticText(self, label = intro), 1, wx.EXPAND|wx.LEFT, border*2 )
		
		bs.Add( hs, 1, wx.EXPAND|wx.ALL, border )
		
		#-------------------------------------------------------------------
		bs.AddSpacer( border )
		
		bs.Add( gs, 0, wx.EXPAND | wx.ALL, border )
		
		buttonBox = wx.BoxSizer( wx.HORIZONTAL )
		buttonBox.AddStretchSpacer()
		buttonBox.Add( self.okBtn, flag = wx.RIGHT, border = border )
		self.okBtn.SetDefault()
		buttonBox.Add( self.cancelBtn )
		bs.Add( buttonBox, 0, wx.EXPAND | wx.ALL, border )
		
		self.SetSizerAndFit(bs)
		bs.Fit( self )
		
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )
Esempio n. 12
0
class ChipImportDialog( wx.Dialog ):
	def __init__( self, chipName, parseTagTime, parent, id = wx.ID_ANY, fileSuffix = 'txt' ):
		wx.Dialog.__init__( self, parent, id, u'{} {}'.format(chipName, _('Import')),
						style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.TAB_TRAVERSAL )
		
		self.chipName = chipName
		self.parseTagTime = parseTagTime
		self.fileSuffix = fileSuffix
		todoList = [
			u'{} {}'.format(chipName, _('Import Data File')),
			u'',
			_('You must first "New" a race and fill in the details.'),
			_('You must also configure a "Tag" field in your Sign-On Excel Sheet and link the sheet to the race.'),
			_('This is required so CrossMgr can link the tags in the import file back to rider numbers and info.'),
			u'',
			_('Race Data:'),
			_('If the first chip read is NOT the start of the race, you will need to enter the start time manually.'),
			_('Otherwise the import will use the first chip read as the race start.'),
			u'',
			_('TimeTrial Data:'),
			_("The first chip read for each rider will be interpreted as the rider's start time."),
			u'',
			_('Warning: Importing from chip data could replace all the data in this race.'),
			_('Proceed with caution.'),
		]
		intro = u'\n'.join(todoList)
		
		gs = wx.FlexGridSizer( rows=0, cols=3, vgap=10, hgap=5 )
		gs.Add( wx.StaticText(self, label = u'{} {}:'.format(chipName, _('Data File'))), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.chipDataFile = wx.TextCtrl( self, -1, '', size=(450,-1) )
		defaultPath = Utils.getFileName()
		if not defaultPath:
			defaultPath = Utils.getDocumentsDir()
		else:
			defaultPath = os.path.join( os.path.split(defaultPath)[0], '' )
		self.chipDataFile.SetValue( defaultPath )
		gs.Add( self.chipDataFile, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.GROW)

		btn = wx.Button( self, label=_('Browse') + u'...' )
		btn.Bind( wx.EVT_BUTTON, self.onBrowseChipReaderDataFile )
		gs.Add( btn, 0, wx.ALIGN_CENTER_VERTICAL )
		
		gs.AddSpacer(1)
		self.dataType = wx.StaticText( self, label = _("Data Is:") )
		gs.Add( self.dataType, 1, wx.ALIGN_LEFT )
		gs.AddSpacer(1)

		gs.Add( wx.StaticText(self, label = _('Data Policy:') ), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.importPolicy = wx.Choice( self, choices = [
				_('Clear All Existing Data Before Import'),
				_('Merge New Data with Existing')
			] )
		self.importPolicy.SetSelection( 0 )
		gs.Add( self.importPolicy, 1, wx.ALIGN_LEFT )
		gs.AddSpacer(1)
        
		gs.Add( wx.StaticText(self, label = _('Import Data Time Adjustment:') ), 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.timeAdjustment = HighPrecisionTimeEdit( self, size=(120,-1) )
		self.behindAhead = wx.Choice( self, choices=[_('Behind'), _('Ahead')] )
		if JChip.readerComputerTimeDiff:
			rtAdjust = JChip.readerComputerTimeDiff.total_seconds()
			if rtAdjust >= 0.0:
				self.behindAhead.SetSelection( 0 )
			else:
				self.behindAhead.SetSelection( 1 )
				rtAdjust *= -1.0
			self.timeAdjustment.SetSeconds( rtAdjust )
		else:
			self.behindAhead.SetSelection( 0 )
		hb = wx.BoxSizer()
		hb.Add( self.behindAhead, flag=wx.ALIGN_BOTTOM|wx.BOTTOM, border=4 )
		hb.Add( self.timeAdjustment, flag=wx.ALL, border=4 )
		gs.Add( hb, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT )
		gs.AddSpacer(1)
		
		self.manualStartTime = wx.CheckBox(self, label = _('Race Start Time (if NOT first recorded time):') )
		self.Bind( wx.EVT_CHECKBOX, self.onChangeManualStartTime, self.manualStartTime )
		gs.Add( self.manualStartTime, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT )
		self.raceStartTime = masked.TimeCtrl( self, fmt24hr=True, value="10:00:00" )
		self.raceStartTime.Enable( False )
		gs.Add( self.raceStartTime, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
		gs.AddSpacer(1)
		
		with Model.LockRace() as race:
			isTimeTrial = getattr(race, 'isTimeTrial', False) if race else False

		if isTimeTrial:
			self.manualStartTime.Enable( False )
			self.manualStartTime.Show( False )
			self.raceStartTime.Enable( False )
			self.raceStartTime.Show( False )
			self.dataType.SetLabel( _('Data will be imported for a Time Trial') )
		else:
			self.dataType.SetLabel( _('Data will be imported for a Race') )
			
		self.okBtn = wx.Button( self, wx.ID_OK )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		bs = wx.BoxSizer( wx.VERTICAL )
		
		border = 4
		
		hs = wx.BoxSizer( wx.HORIZONTAL )
		
		try:
			image = wx.Image( os.path.join(Utils.getImageFolder(), '{}Logo.png'.format(chipName)), wx.BITMAP_TYPE_PNG )
		except Exception as e:
			image = wx.EmptyImage( 32, 32, True )
		hs.Add( wx.StaticBitmap(self, bitmap = image.ConvertToBitmap()), 0 )
		hs.Add( wx.StaticText(self, label = intro), 1, wx.EXPAND|wx.LEFT, border*2 )
		
		bs.Add( hs, 1, wx.EXPAND|wx.ALL, border )
		
		#-------------------------------------------------------------------
		bs.AddSpacer( border )
		
		bs.Add( gs, 0, wx.EXPAND | wx.ALL, border )
		
		buttonBox = wx.BoxSizer( wx.HORIZONTAL )
		buttonBox.AddStretchSpacer()
		buttonBox.Add( self.okBtn, flag = wx.RIGHT, border = border )
		self.okBtn.SetDefault()
		buttonBox.Add( self.cancelBtn )
		bs.Add( buttonBox, 0, wx.EXPAND | wx.ALL, border )
		
		self.SetSizerAndFit(bs)
		bs.Fit( self )
		
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )

	def onChangeManualStartTime( self, event ):
		self.raceStartTime.Enable( event.IsChecked() )
		
	def onBrowseChipReaderDataFile( self, event ):
		defaultPath = self.chipDataFile.GetValue()
		if not defaultPath:
			defaultPath = Utils.getFileName()
			if defaultPath:
				defaultPath = os.path.split(defaultPath)[0]
			else:
				defaultPath = Utils.getDocumentsDir()
			defaultFile = ''
		else:
			defaultPath, defaultFile = os.path.split(defaultPath)
			
		dlg = wx.FileDialog( self, u"{} {}".format( self.chipName, _('Import file') ),
							style=wx.OPEN | wx.CHANGE_DIR,
							wildcard="RFID (*.{})|*.{}".format(self.fileSuffix, self.fileSuffix),
							defaultDir=defaultPath if defaultPath else '',
							defaultFile=defaultFile if defaultFile else '',
							)
		if dlg.ShowModal() == wx.ID_OK:
			self.chipDataFile.SetValue( dlg.GetPath() )
		dlg.Destroy()
	
	def onOK( self, event ):
		fname = self.chipDataFile.GetValue()
		try:
			with open(fname) as f:
				pass
		except IOError:
			Utils.MessageOK( self, u'{}:\n\n"{}"'.format(_('Could not open data file for import'), fname),
									title = _('Cannot Open File'), iconMask = wx.ICON_ERROR)
			return
			
		clearExistingData = (self.importPolicy.GetSelection() == 0)
		timeAdjustment = self.timeAdjustment.GetSeconds()
		if self.behindAhead.GetSelection() == 1:
			timeAdjustment *= -1
		
		# Get the start time.
		if not clearExistingData:
			if not Model.race or not Model.race.startTime:
				Utils.MessageOK( self,
					u'\n\n'.join( [_('Cannot Merge into Unstarted Race.'), _('Clear All Existing Data is allowed.')] ),
					title = _('Import Merge Failed'), iconMask = wx.ICON_ERROR
				)
				return
			startTime = Model.race.startTime.time()
		else:
			if self.manualStartTime.IsChecked():
				startTime = datetime.time(*[int(x) for x in self.raceStartTime.GetValue().split(':')])
			else:
				startTime = None
			
		undo.pushState()
		errors = DoChipImport(	fname, self.parseTagTime, startTime,
								clearExistingData,
								datetime.timedelta(seconds = timeAdjustment) )
		
		if errors:
			# Copy the tags to the clipboard.
			clipboard = wx.Clipboard.Get()
			if not clipboard.IsOpened():
				clipboard.Open()
				clipboard.SetData( wx.TextDataObject('\n'.join(errors)) )
				clipboard.Close()
			
			if len(errors) > 10:
				errors = errors[:10]
				errors.append( '...' )
			tagStr = '\n'.join(errors)
			Utils.MessageOK( self,
							u'{}:\n\n{}\n\n{}.'.format(_('Import File contains errors'), tagStr, _('All errors have been copied to the clipboard')),
							_('Import Warning'),
							iconMask = wx.ICON_WARNING )
		else:
			Utils.MessageOK( self, _('Import Successful'), _('Import Successful') )
		wx.CallAfter( Utils.refresh )
		self.EndModal( wx.ID_OK )
		
	def onCancel( self, event ):
		self.EndModal( wx.ID_CANCEL )
Esempio n. 13
0
class ChangeRaceStartTimeDialog(wx.Dialog):
    def __init__(self, parent, id=wx.ID_ANY):
        wx.Dialog.__init__(self,
                           parent,
                           id,
                           "Change Race Start Time",
                           style=wx.DEFAULT_DIALOG_STYLE | wx.TAB_TRAVERSAL)

        race = Model.race
        if not race:
            return
        bs = wx.GridBagSizer(vgap=5, hgap=5)

        seconds = (race.startTime - race.startTime.replace(
            hour=0, minute=0, second=0)).total_seconds()
        self.timeMsEdit = HighPrecisionTimeEdit(self,
                                                seconds=seconds,
                                                size=(80, -1))
        self.timeMsEdit.SetMinSize((80, -1))

        self.setTimeNow = wx.Button(self, label=_('Tap for NOW'))
        self.setTimeNow.Bind(wx.EVT_LEFT_DOWN, self.onSetTimeNow)

        self.okBtn = wx.Button(self, wx.ID_OK)
        self.Bind(wx.EVT_BUTTON, self.onOK, self.okBtn)

        self.cancelBtn = wx.Button(self, wx.ID_CANCEL)
        self.Bind(wx.EVT_BUTTON, self.onCancel, self.cancelBtn)

        border = 8
        self.timeLabel = wx.StaticText(
            self, label=_('New Race Start Time (24hr clock):'))
        bs.Add(self.timeLabel,
               pos=(0, 0),
               span=(1, 1),
               border=border,
               flag=wx.ALIGN_RIGHT | wx.LEFT | wx.BOTTOM | wx.TOP
               | wx.ALIGN_CENTRE_VERTICAL)
        bs.Add(self.timeMsEdit,
               pos=(0, 1),
               span=(1, 1),
               border=border,
               flag=wx.RIGHT | wx.BOTTOM | wx.TOP | wx.ALIGN_LEFT)
        bs.Add(self.setTimeNow,
               pos=(0, 2),
               span=(1, 1),
               border=border,
               flag=wx.ALL)

        bs.Add(self.okBtn, pos=(1, 1), span=(1, 1), border=border, flag=wx.ALL)
        self.okBtn.SetDefault()
        bs.Add(self.cancelBtn,
               pos=(1, 2),
               span=(1, 1),
               border=border,
               flag=wx.ALL)

        self.SetSizerAndFit(bs)
        bs.Fit(self)

        self.CentreOnParent(wx.BOTH)
        wx.CallAfter(self.SetFocus)

    def onSetTimeNow(self, event):
        tNow = datetime.datetime.now()
        self.timeMsEdit.SetSeconds(
            (tNow - tNow.replace(hour=0, minute=0, second=0)).total_seconds())
        event.Skip()

    def onOK(self, event):
        race = Model.race
        if not race:
            return
        if race.isTimeTrial and race.hasRiderTimes():
            Utils.MessageOKCancel(
                self,
                _('Cannot change Time Trial Start Time') + u'\n\n' +
                _('There are already recorded results.'),
                _('Cannot change Start Time'))
            self.EndModal(wx.ID_OK)

        tOld = race.startTime
        startTimeNew = tOld.replace(hour=0, minute=0, second=0,
                                    microsecond=0) + datetime.timedelta(
                                        seconds=self.timeMsEdit.GetSeconds())
        dTime = (startTimeNew - race.startTime).total_seconds()

        if not dTime:
            return

        if dTime > 0.0 and not Utils.MessageOKCancel(
                self,
                _('Are you Sure you want to change the Race Start to Later?') +
                u'\n' + _('(you can always undo).'), _('Are you sure?')):
            return

        undo.pushState()

        # Adjust all rider times to account for the new start time.
        if not race.isTimeTrial:
            for rider in race.riders.values():
                try:
                    rider.firstTime = max(0.0, rider.firstTime - dTime)
                except TypeError:
                    pass
                rider.times[:] = [max(0.0, v - dTime) for v in rider.times]

            race.numTimeInfo.adjustAllTimes(-dTime)

            # Also fix any unread tags.
            if race.unmatchedTags:
                for times in race.unmatchedTags.values():
                    times[:] = [max(0.0, v - dTime) for v in times]

        race.startTime = startTimeNew
        race.setChanged()
        Utils.refresh()

        self.EndModal(wx.ID_OK)

    def onCancel(self, event):
        self.EndModal(wx.ID_CANCEL)
Esempio n. 14
0
	def __init__( self, parent, id = wx.ID_ANY ):
		wx.Dialog.__init__( self, parent, id, _("Start Race at Time:"),
						style=wx.DEFAULT_DIALOG_STYLE|wx.TAB_TRAVERSAL )
						
		font = wx.Font(24, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
		
		self.startSeconds = None
		self.timer = None
		self.futureRaceTime = None
		
		race = Model.getRace()
		autoStartLabel = wx.StaticText( self, label = _('Automatically Start Race at:') )
		
		# Make sure we don't suggest a start time in the past.
		value = race.scheduledStart
		startSeconds = Utils.StrToSeconds( value ) * 60
		nowSeconds = GetNowSeconds()
		if startSeconds < nowSeconds:
			startOffset = 3 * 60
			startSeconds = nowSeconds - nowSeconds % startOffset
			startSeconds = nowSeconds + startOffset
			value = u'{:02d}:{:02d}'.format(startSeconds // (60*60), (startSeconds // 60) % 60)
		
		self.autoStartTime = HighPrecisionTimeEdit( self, display_seconds=False, value=value, size=wx.Size(60,-1) )
		
		self.pagesLabel = wx.StaticText( self, label=_('After Start, Switch to:') )
		mainWin = Utils.getMainWin()
		if mainWin:
			pageNames = [name for a, b, name in mainWin.attrClassName]
		else:
			pageNames = [
				_('Actions'),
				_('Record'),
				_('Results'),
				_('Passings'),
				_('RiderDetail'),
				_('Chart'),
				_('Animation'),
				_('Recommendations'),
				_('Categories'),
				_('Properties'),
				_('Primes'),
				_('Situation'),
				_('LapCounter'),
			]
		pageNames = pageNames[1:]	# Skip the Actions screen.
		self.pages = wx.Choice( self, choices=pageNames )
		self.pages.SetSelection( 0 )	# Record screen.
		
		self.countdown = CountdownClock( self, size=(400,400), tFuture=None )
		self.countdown.SetBackgroundColour( wx.WHITE );
		self.Bind( EVT_COUNTDOWN, self.onCountdown )
		
		self.okBtn = wx.Button( self, wx.ID_OK, label=_('Start at Above Time') )
		self.Bind( wx.EVT_BUTTON, self.onOK, self.okBtn )
		
		self.start30 = wx.Button( self, label=_('Start in 30s') )
		self.start30.Bind( wx.EVT_BUTTON, lambda event: self.startInFuture(event, 30) )
		self.start60 = wx.Button( self, label=_('Start in 60s') )
		self.start60.Bind( wx.EVT_BUTTON, lambda event: self.startInFuture(event, 60) )

		self.cancelBtn = wx.Button( self, wx.ID_CANCEL )
		self.Bind( wx.EVT_BUTTON, self.onCancel, self.cancelBtn )
		
		vs = wx.BoxSizer( wx.VERTICAL )

		border = 8
		hs = wx.BoxSizer( wx.HORIZONTAL )
		hs.Add( autoStartLabel, border = border, flag=wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL )
		hs.Add( self.autoStartTime, border = border, flag=wx.RIGHT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL )
		hs.Add( self.pagesLabel, border = border, flag=wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL )
		hs.Add( self.pages, border = border, flag=wx.RIGHT|wx.TOP|wx.BOTTOM|wx.ALIGN_BOTTOM|wx.ALIGN_CENTER_VERTICAL )
		vs.Add( hs )
		
		hs = wx.BoxSizer( wx.HORIZONTAL )
		hs.Add( self.okBtn, border = border, flag=wx.ALL )
		hs.Add( self.start30, border = border, flag=wx.TOP|wx.BOTTOM|wx.RIGHT)
		hs.Add( self.start60, border = border, flag=wx.TOP|wx.BOTTOM|wx.RIGHT)
		self.okBtn.SetDefault()
		hs.AddStretchSpacer()
		hs.Add( self.cancelBtn, border = border, flag=wx.ALL )
		vs.Add( hs, flag=wx.EXPAND )
		
		vs.Add( self.countdown, 1, border = border, flag=wx.ALL|wx.ALIGN_CENTRE|wx.EXPAND )
		
		self.SetSizerAndFit( vs )
		
		self.CentreOnParent(wx.BOTH)
		wx.CallAfter( self.SetFocus )
		
		wx.CallLater( 100, self.autoStartTime.SetSize, (48,-1) )