diff --git a/collects/2htdp/private/world.rkt b/collects/2htdp/private/world.rkt index 162947c86a..b10b5f3ca6 100644 --- a/collects/2htdp/private/world.rkt +++ b/collects/2htdp/private/world.rkt @@ -50,23 +50,9 @@ (clock-mixin (class* object% (start-stop<%>) (inspect #f) - - (init-field - world0 ;; World - (name #f) ;; (U #f String) - (state #f) ;; Boolean - (register #f) ;; (U #f IP) - (check-with True) ;; Any -> Boolean - ) - - (init - (on-key K) ;; World KeyEvent -> World - (on-release K) ;; World KeyEvent -> World - (on-mouse K) ;; World Nat Nat MouseEvent -> World - (on-receive #f) ;; (U #f (World S-expression -> World)) - (on-draw #f) ;; (U #f (World -> Scene) (list (World -> Scene) Nat Nat)) - (stop-when False) ;; World -> Boolean - (record? #f)) ;; Boolean + (init-field world0) + (init-field name state register check-with on-key on-mouse) + (init on-release on-receive on-draw stop-when record?) ;; ----------------------------------------------------------------------- (field @@ -159,6 +145,29 @@ (create-frame) (show fst-scene))) + (define/private (deal-with-key %) + (if (not on-key) % + (class % + (super-new) + (define/override (on-char e) + (when live + (let ([e:str (key-event->parts e)]) + (if (string=? e:str "release") + (prelease (key-release->parts e)) + (pkey e:str)))))))) + + (define/private (deal-with-mouse %) + (if (not on-mouse) % + (class % + (super-new) + (define/override (on-event e) + (define-values (x y me) (mouse-event->parts e)) + (when live + (cond + [(and (<= 0 x width) (<= 0 y height)) (pmouse x y me)] + [(member me '("leave" "enter")) (pmouse x y me)] + [else (void)])))))) + ;; effect: create, show and set the-frame (define/pubment (create-frame) (define play-back:cust (make-custodian)) @@ -170,24 +179,9 @@ (label (if name (format "~a" name) "World")) (alignment '(center center)) (style '(no-resize-border metal)))) - (define editor-canvas - (new (class editor-canvas% - (super-new) - ;; deal with keyboard events - (define/override (on-char e) - (when live - (let ([e:str (key-event->parts e)]) - (if (string=? e:str "release") - (prelease (key-release->parts e)) - (pkey e:str))))) - ;; deal with mouse events if live and within range - (define/override (on-event e) - (define-values (x y me) (mouse-event->parts e)) - (when live - (cond - [(and (<= 0 x width) (<= 0 y height)) (pmouse x y me)] - [(member me '("leave" "enter")) (pmouse x y me)] - [else (void)])))) + + (define editor-canvas + (new (deal-with-key (deal-with-mouse editor-canvas%)) (parent frame) (editor visible) (stretchable-width #f) diff --git a/collects/2htdp/tests/jpr-bug.rkt b/collects/2htdp/tests/jpr-bug.rkt new file mode 100644 index 0000000000..7ef0599af8 --- /dev/null +++ b/collects/2htdp/tests/jpr-bug.rkt @@ -0,0 +1,26 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-advanced-reader.ss" "lang")((modname jpr-bug) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #t #t none #f ()))) + +;; This program demonstrated that the idea of using default handlers (K) for +;; absent mouse and key handlers was a horrible idea. The balls on his cannvas +;; just started jumping around when the mouse moved in. + +(require 2htdp/universe) +(require 2htdp/image) + + +(define (animation2) + (local [(define SIZE 300) + (define SCENE (rectangle SIZE SIZE 'outline "black")) + (define dM 1) + (define INIT 0) + (define (suivant m) + (+ m dM)) + (define (dessiner m) + (place-image (circle m 'solid "red") (random SIZE) (random SIZE) SCENE))] + (big-bang INIT + (on-tick suivant 1) + (on-draw dessiner SIZE SIZE)))) + +(animation2) \ No newline at end of file diff --git a/collects/2htdp/universe.rkt b/collects/2htdp/universe.rkt index cac34c0d35..838941f28f 100644 --- a/collects/2htdp/universe.rkt +++ b/collects/2htdp/universe.rkt @@ -3,6 +3,8 @@ ;; DONT USE to-draw IN THIS FILE #| TODO: + -- check that on-release is only defined if on-key is defined + -- yield instead of sync -- run callbacks in user eventspace -- make timer fire just once; restart after on-tick callback finishes @@ -41,31 +43,29 @@ (define new-universe (create-universe universe0)) (define-keywords AllSpec '() define-all - ;; -- on-tick must specify a tick handler; it may specify a clock-tick rate - [on-tick - DEFAULT #'#f - (function-with-arity - 1 - except - [(_ f rate) - #'(list - (proc> 'on-tick (f2h f) 1) - (num> 'on-tick rate (lambda (x) (and (real? x) (positive? x))) - "positive number" "rate"))])] + ;; -- on-tick must specify a tick handler: World -> World + ;; it may specify a clock-tick rate + [on-tick DEFAULT #'#f + (function-with-arity + 1 + except + [(_ f rate) + #'(list + (proc> 'on-tick (f2h f) 1) + (num> 'on-tick rate (lambda (x) (and (real? x) (positive? x))) + "positive number" "rate"))])] ;; -- state specifies whether to display the current state - [state - DEFAULT #'#f - (expr-with-check bool> "expected a boolean (show state or not)")] - ;; -- check-with must specify a predicate - [check-with - DEFAULT #'True - (function-with-arity 1)]) + [state DEFAULT #'#f (expr-with-check bool> "expected a boolean")] + ;; Any -> Boolean + ;; -- check-with: all states should specify this predicate + [check-with DEFAULT #'True (function-with-arity 1)]) ; (create-world world0) (define-keywords WldSpec AllSpec create-world - ;; -- on-draw must specify a rendering function; it may specify dimensions - [on-draw to-draw - DEFAULT #'#f + ;; (U #f (World -> Scene) (list (World -> Scene) Nat Nat)) + ;; on-draw must specify a rendering function; + ;; it may specify dimensions + [on-draw to-draw DEFAULT #'#f (function-with-arity 1 except @@ -73,42 +73,36 @@ #'(list (proc> 'to-draw (f2h f) 1) (nat> 'to-draw width "width") (nat> 'to-draw height "height"))])] - ;; -- on-mouse must specify a mouse event handler - [on-mouse - DEFAULT #'K - (function-with-arity 4)] - ;; -- on-key must specify a key event handler - [on-key - DEFAULT #'K - (function-with-arity 2)] - ;; -- on-release must specify a release event handler - [on-release - DEFAULT #'K - (function-with-arity 2)] + ;; World Nat Nat MouseEvent -> World + ;; on-mouse must specify a mouse event handler + [on-mouse DEFAULT #f (function-with-arity 4)] + ;; World KeyEvent -> World + ;; on-key must specify a key event handler + [on-key DEFAULT #f (function-with-arity 2)] + ;; World KeyEvent -> World + ;; on-release must specify a release event handler + [on-release DEFAULT #'K (function-with-arity 2)] + ;; (U #f (World S-expression -> World)) ;; -- on-receive must specify a receive handler - [on-receive - DEFAULT #'#f - (function-with-arity 2)] + [on-receive DEFAULT #'#f (function-with-arity 2)] + ;; World -> Boolean ;; -- stop-when must specify a predicate; it may specify a rendering function - [stop-when - DEFAULT #'False - (function-with-arity - 1 - except - [(_ stop? last-picture) - #'(list (proc> 'stop-when (f2h stop?) 1) - (proc> 'stop-when (f2h last-picture) 1))])] + [stop-when DEFAULT #'False + (function-with-arity + 1 + except + [(_ stop? last-picture) + #'(list (proc> 'stop-when (f2h stop?) 1) + (proc> 'stop-when (f2h last-picture) 1))])] + ;; (U #f Boolean) ;; -- should the session be recorded and turned into PNGs and an animated GIF - [record? - DEFAULT #'#f - (expr-with-check bool> "expected a boolean (to record? or not)")] - [name - DEFAULT #'#f - (expr-with-check string> "expected a name (string) for the world")] + [record? DEFAULT #'#f (expr-with-check bool> "expected a boolean")] + ;; (U #f String) + ;; -- name specifies one string + [name DEFAULT #'#f (expr-with-check string> "expected a string")] + ;; (U #f IP) ;; -- register must specify the internet address of a host (e.g., LOCALHOST) - [register - DEFAULT #'#f - (expr-with-check ip> "expected a host (ip address)")]) + [register DEFAULT #'#f (expr-with-check ip> "expected a host (ip address)")]) ; (create-universe universe0) (define-keywords UniSpec AllSpec create-universe @@ -155,15 +149,15 @@ ) (provide-primitives - make-package ;; World Sexp -> Package - package? ;; Any -> Boolean - run-movie ;; [Listof Image] -> true - mouse-event? ;; Any -> Boolean : MOUSE-EVTS - mouse=? ;; MOUSE-EVTS MOUSE-EVTS -> Boolean - key-event? ;; Any -> Boolean : KEY-EVTS - key=? ;; KEY-EVTS KEY-EVTS -> Boolean - ;; IP : a string that points to a machine on the net - ) + make-package ;; World Sexp -> Package + package? ;; Any -> Boolean + run-movie ;; [Listof Image] -> true + mouse-event? ;; Any -> Boolean : MOUSE-EVTS + mouse=? ;; MOUSE-EVTS MOUSE-EVTS -> Boolean + key-event? ;; Any -> Boolean : KEY-EVTS + key=? ;; KEY-EVTS KEY-EVTS -> Boolean + ;; IP : a string that points to a machine on the net + ) (provide LOCALHOST ;; IP )