def update_clock(self): '''Updates the clock''' # compute time t = time.time()-self.t0 # update label self.clocklabel.set_markup(time_format(t)) # keep updating return True
def update_clock(self): '''Updates the clock''' # compute time t = time.time() - self.t0 # update label self.clocklabel.set_markup(time_format(t)) # keep updating return True
def new_blank_time(self): '''Record a new time''' t = time_format(time.time()-self.t0) self.rawtimes['times'].insert(0, t) #we prepend to rawtimes, just as we prepend to timemodel if self.offset >= 0: # No IDs in the buffer, so just prepend it to the liststore. self.timemodel.prepend(['', t]) elif self.offset < 0: # IDs in the buffer, so add the time to the oldest ID # put it in the last available ID slot self.timemodel.set_value(self.timemodel.get_iter(-self.offset-1), 1, t) self.offset += 1 self.entrybox.set_text('')
def new_blank_time(self): '''Record a new time''' t = time_format(time.time() - self.t0) self.rawtimes['times'].insert( 0, t) #we prepend to rawtimes, just as we prepend to timemodel if self.offset >= 0: # No IDs in the buffer, so just prepend it to the liststore. self.timemodel.prepend(['', t]) elif self.offset < 0: # IDs in the buffer, so add the time to the oldest ID # put it in the last available ID slot self.timemodel.set_value(self.timemodel.get_iter(-self.offset - 1), 1, t) self.offset += 1 self.entrybox.set_text('')
def sort_results(result_rows, rank_indx, cols): # Try sorting as float, but if that doesn't work, use string. try: # Define a sorter that will handle the Nones def floatsort(x): if x[1][rank_indx] is None: return 1e20 else: return x[1][rank_indx] result_rows = sorted(result_rows, key=floatsort) except TypeError: def stringsort(x): if x[1][rank_indx] is None: return '' else: return x[1][rank_indx] result_rows = sorted(result_rows, key=stringsort) # Remove duplicate entries: If a tag has multiple entries, keep only the # most highly ranked. Also replace total times and pace times with # formatted times, stringify everything but Lap Times, and replace Nones. taglist = set() result_rows_dedup = [] for tag, row in result_rows: if tag in taglist: pass # drop it else: taglist.add(tag) row_new = [] for i, val in enumerate(row): if val is None: if i == rank_indx: val = '_' else: val = '' elif cols[i] in ['Time', 'Pace']: val = time_format(val) elif cols[i] == 'Lap Times': pass # Leave it as is else: val = str(val) row_new.append(val) result_rows_dedup.append((tag, row_new)) return result_rows_dedup
def __init__(self, pytimer, timebtn): '''Builds and display the compilation error window''' super(TimingWin, self).__init__(Gtk.WindowType.TOPLEVEL) self.path = pytimer.path self.projecttype = pytimer.projecttype self.fields = pytimer.fields self.fieldsdic = pytimer.fieldsdic self.write_timing_cb = pytimer.write_updated_timing self.timebtn = timebtn self.rawtimes = pytimer.rawtimes self.timing = pytimer.timing self.numlaps = pytimer.numlaps self.wineditblocktime = None self.winedittime = None self.t0win = None self.modify_bg(Gtk.StateType.NORMAL, fstimer.gui.bgcolor) self.set_transient_for(pytimer.rootwin) self.set_modal(True) self.set_title('fsTimer - ' + os.path.basename(self.path)) self.set_position(Gtk.WindowPosition.CENTER) self.connect('delete_event', lambda b, jnk: self.done_timing(b)) self.set_border_width(10) self.set_size_request(450, 450) # We will put the timing info in a liststore in a scrolledwindow self.timemodel = Gtk.ListStore(str, str) # We will put the liststore in a treeview self.timeview = Gtk.TreeView() column = Gtk.TreeViewColumn('ID', Gtk.CellRendererText(), text=0) self.timeview.append_column(column) column = Gtk.TreeViewColumn('Time', Gtk.CellRendererText(), text=1) self.timeview.append_column(column) #An extra column if it is a handicap race if self.projecttype == 'handicap': renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn('Corrected Time', renderer) column.set_cell_data_func(renderer, self.print_corrected_time) self.timeview.append_column(column) #Another extra column if it is a lap race if self.numlaps > 1: renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn('Completed laps', renderer) column.set_cell_data_func(renderer, self.print_completed_laps) self.timeview.append_column(column) self.timeview.set_model(self.timemodel) self.timeview.connect('size-allocate', self.scroll_times) treeselection = self.timeview.get_selection() # make it multiple selecting treeselection.set_mode(Gtk.SelectionMode.MULTIPLE) # And put it in a scrolled window, in an alignment self.timesw = Gtk.ScrolledWindow() self.timesw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) self.timesw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.timesw.add(self.timeview) timealgn = Gtk.Alignment.new(0, 0, 1, 1) timealgn.add(self.timesw) self.entrybox = Gtk.Entry() self.entrybox.set_max_length(40) self.offset = 0 #this is len(times) - len(ids) self.entrybox.connect('activate', self.record_time) self.entrybox.connect('changed', self.check_for_newtime) # And we will save our file self.timestr = re.sub(' +', '_', time.ctime()).replace(':', '') #we save with the current time in the filename so no chance of being overwritten accidentally # Now lets go on to boxes tophbox = Gtk.HBox() # our default t0, and the stuff on top for setting/edit t0 self.t0 = 0. btn_t0 = Gtk.Button('Start!') btn_t0.connect('clicked', self.set_t0) # time display self.clocklabel = Gtk.Label() self.clocklabel.modify_font(Pango.FontDescription("sans 20")) self.clocklabel.set_markup(time_format(0)) tophbox.pack_start(btn_t0, False, False, 10) tophbox.pack_start(self.clocklabel, False, False, 10) timevbox1 = Gtk.VBox(False, 8) timevbox1.pack_start(tophbox, False, False, 0) timevbox1.pack_start(timealgn, True, True, 0) timevbox1.pack_start(Gtk.Label('Select box below in order to mark times:'), False, False, 0) timevbox1.pack_start(self.entrybox, False, False, 0) # we will keep track of how many racers are still out. self.racers_reg = [] for i_unused in range(self.numlaps): self.racers_reg.append(set([k for k in self.timing.keys()])) self.racers_total = len(self.racers_reg[0]) self.racers_in = [0] * self.numlaps self.lapcounter = defaultdict(int) self.racerslabel = Gtk.Label() self.update_racers_label() timevbox1.pack_start(self.racerslabel, False, False, 0) vbox1align = Gtk.Alignment.new(0, 0, 1, 1) vbox1align.add(timevbox1) # buttons on the right side #First an options button that will actually be a menu options_menu = Gtk.Menu() menu_editreg = Gtk.MenuItem('Edit registration data') menu_editreg.connect_object("activate", self.edit_reg, None) menu_editreg.show() options_menu.append(menu_editreg) menu_resett0 = Gtk.MenuItem('Restart clock') menu_resett0.connect_object("activate", self.restart_t0, None) menu_resett0.show() options_menu.append(menu_resett0) menu_editt0 = Gtk.MenuItem('Edit starting time') menu_editt0.connect_object("activate", self.edit_t0, None) menu_editt0.show() options_menu.append(menu_editt0) menu_savecsv = Gtk.MenuItem('Save results to CSV') menu_savecsv.connect_object("activate", self.print_csv, pytimer) menu_savecsv.show() options_menu.append(menu_savecsv) menu_resume = Gtk.MenuItem('Load saved timing session') menu_resume.connect_object("activate", self.resume_times, None, False) #False is for not merging menu_resume.show() options_menu.append(menu_resume) menu_merge = Gtk.MenuItem('Merge in saved IDs or times') menu_merge.connect_object("activate", self.resume_times, None, True) #True is for merging menu_merge.show() options_menu.append(menu_merge) btnOPTIONS = Gtk.Button('Options') btnOPTIONS.connect_object("event", self.options_btn, options_menu) options_align = Gtk.Alignment.new(1, 0.1, 1, 0) options_align.add(btnOPTIONS) #Then the block of editing buttons btnDROPID = Gtk.Button('Drop ID') btnDROPID.connect('clicked', self.timing_rm_ID) btnDROPTIME = Gtk.Button('Drop time') btnDROPTIME.connect('clicked', self.timing_rm_time) btnEDIT = GtkStockButton('edit',"Edit") btnEDIT.connect('clicked', self.edit_time) edit_vbox = Gtk.VBox(True, 8) edit_vbox.pack_start(btnDROPID, False, False, 0) edit_vbox.pack_start(btnDROPTIME, False, False, 0) edit_vbox.pack_start(btnEDIT, False, False, 0) edit_align = Gtk.Alignment.new(1, 0, 1, 0) edit_align.add(edit_vbox) #Then the print and save buttons btnPRINT = Gtk.Button('Printouts') btnPRINT.connect('clicked', self.print_html, pytimer) btnSAVE = GtkStockButton('save',"Save") btnSAVE.connect('clicked', self.save_times) save_vbox = Gtk.VBox(True, 8) save_vbox.pack_start(btnPRINT, False, False, 0) save_vbox.pack_start(btnSAVE, False, False, 0) save_align = Gtk.Alignment.new(1, 1, 1, 0) save_align.add(save_vbox) #And finally the finish button btnOK = GtkStockButton('close',"Close") btnOK.connect('clicked', self.done_timing) done_align = Gtk.Alignment.new(1, 0.7, 1, 0) done_align.add(btnOK) vsubbox = Gtk.VBox(True, 0) vsubbox.pack_start(options_align, True, True, 0) vsubbox.pack_start(edit_align, True, True, 0) vsubbox.pack_start(save_align, True, True, 0) vsubbox.pack_start(done_align, True, True, 0) vspacer = Gtk.Alignment.new(1, 1, 0, 0) vspacer.add(vsubbox) timehbox = Gtk.HBox(False, 8) timehbox.pack_start(vbox1align, True, True, 0) timehbox.pack_start(vspacer, False, False, 0) self.add(timehbox) self.show_all()
def get_sorted_results(projecttype, passid, numlaps, variablelaps, timing, rawtimes, ranking_key, cols, col_fns): '''returns a sorted list of (id, result) items. The content of result depends on the race type''' # get raw times timeslist = zip(*get_sync_times_and_ids(rawtimes)) #Handle blank times, and handicap correction # Handicap correction if projecttype == 'handicap': new_timeslist = [] for tag, time in timeslist: if tag and time and tag != passid: try: new_timeslist.append( (tag, time_diff(time, timing[tag]['Handicap']))) except AttributeError: # time or Handicap couldn't be converted to timedelta new_timeslist.append((tag, '_')) # Else: drop entries with blank tag, blank time, or pass ID timeslist = list(new_timeslist) #replace else: #Drop times that are blank or have the passid timeslist = [(tag, time) for tag, time in timeslist if tag and time and tag != passid] # Compute lap times, if a lap race if numlaps > 1: # multi laps - groups times by tag # Each value of laptimesdic is a list, sorted in order from # earliest time (1st lap) to latest time (last lap). timeslist_sorted = [] for (tag, time) in timeslist: try: timeslist_sorted.append((tag, time_parse(time))) except AttributeError: pass timeslist_sorted = sorted(timeslist_sorted, key=lambda x: x[1]) laptimesdic = defaultdict(list) for (tag, time) in timeslist_sorted: laptimesdic[tag].append(time_format(time.total_seconds())) # compute the lap times. lap_times = {} total_times = {} for tag in laptimesdic: # First put the total race time if len(laptimesdic[tag]) == numlaps or variablelaps: total_times[tag] = laptimesdic[tag][-1] else: total_times[tag] = '_' # And the first lap lap_times[tag] = ['1 - ' + laptimesdic[tag][0]] # And now the subsequent laps for ii in range(len(laptimesdic[tag]) - 1): try: lap_times[tag].append('{} - {}'.format( ii + 2, time_diff(laptimesdic[tag][ii + 1], laptimesdic[tag][ii]))) except AttributeError: lap_times[tag].append(str(ii + 2) + ' - _') # Now correct timeslist to have the new total times timeslist = list(total_times.items()) else: lap_times = defaultdict(int) # Compute each results row result_rows = [] for tag, time in timeslist: row = get_result_row(tag, time, lap_times, timing, col_fns) result_rows.append((tag, row)) # sort by column of ranking_key. rank_indx = cols.index(ranking_key) return sort_results(result_rows, rank_indx, cols)
def __init__(self, pytimer, timebtn): '''Builds and display the compilation error window''' super(TimingWin, self).__init__(Gtk.WindowType.TOPLEVEL) self.path = pytimer.path self.projecttype = pytimer.projecttype self.fields = pytimer.fields self.fieldsdic = pytimer.fieldsdic self.write_timing_cb = pytimer.write_updated_timing self.timebtn = timebtn self.rawtimes = pytimer.rawtimes self.timing = pytimer.timing self.numlaps = pytimer.numlaps self.wineditblocktime = None self.winedittime = None self.t0win = None self.modify_bg(Gtk.StateType.NORMAL, fstimer.gui.bgcolor) self.set_transient_for(pytimer.rootwin) self.set_modal(True) self.set_title('fsTimer - ' + os.path.basename(self.path)) self.set_position(Gtk.WindowPosition.CENTER) self.connect('delete_event', lambda b, jnk: self.done_timing(b)) self.set_border_width(10) self.set_size_request(450, 450) # We will put the timing info in a liststore in a scrolledwindow self.timemodel = Gtk.ListStore(str, str) # We will put the liststore in a treeview self.timeview = Gtk.TreeView() column = Gtk.TreeViewColumn('ID', Gtk.CellRendererText(), text=0) self.timeview.append_column(column) column = Gtk.TreeViewColumn('Time', Gtk.CellRendererText(), text=1) self.timeview.append_column(column) #An extra column if it is a handicap race if self.projecttype == 'handicap': renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn('Corrected Time', renderer) column.set_cell_data_func(renderer, self.print_corrected_time) self.timeview.append_column(column) #Another extra column if it is a lap race if self.numlaps > 1: renderer = Gtk.CellRendererText() column = Gtk.TreeViewColumn('Completed laps', renderer) column.set_cell_data_func(renderer, self.print_completed_laps) self.timeview.append_column(column) self.timeview.set_model(self.timemodel) self.timeview.connect('size-allocate', self.scroll_times) treeselection = self.timeview.get_selection() # make it multiple selecting treeselection.set_mode(Gtk.SelectionMode.MULTIPLE) # And put it in a scrolled window, in an alignment self.timesw = Gtk.ScrolledWindow() self.timesw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) self.timesw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.timesw.add(self.timeview) timealgn = Gtk.Alignment.new(0, 0, 1, 1) timealgn.add(self.timesw) self.entrybox = Gtk.Entry() self.entrybox.set_max_length(40) self.offset = 0 #this is len(times) - len(ids) self.entrybox.connect('activate', self.record_time) self.entrybox.connect('changed', self.check_for_newtime) # And we will save our file self.timestr = re.sub(' +', '_', time.ctime()).replace(':', '') #we save with the current time in the filename so no chance of being overwritten accidentally # Now lets go on to boxes tophbox = Gtk.HBox() # our default t0, and the stuff on top for setting/edit t0 self.t0 = 0. btn_t0 = Gtk.Button('Start!') btn_t0.connect('clicked', self.set_t0) # time display self.clocklabel = Gtk.Label() self.clocklabel.modify_font(Pango.FontDescription("sans 20")) self.clocklabel.set_markup(time_format(0)) tophbox.pack_start(btn_t0, False, False, 10) tophbox.pack_start(self.clocklabel, False, False, 10) timevbox1 = Gtk.VBox(False, 8) timevbox1.pack_start(tophbox, False, False, 0) timevbox1.pack_start(timealgn, True, True, 0) timevbox1.pack_start( Gtk.Label('Select box below in order to mark times:'), False, False, 0) timevbox1.pack_start(self.entrybox, False, False, 0) # we will keep track of how many racers are still out. self.racers_reg = [] for i_unused in range(self.numlaps): self.racers_reg.append(set([k for k in self.timing.keys()])) self.racers_total = len(self.racers_reg[0]) self.racers_in = [0] * self.numlaps self.lapcounter = defaultdict(int) self.racerslabel = Gtk.Label() self.update_racers_label() timevbox1.pack_start(self.racerslabel, False, False, 0) vbox1align = Gtk.Alignment.new(0, 0, 1, 1) vbox1align.add(timevbox1) # buttons on the right side #First an options button that will actually be a menu options_menu = Gtk.Menu() menu_editreg = Gtk.MenuItem('Edit registration data') menu_editreg.connect_object("activate", self.edit_reg, None) menu_editreg.show() options_menu.append(menu_editreg) menu_resett0 = Gtk.MenuItem('Restart clock') menu_resett0.connect_object("activate", self.restart_t0, None) menu_resett0.show() options_menu.append(menu_resett0) menu_editt0 = Gtk.MenuItem('Edit starting time') menu_editt0.connect_object("activate", self.edit_t0, None) menu_editt0.show() options_menu.append(menu_editt0) menu_savecsv = Gtk.MenuItem('Save results to CSV') menu_savecsv.connect_object("activate", self.print_csv, pytimer) menu_savecsv.show() options_menu.append(menu_savecsv) menu_resume = Gtk.MenuItem('Load saved timing session') menu_resume.connect_object("activate", self.resume_times, None, False) #False is for not merging menu_resume.show() options_menu.append(menu_resume) menu_merge = Gtk.MenuItem('Merge in saved IDs or times') menu_merge.connect_object("activate", self.resume_times, None, True) #True is for merging menu_merge.show() options_menu.append(menu_merge) btnOPTIONS = Gtk.Button('Options') btnOPTIONS.connect_object("event", self.options_btn, options_menu) options_align = Gtk.Alignment.new(1, 0.1, 1, 0) options_align.add(btnOPTIONS) #Then the block of editing buttons btnDROPID = Gtk.Button('Drop ID') btnDROPID.connect('clicked', self.timing_rm_ID) btnDROPTIME = Gtk.Button('Drop time') btnDROPTIME.connect('clicked', self.timing_rm_time) btnEDIT = GtkStockButton('edit', "Edit") btnEDIT.connect('clicked', self.edit_time) edit_vbox = Gtk.VBox(True, 8) edit_vbox.pack_start(btnDROPID, False, False, 0) edit_vbox.pack_start(btnDROPTIME, False, False, 0) edit_vbox.pack_start(btnEDIT, False, False, 0) edit_align = Gtk.Alignment.new(1, 0, 1, 0) edit_align.add(edit_vbox) #Then the print and save buttons btnPRINT = Gtk.Button('Printouts') btnPRINT.connect('clicked', self.print_html, pytimer) btnSAVE = GtkStockButton('save', "Save") btnSAVE.connect('clicked', self.save_times) save_vbox = Gtk.VBox(True, 8) save_vbox.pack_start(btnPRINT, False, False, 0) save_vbox.pack_start(btnSAVE, False, False, 0) save_align = Gtk.Alignment.new(1, 1, 1, 0) save_align.add(save_vbox) #And finally the finish button btnOK = GtkStockButton('close', "Close") btnOK.connect('clicked', self.done_timing) done_align = Gtk.Alignment.new(1, 0.7, 1, 0) done_align.add(btnOK) vsubbox = Gtk.VBox(True, 0) vsubbox.pack_start(options_align, True, True, 0) vsubbox.pack_start(edit_align, True, True, 0) vsubbox.pack_start(save_align, True, True, 0) vsubbox.pack_start(done_align, True, True, 0) vspacer = Gtk.Alignment.new(1, 1, 0, 0) vspacer.add(vsubbox) timehbox = Gtk.HBox(False, 8) timehbox.pack_start(vbox1align, True, True, 0) timehbox.pack_start(vspacer, False, False, 0) self.add(timehbox) self.show_all()
def get_sorted_results(projecttype, passid, numlaps, variablelaps, timing, rawtimes, ranking_key, cols, col_fns): '''returns a sorted list of (id, result) items. The content of result depends on the race type''' # get raw times timeslist = zip(*get_sync_times_and_ids(rawtimes)) #Handle blank times, and handicap correction # Handicap correction if projecttype == 'handicap': new_timeslist = [] for tag, time in timeslist: if tag and time and tag != passid: try: new_timeslist.append( (tag, time_diff(time, timing[tag]['Handicap']))) except AttributeError: # time or Handicap couldn't be converted to timedelta new_timeslist.append((tag, '_')) # Else: drop entries with blank tag, blank time, or pass ID timeslist = list(new_timeslist) #replace else: #Drop times that are blank or have the passid timeslist = [(tag, time) for tag, time in timeslist if tag and time and tag != passid] # Compute lap times, if a lap race if numlaps > 1: # multi laps - groups times by tag # Each value of laptimesdic is a list, sorted in order from # earliest time (1st lap) to latest time (last lap). timeslist_sorted = [] for (tag, time) in timeslist: try: timeslist_sorted.append((tag, time_parse(time))) except AttributeError: pass timeslist_sorted = sorted(timeslist_sorted, key=lambda x: x[1]) laptimesdic = defaultdict(list) for (tag, time) in timeslist_sorted: laptimesdic[tag].append(time_format(time.total_seconds())) # compute the lap times. lap_times = {} total_times = {} for tag in laptimesdic: # First put the total race time if len(laptimesdic[tag]) == numlaps or variablelaps: total_times[tag] = laptimesdic[tag][-1] else: total_times[tag] = '_' # And the first lap lap_times[tag] = ['1 - ' + laptimesdic[tag][0]] # And now the subsequent laps for ii in range(len(laptimesdic[tag])-1): try: lap_times[tag].append( '{} - {}'.format( ii + 2, time_diff(laptimesdic[tag][ii+1], laptimesdic[tag][ii]))) except AttributeError: lap_times[tag].append(str(ii+2) + ' - _') # Now correct timeslist to have the new total times timeslist = list(total_times.items()) else: lap_times = defaultdict(int) # Compute each results row result_rows = [] for tag, time in timeslist: row = get_result_row(tag, time, lap_times, timing, col_fns) result_rows.append((tag, row)) # sort by column of ranking_key. rank_indx = cols.index(ranking_key) return sort_results(result_rows, rank_indx, cols)