diff --git a/CHANGES.txt b/CHANGES.txt index c0ffcb8d9..7715f0983 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -25,6 +25,7 @@ Fixes * Avoid a numpy crash when using a data source of a unicode array (PR#213). * PanTool with `restrict_to_data` selected works with empty data sources (PR#215). + * RangeSelection properly clips bounds when leaving selection area (PR#217). * Fix white gap between image border and image (PR#219). * Fix redraw color mapped image plot when color mapper updates (PR#221) * Fix behaviour of mappers when stretch_data trait is False (PR#227) diff --git a/chaco/tools/range_selection.py b/chaco/tools/range_selection.py index 538423730..3ad1e8a72 100644 --- a/chaco/tools/range_selection.py +++ b/chaco/tools/range_selection.py @@ -510,9 +510,16 @@ def selecting_mouse_leave(self, event): pos = self._get_axis_coord(event) if pos >= high: - selection_high = self.mapper.map_data(high) + # clip to the boundary appropriate for the mapper's orientation. + if self.mapper.sign == 1: + selection_high = self.mapper.map_data(high) + else: + selection_high = self.mapper.map_data(low) elif pos <= low: - selection_low = self.mapper.map_data(low) + if self.mapper.sign == 1: + selection_low = self.mapper.map_data(low) + else: + selection_low = self.mapper.map_data(high) self.selection = (selection_low, selection_high) event.window.set_pointer("arrow") diff --git a/chaco/tools/tests/range_selection_test_case.py b/chaco/tools/tests/range_selection_test_case.py new file mode 100644 index 000000000..c94fb54af --- /dev/null +++ b/chaco/tools/tests/range_selection_test_case.py @@ -0,0 +1,57 @@ +import unittest + +import numpy as np + +from chaco.array_plot_data import ArrayPlotData +from chaco.plot import Plot +from chaco.tools.range_selection import RangeSelection +from enable.testing import EnableTestAssistant + + +class RangeSelectionTestCase(EnableTestAssistant, unittest.TestCase): + + def test_selecting_mouse_leave_clipping(self): + # Regression test for #216. + plot_data = ArrayPlotData() + arr = np.arange(4.0) + plot_data.set_data("x", arr) + plot_data.set_data("y", arr) + + for origin in ('bottom left', 'top left', 'bottom right', 'top right'): + for orientation in ('h', 'v'): + for axis in ('index', 'value'): + plot = Plot( + plot_data, orientation=orientation, origin='top right' + ) + + renderer = plot.plot(('x', 'y'))[0] + renderer.bounds = [10, 20] + tool = RangeSelection( + renderer, left_button_selects=True, axis=axis, + ) + renderer.tools.append(tool) + + low_x, low_y = plot.position + high_x = low_x + renderer.bounds[0] - 1 + high_y = low_y + renderer.bounds[1] - 1 + + cx = 5 + cy = 5 + + bounds = ( + (low_x - 1, low_y), + (high_x + 1, low_y), + (low_x, low_y - 1), + (low_x, high_y + 1), + ) + for x, y in bounds: + self.mouse_down(tool, x=cx, y=cy) + self.mouse_leave(tool, x=x, y=y) + selection = tool.selection + self.assertTrue(selection[0] <= selection[1]) + self.mouse_up(tool, x=x, y=y) + + +if __name__ == '__main__': + import nose + nose.run()