286 lines
9.6 KiB
Scheme
286 lines
9.6 KiB
Scheme
#lang scheme/base
|
|
|
|
(provide define/chk
|
|
to-img
|
|
x-place?
|
|
y-place?
|
|
mode?
|
|
angle?
|
|
side-count?
|
|
image-color?
|
|
pen-style?
|
|
pen-cap?
|
|
pen-join?
|
|
image-snip->image
|
|
bitmap->image
|
|
check-mode/color-combination)
|
|
|
|
(require htdp/error
|
|
scheme/class
|
|
lang/posn
|
|
scheme/gui/base
|
|
"../../mrlib/image-core.ss"
|
|
(for-syntax scheme/base
|
|
scheme/list))
|
|
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;
|
|
;
|
|
; ;; ;; ;;
|
|
; ;; ;; ;;
|
|
; ;;;; ;;;;;;;;; ;;;; ;;;; ;;;; ;;;;;; ;;;; ;;;; ;; ;;; ;; ;; ;;; ;;;;;;
|
|
; ;; ;; ;;;; ;;;; ;;;;;; ;;;; ;;;;;; ;;;;;; ;; ;; ;;;;;; ;;;;; ;; ;;;;;; ;;;;;;
|
|
; ;;;;;;;; ;; ;; ;;; ;;; ;; ;;; ;; ;; ;;;;;;;;;;; ;;;;; ;; ;; ;; ;;; ;;
|
|
; ;;; ;; ;; ;;; ;;; ;; ;;; ;; ;; ;;; ;;; ;;;;; ;; ;; ;; ;;; ;;
|
|
; ;;; ;; ;; ;; ;;;;;; ;; ;;;;;; ;; ;; ;;; ;; ;;;;;; ;; ;; ;; ;; ;; ;;;;;;
|
|
; ;;;; ;; ;; ;;;; ;; ;;;; ;; ;; ;;;; ;;;; ;; ;;; ;; ;; ;; ;;;;;
|
|
; ;; ;;;
|
|
; ;;;;;
|
|
;
|
|
;
|
|
|
|
|
|
(define-syntax define/chk
|
|
(λ (stx)
|
|
(syntax-case stx ()
|
|
[(define/chk (fn-name args ... . final-arg) body ...)
|
|
(identifier? #'final-arg)
|
|
(let ([len (length (syntax->list #'(args ...)))])
|
|
(with-syntax ([(i ...) (build-list len add1)])
|
|
#`(define (fn-name args ... . final-arg)
|
|
(let ([args (check/normalize 'fn-name 'args args i)] ...
|
|
[final-arg (map/i (λ (x j) (check/normalize 'fn-name 'final-arg x (+ #,len j)))
|
|
final-arg)])
|
|
body ...))))]
|
|
[(define/chk (fn-name args ...) body ...)
|
|
(with-syntax ([(i ...) (build-list (length (syntax->list #'(args ...))) add1)])
|
|
#'(define (fn-name args ...)
|
|
(let ([args (check/normalize 'fn-name 'args args i)] ...)
|
|
body ...)))])))
|
|
|
|
(define (map/i f l)
|
|
(let loop ([l l]
|
|
[i 0])
|
|
(cond
|
|
[(null? l) null]
|
|
[else (cons (f (car l) i)
|
|
(loop (cdr l) (+ i 1)))])))
|
|
|
|
;; check/normalize : symbol symbol any number -> any
|
|
;; based on the name of the argument, checks to see if the input
|
|
;; is valid and, if so, transforms it to a specific kind of value
|
|
;; width, height -> number
|
|
;; mode -> 'outline 'solid
|
|
;; color -> (is-a?/c color<%>)
|
|
(define (check/normalize fn-name argname arg i)
|
|
(case argname
|
|
[(x-place)
|
|
(check-arg fn-name
|
|
(x-place? arg)
|
|
'x-place
|
|
i
|
|
arg)
|
|
(let ([sym (if (string? arg)
|
|
(string->symbol arg)
|
|
arg)])
|
|
(if (eq? sym 'center)
|
|
'middle
|
|
sym))]
|
|
[(y-place)
|
|
(check-arg fn-name
|
|
(y-place? arg)
|
|
'y-place
|
|
i
|
|
arg)
|
|
(let ([sym (if (string? arg)
|
|
(string->symbol arg)
|
|
arg)])
|
|
(if (eq? sym 'center)
|
|
'middle
|
|
sym))]
|
|
[(image image1 image2 image3)
|
|
(check-arg fn-name
|
|
(image? arg)
|
|
'image
|
|
i
|
|
arg)
|
|
(to-img arg)]
|
|
[(mode)
|
|
(check-arg fn-name
|
|
(mode? arg)
|
|
'mode
|
|
i
|
|
arg)
|
|
(if (string? arg)
|
|
(string->symbol arg)
|
|
arg)]
|
|
[(width height radius side-length side-length1 side-length2)
|
|
(check-arg fn-name
|
|
(and (real? arg)
|
|
(not (negative? arg)))
|
|
'non-negative-real-number
|
|
i arg)
|
|
arg]
|
|
[(dx dy x1 y1 x2 y2 factor x-factor y-factor pull1 pull2)
|
|
(check-arg fn-name
|
|
(real? arg)
|
|
'real\ number
|
|
i arg)
|
|
arg]
|
|
[(side-count)
|
|
(check-arg fn-name
|
|
(side-count? arg)
|
|
'side-count
|
|
i arg)
|
|
arg]
|
|
[(step-count)
|
|
(check-arg fn-name
|
|
(step-count? arg)
|
|
'step-count
|
|
i arg)
|
|
arg]
|
|
[(angle angle1 angle2)
|
|
(check-arg fn-name
|
|
(angle? arg)
|
|
'angle\ in\ degrees
|
|
i arg)
|
|
(if (< arg 0)
|
|
(+ arg 360)
|
|
arg)]
|
|
[(color)
|
|
(check-arg fn-name (or (image-color? arg) (pen? arg)) 'image-color-or-pen i arg)
|
|
;; return either a string, color, or a pen,
|
|
;; (technically, the string case is redundant,
|
|
;; but since there may be saved files that have
|
|
;; strings in the color positions we leave them
|
|
;; here too; note that using a pen struct means
|
|
;; 'smoothed mode, but a color (or string) means
|
|
;; 'aligned mode, so that's not redundant).
|
|
(cond
|
|
[(color? arg) arg]
|
|
[(pen? arg) arg]
|
|
[else
|
|
(let* ([color-str
|
|
(if (symbol? arg)
|
|
(symbol->string arg)
|
|
arg)])
|
|
(if (send the-color-database find-color color-str)
|
|
color-str
|
|
"black"))])]
|
|
[(string)
|
|
(check-arg fn-name (string? arg) 'string i arg)
|
|
arg]
|
|
[(font-size)
|
|
(check-arg fn-name (and (integer? arg) (<= 1 arg 255)) 'font-size i arg)
|
|
arg]
|
|
[(face)
|
|
(check-arg fn-name (or (not arg) (string? arg)) 'face i arg)
|
|
arg]
|
|
[(family)
|
|
(check-arg fn-name (memq arg '(default decorative roman script swiss modern symbol system)) 'family i arg)
|
|
arg]
|
|
[(style)
|
|
(check-arg fn-name (memq arg '(normal italic slant)) 'style i arg)
|
|
arg]
|
|
[(weight)
|
|
(check-arg fn-name (memq arg '(normal bold light)) 'weight i arg)
|
|
arg]
|
|
[(underline)
|
|
(and arg #t)]
|
|
[(posns)
|
|
(check-arg fn-name
|
|
(and (list? arg)
|
|
(andmap posn? arg))
|
|
'list-of-posns
|
|
i arg)
|
|
(check-arg fn-name
|
|
(>= (length arg) 3)
|
|
'list-of-at-least-three-posns
|
|
i arg)
|
|
arg]
|
|
[(int0-255-1 int0-255-2 int0-255-3)
|
|
(check-arg fn-name (and (integer? arg) (<= 0 arg 255))
|
|
'integer\ between\ 0\ and\ 255 i arg)
|
|
arg]
|
|
[(real-0-255)
|
|
(check-arg fn-name (and (integer? arg) (<= 0 arg 255))
|
|
'real\ number\ between\ 0\ and\ 255 i arg)
|
|
arg]
|
|
|
|
[(pen-style)
|
|
(check-arg fn-name (pen-style? arg) 'pen-style i arg)
|
|
(if (string? arg)
|
|
(string->symbol arg)
|
|
arg)]
|
|
[(pen-cap)
|
|
(check-arg fn-name (pen-cap? arg) 'pen-cap i arg)
|
|
(if (string? arg)
|
|
(string->symbol arg)
|
|
arg)]
|
|
[(pen-join)
|
|
(check-arg fn-name (pen-join? arg) 'pen-join i arg)
|
|
(if (string? arg)
|
|
(string->symbol arg)
|
|
arg)]
|
|
[else
|
|
(error 'check "the function ~a has an argument with an unknown name: ~s"
|
|
fn-name
|
|
argname)]))
|
|
|
|
(define (y-place? arg)
|
|
(member arg '("top" top "bottom" bottom "middle" middle "center" center "baseline" baseline)))
|
|
(define (x-place? arg)
|
|
(member arg '("left" left "right" right "middle" middle "center" center)))
|
|
(define (mode? arg)
|
|
(member arg '(solid outline "solid" "outline")))
|
|
(define (angle? arg)
|
|
(and (real? arg)
|
|
(< -360 arg 360)))
|
|
(define (side-count? i)
|
|
(and (integer? i)
|
|
(3 . <= . i)))
|
|
(define (step-count? i)
|
|
(and (integer? i)
|
|
(1 . <= . i)))
|
|
(define (image-color? c) (or (symbol? c) (string? c) (color? c)))
|
|
(define (pen-style? arg)
|
|
(member (if (string? arg) (string->symbol arg) arg)
|
|
'(solid dot long-dash short-dash dot-dash)))
|
|
(define (pen-cap? arg)
|
|
(member (if (string? arg) (string->symbol arg) arg)
|
|
'(round projecting butt)))
|
|
(define (pen-join? arg)
|
|
(member (if (string? arg) (string->symbol arg) arg)
|
|
'(round bevel miter)))
|
|
|
|
(define (to-img arg)
|
|
(cond
|
|
[(is-a? arg image-snip%) (image-snip->image arg)]
|
|
[(is-a? arg bitmap%) (bitmap->image arg)]
|
|
[else arg]))
|
|
|
|
(define (image-snip->image is)
|
|
(bitmap->image (send is get-bitmap)
|
|
(or (send is get-bitmap-mask)
|
|
(send (send is get-bitmap) get-loaded-mask))))
|
|
|
|
(define (bitmap->image bm [mask-bm (send bm get-loaded-mask)])
|
|
(let ([w (send bm get-width)]
|
|
[h (send bm get-height)])
|
|
(make-image (make-translate (/ w 2)
|
|
(/ h 2)
|
|
(make-bitmap bm mask-bm 0 1 1 #f #f))
|
|
(make-bb w h h)
|
|
#f)))
|
|
|
|
|
|
;; checks the dependent part of the 'color' specification
|
|
(define (check-mode/color-combination fn-name i mode color)
|
|
(cond
|
|
[(eq? mode 'solid)
|
|
(check-arg fn-name (image-color? color) 'image-color i color)]
|
|
[(eq? mode 'outline)
|
|
(void)])) |