racket/collects/redex/private/arrow.ss
2009-02-17 16:14:12 +00:00

133 lines
4.9 KiB
Scheme

#lang scheme/base
(require texpict/mrpict
scheme/gui/base
scheme/class
scheme/contract)
(provide/contract
[make-arrow-pict
(-> string?
(symbols 'curvy 'straight 'straight-double 'map)
symbol?
number?
(-> pict?))])
(define (make-arrow-pict sample-str style font-family font-size)
(let ([ans #f])
(λ ()
(or ans
(begin
(set! ans (raw-make-arrow-pict sample-str style font-family font-size))
ans)))))
(define (raw-make-arrow-pict sample-str style font-family font-size)
(let-values ([(w h d a) (send (dc-for-text-size) get-text-extent sample-str
(send the-font-list
find-or-create-font
font-size
font-family
'normal
'normal))])
(let* ([ps-pen-width-factor 0.042] ;; factor of the height to get the pen width
[screen-pen-width-factor .08]
[line-pos (+ a (/ (- h a) 2))]
[head-width (/ w 5)]
[head-height (* (- h a) 9/16)]
[path (and (eq? style 'curvy)
(let* ([b (blank w (- h a d) d)]
[a-sz (* head-width 1)]
[p (new dc-path%)]
[inc (/ (- w head-width) 3)])
(send p move-to 0 line-pos)
(let ([y (- line-pos (/ a-sz 2))])
(send p curve-to
0 line-pos
(/ inc 2) y
inc y)
(let ([y2 (+ line-pos (/ a-sz 2))])
(send p curve-to
(* 3/2 inc) y
(* 3/2 inc) y2
(* 2 inc) y2)
(send p curve-to
(* 5/2 inc) y2
(* 5/2 inc) line-pos
(* 3 inc) line-pos)
(send p line-to w line-pos)))
p))])
(inset
(dc
(λ (dc dx dy)
(let ([old-pen (send dc get-pen)]
[old-brush (send dc get-brush)]
[pen-width-factor
(if (or (is-a? dc printer-dc%)
(is-a? dc post-script-dc%))
ps-pen-width-factor
screen-pen-width-factor)])
(send dc set-pen (send old-pen get-color) (* h pen-width-factor) 'solid)
;; main line of arrow
(case style
[(curvy)
(send dc draw-path path dx dy)]
[(map)
(send dc draw-line
dx
(- (+ dy line-pos) (/ head-height 2))
dx
(+ (+ dy line-pos) (/ head-height 2)))
(send dc draw-line
dx
(+ dy line-pos)
(+ dx w)
(+ dy line-pos))]
[(straight)
(send dc draw-line
dx
(+ dy line-pos)
(+ dx w)
(+ dy line-pos))]
[(straight-double)
(send dc draw-line
dx
(+ dy line-pos -1)
(+ dx w -2)
(+ dy line-pos -1))
(send dc draw-line
dx
(+ dy line-pos 1)
(+ dx w -2)
(+ dy line-pos 1))])
(unless (eq? style 'straight-double)
;; when a single line arrow, make the arrow head's lines a tiny bit thinner
(send dc set-pen (send old-pen get-color) (* h pen-width-factor .8) 'solid))
;; upper line of arrowhead
(send dc draw-spline
(+ dx w)
(+ dy line-pos)
(+ dx w (- head-width) (* head-width 1/5))
(+ dy line-pos (- (* head-height 4/16)))
(+ dx w (- head-width))
(+ dy line-pos (- (/ head-height 2))))
;; lower line of arrowhead
(send dc draw-spline
(+ dx w)
(+ dy line-pos)
(+ dx w (- head-width) (* head-width 1/5))
(+ dy line-pos (+ (* head-height 4/16)))
(+ dx w (- head-width))
(+ dy line-pos (+ (/ head-height 2))))
(send dc set-pen old-pen)
(send dc set-brush old-brush)))
w h (- h d) d)
2 0))))