Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/scan.py
diff options
context:
space:
mode:
Diffstat (limited to 'scan.py')
-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):