Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Silbe <sascha-pgp@silbe.org>2013-02-18 19:11:09 (GMT)
committer Sascha Silbe <sascha-pgp@silbe.org>2013-02-18 19:11:09 (GMT)
commit8e60f768cf90f5addfda78b876bd87ed2769b811 (patch)
tree1a369bd3a9dcd38f49dd692c4d147a6f7f4420a4
parentb94db04994456072d28bd5cc34a5dc0ff99570e0 (diff)
Add support for showing options that were inactive during start-up
SANE options can be interdependent, e.g. the JPEG compression ratio (integer) may only be available if JPEG compression (bool) is enabled. Since these values can change at run-time in response to user actions, we need to cope with options becoming active or inactive. Previously we skipped inactive options and copied the current value of the (active) options to the widget right away when adding it. Since we now need to query the value of each option after each user action (since the activeness of the option might have changed and the previous value might not have been known), we do a single "update" run on start-up after all widgets have been added, rather than having two different places (per widget) where the value is set and special-casing the inactive options when adding the widgets.
-rw-r--r--scan.py124
1 files changed, 87 insertions, 37 deletions
diff --git a/scan.py b/scan.py
index 1bee370..a887f58 100644
--- a/scan.py
+++ b/scan.py
@@ -55,6 +55,9 @@ class SettingsToolbar(gtk.ToolPalette):
def __init__(self):
gtk.ToolPalette.__init__(self)
self._scanner = None
+ self._widget_by_option = {}
+ self._toolitem_by_option = {}
+ self._updating = False
def modify_bg(self, state, color):
gtk.ToolPalette.modify_bg(self, state, color)
@@ -68,6 +71,8 @@ class SettingsToolbar(gtk.ToolPalette):
self._add_options()
def _clear(self):
+ self._widget_by_option = {}
+ self._toolitem_by_option = {}
for widget in list(self):
self.remove(widget)
@@ -113,25 +118,17 @@ class SettingsToolbar(gtk.ToolPalette):
for option_name in group:
py_name = name_map[option_name]
option = self._scanner[py_name]
- if not option.is_active():
- # FIXME: check SANE docs what inactive is used for
- # I have a feeling we might need to cope with this
- # changing after changing other settings like the mode
- # (color/gray/...)
- logging.warning('skipping inactive option %r', option_name)
- continue
- value = getattr(self._scanner, py_name)
if (option.type == sane.TYPE_BOOL):
- widget = self._add_bool(option, value)
+ widget = self._add_bool(option)
elif (option.type == sane.TYPE_INT):
- widget = self._add_integer(option, value)
+ widget = self._add_integer(option)
elif (option.type == sane.TYPE_FIXED):
- widget = self._add_fixed_point(option, value)
+ widget = self._add_fixed_point(option)
elif (option.type == sane.TYPE_STRING):
- widget = self._add_string(option, value)
+ widget = self._add_string(option)
elif (option.type == sane.TYPE_BUTTON):
- widget = self._add_action(option, value)
+ widget = self._add_action(option)
else:
logging.warning('Skipping setting %r of unknown type %r',
option_name, option.type)
@@ -142,7 +139,7 @@ class SettingsToolbar(gtk.ToolPalette):
' widget', option_name, option.type)
continue
- widget.set_sensitive(option.is_settable())
+ widget.show()
# FIXME: take translation from SANE
label = gtk.Label(_(option.title))
@@ -155,6 +152,7 @@ class SettingsToolbar(gtk.ToolPalette):
tool_item = gtk.ToolItem()
tool_item.add(hbox)
+ hbox.show()
# FIXME: take translation from SANE
tool_item.set_tooltip_text(_(option.desc))
# TODO: represent unit
@@ -162,8 +160,13 @@ class SettingsToolbar(gtk.ToolPalette):
tool_group.insert(tool_item, -1)
logging.debug('%r size request: %r', tool_group, tool_group.size_request())
- self.show_all()
+ self._widget_by_option[py_name] = widget
+ self._toolitem_by_option[py_name] = tool_item
+ self._update_state()
+ self.show()
+
+ def _update_size(self):
# HACK to work around GTK not calculating the size of
# ToolItemGroups (and thus this ToolPalette) correctly. See
# http://mail.gnome.org/archives/gtkmm-list/2011-September/msg00112.html
@@ -175,23 +178,22 @@ class SettingsToolbar(gtk.ToolPalette):
self.set_size_request(-1, tool_groups_height)
- def _add_bool(self, option, value):
+ def _add_bool(self, option):
button = gtk.CheckButton()
- button.set_active(value)
button.connect('toggled', lambda widget,
option=option: self._toggle_cb(widget, option))
return button
- def _add_integer(self, option, value):
+ def _add_integer(self, option):
if isinstance(option.constraint, tuple):
- return self._add_spinbutton(option, value)
+ return self._add_spinbutton(option)
elif isinstance(option.constraint, list):
- return self._add_combo(option, value)
- return self._add_spinbutton(option, value)
+ return self._add_combo(option)
+ return self._add_spinbutton(option)
- def _add_fixed_point(self, option, value):
+ def _add_fixed_point(self, option):
if isinstance(option.constraint, tuple):
- return self._add_spinbutton(option, value)
+ return self._add_spinbutton(option)
elif isinstance(option.constraint, list):
# TODO
return None
@@ -200,17 +202,17 @@ class SettingsToolbar(gtk.ToolPalette):
return None
@trace()
- def _add_string(self, option, value):
+ def _add_string(self, option):
if option.constraint:
- return self._add_combo(option, value)
+ return self._add_combo(option)
- return self._add_entry(option, value)
+ return self._add_entry(option)
- def _add_action(self, option, value):
+ def _add_action(self, option):
# TODO
return None
- def _add_spinbutton(self, option, value):
+ def _add_spinbutton(self, option):
if isinstance(option.constraint, tuple):
lower, upper, step = option.constraint
else:
@@ -220,17 +222,17 @@ class SettingsToolbar(gtk.ToolPalette):
# no quantization set => guess it
step = 1
- spin_adj = gtk.Adjustment(value, lower, upper, step, step*10, 0)
+ spin_adj = gtk.Adjustment(lower, lower, upper, step, step*10, 0)
spin = gtk.SpinButton(spin_adj, 0, 0)
spin.props.snap_to_ticks = True
spin.set_digits(self._calc_digits(step))
- if isinstance(value, float):
+ if option.type == sane.TYPE_INT:
spin.connect('value-changed', lambda widget, option=option:
- self._spin_float_changed_cb(widget, option))
+ self._spin_int_changed_cb(widget, option))
else:
spin.connect('value-changed', lambda widget, option=option:
- self._spin_int_changed_cb(widget, option))
+ self._spin_float_changed_cb(widget, option))
spin.set_numeric(True)
spin.show()
@@ -245,10 +247,9 @@ class SettingsToolbar(gtk.ToolPalette):
return digits
- def _add_entry(self, option, value):
+ def _add_entry(self, option):
# untested
entry = gtk.Entry()
- entry.set_text(value)
entry.connect('focus-out-event', lambda widget, option=option:
self._entry_changed_cb(widget, option))
entry.connect('activated', lambda widget, option=option:
@@ -256,38 +257,87 @@ class SettingsToolbar(gtk.ToolPalette):
return entry
@trace()
- def _add_combo(self, option, value):
+ def _add_combo(self, option):
box = ComboBox()
for combo_value in option.constraint:
# FIXME: take translation from SANE
box.append_item(combo_value, _(combo_value))
- new_idx = option.constraint.index(value)
- box.set_active(new_idx)
box.connect('changed', lambda widget, option=option:
self._combo_changed_cb(widget, option))
return box
@trace()
def _toggle_cb(self, button, option):
+ if self._updating:
+ return
new_value = button.get_active()
setattr(self._scanner, option.py_name, new_value)
+ self._update_state()
@trace()
def _entry_changed_cb(self, entry, option):
+ if self._updating:
+ return
setattr(self._scanner, option.py_name, entry.get_text())
+ self._update_state()
@trace()
def _combo_changed_cb(self, combo, option):
+ if self._updating:
+ return
setattr(self._scanner, option.py_name, combo.get_value())
+ self._update_state()
@trace()
def _spin_float_changed_cb(self, spin, option):
+ if self._updating:
+ return
setattr(self._scanner, option.py_name, spin.get_value())
+ self._update_state()
@trace()
def _spin_int_changed_cb(self, spin, option):
+ if self._updating:
+ return
setattr(self._scanner, option.py_name, int(spin.get_value()))
+ self._update_state()
+
+ def _update_state(self):
+ """(Re-)check SANE attributes after changes were made (or on start-up)
+
+ Some SANE options are interdependent, so we need to update
+ attributes after every change. E.g. the JPEG compression ratio
+ (integer) is only available if JPEG compression (bool) is
+ enabled. In addition, the current value is only available for
+ "active" options, so we can't set the values of widgets for
+ inactive options.
+ """
+ try:
+ self._updating = True
+ for py_option_name, widget in self._widget_by_option.items():
+ toolitem = self._toolitem_by_option[py_option_name]
+ option = self._scanner[py_option_name]
+ widget.set_sensitive(option.is_settable())
+ if not option.is_active():
+ toolitem.hide()
+ continue
+
+ value = getattr(self._scanner, py_option_name)
+ if isinstance(widget, gtk.CheckButton):
+ widget.set_active(value)
+ elif isinstance(widget, gtk.SpinButton):
+ widget.set_value(value)
+ elif isinstance(widget, gtk.Entry):
+ widget.set_text(value)
+ elif isinstance(widget, ComboBox):
+ new_idx = option.constraint.index(value)
+ widget.set_active(new_idx)
+ toolitem.show()
+
+ self._update_size()
+ finally:
+ self._updating = False
class ScanThread(threading.Thread):