#lang racket (require 2htdp/universe) ; for key=?, mouse=? (require 2htdp/image) (require "interfaces.rkt") ;; The SWorld% class ;; provide the function, not the class. (provide make-sworld) (define EMPTY-CANVAS (empty-scene CANVAS-WIDTH CANVAS-HEIGHT)) ;; Like the World% class in 10-4, but is stateful itself. ;; It needs to be stable so the ball factory will know where to put ;; a new ball. ; ListOfWidget ListOfSWidget -> World (define (make-sworld objs sobjs) (new SWorld% [objs objs][sobjs sobjs])) (define SWorld% (class* object% (SWorld<%>) (init-field objs) ; ListOfWidget (init-field sobjs) ; ListOfSWidget (super-new) (define/public (add-widget w) (set! objs (cons w objs))) (define/public (add-stateful-widget w) (set! sobjs (cons w sobjs))) ;; ((Widget -> Widget) && (SWidget -> Void)) -> Void (define (process-widgets fn) (begin (set! objs (map fn objs)) (for-each fn sobjs))) ;; after-tick : -> Void ;; Use map on the Widgets in this World; use for-each on the ;; stateful widgets (define/public (after-tick) (process-widgets (lambda (obj) (send obj after-tick)))) ;; to-scene : -> Scene ;; Use HOFC foldr on the Widgets and SWidgets in this World ;; Note: the append is inefficient, but clear. (define/public (to-scene) (foldr (lambda (obj scene) (send obj add-to-scene scene)) EMPTY-CANVAS (append objs sobjs))) ;; after-key-event : KeyEvent -> Void ;; STRATEGY: Pass the KeyEvents on to the objects in the world. (define/public (after-key-event kev) (process-widgets (lambda (obj) (send obj after-key-event kev)))) ;; world-after-mouse-event : Nat Nat MouseEvent -> Void ;; STRATEGY: Cases on mev (define/public (after-mouse-event mx my mev) (cond [(mouse=? mev "button-down") (world-after-button-down mx my)] [(mouse=? mev "drag") (world-after-drag mx my)] [(mouse=? mev "button-up") (world-after-button-up mx my)] [else this])) ;; the next few functions are local functions, not in the interface. (define (world-after-button-down mx my) (process-widgets (lambda (obj) (send obj after-button-down mx my)))) (define (world-after-button-up mx my) (process-widgets (lambda (obj) (send obj after-button-up mx my)))) (define (world-after-drag mx my) (process-widgets (lambda (obj) (send obj after-drag mx my)))) ))