You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
typesetting/quad/quad/quad.rkt

128 lines
4.2 KiB
Racket

6 years ago
#lang debug racket/base
(require racket/struct racket/format racket/list racket/string racket/promise racket/dict racket/match)
6 years ago
(provide (all-defined-out))
(module+ test (require rackunit))
5 years ago
(define (size q)
(match (quad-size q)
[(? procedure? proc) (proc q)]
[(? promise? prom) (force prom)]
[val val]))
(define (printable? q [signal #f])
5 years ago
(match (quad-printable q)
5 years ago
[(? procedure? proc) (proc q signal)]
5 years ago
[val val]))
5 years ago
(define (draw q [surface (current-output-port)])
((quad-draw-start q) q surface)
((quad-draw q) q surface)
((quad-draw-end q) q surface))
(define (hashes-equal? h1 h2)
(and (= (length (hash-keys h1)) (length (hash-keys h2)))
(for/and ([(k v) (in-hash h1)])
(and (hash-has-key? h2 k) (equal? (hash-ref h2 k) v)))))
5 years ago
(define (quad=? q1 q2 recur?)
(and
;; exclude attrs from initial comparison
5 years ago
(for/and ([getter (in-list (list quad-elems quad-size quad-in quad-out quad-inner
quad-offset quad-origin quad-printable
quad-draw-start quad-draw-end quad-draw))])
(equal? (getter q1) (getter q2)))
;; and compare them key-by-key
(hashes-equal? (quad-attrs q1) (quad-attrs q2))))
6 years ago
5 years ago
(struct quad (type
5 years ago
copier
5 years ago
attrs
elems
5 years ago
size
in
out
inner
offset
origin
printable
draw-start
draw
draw-end)
#:property prop:custom-write
(λ (v p w?) (display
(format "<quad ~a~a>"
(string-join (map ~v (flatten (hash->list (quad-attrs v))))
" " #:before-first "(" #:after-last ")")
(string-join (map ~v (quad-elems v)) " " #:before-first " ")) p))
#:methods gen:equal+hash
[(define equal-proc quad=?)
(define (hash-proc h recur) (equal-hash-code h))
(define (hash2-proc h recur) (equal-secondary-hash-code h))])
5 years ago
(define (default-printable q [sig #f]) #t)
5 years ago
5 years ago
(define (default-draw q surface)
(for-each (λ (qi) (draw qi surface)) (quad-elems q)))
6 years ago
5 years ago
;; why 'nw and 'ne as defaults for in and out points:
;; if size is '(0 0), 'nw and 'ne are the same point,
5 years ago
;; and everything piles up at the origin
;; if size is otherwise, the items don't pile up (but rather lay out in a row)
;; todo: convert immutable hashes to mutable on input?
5 years ago
(define (make-quad
#:type [type quad]
5 years ago
#:copier [copier (λ (x as es) (struct-copy quad x
[attrs as]
[elems es]))]
5 years ago
#:attrs [attrs (make-hasheq)]
#:elems [elems null]
#:size [size '(0 0)]
5 years ago
#:in [in 'nw]
#:out [out 'ne]
#:inner [inner #f]
#:offset [offset '(0 0)]
#:origin [origin '(0 0)]
5 years ago
#:printable [printable default-printable]
#:draw-start [draw-start void]
5 years ago
#:draw [draw default-draw]
#:draw-end [draw-end void]
5 years ago
. args)
5 years ago
(unless (andmap (λ (x) (not (pair? x))) elems)
(raise-argument-error 'make-quad "elements that are not lists" elems))
5 years ago
(match args
[(list (== #false) elems ...) (make-quad #:elems elems)]
[(list (? hash? attrs) elems ...) (make-quad #:attrs attrs #:elems elems)]
[(list (? dict? assocs) elems ...) assocs (make-quad #:attrs (make-hasheq assocs) #:elems elems)]
[(list elems ..1) (make-quad #:elems elems)]
5 years ago
;; all cases end up below
[null (type type
5 years ago
copier
5 years ago
attrs
5 years ago
elems
size
in
out
inner
offset
origin
printable
draw-start
draw
draw-end)]))
5 years ago
(define q make-quad)
6 years ago
6 years ago
(module+ test
(require racket/port)
5 years ago
(define q1 (q #f #\H #\e #\l #\o))
(define q2 (q #f #\H #\e #\l #\o))
(define q3 (q #f #\H #\e #\l))
(check-true (equal? q1 q1))
(check-true (equal? q1 q2))
(check-false (equal? q1 q3))
(define q4 (struct-copy quad q1
[draw (λ (q surface) (display "foo" surface))]))
(check-equal? (with-output-to-string (λ () (draw q4))) "foo"))