Skip to content

Commit 58b5d7e

Browse files
committed
Fix handling of empty selection in the 2D plot snip
2D plot snips allow the user to select a region and zoom the plot to that region -- Sometimes, when the user just clicks on the snip, the system interprets this as a selection and the snip attempts to zoom to an empty region. Empty regions have +nan.0 values, and the code fails with an exception when it attempts to covert the +nan.0 to an exact number.
1 parent c9f164a commit 58b5d7e

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

plot-gui-lib/plot/private/gui/snip2d.rkt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,14 @@
107107
(define (zoom-or-unzoom)
108108
(cond [dragging?
109109
(set! dragging? #f)
110-
(define new-rect (area-bounds->plot-bounds (get-new-area-bounds-rect)))
111-
(cond [(and (rect-rational? new-rect) (not (rect-zero-area? new-rect)))
110+
(define new-rect
111+
(let ([bounds (get-new-area-bounds-rect)])
112+
;; BOUNDS might be +nan.0 for an empty selection
113+
(and (rect-rational? bounds)
114+
(area-bounds->plot-bounds bounds))))
115+
(cond [(and new-rect
116+
(rect-rational? new-rect)
117+
(not (rect-zero-area? new-rect)))
112118
#;(printf "~a: new-plot-bounds-rect = ~v~n"
113119
(current-milliseconds) new-rect)
114120
(set! plot-bounds-rects (cons plot-bounds-rect plot-bounds-rects))
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#lang racket
2+
(require plot racket/gui/base racket/draw rackunit)
3+
4+
;; 2D interactive plots would occasionally thrown an exception if the user
5+
;; clicked on the plot. This was because the system would interpret it as a
6+
;; drag-select operation which started and finished at the same place,
7+
;; resulting in an empty selection -- empty selections are represented using
8+
;; +nan.0, which cannot be converted to an exact number.
9+
;;
10+
;; In this test we simulate an empty selection using mouse events sent
11+
;; directly to the snips `on-event` method.
12+
13+
(define empty-selection-zoom
14+
(test-suite
15+
"empty-selection-zoom"
16+
(test-case "empty-selection-zoom"
17+
18+
;; Scaffolding, construct a pasteboard to hold our plot snip
19+
(define tl (new frame% [label "hello"] [width 800] [height 600]))
20+
(define pb [new pasteboard%])
21+
(define editor (new editor-canvas% [parent tl] [editor pb]))
22+
23+
;; Construct the plot snip and add it to the pasteboard so it has an
24+
;; administrator.
25+
(define snip (plot-snip (function sin -3 3)))
26+
(send pb insert snip)
27+
28+
;; Show the frame -- this is not strictly needed, but will ensure that
29+
;; all widgets have their proper dimensions set and mouse events will be
30+
;; "interpreted" according to correct snip positions.
31+
(send tl show #t)
32+
33+
;; Construct a dummy DC and the left-click, drag, left-release events
34+
;; which will simulate the drag-selection on the snip. Note that the
35+
;; start and end events have the same X, Y coordinates, which will result
36+
;; in an empty rectangle being selected.
37+
(define dc (new record-dc% [width 800] [height 600]))
38+
(define click (new mouse-event% [event-type 'left-down] [x 10] [y 10]))
39+
(define drag (new mouse-event% [event-type 'motion] [left-down #t] [x 11] [y 11]))
40+
(define unclick (new mouse-event% [event-type 'left-up] [x 10] [y 10]))
41+
42+
;; Send the snip the events -- the snip will think the user is selecting
43+
;; a region on the plot.
44+
(send snip on-event dc 0 0 0 0 click)
45+
(send snip on-event dc 0 0 0 0 drag)
46+
(after
47+
(check-not-exn
48+
;; zoom is triggered when the user releases the mouse event -- this
49+
;; used to throw an exception as it tried to operate on an empty
50+
;; rectangle, containing +nan.0 numbers.
51+
(lambda () (send snip on-event dc 0 0 0 0 unclick)))
52+
(send tl show #f)))))
53+
54+
(module+ test
55+
(require rackunit/text-ui)
56+
(run-tests empty-selection-zoom))

0 commit comments

Comments
 (0)