
This adds the option to generate random terms that satisfy judgment-forms and metafunctions. Currently functionality does not include: - patterns/terms using: ellipses, in-hole/hole and relatives, side-conditions, unquotes - define-relation - redex-check integration
750 lines
26 KiB
Racket
750 lines
26 KiB
Racket
#lang racket/base
|
|
|
|
(require racket/contract
|
|
racket/set
|
|
racket/function
|
|
racket/match
|
|
racket/vector
|
|
racket/list
|
|
racket/class
|
|
racket/pretty
|
|
racket/gui/base
|
|
racket/string
|
|
"jdg-gen.rkt"
|
|
"judgment-form.rkt"
|
|
"search.rkt"
|
|
"trace-layout.rkt"
|
|
(only-in "pat-unify.rkt"
|
|
env-eqs
|
|
env-dqs))
|
|
|
|
(provide make-tree
|
|
show-trace
|
|
raw-locs
|
|
format-trace)
|
|
|
|
;; tree browser prototype
|
|
;;
|
|
;; uses a mapping to a geometric series to get an "axis at infinity" effect
|
|
;;
|
|
;; TODO:
|
|
;; * the layout algorithm is pretty dumb right now, could definitely be improved
|
|
;; * zooming/panning starts getting slow for trees with around 1,000 nodes
|
|
;;
|
|
|
|
|
|
(define loc? (listof exact-nonnegative-integer?))
|
|
(define trace-element? (cons/c loc? list?))
|
|
(define trace? (listof trace-element?))
|
|
;; well-formed trace: nodes with no siblings have a parent
|
|
;; and nodes that aren't the oldest sibling (index 0) have a next-youngest
|
|
;; this is a little slow right now - mabe overkill, but probably will have a similar
|
|
;; complexity to a layout algorithm that scans the entire trace
|
|
(define (trace-is-well-formed? trace)
|
|
(define locs (set))
|
|
(define (add-check-for-replaces loc)
|
|
(set! locs (set-remove-all locs (curry loc-prefix-same? loc)))
|
|
(set! locs (set-add locs loc)))
|
|
(for/and ([t-e (in-list trace)])
|
|
(add-check-for-replaces (car t-e))
|
|
(match t-e
|
|
[`(() ,rest ...)
|
|
#t]
|
|
[`((,locs-parent ... 0) ,rest ...)
|
|
(set-member? locs locs-parent)]
|
|
[`((,locs-parent ... ,n) ,rest ...)
|
|
(set-member? locs `(,@locs-parent ,(- n 1)))])))
|
|
(define well-formed-trace? (and/c trace? trace-is-well-formed?))
|
|
|
|
(define (show-trace)
|
|
(define tr (get-most-recent-trace))
|
|
(when tr
|
|
(define trace (format-trace tr))
|
|
(when trace
|
|
(show-trace-frame trace))))
|
|
|
|
(define (format-trace tr)
|
|
(map (match-lambda
|
|
[(vector 'info clause-name
|
|
(gen-trace tr-loc clause input state bound env))
|
|
(list (reverse tr-loc) clause-name state input (clause-head-pat clause) bound 0 env)])
|
|
tr))
|
|
|
|
(define/contract (show-trace-frame trace)
|
|
(-> well-formed-trace? any)
|
|
(define tf (new tree-frame% [t trace] [w 600] [h 600]))
|
|
(send tf display))
|
|
|
|
(define (set-remove-all old-set pred?)
|
|
(for/fold ([new-s (set)])
|
|
([s old-set])
|
|
(if (pred? s)
|
|
new-s
|
|
(set-add new-s s))))
|
|
|
|
(define (loc-prefix-same? parent child)
|
|
(and (<= (length parent) (length child))
|
|
(for/and ([e1 parent] [e2 child])
|
|
(equal? e1 e2))))
|
|
|
|
(struct gen-tree
|
|
(loc attributes [children #:mutable])
|
|
#:transparent)
|
|
|
|
(struct attributes
|
|
(label id in-bound term body coords [focus #:mutable] env)
|
|
#:transparent)
|
|
|
|
(struct coords
|
|
(x y)
|
|
#:transparent
|
|
#:mutable)
|
|
|
|
(struct trace-step (path b-factor attributes)
|
|
#:transparent)
|
|
|
|
(struct lvar (id) #:prefab)
|
|
|
|
(define SCROLL-RANGE 10000)
|
|
|
|
;; doesn't currently use all the information in the trace
|
|
(define (make-tree trace)
|
|
(let loop ([tree (vector 0)]
|
|
[t trace])
|
|
(match t
|
|
[`((,loc ,name ,state ,term ,body ,bound ,depth ,env) ,remaining-traces ...)
|
|
(define atts (attributes name (gensym) (positive? bound) term body (coords #f #f) #f env))
|
|
(loop (insert-tree-atts loc atts tree) remaining-traces)]
|
|
[else
|
|
tree])))
|
|
|
|
(define (trace-step-loc t-step)
|
|
(match t-step
|
|
[`(,loc ,name ,state ,term ,body ,bound ,depth ,env)
|
|
loc]))
|
|
|
|
(define (trace-step->atts t-step)
|
|
(match t-step
|
|
[`(,loc ,name ,state ,term ,body ,bound ,depth ,env)
|
|
(attributes name (gensym) (positive? bound) term body (coords #f #f) #f env)]))
|
|
|
|
(define (insert-tree-atts loc attributes tree-root)
|
|
(insert-tree-node loc (gen-tree loc attributes (make-vector 0)) tree-root))
|
|
|
|
(define (insert-tree-node full-loc node tree-root)
|
|
(define (insert-node loc node tree)
|
|
(match loc
|
|
[`(,i) ;; append or replace
|
|
(cond [(or (= 0 (vector-length (gen-tree-children tree)))
|
|
(not (vector-member full-loc
|
|
(vector-map gen-tree-loc (gen-tree-children tree)))))
|
|
(define new-children (vector-append (gen-tree-children tree)
|
|
(vector node)))
|
|
(set-gen-tree-children! tree new-children)
|
|
#f]
|
|
[else
|
|
(define old-node
|
|
(vector-ref (gen-tree-children tree)
|
|
(vector-member full-loc
|
|
(vector-map gen-tree-loc (gen-tree-children tree)))))
|
|
(vector-set! (gen-tree-children tree) i
|
|
node)
|
|
old-node])]
|
|
[`(,i ,is ...)
|
|
(insert-node is node (vector-ref (gen-tree-children tree) i))]
|
|
['() ;; initial tree (or replacement)
|
|
(set! tree-root node)]
|
|
[else (error "tree didn't have expected generation pattern" loc tree)]))
|
|
(insert-node full-loc node tree-root)
|
|
tree-root)
|
|
|
|
(define (get-node-at-loc loc tree-root)
|
|
(let recur ([t tree-root]
|
|
[l loc])
|
|
(match l
|
|
[`(,i)
|
|
(if (and (0 . < . (vector-length (gen-tree-children t)))
|
|
(i . < . (vector-length (gen-tree-children t))))
|
|
(vector-ref (gen-tree-children t) i)
|
|
#f)]
|
|
['() t]
|
|
[`(,i ,is ...)
|
|
(recur (vector-ref (gen-tree-children t) i) is)]
|
|
[else #f])))
|
|
|
|
(define (remove-tree-node loc tree-root)
|
|
(let recur ([t tree-root]
|
|
[l loc])
|
|
(match l
|
|
[`(,i)
|
|
(if (= (vector-length (gen-tree-children t)) (+ i 1))
|
|
(set-gen-tree-children! t (vector-take (gen-tree-children t) i))
|
|
(error "can only remove the last child of a node"))]
|
|
[`(,i ,is ...)
|
|
(recur (vector-ref (gen-tree-children t) i) is)]
|
|
[`()
|
|
(error "can't remove tree root")]))
|
|
tree-root)
|
|
|
|
|
|
(define (set-focus-to-true node)
|
|
(match node
|
|
[(gen-tree loc as cs)
|
|
(set-attributes-focus! as #t)]
|
|
[else
|
|
(void)]))
|
|
|
|
(define (all-trees trace)
|
|
(for/list ([i (length trace)]) (make-tree (take trace i))))
|
|
|
|
(define no-pen (new pen% [style 'transparent]))
|
|
(define no-brush (new brush% [style 'transparent]))
|
|
(define green-brush (new brush% [color "Medium Sea Green"]))
|
|
(define focus-brush (new brush% [color "Red"]))
|
|
(define blue-pen (new pen% [color "Steel Blue"] [width 2]))
|
|
(define grey-pen (new pen% [color "Light Slate Grey"] [width 1]))
|
|
(define grey-brush (new pen% [color "Slate Grey"]))
|
|
|
|
(define (add-layout-info tree locs->x-coords)
|
|
(let loop ([t tree]
|
|
[depth 1])
|
|
(match t
|
|
[(gen-tree loc (attributes p b-f b l l2 cs f e) children)
|
|
(for ([c children])
|
|
(loop c (add1 depth)))
|
|
(set-coords-x! cs (hash-ref locs->x-coords loc))
|
|
(set-coords-y! cs depth)]))
|
|
tree)
|
|
|
|
(define (max-depth trace)
|
|
(define max-d 0)
|
|
(let loop ([t trace])
|
|
(match t
|
|
[`((,loc ,other-stuff ...) ,remaining-traces ...)
|
|
(when (> (add1 (length loc)) max-d)
|
|
(set! max-d (add1 (length loc))))
|
|
(loop remaining-traces)]
|
|
[else max-d])))
|
|
|
|
(define (raw-locs trace)
|
|
(map (match-lambda
|
|
[`(,loc ,name ,state ,term ,body ,bound ,depth ,env)
|
|
loc])
|
|
trace))
|
|
|
|
;; handles keeping track of the trace
|
|
;; and mutating the tree
|
|
;; tree-frame does the drawing
|
|
(define trace-state%
|
|
(class object%
|
|
|
|
(init trace-init)
|
|
|
|
(define step 0)
|
|
(define tree #f)
|
|
(define trace trace-init)
|
|
(define tr-locs (raw-locs trace))
|
|
(define-values (locs->widths locs->coords)
|
|
(trace->widths/coords tr-locs))
|
|
(define final-tree (make-tree trace))
|
|
(define width (hash-ref locs->widths '()))
|
|
(define depth (apply max (map length tr-locs)))
|
|
(define last-atts #f)
|
|
(define lvars->names (make-hash))
|
|
(define names-inc 0)
|
|
(define subtree-stack '())
|
|
|
|
(super-new)
|
|
|
|
(update-tree-one-step)
|
|
|
|
(define/public (take-step)
|
|
(unless (equal? step (sub1 (length trace)))
|
|
(set! step (add1 step))
|
|
(update-tree-one-step)))
|
|
|
|
(define/public (step-back)
|
|
(unless (= step 0)
|
|
(match (first subtree-stack)
|
|
[`(,loc ,subtree)
|
|
(if subtree
|
|
(set! tree (insert-tree-node loc subtree tree))
|
|
(set! tree (remove-tree-node loc tree)))])
|
|
(set! subtree-stack (rest subtree-stack))
|
|
(set! step (sub1 step))
|
|
(defocus)
|
|
(set-focus-to-true (get-node-at-loc (trace-step-loc (list-ref trace step)) tree))
|
|
(set! last-atts (trace-step->atts (list-ref trace step)))
|
|
(add-layout-info tree locs->coords)))
|
|
|
|
(define/public (rewind)
|
|
(set! step 0)
|
|
(set! tree #f)
|
|
(update-tree-one-step))
|
|
|
|
(define/public (fast-forward)
|
|
(for ([i (in-range (add1 step) (length trace))])
|
|
(take-step)))
|
|
|
|
(define/public (get-tree) tree)
|
|
|
|
(define/public (get-width) width)
|
|
(define/public (get-depth) depth)
|
|
|
|
(define/public (current-atts)
|
|
last-atts)
|
|
|
|
(define/public (prettify-pat term)
|
|
(match term
|
|
[`(name ,id ,bound)
|
|
id]
|
|
[`(list ,subterms ...)
|
|
(for/list ([s subterms]) (prettify-pat s))]
|
|
[`(cstr (,nts ...) ,term)
|
|
`(cstr (,@nts) ,(prettify-pat term))]
|
|
[else term]))
|
|
|
|
;; TODO: "garbage collect" vars,
|
|
;; treating rule and input as roots
|
|
(define/public (format-pattern p eqs)
|
|
(match p
|
|
[`(name ,id ,bound)
|
|
(format-pattern (hash-ref eqs (lvar id)) eqs)]
|
|
[(lvar id)
|
|
(format-pattern (hash-ref eqs (lvar id)) eqs)]
|
|
[`(list ,subterms ...)
|
|
(for/list ([s subterms]) (format-pattern s eqs))]
|
|
[`(cstr (,nts ...) ,p)
|
|
`(cstr (,@nts) ,(format-pattern p eqs))]
|
|
[else p]))
|
|
|
|
(define/public (update-focus x y-index)
|
|
(defocus)
|
|
(define as (get-coord-atts x y-index))
|
|
(when as
|
|
(set-attributes-focus! as #t))
|
|
as)
|
|
|
|
(define/public (get-coord-atts x y-index)
|
|
(define (get-x t-node)
|
|
(match t-node
|
|
[(gen-tree loc (attributes p b-f b l l2 (coords x y) f e) cs)
|
|
x]
|
|
[else +inf.0]))
|
|
(define closest-node
|
|
(let recur ([t tree]
|
|
[d (sub1 y-index)])
|
|
(cond
|
|
[(= d 0)
|
|
t]
|
|
[else
|
|
(match t
|
|
[(gen-tree loc as '#())
|
|
#f]
|
|
[(gen-tree loc as children)
|
|
(define c-closest-ns (for/list ([c children])
|
|
(recur c (sub1 d))))
|
|
(first (sort c-closest-ns <
|
|
#:key (λ (c) (if c
|
|
(abs (- x (get-x c)))
|
|
+inf.0))))])])))
|
|
(match closest-node
|
|
[(gen-tree loc as children)
|
|
(set-attributes-focus! as #t)
|
|
as]
|
|
[else #f]))
|
|
|
|
(define/public (focus-coords)
|
|
(let recur ([t tree])
|
|
(match t
|
|
[(gen-tree loc (attributes p b-f b l l2 cs #t e) children)
|
|
cs]
|
|
[(gen-tree loc as '#())
|
|
#f]
|
|
[(gen-tree loc as children)
|
|
(define s-t-l (memf (λ (e) e)
|
|
(for/list ([c children]) (recur c))))
|
|
(if (or (not s-t-l) (empty? s-t-l))
|
|
#f
|
|
(first s-t-l))])))
|
|
|
|
(define/public (format-info as)
|
|
(match as
|
|
[(attributes name id bound term body coords f e)
|
|
(define eqs (env-eqs e))
|
|
(define sorted-vars (sort (hash-keys eqs)
|
|
(λ (l r) (string<? (symbol->string (lvar-id l))
|
|
(symbol->string (lvar-id r))))))
|
|
(string-append
|
|
(string-join
|
|
(for/list ([k sorted-vars])
|
|
(string-append (symbol->string (lvar-id k)) "\t = "
|
|
(match (hash-ref eqs k)
|
|
[(lvar next) (symbol->string next)]
|
|
[`(name ,next ,_) (symbol->string next)]
|
|
[else " - "]) "\t = "
|
|
(string-replace (pretty-format (format-pattern (hash-ref eqs k) eqs)) "\n" "\n\t \t ")))
|
|
"\n")
|
|
"\n\n"
|
|
(string-join
|
|
(for/list ([dq (in-list (env-dqs e))])
|
|
(string-append (format "~s" (first dq)) " ≠\n\t"
|
|
(format "~s" (second dq))))
|
|
"\n"))]))
|
|
|
|
(define/private (defocus)
|
|
(let recur ([t tree])
|
|
(match t
|
|
[(gen-tree loc as '#())
|
|
(set-attributes-focus! as #f)]
|
|
[(gen-tree loc as children)
|
|
(set-attributes-focus! as #f)
|
|
(for ([c children]) (recur c))])))
|
|
|
|
(define/private (update-tree-one-step)
|
|
(define trace-step (list-ref trace step))
|
|
(when tree (defocus))
|
|
(match trace-step
|
|
[`(,loc ,name ,state ,term ,body ,bound ,depth ,env)
|
|
(set! subtree-stack (cons (list loc (get-node-at-loc loc tree)) subtree-stack))
|
|
(define atts (attributes name (gensym) (positive? bound) term body (coords #f #f) #t env))
|
|
(set! last-atts atts)
|
|
(set! tree (insert-tree-atts loc atts tree))]
|
|
[else (error "Trace had incorrect format, failed to update tree")])
|
|
(add-layout-info tree locs->coords))
|
|
|
|
))
|
|
;; end trace-state%
|
|
|
|
|
|
(define yscale-base .632)
|
|
(define (set-y-base f) (set! yscale-base f))
|
|
(define (ybase-sum) (/ yscale-base (- 1 yscale-base)))
|
|
(define (find-ybase-center)
|
|
(define mid (/ (ybase-sum) 2))
|
|
(define sums (for/hash ([i 10]) (values (abs (- mid
|
|
(apply + (for/list ([k i])
|
|
(expt yscale-base i)))))
|
|
i)))
|
|
(hash-ref sums (apply min (hash-keys sums))))
|
|
|
|
|
|
(define trans-steps 15)
|
|
(define (set-t-s x) (set! trans-steps x))
|
|
|
|
(define Y-SHIFT 0)
|
|
(define (set-y-shift s) (set! Y-SHIFT s))
|
|
|
|
(define tree-canvas%
|
|
(class canvas%
|
|
|
|
(super-new)
|
|
|
|
(define scroll-handler (λ (e) #f))
|
|
(define/public (set-scroll-handler f)
|
|
(set! scroll-handler f))
|
|
(define/override (on-scroll event)
|
|
(scroll-handler event))
|
|
|
|
(define key-handler (λ (e) #f))
|
|
(define/public (set-key-handler f)
|
|
(set! key-handler f))
|
|
(define/override (on-char event)
|
|
(key-handler event))))
|
|
|
|
(define tree-frame%
|
|
(class frame%
|
|
|
|
(init t w h)
|
|
(define trace (new trace-state% [trace-init t]))
|
|
(define width w)
|
|
(define height h)
|
|
(define shift (/ w 2))
|
|
|
|
(super-new [label "Generation Trace"])
|
|
|
|
(define (t-width)
|
|
(send trace get-width))
|
|
(define (depth)
|
|
(send trace get-depth))
|
|
|
|
(define y-index 1)
|
|
(define x-coord 0)
|
|
(define scale 1)
|
|
(define/private (rescale factor)
|
|
(set! scale (* scale factor)))
|
|
(define/private (trans-x x)
|
|
(set! x-coord (+ x-coord x))
|
|
(update-scroll-x x-coord))
|
|
(define/private (shift-y steps)
|
|
(set! y-index (+ y-index steps))
|
|
(update-scroll-y y-index))
|
|
|
|
(define rescale-factor (/ w (t-width)))
|
|
(define scale-factor (expt rescale-factor (/ 1 (depth))))
|
|
|
|
(rescale rescale-factor)
|
|
(define canvas (new tree-canvas% [parent this]
|
|
[min-width w]
|
|
[min-height h]
|
|
[style (list 'hscroll 'vscroll)]
|
|
[paint-callback (lambda (canvas dc)
|
|
(draw-t))]))
|
|
(send canvas set-scroll-range 'horizontal SCROLL-RANGE)
|
|
(send canvas set-scroll-range 'vertical SCROLL-RANGE)
|
|
(send canvas set-scroll-pos 'vertical 0)
|
|
(send canvas set-scroll-pos 'horizontal (/ SCROLL-RANGE 2))
|
|
|
|
(send canvas set-scroll-handler
|
|
(λ (event)
|
|
(define dir (send event get-direction))
|
|
(define pos (update-scroll-pos event))
|
|
(define x-pos x-coord)
|
|
(define y-pos y-index)
|
|
(match dir
|
|
['horizontal
|
|
(set! x-pos (* (t-width) (- .5 (/ pos SCROLL-RANGE))))]
|
|
['vertical
|
|
(set! y-pos (- (* (depth) (/ pos SCROLL-RANGE))))])
|
|
(animate-transition (- x-pos x-coord) (- y-pos y-index))))
|
|
|
|
(send canvas set-key-handler
|
|
(λ (event)
|
|
(define-values (d-x d-y)
|
|
(match (send event get-key-code)
|
|
['wheel-down
|
|
(values 0 (- (/ (depth) 40)))]
|
|
['wheel-up
|
|
(values 0 (/ (depth) 40))]
|
|
['wheel-right
|
|
(values (- (/ (t-width) 40)) 0)]
|
|
['wheel-left
|
|
(values (/ (t-width) 40) 0)]
|
|
['left
|
|
(send trace step-back)
|
|
(update/all-steps)
|
|
(values #f #f)]
|
|
['right
|
|
(send trace take-step)
|
|
(update/all-steps)
|
|
(values #f #f)]
|
|
[else
|
|
(values #f #f)]))
|
|
(when (and d-x d-y)
|
|
(animate-transition d-x d-y))))
|
|
|
|
(define/private (update-scroll-pos event)
|
|
(define pos (send event get-position))
|
|
(match (send event get-event-type)
|
|
['line-up
|
|
(- pos (/ SCROLL-RANGE 20))]
|
|
['line-down
|
|
(+ pos (/ SCROLL-RANGE 20))]
|
|
['page-up
|
|
(- pos (/ SCROLL-RANGE 20))]
|
|
['page-down
|
|
(+ pos (/ SCROLL-RANGE 20))]
|
|
[else pos]))
|
|
|
|
(define/private (update-scroll-x x)
|
|
(send canvas set-scroll-pos 'horizontal (+ (* (- x) (/ SCROLL-RANGE (t-width)))
|
|
(/ SCROLL-RANGE 2))))
|
|
(define/private (update-scroll-y y-index)
|
|
(send canvas set-scroll-pos 'vertical (max 0 (* (/ y-index (- (depth))) SCROLL-RANGE))))
|
|
|
|
(define dc (send canvas get-dc))
|
|
|
|
(define/public (display)
|
|
(send this show #t))
|
|
|
|
(define panel1 (new vertical-panel% [parent this]
|
|
[min-height 80]
|
|
[stretchable-height 80]))
|
|
(define panel2 (new horizontal-panel% [parent panel1]
|
|
[min-height 40]
|
|
[stretchable-height 40]))
|
|
(define rule-message (new text-field% [parent panel2]
|
|
[label "Rule:"]))
|
|
(define rewind-button (new button% [parent panel2]
|
|
[label "<<"]
|
|
[callback (λ (b e)
|
|
(send trace rewind)
|
|
(update/all-steps))]))
|
|
(define back-button (new button% [parent panel2]
|
|
[label "Back"]
|
|
[callback (λ (b e)
|
|
(send trace step-back)
|
|
(update/all-steps))]))
|
|
(define step-button (new button% [parent panel2]
|
|
[label "Step"]
|
|
[callback (λ (b e)
|
|
(send trace take-step)
|
|
(update/all-steps))]))
|
|
(define ff-button (new button% [parent panel2]
|
|
[label ">>"]
|
|
[callback (λ (b e)
|
|
(send trace fast-forward)
|
|
(update/all-steps))]))
|
|
(define term-message (new text-field% [parent panel1]
|
|
[label "Term:"]))
|
|
(define body-message (new text-field% [parent panel1]
|
|
[label "Body:"]))
|
|
(update-messages)
|
|
|
|
(define/private (update/all-steps)
|
|
(define f-coords (send trace focus-coords))
|
|
(cond
|
|
[f-coords
|
|
(define center-x (x-inv-map shift))
|
|
(define ∆x (- center-x (coords-x f-coords)))
|
|
(define ∆y (- 5 (+ y-index (coords-y f-coords))))
|
|
(animate-transition ∆x ∆y)]
|
|
[else
|
|
(send canvas refresh-now
|
|
(λ (dc) (draw-t)))])
|
|
(update-messages))
|
|
|
|
(define/private (update-messages [atts #f])
|
|
(define as (if atts atts (send trace current-atts)))
|
|
(match as
|
|
[(attributes name id bound term body coords f e)
|
|
(send rule-message set-value (format "~s" name))
|
|
(send term-message set-value (format "~s" (send trace prettify-pat term)))
|
|
(send body-message set-value (format "~s" (send trace prettify-pat body)))])
|
|
(send panel1 refresh))
|
|
|
|
(define/private (pop-info-window as)
|
|
(define info-w (new frame% [label "Environment"]
|
|
[width 300]
|
|
[height 300]))
|
|
(define output-string (send trace format-info as))
|
|
(define env-text (new text-field% [label #f]
|
|
[parent info-w]
|
|
[style '(multiple)]
|
|
[init-value output-string]))
|
|
(send info-w show #t))
|
|
|
|
(define y-scale (/ h (ybase-sum)))
|
|
(define y-cs (for/list ([y 10])
|
|
(* y-scale
|
|
(apply + (for/list ([i (in-range 1 y)]) (expt yscale-base i))))))
|
|
(define/private (i-for-y y-raw)
|
|
(define y (- y-raw Y-SHIFT))
|
|
(define diffs (for/hash ([i 10] [y-c y-cs])
|
|
(values (+ 0.0 (abs (- y y-c))) i)))
|
|
(hash-ref diffs (+ 0.0 (apply min (hash-keys diffs)))))
|
|
|
|
(define/private (delta-x x)
|
|
(/ (- (/ width 2) x) scale))
|
|
(define/private (x-inv-map x)
|
|
(- (/ (- x shift) scale) x-coord))
|
|
|
|
(define/override (on-subwindow-event receiver event)
|
|
(cond
|
|
[(and (eq? receiver canvas)
|
|
(send event button-down?))
|
|
(define x (send event get-x))
|
|
(define y (send event get-y))
|
|
(define ∆x (delta-x x))
|
|
(define actual-y (- (i-for-y y) y-index))
|
|
(define actual-x (x-inv-map x))
|
|
(cond
|
|
[(send event button-down? 'left)
|
|
(define focus-as (send trace update-focus actual-x (round actual-y)))
|
|
(update-messages focus-as)
|
|
(send canvas refresh-now
|
|
(λ (dc) (draw-t)))]
|
|
[(send event button-down? 'right)
|
|
(pop-info-window (send trace get-coord-atts actual-x (round actual-y)))])]
|
|
[else
|
|
#f]))
|
|
|
|
(define/private (animate-transition ∆x ∆y)
|
|
(define scaling (expt scale-factor ∆y))
|
|
(define trans-steps (inexact->exact (ceiling (max (abs (/ (* ∆x 40) (t-width)))
|
|
(abs (/ (* ∆y 40) (depth)))
|
|
1))))
|
|
(define dx (/ ∆x trans-steps))
|
|
(define dy (/ ∆y trans-steps))
|
|
(define ds (expt scaling (/ 1 trans-steps)))
|
|
(for ([i trans-steps])
|
|
(trans-x dx)
|
|
(shift-y dy)
|
|
(rescale ds)
|
|
(send canvas refresh-now
|
|
(λ (dc) (draw-t)))))
|
|
|
|
(define map-y-memo (make-hash))
|
|
(define map-y-int-memo (make-hash))
|
|
(define/private (map-y-int y)
|
|
(hash-ref map-y-int-memo y
|
|
(λ ()
|
|
(define res (if (< 0 y)
|
|
(+ Y-SHIFT (* (apply + (for/list ([i (in-range 1 y)])
|
|
(expt yscale-base i)))
|
|
y-scale))
|
|
(- Y-SHIFT (* (+ (abs y) 1) y-scale))))
|
|
(hash-set! map-y-int-memo y res)
|
|
res)))
|
|
(define/private (map-y y)
|
|
(hash-ref map-y-memo y
|
|
(λ ()
|
|
(define y-t (truncate y))
|
|
(define res (if (= y y-t)
|
|
(map-y-int y)
|
|
(let ([frac (abs (- y y-t))]
|
|
[next (if (<= 0 y-t) (+ y-t 1) (- y-t 1))])
|
|
(+ (* frac (map-y-int next))
|
|
(* (- 1 frac) (map-y-int y-t))))))
|
|
(hash-set! map-y-memo y res)
|
|
res)))
|
|
|
|
(define/private (adjust-x x)
|
|
(* scale (+ x-coord x)))
|
|
(define/private (adjust-y y)
|
|
(+ y y-index))
|
|
|
|
(define/private (line x1-raw y1-raw x2-raw y2-raw)
|
|
(define x1 (adjust-x x1-raw))
|
|
(define x2 (adjust-x x2-raw))
|
|
(define y1 (adjust-y y1-raw))
|
|
(define y2 (adjust-y y2-raw))
|
|
(when (or (and (x1 . > . (- shift)) (x1 . < . shift)
|
|
(y1 . > . -1) (y1 . < . 10))
|
|
(and (x2 . > . (- shift)) (x2 . < . shift)
|
|
(y2 . > . -1) (y2 . < . 10)))
|
|
(send dc set-brush no-brush)
|
|
(send dc set-pen blue-pen)
|
|
(send dc draw-line (+ shift x1) (map-y y1) (+ shift x2) (map-y y2))))
|
|
|
|
(define/private (node x-raw y-raw focus?)
|
|
(define x (adjust-x x-raw))
|
|
(define y (adjust-y y-raw))
|
|
(when (and (x . > . (- shift)) (x . < . shift)
|
|
(y . < . 8) (y . > . -1))
|
|
(send dc set-pen no-pen)
|
|
(cond
|
|
[focus?
|
|
(send dc set-brush focus-brush)
|
|
(send dc draw-ellipse (+ shift (- x 7)) (- (map-y y) 7) 14 14)]
|
|
[else
|
|
(send dc set-brush green-brush)
|
|
(send dc draw-ellipse (+ shift (- x 5)) (- (map-y y) 5) 10 10)])))
|
|
|
|
(define/private (draw-t)
|
|
(define (draw-subtree t d)
|
|
(match t
|
|
[(gen-tree loc (attributes p b-f b l l2 (coords x y) f e) '#())
|
|
(node x y f)]
|
|
[(gen-tree loc (attributes p b-f b l l2 (coords x y) f e) children)
|
|
(for ([c children])
|
|
(match c
|
|
[(gen-tree loc (attributes p b-f b l l2 (coords c-x c-y) f e) children)
|
|
(line x y c-x c-y)
|
|
(draw-subtree c (add1 d))]))
|
|
(node x y f)]))
|
|
(send dc set-smoothing 'aligned)
|
|
(draw-subtree (send trace get-tree) 0))))
|
|
|
|
;;; end treeframe%
|