class Actions(wx.Panel): iResetStartClockOnFirstTag = 1 iSkipFirstTagRead = 2 def __init__(self, parent, id=wx.ID_ANY): wx.Panel.__init__(self, parent, id) self.SetBackgroundColour(wx.Colour(255, 255, 255)) ps = wx.BoxSizer(wx.VERTICAL) self.splitter = wx.SplitterWindow(self, wx.VERTICAL) ps.Add(self.splitter, 1, flag=wx.EXPAND) self.SetSizer(ps) #--------------------------------------------------------------------------------------------- self.leftPanel = wx.Panel(self.splitter) bs = wx.BoxSizer(wx.VERTICAL) self.leftPanel.SetSizer(bs) self.leftPanel.SetBackgroundColour(wx.Colour(255, 255, 255)) self.leftPanel.Bind(wx.EVT_SIZE, self.setWrappedRaceInfo) buttonSize = 220 self.button = RoundButton(self.leftPanel, size=(buttonSize, buttonSize)) self.button.SetLabel(FinishText) self.button.SetFontToFitLabel() self.button.SetForegroundColour(wx.Colour(128, 128, 128)) self.Bind(wx.EVT_BUTTON, self.onPress, self.button) self.clock = Clock(self, size=(190, 190), checkFunc=self.updateClock) self.clock.SetBackgroundColour(wx.WHITE) self.raceIntro = wx.StaticText(self.leftPanel, label=u'') self.raceIntro.SetFont(wx.Font(20, wx.DEFAULT, wx.NORMAL, wx.NORMAL)) self.chipTimingOptions = wx.RadioBox( self.leftPanel, label=_("Chip Timing Options"), majorDimension=1, choices=Properties.RfidProperties.choices, style=wx.RA_SPECIFY_COLS) self.Bind(wx.EVT_RADIOBOX, self.onChipTimingOptions, self.chipTimingOptions) self.settingsButton = wx.BitmapButton( self.leftPanel, bitmap=Utils.GetPngBitmap('settings-icon.png')) self.settingsButton.SetToolTip(wx.ToolTip(_('Properties Shortcut'))) self.settingsButton.Bind(wx.EVT_BUTTON, self.onShowProperties) self.startRaceTimeCheckBox = wx.CheckBox( self.leftPanel, label=_('Start Race Automatically at Future Time')) hsSettings = wx.BoxSizer(wx.HORIZONTAL) hsSettings.Add(self.settingsButton, flag=wx.ALIGN_CENTER_VERTICAL) hsSettings.Add(self.startRaceTimeCheckBox, flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL, border=12) border = 8 hs = wx.BoxSizer(wx.HORIZONTAL) hs.Add(self.button, border=border, flag=wx.LEFT | wx.TOP) hs.Add(self.raceIntro, 1, border=border, flag=wx.LEFT | wx.TOP | wx.RIGHT | wx.EXPAND) bs.Add(hs, border=border, flag=wx.ALL) hsClock = wx.BoxSizer(wx.HORIZONTAL) hsClock.AddSpacer(26) hsClock.Add(self.clock) hsClock.Add(hsSettings, border=4, flag=wx.LEFT) bs.Add(hsClock, border=4, flag=wx.ALL) bs.Add(self.chipTimingOptions, border=border, flag=wx.ALL) #--------------------------------------------------------------------------------------------- self.rightPanel = wx.Panel(self.splitter) self.rightPanel.SetBackgroundColour(wx.Colour(255, 255, 255)) checklistTitle = wx.StaticText(self.rightPanel, label=_('Checklist:')) checklistTitle.SetFont( wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.checklist = Checklist.Checklist(self.rightPanel) hsSub = wx.BoxSizer(wx.VERTICAL) hsSub.Add(checklistTitle, 0, flag=wx.ALL, border=4) hsSub.Add(self.checklist, 1, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=4) self.rightPanel.SetSizer(hsSub) #--------------------------------------------------------------------------------------------- self.splitter.SplitVertically(self.leftPanel, self.rightPanel) self.splitter.SetMinimumPaneSize(100) wx.CallAfter(self.refresh) wx.CallAfter(self.splitter.SetSashPosition, 650) wx.CallAfter(self.GetSizer().Layout) def setWrappedRaceInfo(self, event=None): wrapWidth = self.leftPanel.GetClientSize( )[0] - self.button.GetClientSize()[0] - 20 dc = wx.WindowDC(self.raceIntro) dc.SetFont(self.raceIntro.GetFont()) label = wordwrap(Model.race.getRaceIntro() if Model.race else u'', wrapWidth, dc) self.raceIntro.SetLabel(label) self.leftPanel.GetSizer().Layout() if event: event.Skip() def updateChipTimingOptions(self): if not Model.race: return iSelection = self.chipTimingOptions.GetSelection() race = Model.race race.resetStartClockOnFirstTag = bool( iSelection == self.iResetStartClockOnFirstTag) race.skipFirstTagRead = bool(iSelection == self.iSkipFirstTagRead) def updateClock(self): mainWin = Utils.getMainWin() return not mainWin or mainWin.isShowingPage(self) def onShowProperties(self, event): if not Model.race: Utils.MessageOK( self, _("You must have a valid race. Open or New a race first."), _("No Valid Race"), iconMask=wx.ICON_ERROR) return if not hasattr(self, 'propertiesDialog'): self.propertiesDialog = PropertiesDialog(self, showFileFields=False, updateProperties=True, size=(600, 400)) else: self.propertiesDialog.properties.refresh(forceUpdate=True) self.propertiesDialog.properties.setPage('raceOptionsProperties') if self.propertiesDialog.ShowModal() == wx.ID_OK: self.propertiesDialog.properties.doCommit() Utils.refresh() def onChipTimingOptions(self, event): if not Model.race: return self.updateChipTimingOptions() def onPress(self, event): if not Model.race: return with Model.LockRace() as race: running = race.isRunning() if running: self.onFinishRace(event) return self.updateChipTimingOptions() if getattr(Model.race, 'enableJChipIntegration', False): try: externalFields = race.excelLink.getFields() externalInfo = race.excelLink.read() except: externalFields = [] externalInfo = {} if not externalInfo: Utils.MessageOK( self, u'\n\n'.join([ _('Cannot Start. Excel Sheet read failure.'), _('The Excel file is either unconfigured or unreadable.' ) ]), _('Excel Sheet Read '), wx.ICON_ERROR) return try: i = next((i for i, field in enumerate(externalFields) if field.startswith('Tag'))) except StopIteration: Utils.MessageOK( self, u'\n\n'.join([ _('Cannot Start. Excel Sheet missing Tag column.'), _('The Excel file must contain a Tag column to use RFID.' ) ]), _('Excel Sheet missing Tag column'), wx.ICON_ERROR) return if self.startRaceTimeCheckBox.IsChecked(): self.onStartRaceTime(event) else: self.onStartRace(event) def onStartRace(self, event): if Model.race and Utils.MessageOKCancel(self, _('Start Race Now?\n\n'), _('Start Race')): StartRaceNow() def onStartRaceTime(self, event): if Model.race is None: return dlg = StartRaceAtTime(self) dlg.ShowModal() dlg.Destroy() def onFinishRace(self, event): if Model.race is None or not Utils.MessageOKCancel( self, _('Finish Race Now?'), _('Finish Race')): return with Model.LockRace() as race: race.finishRaceNow() if race.numLaps is None: race.numLaps = race.getMaxLap() SetNoDataDNS() Model.resetCache() Utils.writeRace() self.refresh() mainWin = Utils.getMainWin() if mainWin: mainWin.refresh() OutputStreamer.writeRaceFinish() OutputStreamer.StopStreamer() try: ChipReader.chipReaderCur.StopListener() except: pass if getattr(Model.race, 'ftpUploadDuringRace', False): realTimeFtpPublish.publishEntry(True) def commit(self): self.checklist.commit() def refresh(self): self.clock.Start() self.button.Enable(False) self.startRaceTimeCheckBox.Enable(False) self.settingsButton.Enable(False) self.button.SetLabel(StartText) self.button.SetForegroundColour(wx.Colour(100, 100, 100)) self.chipTimingOptions.SetSelection(0) self.chipTimingOptions.Enable(False) with Model.LockRace() as race: if race: self.settingsButton.Enable(True) # Adjust the chip recording options for TT. if getattr(race, 'isTimeTrial', False): race.resetStartClockOnFirstTag = False race.skipFirstTagRead = False if getattr(race, 'resetStartClockOnFirstTag', True): self.chipTimingOptions.SetSelection( self.iResetStartClockOnFirstTag) elif getattr(race, 'skipFirstTagRead', False): self.chipTimingOptions.SetSelection(self.iSkipFirstTagRead) if race.startTime is None: self.button.Enable(True) self.button.SetLabel(StartText) self.button.SetForegroundColour(wx.Colour(0, 128, 0)) self.startRaceTimeCheckBox.Enable(True) self.startRaceTimeCheckBox.Show(True) self.chipTimingOptions.Enable( getattr(race, 'enableJChipIntegration', False)) self.chipTimingOptions.Show( getattr(race, 'enableJChipIntegration', False)) elif race.isRunning(): self.button.Enable(True) self.button.SetLabel(FinishText) self.button.SetForegroundColour(wx.Colour(128, 0, 0)) self.startRaceTimeCheckBox.Enable(False) self.startRaceTimeCheckBox.Show(False) self.chipTimingOptions.Enable(False) self.chipTimingOptions.Show(False) # Adjust the time trial display options. if getattr(race, 'isTimeTrial', False): self.chipTimingOptions.Enable(False) self.chipTimingOptions.Show(False) self.GetSizer().Layout() self.setWrappedRaceInfo() self.checklist.refresh() mainWin = Utils.getMainWin() if mainWin is not None: mainWin.updateRaceClock()
def __init__( self, parent, id = wx.ID_ANY, title='', size=(1000,800) ): wx.Frame.__init__(self, parent, id, title, size=size) self.db = Database() self.bufferSecs = 10 self.setFPS( 30 ) self.xFinish = None self.tFrameCount = self.tLaunch = self.tLast = now() self.frameCount = 0 self.fpt = timedelta(seconds=0) self.iTriggerSelect = None self.triggerInfo = None self.tsMax = None self.captureTimer = wx.CallLater( 10, self.stopCapture ) self.tdCaptureBefore = tdCaptureBeforeDefault self.tdCaptureAfter = tdCaptureAfterDefault self.config = wx.Config() self.requestQ = Queue() # Select photos from photobuf. self.dbWriterQ = Queue() # Photos waiting to be written self.messageQ = Queue() # Collection point for all status/failure messages. self.SetBackgroundColour( wx.Colour(232,232,232) ) self.focusDialog = FocusDialog( self ) self.photoDialog = PhotoDialog( self ) self.autoCaptureDialog = AutoCaptureDialog( self ) self.triggerDialog = TriggerDialog( self ) mainSizer = wx.BoxSizer( wx.VERTICAL ) #------------------------------------------------------------------------------------------------ headerSizer = wx.BoxSizer( wx.HORIZONTAL ) self.logo = Utils.GetPngBitmap('CrossMgrHeader.png') headerSizer.Add( wx.StaticBitmap(self, wx.ID_ANY, self.logo) ) self.title = wx.StaticText(self, label='CrossMgr Video\nVersion {}'.format(AppVerName.split()[1]), style=wx.ALIGN_RIGHT ) self.title.SetFont( wx.Font( (0,28), wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL ) ) headerSizer.Add( self.title, flag=wx.ALL, border=10 ) clock = Clock( self, size=(90,90) ) clock.SetBackgroundColour( self.GetBackgroundColour() ) clock.Start() headerSizer.Add( clock, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, border=4 ) #------------------------------------------------------------------------------ self.cameraDevice = wx.StaticText( self ) self.cameraResolution = wx.StaticText( self ) self.targetFPS = wx.StaticText( self, label='30 fps' ) self.actualFPS = wx.StaticText( self, label='30.0 fps' ) boldFont = self.cameraDevice.GetFont() boldFont.SetWeight( wx.BOLD ) for w in (self.cameraDevice, self.cameraResolution, self.targetFPS, self.actualFPS): w.SetFont( boldFont ) fgs = wx.FlexGridSizer( 2, 2, 2 ) # 2 Cols fgs.Add( wx.StaticText(self, label='Camera Device:'), flag=wx.ALIGN_RIGHT ) fgs.Add( self.cameraDevice ) fgs.Add( wx.StaticText(self, label='Resolution:'), flag=wx.ALIGN_RIGHT ) fgs.Add( self.cameraResolution ) fgs.Add( wx.StaticText(self, label='Target:'), flag=wx.ALIGN_RIGHT ) fgs.Add( self.targetFPS, flag=wx.ALIGN_RIGHT ) fgs.Add( wx.StaticText(self, label='Actual:'), flag=wx.ALIGN_RIGHT ) fgs.Add( self.actualFPS, flag=wx.ALIGN_RIGHT ) self.focus = wx.Button( self, label="Focus..." ) self.focus.Bind( wx.EVT_BUTTON, self.onFocus ) self.reset = wx.Button( self, label="Reset Camera" ) self.reset.Bind( wx.EVT_BUTTON, self.resetCamera ) self.manage = wx.Button( self, label="Manage Database" ) self.manage.Bind( wx.EVT_BUTTON, self.manageDatabase ) self.autoCaptureBtn = wx.Button( self, label="Config Auto Capture" ) self.autoCaptureBtn.Bind( wx.EVT_BUTTON, self.autoCaptureConfig ) self.help = wx.Button( self, wx.ID_HELP ) self.help.Bind( wx.EVT_BUTTON, self.onHelp ) self.snapshot, self.autoCapture, self.capture = CreateCaptureButtons( self ) self.snapshot.Bind( wx.EVT_LEFT_DOWN, self.onStartSnapshot ) self.focusDialog.snapshot.Bind( wx.EVT_LEFT_DOWN, self.onStartSnapshot ) self.autoCapture.Bind( wx.EVT_LEFT_DOWN, self.onStartAutoCapture ) self.focusDialog.autoCapture.Bind( wx.EVT_LEFT_DOWN, self.onStartAutoCapture ) self.capture.Bind( wx.EVT_LEFT_DOWN, self.onStartCapture ) self.capture.Bind( wx.EVT_LEFT_UP, self.onStopCapture ) self.focusDialog.capture.Bind( wx.EVT_LEFT_DOWN, self.onStartCapture ) self.focusDialog.capture.Bind( wx.EVT_LEFT_UP, self.onStopCapture ) headerSizer.Add( fgs, flag=wx.ALIGN_CENTER_VERTICAL ) fgs = wx.FlexGridSizer( rows=2, cols=0, hgap=8, vgap=4 ) fgs.Add( self.focus, flag=wx.EXPAND ) fgs.Add( self.reset, flag=wx.EXPAND ) fgs.Add( self.manage, flag=wx.EXPAND ) fgs.Add( self.autoCaptureBtn, flag=wx.EXPAND ) fgs.Add( self.help, flag=wx.EXPAND ) headerSizer.Add( fgs, flag=wx.ALIGN_CENTRE|wx.LEFT, border=4 ) headerSizer.AddStretchSpacer() headerSizer.Add( self.snapshot, flag=wx.ALIGN_CENTRE_VERTICAL|wx.LEFT, border=8 ) headerSizer.Add( self.autoCapture, flag=wx.ALIGN_CENTRE_VERTICAL|wx.LEFT, border=8 ) headerSizer.Add( self.capture, flag=wx.ALIGN_CENTRE_VERTICAL|wx.LEFT|wx.RIGHT, border=8 ) #------------------------------------------------------------------------------ mainSizer.Add( headerSizer, flag=wx.EXPAND ) #------------------------------------------------------------------------------------------------ self.finishStrip = FinishStripPanel( self, size=(-1,wx.GetDisplaySize()[1]//2) ) self.finishStrip.finish.Bind( wx.EVT_RIGHT_DOWN, self.onRightClick ) self.primaryBitmap = ScaledBitmap( self, style=wx.BORDER_SUNKEN, size=(int(imageWidth*0.75), int(imageHeight*0.75)) ) self.primaryBitmap.SetTestBitmap() self.primaryBitmap.Bind( wx.EVT_LEFT_UP, self.onFocus ) self.primaryBitmap.Bind( wx.EVT_RIGHT_UP, self.onFocus ) hsDate = wx.BoxSizer( wx.HORIZONTAL ) hsDate.Add( wx.StaticText(self, label='Show Triggers for'), flag=wx.ALIGN_CENTER_VERTICAL ) tQuery = now() self.date = wx.adv.DatePickerCtrl( self, dt=wx.DateTime.FromDMY( tQuery.day, tQuery.month-1, tQuery.year ), style=wx.adv.DP_DROPDOWN|wx.adv.DP_SHOWCENTURY ) self.date.Bind( wx.adv.EVT_DATE_CHANGED, self.onQueryDateChanged ) hsDate.Add( self.date, flag=wx.LEFT, border=2 ) self.dateSelect = wx.Button( self, label='Select Date' ) hsDate.Add( self.dateSelect, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border=2 ) self.dateSelect.Bind( wx.EVT_BUTTON, self.onDateSelect ) hsDate.Add( wx.StaticText(self, label='Filter by Bib'), flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT, border=12 ) self.bib = wx.lib.intctrl.IntCtrl( self, style=wx.TE_PROCESS_ENTER, size=(64,-1), min=1, allow_none=True, value=None ) self.bib.Bind( wx.EVT_TEXT_ENTER, self.onQueryBibChanged ) hsDate.Add( self.bib, flag=wx.LEFT, border=2 ) self.tsQueryLower = datetime(tQuery.year, tQuery.month, tQuery.day) self.tsQueryUpper = self.tsQueryLower + timedelta(days=1) self.bibQuery = None self.triggerList = AutoWidthListCtrl( self, style=wx.LC_REPORT|wx.BORDER_SUNKEN|wx.LC_SORT_ASCENDING|wx.LC_HRULES ) self.il = wx.ImageList(16, 16) self.sm_close = [] for bm in getCloseFinishBitmaps(): self.sm_close.append( self.il.Add(bm) ) self.sm_up = self.il.Add( Utils.GetPngBitmap('SmallUpArrow.png')) self.sm_up = self.il.Add( Utils.GetPngBitmap('SmallUpArrow.png')) self.sm_dn = self.il.Add( Utils.GetPngBitmap('SmallDownArrow.png')) self.triggerList.SetImageList(self.il, wx.IMAGE_LIST_SMALL) self.fieldCol = {f:c for c, f in enumerate('ts bib name team wave race_name note kmh mph frames'.split())} headers = ['Time', 'Bib', 'Name', 'Team', 'Wave', 'Race', 'Note', 'km/h', 'mph', 'Frames'] for i, h in enumerate(headers): self.triggerList.InsertColumn( i, h, wx.LIST_FORMAT_RIGHT if h in ('Bib','km/h','mph','Frames') else wx.LIST_FORMAT_LEFT ) self.itemDataMap = {} self.triggerList.Bind( wx.EVT_LIST_ITEM_SELECTED, self.onTriggerSelected ) self.triggerList.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.onTriggerEdit ) self.triggerList.Bind( wx.EVT_LIST_ITEM_RIGHT_CLICK, self.onTriggerRightClick ) #self.triggerList.Bind( wx.EVT_LIST_DELETE_ITEM, self.onTriggerDelete ) vsTriggers = wx.BoxSizer( wx.VERTICAL ) vsTriggers.Add( hsDate ) vsTriggers.Add( self.triggerList, 1, flag=wx.EXPAND|wx.TOP, border=2) #------------------------------------------------------------------------------------------------ mainSizer.Add( self.finishStrip, 1, flag=wx.EXPAND ) border=2 row1Sizer = wx.BoxSizer( wx.HORIZONTAL ) row1Sizer.Add( self.primaryBitmap, flag=wx.ALL, border=border ) row1Sizer.Add( vsTriggers, 1, flag=wx.TOP|wx.BOTTOM|wx.RIGHT|wx.EXPAND, border=border ) mainSizer.Add( row1Sizer, flag=wx.EXPAND ) self.Bind(wx.EVT_CLOSE, self.onCloseWindow) self.readOptions() self.updateFPS( int(float(self.targetFPS.GetLabel().split()[0])) ) self.updateAutoCaptureLabel() self.SetSizerAndFit( mainSizer ) # Start the message reporting thread so we can see what is going on. self.messageThread = threading.Thread( target=self.showMessages ) self.messageThread.daemon = True self.messageThread.start() wx.CallLater( 300, self.refreshTriggers )