Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slider in image contrast editor on python >=3.10 #76

Merged
merged 6 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ on:
- '**/*.md'
- '**/*.rst'
- '**/*.txt'
- 'hyperspy_gui_traitsui/_external/*.py'
schedule:
# run once a week
- cron: '16 13 * * 5'
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ jobs:
# correct version with setuptools_scm
run: |
git remote add upstream https://github.com/hyperspy/hyperspy_gui_traitsui.git
git fetch --prune --unshallow
git fetch upstream --tags

- uses: actions/setup-python@v5
Expand Down Expand Up @@ -76,12 +75,16 @@ jobs:
- name: Install HyperSpy (RELEASE_next_major)
if: contains( matrix.LABEL, 'RnM')
run: |
pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_major
# pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_major
# revert back when hyperspy 2.1 is released
pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_minor

- name: Install HyperSpy (RELEASE_next_patch)
if: contains( matrix.LABEL, 'RnP')
run: |
pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_patch
# pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_patch
# revert back when hyperspy 2.1 is released
pip install git+https://github.com/hyperspy/hyperspy.git@RELEASE_next_minor

- name: Install exSpy
if: ${{ ! contains( matrix.LABEL, 'minimum') }}
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

## v2.1 (UNRELEASED)

* Fix slider in image contrast editor on python >=3.10 ([#76](https://github.com/hyperspy/hyperspy_gui_traitsui/pull/76)).
* Fix getting version with editable installation ([#75](https://github.com/hyperspy/hyperspy_gui_traitsui/pull/75)).
* Add releasing guide and release script ([#75](https://github.com/hyperspy/hyperspy_gui_traitsui/pull/75)).
* Fix regression with editable installation ([#74](https://github.com/hyperspy/hyperspy_gui_traitsui/pull/74)).
Expand Down
211 changes: 211 additions & 0 deletions hyperspy_gui_traitsui/_external/bounds_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
# (C) Copyright 2004-2023 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!

# Use upstream version when https://github.com/enthought/traitsui/pull/2048
# is merged and release

from pyface.qt import QtGui, QtCore

from traits.api import Float, Any, Str, Union

from traitsui.editors.api import RangeEditor
try:
from traitsui.qt.editor import Editor
except:
Dismissed Show dismissed Hide dismissed
from traitsui.qt4.editor import Editor

Check warning on line 22 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L21-L22

Added lines #L21 - L22 were not covered by tests
from .range_slider import RangeSlider


class _BoundsEditor(Editor):

evaluate = Any()

min = Any()
max = Any()
low = Any()
high = Any()
format_str = Str()

def init(self, parent):
"""Finishes initializing the editor by creating the underlying toolkit
widget.
"""
factory = self.factory
if not factory.low_name:
self.low = factory.low

Check warning on line 42 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L42

Added line #L42 was not covered by tests

if not factory.high_name:
self.high = factory.high

Check warning on line 45 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L45

Added line #L45 was not covered by tests

self.max = factory.max
self.min = factory.min

self.format_str = factory.format_str

self.evaluate = factory.evaluate
self.sync_value(factory.evaluate_name, "evaluate", "from")

self.sync_value(factory.low_name, "low", "both")
self.sync_value(factory.high_name, "high", "both")

self.control = QtGui.QWidget()
panel = QtGui.QHBoxLayout(self.control)
panel.setContentsMargins(0, 0, 0, 0)

self._label_lo = QtGui.QLineEdit(self.format_str % self.low)
self._label_lo.editingFinished.connect(self.update_low_on_enter)
panel.addWidget(self._label_lo)

# The default size is a bit too big and probably doesn't need to grow.
sh = self._label_lo.sizeHint()
sh.setWidth(sh.width() // 2)
self._label_lo.setMaximumSize(sh)

self.control.slider = slider = RangeSlider(QtCore.Qt.Orientation.Horizontal)
slider.setTracking(factory.auto_set)
slider.setMinimum(0)
slider.setMaximum(10000)
slider.setPageStep(1000)
slider.setSingleStep(100)
slider.setLow(self._convert_to_slider(self.low))
slider.setHigh(self._convert_to_slider(self.high))

slider.sliderMoved.connect(self.update_object_on_scroll)
panel.addWidget(slider)

self._label_hi = QtGui.QLineEdit(self.format_str % self.high)
self._label_hi.editingFinished.connect(self.update_high_on_enter)
panel.addWidget(self._label_hi)

# The default size is a bit too big and probably doesn't need to grow.
sh = self._label_hi.sizeHint()
sh.setWidth(sh.width() // 2)
self._label_hi.setMaximumSize(sh)

self.set_tooltip(slider)
self.set_tooltip(self._label_lo)
self.set_tooltip(self._label_hi)

def update_low_on_enter(self):
try:
try:
low = eval(str(self._label_lo.text()).strip())

Check warning on line 99 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L97-L99

Added lines #L97 - L99 were not covered by tests
if self.evaluate is not None:
low = self.evaluate(low)
except Exception as ex:
low = self.low
self._label_lo.setText(self.format_str % self.low)

Check warning on line 104 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L101-L104

Added lines #L101 - L104 were not covered by tests

if not self.factory.is_float:
low = int(low)

Check warning on line 107 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L107

Added line #L107 was not covered by tests

if low > self.high:
low = self.high - self._step_size()
self._label_lo.setText(self.format_str % low)

Check warning on line 111 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L110-L111

Added lines #L110 - L111 were not covered by tests

self.control.slider.setLow(self._convert_to_slider(low))
self.low = low
except:
Dismissed Show dismissed Hide dismissed
Dismissed Show dismissed Hide dismissed
pass

Check warning on line 116 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L113-L116

Added lines #L113 - L116 were not covered by tests

def update_high_on_enter(self):
try:
try:
high = eval(str(self._label_hi.text()).strip())

Check warning on line 121 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L119-L121

Added lines #L119 - L121 were not covered by tests
if self.evaluate is not None:
high = self.evaluate(high)
except:
Dismissed Show dismissed Hide dismissed
high = self.high
self._label_hi.setText(self.format_str % self.high)

Check warning on line 126 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L123-L126

Added lines #L123 - L126 were not covered by tests

if not self.factory.is_float:
high = int(high)

Check warning on line 129 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L129

Added line #L129 was not covered by tests

if high < self.low:
high = self.low + self._step_size()
self._label_hi.setText(self.format_str % high)

Check warning on line 133 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L132-L133

Added lines #L132 - L133 were not covered by tests

self.control.slider.setHigh(self._convert_to_slider(high))
self.high = high
except:
Dismissed Show dismissed Hide dismissed
Dismissed Show dismissed Hide dismissed
pass

Check warning on line 138 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L135-L138

Added lines #L135 - L138 were not covered by tests

def update_object_on_scroll(self, pos):
low = self._convert_from_slider(self.control.slider.low())
high = self._convert_from_slider(self.control.slider.high())

Check warning on line 142 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L141-L142

Added lines #L141 - L142 were not covered by tests

if self.factory.is_float:
self.low = low
self.high = high

Check warning on line 146 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L145-L146

Added lines #L145 - L146 were not covered by tests
else:
self.low = int(low)
self.high = int(high)

Check warning on line 149 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L148-L149

Added lines #L148 - L149 were not covered by tests

# update the sliders to the int values or the sliders
# will jiggle
self.control.slider.setLow(self._convert_to_slider(low))
self.control.slider.setHigh(self._convert_to_slider(high))

Check warning on line 154 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L153-L154

Added lines #L153 - L154 were not covered by tests

def update_editor(self):
return

def _check_max_and_min(self):
# check if max & min have been defined:
if self.max is None:
self.max = self.high
if self.min is None:
self.min = self.low

def _step_size(self):
slider_delta = (
self.control.slider.maximum() - self.control.slider.minimum()
)
range_delta = self.max - self.min

return float(range_delta) / slider_delta

def _convert_from_slider(self, slider_val):
self._check_max_and_min()
return self.min + slider_val * self._step_size()

Check warning on line 176 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L175-L176

Added lines #L175 - L176 were not covered by tests

def _convert_to_slider(self, value):
self._check_max_and_min()
return (
self.control.slider.minimum()
+ (value - self.min) / self._step_size()
)

def _low_changed(self, low):
if self.control is None:
return
if self._label_lo is not None:
self._label_lo.setText(self.format_str % low)

self.control.slider.setLow(self._convert_to_slider(low))

def _high_changed(self, high):
if self.control is None:
return
if self._label_hi is not None:
self._label_hi.setText(self.format_str % high)

self.control.slider.setHigh(self._convert_to_slider(self.high))


class BoundsEditor(RangeEditor):

min = Union(None, Float)
max = Union(None, Float)

def _get_simple_editor_class(self):
return _BoundsEditor

def _get_custom_editor_class(self):
return _BoundsEditor

Check warning on line 211 in hyperspy_gui_traitsui/_external/bounds_editor.py

View check run for this annotation

Codecov / codecov/patch

hyperspy_gui_traitsui/_external/bounds_editor.py#L211

Added line #L211 was not covered by tests
Loading
Loading