summaryrefslogtreecommitdiff
path: root/timer-applet/src/timerapplet/ui/DurationChooser.py
diff options
context:
space:
mode:
Diffstat (limited to 'timer-applet/src/timerapplet/ui/DurationChooser.py')
-rw-r--r--timer-applet/src/timerapplet/ui/DurationChooser.py166
1 files changed, 166 insertions, 0 deletions
diff --git a/timer-applet/src/timerapplet/ui/DurationChooser.py b/timer-applet/src/timerapplet/ui/DurationChooser.py
new file mode 100644
index 00000000..77d0a7ed
--- /dev/null
+++ b/timer-applet/src/timerapplet/ui/DurationChooser.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2008 Jimmy Do <[email protected]>
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from gettext import gettext as _
+import math
+import gobject
+import gtk
+
+class DurationChooser(gtk.VBox):
+ __gsignals__ = {'duration-changed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())}
+ MAX_HOURS = 48
+ MAX_MINUTES = 999
+ MAX_SECONDS = 999
+
+ def __init__(self, size_group):
+ gtk.VBox.__init__(self, False, 6)
+
+ self._hours_spin = self._add_row(_('_Hours:'),
+ size_group,
+ DurationChooser.MAX_HOURS)
+ self._minutes_spin = self._add_row(_('_Minutes:'),
+ size_group,
+ DurationChooser.MAX_MINUTES)
+ self._seconds_spin = self._add_row(_('_Seconds:'),
+ size_group,
+ DurationChooser.MAX_SECONDS)
+
+ def get_duration(self):
+ """Return numerical representations of the values in the spinbuttons.
+
+ This method does not just call get_value_as_int() on each spinbutton because
+ get_value_as_int() does not return the most up-to-date value if the user is
+ in the middle of editing the value in a spinbutton. Instead, it actually
+ returns the value previously "confirmed" for the spinbutton (for example,
+ by moving focus to another widget).
+
+ Example: User starts with all spinboxes set to 0. He types 5 in 'Minutes' and
+ immediately uses the keyboard to activate the 'Save as Preset' button. Because
+ the user never moved focus out of the spinbutton, get_value_as_int() will report
+ the previous value of 0, and the saved preset will not have the expected duration
+ of 5 minutes.
+
+ If a particular spinbutton is empty or contains a non-float value, then this method
+ will report its value as zero.
+
+ Returns a tuple in this format: (hours, minutes, seconds)
+
+ """
+ hours_str = self._hours_spin.props.text
+ minutes_str = self._minutes_spin.props.text
+ seconds_str = self._seconds_spin.props.text
+ hours = 0
+ minutes = 0
+ seconds = 0
+
+ try:
+ hours = float(hours_str)
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+
+ try:
+ minutes = float(minutes_str)
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+
+ try:
+ seconds = float(seconds_str)
+ except TypeError:
+ pass
+ except ValueError:
+ pass
+
+ minutes_fraction = minutes - int(minutes)
+ hours_fraction = hours - int(hours)
+
+ # Distribute overflow from seconds to minutes to hours.
+ if seconds > 59:
+ minutes = math.floor(seconds / 60)
+ seconds = seconds % 60
+ if minutes > 59:
+ hours = math.floor(minutes / 60)
+ minutes = minutes % 60
+ if hours > DurationChooser.MAX_HOURS:
+ hours = DurationChooser.MAX_HOURS
+
+ # Distribute fractions.
+ if hours_fraction > 0:
+ minutes = int(hours_fraction * 60)
+ if minutes_fraction > 0:
+ seconds = int(minutes_fraction * 60)
+
+ return (int(hours), int(minutes), int(seconds))
+
+ def set_duration(self, hours, minutes, seconds):
+ self._hours_spin.set_value(hours)
+ self._minutes_spin.set_value(minutes)
+ self._seconds_spin.set_value(seconds)
+
+ def normalize_fields(self):
+ (hours, minutes, seconds) = self.get_duration()
+ self._hours_spin.set_value(hours)
+ self._minutes_spin.set_value(minutes)
+ self._seconds_spin.set_value(seconds)
+
+ def clear(self):
+ self._hours_spin.set_value(0)
+ self._minutes_spin.set_value(0)
+ self._seconds_spin.set_value(0)
+
+ def focus_hours(self):
+ self._hours_spin.grab_focus()
+
+ def _add_row(self, row_label_str, size_group, max_spin_val):
+ row_hbox = gtk.HBox(False, 6)
+
+ label = gtk.Label(row_label_str)
+ label.set_property('xalign', 0.0)
+ label.set_property('use-underline', True)
+ size_group.add_widget(label)
+
+ spin_adj = gtk.Adjustment(0, 0, max_spin_val, 1, 1, 0)
+ spin_button = gtk.SpinButton(spin_adj, 1.0, 0)
+ spin_button.props.activates_default = True
+ spin_button.props.numeric = False
+ spin_button.props.update_policy = gtk.UPDATE_IF_VALID
+
+ label.set_mnemonic_widget(spin_button)
+
+ row_hbox.pack_start(label, False, False, 0)
+ row_hbox.pack_start(spin_button, True, True, 0)
+ self.pack_start(row_hbox, False, False, 0)
+
+ spin_button.connect('changed', self._on_spin_button_val_changed)
+ spin_button.connect('focus-out-event', self._on_spin_button_focus_out)
+ spin_button.connect('activate', self._on_spin_button_activate)
+
+ label.show()
+ spin_button.show()
+ row_hbox.show()
+ return spin_button
+
+ def _on_spin_button_val_changed(self, spin_button):
+ self.emit('duration-changed')
+
+ def _on_spin_button_focus_out(self, spin_button, event):
+ self.normalize_fields()
+
+ def _on_spin_button_activate(self, entry):
+ self.normalize_fields()