diff options
Diffstat (limited to 'scan.py')
-rw-r--r-- | scan.py | 124 |
1 files changed, 87 insertions, 37 deletions
@@ -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): |