#lang debug racket/base (require racket/match racket/function racket/promise racket/dict "generic.rkt") (provide (all-defined-out)) (module+ test (require rackunit)) (define (default-visibility-proc q sig) (match (elems q) [(list (? (λ (x) (and (char? x) (char-whitespace? x))) c)) (case sig [(start end) #f] [else #t])] [else #t])) (struct $quad (attrs elems) #:transparent #:mutable #:methods gen:quad [(define (elems q) ($quad-elems q)) (define (attrs q) ($quad-attrs q)) ;; why 'nw and 'ne as defaults for in and out points ;; if size is '(0 0), the points are the same, and everything piles up at the origin ;; if size is otherwise, the items don't pile up (but rather lay out in a row) (define (in q) (hash-ref (attrs q) 'in 'nw)) (define (out q) (hash-ref (attrs q) 'out 'ne)) (define (inner q) (hash-ref (attrs q) 'inner (λ () (in q)))) (define (printable? q [signal #f]) (let ([v (hash-ref (attrs q) 'printable? (λ () (default-visibility-proc q signal)))]) (cond [(procedure? v) (v signal)] [(promise? v) (force v)] [else v]))) (define (size q) (let ([v (hash-ref (attrs q) 'size '(0 0))]) (cond [(procedure? v) (v)] [(promise? v) (force v)] [else v]))) (define (offset q [signal #f]) (hash-ref (attrs q) 'offset '(0 0))) (define (origin q) (hash-ref (attrs q) 'origin '(0 0))) (define (set-origin! q val) (set-$quad-attrs! q (hash-set (attrs q) 'origin val))) (define (draw q [surface #f]) (define (default-draw-proc q surface) (for-each (λ (e) (draw e surface)) (elems q))) ((hash-ref (attrs q) 'draw (λ () default-draw-proc)) q surface))]) (define (quad-attrs? x) (and (hash? x) (hash-eq? x))) (define (quad-elem? x) (or (char? x) (string? x) ($quad? x))) (define (quad-elems? xs) (and (pair? xs) (andmap quad-elem? xs))) (define (quad #:type [type $quad] . xs) (match xs [(list #f xs ...) (apply quad #:type type (hasheq) xs)] [(list (list (? symbol? sym) rest ...) (? quad-elem? elems) ...) (type (apply hasheq (cons sym rest)) elems)] [(list (? dict? attrs) (? quad-elem? elems) ...) (type (for/hasheq ([(k v) (in-dict attrs)]) (values k v)) elems)] [(list (? quad-attrs? attrs) (? quad-elem? elems) ...) (type attrs elems)] [(list (? quad-elem? elems) ...) (apply quad #:type type #f elems)] [else (error 'bad-quad-input)])) (define q quad) (define (quads? xs) (andmap quad? xs)) (define (atomic-quad? x) (and (quad? x) (match (elems x) [(list (? char?)) #t] [else #f]))) (define (atomic-quads? xs) (andmap atomic-quad? xs)) (module+ test (check-true (atomic-quad? ($quad '#hasheq() '(#\H)))) (check-true (atomic-quads? (list ($quad '#hasheq() '(#\H)))))) #| (struct $break $quad () #:transparent) (define (break . xs) (apply quad #:type $break xs)) (define b break) |# (module+ test (define x ($quad (hasheq 'entrance 0 'exit 10+10i 'inner 5+5i 'size 8+8i 'draw (λ (q doc) (println "foo"))) '(#\H #\e #\l #\o))) (draw x))