#lang racket/base (require slideshow/base slideshow/pict racket/contract/base racket/list racket/match racket/stxparam (for-syntax racket/base racket/list racket/set syntax/parse) "pict.rkt") (provide (all-from-out "pict.rkt")) (define-syntax-rule (define-with-parameter name parameter) (define-syntax-rule (name value body (... ...)) (parameterize ([parameter value]) body (... ...)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Font Controls ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-with-parameter with-size current-font-size) (define-syntax-rule (with-scale scale expr) (with-size (inexact->exact (ceiling (* scale (current-font-size)))) expr)) (define-syntax-rule (define-scale name scale) (define-syntax-rule (name expr) (with-scale scale expr))) (define-scale big 3/2) (define-scale small 2/3) (define-with-parameter with-font current-main-font) (define-syntax-rule (with-style style expr) (with-font (cons style (current-main-font)) expr)) (define-syntax-rule (define-style name style) (define-syntax-rule (name expr) (with-style style expr))) (define-style bold 'bold) (define-style italic 'italic) (define-style subscript 'subscript) (define-style superscript 'superscript) (define-style caps 'caps) (provide with-size with-scale big small with-font with-style bold italic subscript superscript caps) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Slide / Paragraph Manipulation ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-with-parameter column current-para-width) (define (columns . picts) (apply hc-append gap-size (map baseless picts))) (define (column-size n [r (/ n)]) (* r (- (current-para-width) (* (sub1 n) gap-size)))) (define-syntax-rule (two-columns a b) (columns (column (column-size 2) a) (column (column-size 2) b))) (define (mini-slide . picts) (apply vc-append gap-size picts)) (provide column columns column-size two-columns mini-slide) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Simple Tables ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define =! (case-lambda [(n) n] [(n . ns) (if (apply = n ns) n (error '=! "not all equal: ~a" (cons n ns)))])) (define (elem->pict elem) (if (string? elem) (t elem) elem)) (define (tabular #:gap [gap gap-size] #:vgap [vgap gap] #:hgap [hgap gap] #:align [align lbl-superimpose] #:halign [halign align] #:valign [valign align] . cells) (let* ([rows (length cells)] [cols (apply =! (map length cells))] [picts (map elem->pict (append* cells))] [haligns (for/list ([i (in-range 0 cols)]) halign)] [valigns (for/list ([i (in-range 0 rows)]) valign)] [hseps (for/list ([i (in-range 1 cols)]) hgap)] [vseps (for/list ([i (in-range 1 rows)]) vgap)]) (table cols picts haligns valigns hseps vseps))) (define (matrixof c) (and/c (listof (listof c)) (flat-named-contract "matrix" (match-lambda [(list) #t] [(list _) #t] [(list xs ...) (apply = (map length xs))])))) (provide/contract [tabular (->* [] [#:gap natural-number/c #:hgap natural-number/c #:vgap natural-number/c #:align (->* [] [] #:rest (listof pict?) pict?) #:halign (->* [] [] #:rest (listof pict?) pict?) #:valign (->* [] [] #:rest (listof pict?) pict?)] #:rest (matrixof (or/c string? pict?)) pict?)]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Slide Staging ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-syntax-rule (slide/staged [name ...] body ...) (staged [name ...] (slide body ...))) (provide slide/staged) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Misc ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (blank-line) (blank 0 (current-font-size))) (provide/contract [blank-line (-> pict?)]) ;; Revealing slides. Similar to staging slides, can probably be implemented ;; in terms of staged slides. (provide reveal revealing-slide items-slide) (define-syntax-parameter reveal (lambda (stx) (raise-syntax-error 'reveal "reveal"))) (define-for-syntax (find-reveals stx) (syntax-case stx (reveal) [(reveal n stuff ...) (set-add (find-reveals #'(stuff ...)) (syntax-e #'n))] [(x rest ...) (set-union (find-reveals #'x) (find-reveals #'(rest ...)))] [else (set)])) (define-for-syntax (largest stuff) (define all (sort (set->list stuff) >)) (if (null? all) -1 (first all))) ;; reveals elements one at a time but uses ghost so that the slide doesn't ;; change its layout during each reveal. ;; for each element you want to reveal wrap the element in a (reveal): ;; (reveal N element) ;; ;; where N is the order of the reveal you want. 0 will be shown first, then 1, 2, ... (define-syntax (revealing-slide stx) (syntax-case stx () [(_ stuff ...) (let () (define max-reveals (largest (find-reveals stx))) (define slides (for/list ([i (add1 max-reveals)]) (with-syntax ([i i]) (syntax (syntax-parameterize ([reveal (syntax-rules () [(reveal n pict) (show pict (>= i n))] [(reveal n) (>= i n)])]) (slide stuff ...)))))) (with-syntax ([(slides ...) slides]) #'(begin slides ...)))])) ;; (items-slide ("a" "b" "c") #:title "whatever" (reveal 0 ...) (reveal 1 ...) (reveal 2 ...) ;; this will show a, b, c on the left side with one of them highlighted at a time. ;; the first element, a, will be synchronized with showing the first reveal, then ;; the second element, b, will be synchronized with the second reveal, etc. (define-syntax (items-slide stx) (syntax-parse stx [(_ (item ...) (~seq keyword-name:keyword keyword-value:expr) ... stuff:expr ...) (let () (define max-reveals (length (syntax->list #'(item ...)))) (define slides (for/list ([i max-reveals]) (with-syntax ([i i] [(keywords ...) (apply append (syntax->list #'((keyword-name keyword-value) ...)))]) (syntax (syntax-parameterize ([reveal (syntax-rules () [(reveal n pict) (show pict (= i n))])]) (let ([show-items (for/fold ([start (blank)]) ([in '(item ...)] [current (in-naturals)]) (vr-append start (if (= current i) (text in null (current-font-size)) (colorize/alpha (text in null (- (current-font-size) 3)) 0 0 0 0.3)) (blank 1 10)))] [data (for/fold ([start (blank)]) ([thing (list stuff ...)]) (lt-superimpose start thing))]) (slide keywords ... (ht-append show-items (blank 50 1) data)))))))) (with-syntax ([(slides ...) slides]) #'(begin slides ...)))]))