def connect_current_combo(client, prop, widget): """ Connect widget.currentIndexChanged and client.prop client.prop should be a callback property """ def _push_combo(value): # NOTE: we can't use findData here because if the data is not a # string, PySide will crash try: idx = _find_combo_data(widget, value) except ValueError: if value is None: idx = -1 else: raise widget.setCurrentIndex(idx) def _pull_combo(idx): if idx == -1: setattr(client, prop, None) else: setattr(client, prop, widget.itemData(idx)) add_callback(client, prop, _push_combo) widget.currentIndexChanged.connect(_pull_combo)
def add_tool(self, tool): if isinstance(tool, DropdownTool) and len(tool.subtools) > 0: menu = QtWidgets.QMenu(self) for t in tool.subtools: action = self._make_action(t) menu.addAction(action) elif len(tool.menu_actions()) > 0: menu = QtWidgets.QMenu(self) for ma in tool.menu_actions(): ma.setParent(self) menu.addAction(ma) else: menu = None action = self._make_action(tool, menu=menu) self.addAction(action) self.actions[tool.tool_id] = action # Bind tool visibility to tool.enabled def toggle(state): action.setVisible(state) action.setEnabled(state) add_callback(tool, 'enabled', toggle) self.tools[tool.tool_id] = tool return action
def connect_float_edit(client, prop, widget): """ Connect widget.setText and client.prop Also pretty-print the number client.prop should be a callback property """ v = QtGui.QDoubleValidator(None) v.setDecimals(4) widget.setValidator(v) def update_prop(): val = widget.text() try: setattr(client, prop, float(val)) except ValueError: setattr(client, prop, 0) def update_widget(val): if val is None: val = 0. widget.setText(pretty_number(val)) add_callback(client, prop, update_widget) widget.editingFinished.connect(update_prop) update_widget(getattr(client, prop))
def _connect(self): ui = self.ui ui.monochrome.toggled.connect(self._update_rgb_console) ui.rgb_options.colors_changed.connect(self.update_window_title) # sync client and widget slices ui.slice.slice_changed.connect( lambda: setattr(self, 'slice', self.ui.slice.slice)) update_ui_slice = lambda val: setattr(ui.slice, 'slice', val) add_callback(self.client, 'slice', update_ui_slice) add_callback(self.client, 'display_data', self.ui.slice.set_data) # sync window title to data/attribute add_callback(self.client, 'display_data', nonpartial(self._display_data_changed)) add_callback(self.client, 'display_attribute', nonpartial(self._display_attribute_changed)) add_callback(self.client, 'display_aspect', nonpartial(self.client._update_aspect)) # sync data/attribute combos with client properties connect_current_combo(self.client, 'display_data', self.ui.displayDataCombo) connect_current_combo(self.client, 'display_attribute', self.ui.attributeComboBox) connect_current_combo(self.client, 'display_aspect', self.ui.aspectCombo)
def _mouse_modes(self): axes = self.client.axes def apply_mode(mode): for roi_mode in roi_modes: if roi_mode != mode: roi_mode._roi_tool.reset() self.apply_roi(mode.roi()) rect = RectangleMode(axes, roi_callback=apply_mode) circ = CircleMode(axes, roi_callback=apply_mode) poly = PolyMode(axes, roi_callback=apply_mode) roi_modes = [rect, circ, poly] contrast = ContrastMode(axes, move_callback=self._set_norm) self._contrast = contrast # Get modes from tools tool_modes = [] for tool in self._tools: tool_modes += tool._get_modes(axes) add_callback(self.client, 'display_data', tool._display_data_hook) return [rect, circ, poly, contrast] + tool_modes
def _setup_grip(self): def _set_client_from_grip(value): """Update client.slice given grip value""" if not self.main.enabled: return slc = list(self.client.slice) # client.slice stored in pixel coords value = Extractor.world2pixel(self.data, self.profile_axis, value) slc[self.profile_axis] = value # prevent callback bouncing. Fixes #298 with ignore_callback(self.grip, 'value'): self.client.slice = tuple(slc) def _set_grip_from_client(slc): """Update grip.value given client.slice""" if not self.main.enabled: return # grip.value is stored in world coordinates val = slc[self.profile_axis] val = Extractor.pixel2world(self.data, self.profile_axis, val) # If pix2world not monotonic, this can trigger infinite recursion. # Avoid by disabling callback loop # XXX better to specifically ignore _set_client_from_grip with ignore_callback(self.client, 'slice'): self.grip.value = val self.grip = self.main.profile.new_value_grip() add_callback(self.client, 'slice', _set_grip_from_client) add_callback(self.grip, 'value', _set_client_from_grip)
def connect_bool_button(client, prop, widget): """ Connect widget.setChecked and client.prop client.prop should be a callback property """ add_callback(client, prop, widget.setChecked) widget.toggled.connect(partial(setattr, client, prop))
def __init__(self, viewer, **kwargs): super(SpectrumExtractorMode, self).__init__(viewer, **kwargs) self._roi_tool = qt_roi.QtRectangularROI(self._axes) # default self._tool = SpectrumTool(self.viewer, self) self._release_callback = self._tool._update_profile self._move_callback = self._tool._move_profile self._roi_callback = None add_callback(viewer.client, 'display_data', self._display_data_hook)
def connect_int_spin(client, prop, widget): """ Connect client.prop to widget.valueChanged client.prop should be a callback property """ add_callback(client, prop, widget.setValue) widget.valueChanged.connect(partial(setattr, client, prop))
def __init__(self, grip, **kwargs): self.grip = grip add_callback(grip, 'range', self._update) ax = grip.viewer.axes trans = blended_transform_factory(ax.transData, ax.transAxes) kwargs.setdefault('lw', 2) kwargs.setdefault('alpha', 0.5) kwargs.setdefault('c', '#ffb304') self._line, = ax.plot(self.x, self.y, transform=trans, **kwargs)
def _mouse_modes(self): modes = [] modes.append(("Rectangle", get_icon("glue_square"), lambda tf: self._set_roi_mode("rectangle", tf))) modes.append(("Circle", get_icon("glue_circle"), lambda tf: self._set_roi_mode("circle", tf))) modes.append(("Polygon", get_icon("glue_lasso"), lambda tf: self._set_roi_mode("polygon", tf))) for tool in self._tools: modes += tool._get_modes(self.canvas) add_callback(self.client, "display_data", tool._display_data_hook) return modes
def _mouse_modes(self): modes = [] modes.append(("Rectangle", get_icon('glue_square'), lambda tf: self._set_roi_mode('rectangle', tf))) modes.append(("Circle", get_icon('glue_circle'), lambda tf: self._set_roi_mode('circle', tf))) modes.append(("Polygon", get_icon('glue_lasso'), lambda tf: self._set_roi_mode('polygon', tf))) for tool in self._tools: modes += tool._get_modes(self.viewer) add_callback(self.client, 'display_data', tool._display_data_hook) return modes
def new_value_grip(self, callback=None): """ Create and return new ValueGrip :param callback: A callback function to be invoked whenever the grip.value property changes """ result = self.value_cls(self) result.value = self._center[0] if callback is not None: add_callback(result, 'value', callback) self.grips.append(result) self.active_grip = result return result
def _connect(self): add_callback(self.viewer_state, 'x_att', self.reset) add_callback(self.viewer_state, 'y_att', self.reset) def _on_tab_change(index): for i, ctx in enumerate(self._contexts): ctx.set_enabled(i == index) if i == index: self.profile.active_grip = ctx.grip self._tabs.currentChanged.connect(_on_tab_change) _on_tab_change(self._tabs.currentIndex()) self.widget.subset_dropped.connect(self._extract_subset_profile)
def _connect(self): add_callback(self.client, 'slice', self._check_invalidate, echo_old=True) def _on_tab_change(index): for i, ctx in enumerate(self._contexts): ctx.set_enabled(i == index) if i == index: self.profile.active_grip = ctx.grip self._tabs.currentChanged.connect(_on_tab_change) _on_tab_change(self._tabs.currentIndex()) self.widget.subset_dropped.connect(self._extract_subset_profile)
def add_mode(self, mode): parent = QtWidgets.QToolBar.parent(self) def toggle(): self._custom_mode(mode) def enable(): # turn on if not if self._active != mode.mode_id: self._custom_mode(mode) action = QtWidgets.QAction(mode.icon, mode.action_text, parent) action.triggered.connect(nonpartial(toggle)) parent.addAction(action) self.__signals.extend([toggle, enable]) if mode.shortcut is not None: action.setShortcut(mode.shortcut) action.setShortcutContext(Qt.WidgetShortcut) action.setToolTip(mode.tool_tip) action.setCheckable(True) self.buttons[mode.mode_id] = action menu_actions = mode.menu_actions() if len(menu_actions) > 0: menu = QtWidgets.QMenu(self) for ma in mode.menu_actions(): ma.setParent(self) menu.addAction(ma) action.setMenu(menu) menu.triggered.connect(nonpartial(enable)) self.addAction(action) # bind action status to mode.enabled def toggle(state): action.setVisible(state) action.setEnabled(state) add_callback(mode, 'enabled', toggle) return action
def new_range_grip(self, callback=None): """ Create and return new RangeGrip :param callback: A callback function to be invoked whenever the grip.range property changes """ result = self.range_cls(self) center = self._center[0] width = self._width result.range = center - width / 4, center + width / 4 if callback is not None: add_callback(result, 'range', callback) self.grips.append(result) self.active_grip = result return result
def add_mode(self, mode): parent = QtGui.QToolBar.parent(self) def toggle(): self._custom_mode(mode) def enable(): # turn on if not if self._active != mode.mode_id: self._custom_mode(mode) action = QtGui.QAction(mode.icon, mode.action_text, parent) action.triggered.connect(nonpartial(toggle)) parent.addAction(action) self.__signals.extend([toggle, enable]) if mode.shortcut is not None: action.setShortcut(mode.shortcut) action.setShortcutContext(Qt.WidgetShortcut) action.setToolTip(mode.tool_tip) action.setCheckable(True) self.buttons[mode.mode_id] = action menu_actions = mode.menu_actions() if len(menu_actions) > 0: menu = QtGui.QMenu(self) for ma in mode.menu_actions(): ma.setParent(self) menu.addAction(ma) action.setMenu(menu) menu.triggered.connect(nonpartial(enable)) self.addAction(action) # bind action status to mode.enabled def toggle(state): action.setVisible(state) action.setEnabled(state) add_callback(mode, 'enabled', toggle) return action
def _connect(self): ui = self.ui ui.monochrome.toggled.connect(self._update_rgb_console) ui.rgb_options.colors_changed.connect(self.update_window_title) # sync client and widget slices ui.slice.slice_changed.connect(lambda: setattr(self, 'slice', self.ui.slice.slice)) update_ui_slice = lambda val: setattr(ui.slice, 'slice', val) add_callback(self.client, 'slice', update_ui_slice) add_callback(self.client, 'display_data', self.ui.slice.set_data) # sync window title to data/attribute add_callback(self.client, 'display_data', nonpartial(self._display_data_changed)) add_callback(self.client, 'display_attribute', nonpartial(self._display_attribute_changed)) add_callback(self.client, 'display_aspect', nonpartial(self.client._update_aspect)) # sync data/attribute combos with client properties connect_current_combo(self.client, 'display_data', self.ui.displayDataCombo) connect_current_combo(self.client, 'display_attribute', self.ui.attributeComboBox) connect_current_combo(self.client, 'display_aspect', self.ui.aspectCombo)
def _setup_grip(self): def _set_state_from_grip(value): """Update state.slices given grip value""" if not self.main.enabled: return slc = list(self.viewer_state.slices) # state.slices stored in pixel coords value = Extractor.world2pixel( self.data, self.profile_axis, value) slc[self.profile_axis] = value # prevent callback bouncing. Fixes #298 self.viewer_state.slices = tuple(slc) def _set_grip_from_state(slc): """Update grip.value given state.slices""" if not self.main.enabled: return # grip.value is stored in world coordinates val = slc[self.profile_axis] if isinstance(val, AggregateSlice): val = val.center val = Extractor.pixel2world(self.data, self.profile_axis, val) # If pix2world not monotonic, this can trigger infinite recursion. # Avoid by disabling callback loop # XXX better to specifically ignore _set_state_from_grip with ignore_callback(self.grip, 'value'): self.grip.value = val self.grip = self.main.profile.new_value_grip() add_callback(self.viewer_state, 'slices', _set_grip_from_state) add_callback(self.grip, 'value', _set_state_from_grip)
def _setup_grip(self): def _set_client_from_grip(value): """Update client.slice given grip value""" if not self.main.enabled: return slc = list(self.client.slice) # client.slice stored in pixel coords value = Extractor.world2pixel( self.data, self.profile_axis, value) slc[self.profile_axis] = value # prevent callback bouncing. Fixes #298 with ignore_callback(self.grip, 'value'): self.client.slice = tuple(slc) def _set_grip_from_client(slc): """Update grip.value given client.slice""" if not self.main.enabled: return # grip.value is stored in world coordinates val = slc[self.profile_axis] val = Extractor.pixel2world(self.data, self.profile_axis, val) # If pix2world not monotonic, this can trigger infinite recursion. # Avoid by disabling callback loop # XXX better to specifically ignore _set_client_from_grip with ignore_callback(self.client, 'slice'): self.grip.value = val self.grip = self.main.profile.new_value_grip() add_callback(self.client, 'slice', _set_grip_from_client) add_callback(self.grip, 'value', _set_client_from_grip)
def _connect(self): add_callback(self, 'ylog', self._set_ylog) add_callback(self, 'height_attr', nonpartial(self._relayout)) add_callback(self, 'order_attr', nonpartial(self._relayout)) add_callback(self, 'parent_attr', nonpartial(self._relayout))
def _connect(self): add_callback(self, 'xlog', self._set_xlog) add_callback(self, 'ylog', self._set_ylog) add_callback(self, 'xflip', self._set_limits) add_callback(self, 'yflip', self._set_limits) add_callback(self, 'xmin', self._set_limits) add_callback(self, 'xmax', self._set_limits) add_callback(self, 'ymin', self._set_limits) add_callback(self, 'ymax', self._set_limits) add_callback(self, 'xatt', partial(self._set_xydata, 'x')) add_callback(self, 'yatt', partial(self._set_xydata, 'y')) add_callback(self, 'jitter', self._jitter) self.axes.figure.canvas.mpl_connect('draw_event', lambda x: self._pull_properties())
def add_tool(self, tool): parent = QtWidgets.QToolBar.parent(self) if isinstance(tool.icon, six.string_types): if os.path.exists(tool.icon): icon = QtGui.QIcon(tool.icon) else: icon = get_icon(tool.icon) else: icon = tool.icon action = QtWidgets.QAction(icon, tool.action_text, parent) def toggle(checked): if checked: self.active_tool = tool else: self.active_tool = None def trigger(checked): self.active_tool = tool parent.addAction(action) if isinstance(tool, CheckableTool): action.toggled.connect(toggle) else: action.triggered.connect(trigger) shortcut = None if tool.shortcut is not None: # Make sure that the keyboard shortcut is unique for m in self.tools.values(): if tool.shortcut == m.shortcut: warnings.warn("Tools '{0}' and '{1}' have the same shortcut " "('{2}'). Ignoring shortcut for " "'{1}'".format(m.tool_id, tool.tool_id, tool.shortcut)) break else: shortcut = tool.shortcut action.setShortcut(tool.shortcut) action.setShortcutContext(Qt.WidgetShortcut) if shortcut is None: action.setToolTip(tool.tool_tip) else: action.setToolTip(tool.tool_tip + " [shortcut: {0}]".format(shortcut)) action.setCheckable(isinstance(tool, CheckableTool)) self.actions[tool.tool_id] = action menu_actions = tool.menu_actions() if len(menu_actions) > 0: menu = QtWidgets.QMenu(self) for ma in tool.menu_actions(): ma.setParent(self) menu.addAction(ma) action.setMenu(menu) menu.triggered.connect(trigger) self.addAction(action) # Bind tool visibility to tool.enabled def toggle(state): action.setVisible(state) action.setEnabled(state) add_callback(tool, 'enabled', toggle) self.tools[tool.tool_id] = tool return action
def add_tool(self, tool): parent = QtWidgets.QToolBar.parent(self) if isinstance(tool.icon, six.string_types): if os.path.exists(tool.icon): icon = QtGui.QIcon(tool.icon) else: icon = get_icon(tool.icon) else: icon = tool.icon action = QtWidgets.QAction(icon, tool.action_text, parent) def toggle(checked): if checked: self.active_tool = tool else: self.active_tool = None def trigger(checked): self.active_tool = tool parent.addAction(action) if isinstance(tool, CheckableTool): action.toggled.connect(toggle) else: action.triggered.connect(trigger) shortcut = None if tool.shortcut is not None: # Make sure that the keyboard shortcut is unique for m in self.tools.values(): if tool.shortcut == m.shortcut: warnings.warn( "Tools '{0}' and '{1}' have the same shortcut " "('{2}'). Ignoring shortcut for " "'{1}'".format(m.tool_id, tool.tool_id, tool.shortcut)) break else: shortcut = tool.shortcut action.setShortcut(tool.shortcut) action.setShortcutContext(Qt.WidgetShortcut) if shortcut is None: action.setToolTip(tool.tool_tip) else: action.setToolTip(tool.tool_tip + " [shortcut: {0}]".format(shortcut)) action.setCheckable(isinstance(tool, CheckableTool)) self.actions[tool.tool_id] = action menu_actions = tool.menu_actions() if len(menu_actions) > 0: menu = QtWidgets.QMenu(self) for ma in tool.menu_actions(): ma.setParent(self) menu.addAction(ma) action.setMenu(menu) menu.triggered.connect(trigger) self.addAction(action) # Bind tool visibility to tool.enabled def toggle(state): action.setVisible(state) action.setEnabled(state) add_callback(tool, 'enabled', toggle) self.tools[tool.tool_id] = tool return action