#! /usr/bin/env python title = "gStopwatch" version = "1.0" copyright = "Copyright (C) 2006 George F. Rice (I guess) but this version is screwed up by Walerian 'Cobra' Walawski" website = "http://drgeorge.org/stopwatch/" authors = ["George F. Rice","Walerian 'Cobra' Walawski (LOL, don't sue me plx)"] icon = "icon.png" license = "gpl.txt" """ -------------------------------------------------------------------------------------- gStopwatch -------------------------------------------------------------------------------------- I don't have time to write anything sensible here... I've needed app. like one by George F. Rice but a way more simple... So I've screwed up George's code. This version probably won't make your PC explode... But I don't guarantee that ;-) Also, I have no time to list changes; see changes.jpg :-D -------------------------------------------------------------------------------------- Stopwatch, a multi-lap timing application for GTK+ compatible devices Copyright (C) 2006 George F. Rice This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ import time class stopwatch: """ Implements a timer with multiple named lap timers. A newly created timer is NOT running. Use start() and stop() to begin/end. Check boolean '.running'. A lap timer is created on reference. """ def __init__(self, name = "stopwatch"): self.name = name self.startTime = time.time() self.elapsedTime = 0.0 self.running = False self.lap = {} def start(self): """ Start or restart the timer. Note that while the timer is running, only the getElapsedTime() method is accurate for determining elapsed time. """ if not self.running: self.startTime = time.time() self.running = True def stop(self): """ Stop the timer and update the elapsedTime attribute. """ if self.running: self.elapsedTime += time.time() - self.startTime self.running = False def getElapsedTime(self): """ Returns the elapsed time as a float in seconds, regardless of the state of the timer. """ if self.running: return self.elapsedTime + (time.time() - self.startTime) else: return self.elapsedTime def stopLapTimer(self, lap = "lap timer"): """ Set (or reset) the named (or default) lap timer to the current elapsed time. The lap time is returned. """ self.lap[lap] = self.getElapsedTime() return self.lap[lap] def getLapTime(self, lap = "lap timer"): """ Return the named (or default) lap time. If it doesn't exist, it is created as the current elapsed time. """ try: return self.lap[lap] except: self.lap[lap] = self.getElapsedTime() return self.lap[lap] def getFormattedTime(self, lap = None): """ Return specified lap time (or elapsed time if omitted) formatted as HH:MM:SS.ds """ if lap == None: _et = self.getElapsedTime() else: _et = self.getLapTime(lap) _et += 0.005 # round to nearest hundredth _hh = int(_et / 3600) _et -= (_hh * 3600) _mm = int(_et / 60) _et -= (_mm * 60) _ss = int(_et) _et -= _ss _ds = int(_et * 100) return "%.2d:%.2d:%.2d.%.2d" % (_hh, _mm, _ss, _ds) import gobject import gtk import pango import sys import string class gtkStopwatch: """ Implement a stopwatch GUI for generic GTK+ systems """ def __init__(self): # Set the important instance attributes. self.gtimer = None # timer object used to drive the stopwatch updates self.refreshRate = 30 # frequency by which the display is updated (msec) self.filename = None # holds the currently open filename self.dirty = False # True of self.sw doesn't match self.filename self.sw = stopwatch() # model of a stopwatch, q.v. # Create the main application window self.app = gtk.Window() self.app.set_size_request(480,70) self.app.set_resizable(False) self.app.set_icon_from_file(sys.path[0]+"/"+icon) self.app.set_title(title) self.app.connect("delete_event", self.fileExit) # Create the main layout manager (a vertical box) self._vbox = gtk.VBox(True, 0) self.app.add(self._vbox) # Create top row - start/stop and reset buttons, and stopwatch display # Pango is used to create the giant 50 point stopwatch display self._pango = pango.AttrList() self._pango.insert(pango.AttrSize(60000,0,12)) self._time = gtk.Label("00:00:00.00") self._time.set_alignment(1,0) self._time.set_attributes(self._pango) self._bStart = gtk.Button("Start") self._bReset = gtk.Button("Reset") self._bAbout = gtk.Button("About") self._bStart.connect("clicked", self.toolsToggle, None) self._bReset.connect("clicked", self.toolsReset, None) self._bAbout.connect("clicked", self.helpAbout, None) self._ebox = gtk.HBox(False, 0) self._ebox2 = gtk.VBox(False, 0) self._vbox.pack_start(self._ebox, False, False, 0) self._ebox.pack_start(self._time, False, False, 0) self._ebox.pack_start(self._ebox2, False, False, 0) self._ebox2.pack_start(self._bStart, True, False, 0) self._ebox2.pack_start(self._bReset, True, False, 0) self._ebox2.pack_start(self._bAbout, True, False, 0) self._table = gtk.Table(6, 5, True) self.lapLabel = {} # given lap timer display widget, return default lap timer label self.lapTimers = [] # list of the lap timer widgets (name / value pairs) # Create the lap timers. for y in range(9): for x in [0,2,4]: lapDefaultName = "Lap %d" % (y + [1, 10, 19][x/2], ) self.sw.getLapTime(lapDefaultName) # creates the lap timer in the model # The label is a text view, so that it can be easily renamed by the user. _lLapName = gtk.TextView() _lLapName.get_buffer().set_text(lapDefaultName) _lLapName.set_wrap_mode(gtk.WRAP_NONE) _lLapName.set_justification(gtk.JUSTIFY_RIGHT) _lLapName.set_pixels_above_lines(5) _lLapName.set_accepts_tab(False) self._table.attach(_lLapName, x,x+1,y,y+1) _lLapName.show() # The lap time is a button; clicking the button records the lap time. _bLapValue = gtk.Button("") self._table.attach(_bLapValue, x+1,x+2,y,y+1) _bLapValue.show() _bLapValue.connect("clicked", self.recordLap, None) self.lapLabel[_bLapValue] = lapDefaultName self.lapTimers.append((_lLapName, _bLapValue, lapDefaultName)) # Pack the applications elements and show them. self._time.show() self._bStart.show() self._bReset.show() self._bAbout.show() self._ebox.show() self._ebox2.show() self._table.show() self._vbox.show() self.app.show() def refreshTime(self): """ Update the time on the display. This is normalled called from a gobject timer, but can be called manually when needed. """ self._time.set_text(self.sw.getFormattedTime()) return True def recordLap(self, widget, data=None): """ Record and display a lap time. """ lapName = self.lapLabel[widget] self.sw.stopLapTimer(lapName) widget.set_label(self.sw.getFormattedTime(lapName)) self.dirty = True return True def fileNew(self, widget=None, data=None): """ Discard all current data, and create a new stopwatch. """ self.dirty = False self.setFilename(None) self.toolsReset() self.sw = stopwatch() # Reset the labels and clear any lap times previously recorded for _lLapName, _bLapValue, defaultLapName in self.lapTimers: _bLapValue.set_label("") _lLapName.get_buffer().set_text(defaultLapName) self.sw.getLapTime(defaultLapName) # creates the lap timer in the model def fileExit(self, widget=None, data=None): """ Terminate this application. If data is dirty, offer user chance to save data or to cancel this operation. """ gtk.main_quit() return True def editCut(self, widget=None, data=None): """ Cut the selected lap timer label to the default clipboard. """ w = self.app.get_focus() if isinstance(w, gtk.TextView): w.get_buffer().cut_clipboard(gtk.clipboard_get() , w.get_editable()) return True def editCopy(self, widget=None, data=None): """ Copy the selected lap timer label or lap time to the default clipboard. """ w = self.app.get_focus() if isinstance(w, gtk.TextView): w.get_buffer().copy_clipboard(gtk.clipboard_get()) elif isinstance(w, gtk.Button): gtk.clipboard_get().set_text(w.get_label()) return True def editCopyTime(self, widget=None, data=None): """ Copy the main timer value to the default clipboard. """ gtk.clipboard_get().set_text(self._time.get_text()) return True def editPaste(self, widget=None, data=None): """ Paste the contents of the default clipboard to the selected lap timer label. """ w = self.app.get_focus() if isinstance(w, gtk.TextView): w.get_buffer().paste_clipboard(gtk.clipboard_get(), None, w.get_editable()) return True def setRefreshRate(self, rate): """ Sets rate at which stopwatch time is updated. If stopwatch is not running, display will still be updated once. """ if self.sw.running: if self.refreshRate: try: gobject.source_remove(self.gtimer) except: pass if rate: self.gtimer = gobject.timeout_add(rate, self.refreshTime) else: self.refreshTime() self.refreshRate = rate def viewFast(self, widget=None, data=None): """ Set the refresh rate to about what the human eye can discern. It looks cool, but isn't really necessary and burns extra cycles. """ self.setRefreshRate(20) return True def viewSlow(self, widget=None, data=None): """ Set the refresh rate to tenths of a second, a good compromise between impressive updating and CPU utilization. """ self.setRefreshRate(100) return True def viewOff(self, widget=None, data=None): """ Disable updating of the timer display. The timer continues to run internally, and is refreshed each time this is called. """ self.setRefreshRate(0) self.refreshTime() return True def toolsToggle(self, widget, data=None): """ If the stopwatch is running, stop it. Otherwise, (re)start it. """ if self.sw.running: self.toolsStop(widget) else: self.toolsStart(widget) def toolsStart(self, widget=None, data=None): """ If not running, start the stopwatch. """ self.dirty = True self.sw.start() if self.refreshRate: self.gtimer = gobject.timeout_add(self.refreshRate, self.refreshTime) self._bStart.set_label("Pause") def toolsStop(self, widget=None, data=None): """ If running, stop the stopwatch. """ if self.sw.running: try: gobject.source_remove(self.gtimer) except: pass self.dirty = True self.sw.stop() self._time.set_text(self.sw.getFormattedTime()) self._bStart.set_label("Start") def toolsReset(self, widget=None, data=None): """ Reset the stopwatch, preserving the lap names. To also clear lap timer names, use fileNew instead. """ self.dirty = True self.toolsStop(widget) self.sw.elapsedTime = 0.0 self.refreshTime() for _lLapName, _bLapValue, lapDefaultName in self.lapTimers: _bLapValue.set_label("") def helpAbout(self, widget=None, data=None): """ Show the Help->About dialog box. """ dialog = gtk.AboutDialog() dialog.set_name(title) dialog.set_version(version) dialog.set_copyright(copyright) dialog.set_website(website) try: dialog.set_logo(gtk.gdk.pixbuf_new_from_file(sys.path[0]+"/"+icon)) except: pass try: f = open(license) l = string.join(f.readlines(), '\n') dialog.set_license(l) except: pass response = dialog.run() dialog.destroy() def main(self): """ The main program is called to start the user interface. """ gtk.main() if __name__ == "__main__": gtksw = gtkStopwatch() gtksw.main()