move racket/draw overview to the Guide and expand it
--- plus some minor collateral API improvements
This commit is contained in:
parent
0b19c6e798
commit
8b3165d55b
|
@ -28,24 +28,40 @@
|
|||
(properties #:check-immutable check-immutable
|
||||
[[brush-style-symbol? style] 'solid])
|
||||
|
||||
(init-rest args)
|
||||
(super-new)
|
||||
(init [(_color color) black]
|
||||
[(_style style) 'solid]
|
||||
[(_stipple stipple) #f])
|
||||
|
||||
(case-args
|
||||
args
|
||||
[() (void)]
|
||||
[([color% _color]
|
||||
[brush-style-symbol? _style])
|
||||
(set! color (color->immutable-color _color))
|
||||
(set! style _style)]
|
||||
[([string? _color]
|
||||
[brush-style-symbol? _style])
|
||||
(set! color (send the-color-database find-color _color))
|
||||
(set! style _style)]
|
||||
(init-name 'brush%))
|
||||
(set! color
|
||||
(cond
|
||||
[(string? _color) (or (send the-color-database find-color _color) black)]
|
||||
[(color . is-a? . color%)
|
||||
(color->immutable-color _color)]
|
||||
[else
|
||||
(raise-type-error (init-name 'brush%)
|
||||
"string or color%"
|
||||
_color)]))
|
||||
|
||||
(set! style
|
||||
(if (brush-style-symbol? _style)
|
||||
_style
|
||||
(raise-type-error (init-name 'brush%)
|
||||
"brush style symbol"
|
||||
_style)))
|
||||
|
||||
(define immutable? #f)
|
||||
(define lock-count 0)
|
||||
(define stipple #f)
|
||||
|
||||
(when _stipple
|
||||
(unless (_stipple . is-a? . bitmap%)
|
||||
(raise-type-error (init-name 'brush%)
|
||||
"bitmap% or #f"
|
||||
_stipple))
|
||||
(set-stipple _stipple))
|
||||
|
||||
(super-new)
|
||||
|
||||
(define/public (set-immutable) (set! immutable? #t))
|
||||
(define/public (is-immutable?) (or immutable? (positive? lock-count)))
|
||||
(define/public (adjust-lock v) (set! lock-count (+ lock-count v)))
|
||||
|
@ -71,7 +87,6 @@
|
|||
|
||||
(define/public (get-color) color)
|
||||
|
||||
(define stipple #f)
|
||||
(def/public (get-stipple) stipple)
|
||||
(def/public (set-stipple [(make-or-false bitmap%) s])
|
||||
(check-immutable 'set-stipple)
|
||||
|
@ -95,7 +110,8 @@
|
|||
(values (color->immutable-color _color) _style)]
|
||||
[([string? _color]
|
||||
[brush-style-symbol? _style])
|
||||
(values (send the-color-database find-color _color)
|
||||
(values (or (send the-color-database find-color _color)
|
||||
black)
|
||||
_style)]
|
||||
(method-name 'find-or-create-brush 'brush-list%))])
|
||||
(let ([key (vector (send col red) (send col green) (send col blue)
|
||||
|
|
|
@ -36,15 +36,20 @@
|
|||
|
||||
(define 2pi (* 2 pi))
|
||||
|
||||
(define black (send the-color-database find-color "black"))
|
||||
|
||||
(define (copy-color c)
|
||||
(if (send c is-immutable?)
|
||||
c
|
||||
(let ([c (make-object color%
|
||||
(color-red c)
|
||||
(color-green c)
|
||||
(color-blue c))])
|
||||
(send c set-immutable)
|
||||
c)))
|
||||
(if (string? c)
|
||||
(or (send the-color-database find-color c)
|
||||
black)
|
||||
(if (send c is-immutable?)
|
||||
c
|
||||
(let ([c (make-object color%
|
||||
(color-red c)
|
||||
(color-green c)
|
||||
(color-blue c))])
|
||||
(send c set-immutable)
|
||||
c))))
|
||||
|
||||
(define -bitmap-dc% #f)
|
||||
(define (install-bitmap-dc-class! v) (set! -bitmap-dc% v))
|
||||
|
@ -268,7 +273,6 @@
|
|||
(define contexts (make-vector (vector-length font-maps) #f))
|
||||
(define desc-layoutss (make-vector (vector-length font-maps) #f))
|
||||
|
||||
(define black (send the-color-database find-color "black"))
|
||||
(define pen (send the-pen-list find-or-create-pen "black" 1 'solid))
|
||||
(define brush (send the-brush-list find-or-create-brush "white" 'solid))
|
||||
(define font (send the-font-list find-or-create-font 12 'default))
|
||||
|
@ -554,11 +558,11 @@
|
|||
(define/private (brush-draws?)
|
||||
(not (eq? (send brush get-style) 'transparent)))
|
||||
|
||||
(def/public (set-text-foreground [color% c])
|
||||
(def/public (set-text-foreground [(make-alts color% string?) c])
|
||||
(set! text-fg (copy-color c)))
|
||||
(def/public (set-text-background [color% c])
|
||||
(def/public (set-text-background [(make-alts color% string?) c])
|
||||
(set! text-bg (copy-color c)))
|
||||
(def/public (set-background [color% c])
|
||||
(def/public (set-background [(make-alts color% string?) c])
|
||||
(set! pen-stipple-s #f)
|
||||
(set! brush-stipple-s #f)
|
||||
(set! bg (copy-color c)))
|
||||
|
|
|
@ -42,33 +42,58 @@
|
|||
[[pen-style-symbol? style] 'solid]
|
||||
[[pen-width? width] 0])
|
||||
|
||||
(init-rest args)
|
||||
(super-new)
|
||||
(init [(_color color) black]
|
||||
[(_width width) 0]
|
||||
[(_style style) 'solid]
|
||||
[(_cap cap) 'round]
|
||||
[(_join join) 'round]
|
||||
[(_stipple stipple) #f])
|
||||
|
||||
(case-args
|
||||
args
|
||||
[() (void)]
|
||||
[([color% _color]
|
||||
[pen-width? _width]
|
||||
[pen-style-symbol? _style]
|
||||
[pen-cap-symbol? [_cap 'round]]
|
||||
[pen-join-symbol? [_join 'round]])
|
||||
(set! color (color->immutable-color _color))
|
||||
(set! width _width)
|
||||
(set! style _style)
|
||||
(set! cap _cap)
|
||||
(set! join _join)]
|
||||
[([string? _color]
|
||||
[pen-width? _width]
|
||||
[pen-style-symbol? _style]
|
||||
[pen-cap-symbol? [_cap 'round]]
|
||||
[pen-join-symbol? [_join 'round]])
|
||||
(set! color (send the-color-database find-color _color))
|
||||
(set! width _width)
|
||||
(set! style _style)
|
||||
(set! cap _cap)
|
||||
(set! join _join)]
|
||||
(init-name 'pen%))
|
||||
(set! color
|
||||
(cond
|
||||
[(string? _color) (or (send the-color-database find-color _color) black)]
|
||||
[(color . is-a? . color%)
|
||||
(color->immutable-color _color)]
|
||||
[else
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"string or color%"
|
||||
_color)]))
|
||||
(set! width
|
||||
(if (pen-width? _width)
|
||||
_width
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"real in [0, 255]"
|
||||
_width)))
|
||||
|
||||
(set! style
|
||||
(if (pen-style-symbol? _style)
|
||||
_style
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"pen style symbol"
|
||||
_style)))
|
||||
|
||||
(set! cap
|
||||
(if (pen-cap-symbol? _cap)
|
||||
_cap
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"pen cap symbol"
|
||||
_cap)))
|
||||
|
||||
(set! join
|
||||
(if (pen-join-symbol? _join)
|
||||
_join
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"pen join symbol"
|
||||
_join)))
|
||||
|
||||
(when _stipple
|
||||
(unless (_stipple . is-a? . bitmap%)
|
||||
(raise-type-error (init-name 'pen%)
|
||||
"bitmap% or #f"
|
||||
_stipple))
|
||||
(set-stipple _stipple))
|
||||
|
||||
(super-new)
|
||||
|
||||
(define immutable? #f)
|
||||
(define lock-count 0)
|
||||
|
@ -78,7 +103,7 @@
|
|||
|
||||
(define/private (check-immutable s)
|
||||
(when (or immutable? (positive? lock-count))
|
||||
(error (method-name 'brush% s) "object is ~a"
|
||||
(error (method-name 'pen% s) "object is ~a"
|
||||
(if immutable? "immutable" "locked"))))
|
||||
|
||||
(define/public (set-color . args)
|
||||
|
@ -128,7 +153,8 @@
|
|||
[pen-style-symbol? _style]
|
||||
[pen-cap-symbol? [_cap 'round]]
|
||||
[pen-join-symbol? [_join 'round]])
|
||||
(values (send the-color-database find-color _color)
|
||||
(values (or (send the-color-database find-color _color)
|
||||
black)
|
||||
_width _style _cap _join)]
|
||||
(method-name 'find-or-create-pen 'pen-list%))])
|
||||
(let ([key (vector (send col red) (send col green) (send col blue)
|
||||
|
|
|
@ -145,50 +145,56 @@
|
|||
[(syntax? s) (loop (syntax-e s) ops)]
|
||||
[else (loop ((car ops) s) (cdr ops))])))
|
||||
|
||||
(define ((do-eval ev) s)
|
||||
(define (extract-to-evaluate s)
|
||||
(let loop ([s s][expect #f])
|
||||
(syntax-case s (code:comment eval:alts eval:check)
|
||||
[(code:line v (code:comment . rest))
|
||||
(loop (extract s cdr car) expect)]
|
||||
[(code:comment . rest)
|
||||
(list (list (void)) "" "")]
|
||||
(values #f expect)]
|
||||
[(eval:alts p e)
|
||||
(loop (extract s cdr cdr car) expect)]
|
||||
[(eval:check e expect)
|
||||
(loop (extract s cdr car)
|
||||
(list (syntax->datum (datum->syntax #f (extract s cdr cdr car)))))]
|
||||
[else
|
||||
(let ([r (with-handlers ([(lambda (x)
|
||||
(not (exn:break? x)))
|
||||
(lambda (e)
|
||||
(list (if (exn? e)
|
||||
(exn-message e)
|
||||
(format "uncaught exception: ~s" e))
|
||||
(get-output ev)
|
||||
(get-error-output ev)))])
|
||||
(list (let ([v (do-plain-eval ev s #t)])
|
||||
(if (call-in-sandbox-context
|
||||
ev
|
||||
(let ([cp (current-print)])
|
||||
(lambda ()
|
||||
(and (eq? (current-print) cp)
|
||||
(print-as-expression)))))
|
||||
(make-reader-graph (copy-value v (make-hasheq)))
|
||||
(box
|
||||
(call-in-sandbox-context
|
||||
(values s expect)])))
|
||||
|
||||
(define ((do-eval ev) s)
|
||||
(let-values ([(s expect) (extract-to-evaluate s)])
|
||||
(if s
|
||||
(let ([r (with-handlers ([(lambda (x)
|
||||
(not (exn:break? x)))
|
||||
(lambda (e)
|
||||
(list (if (exn? e)
|
||||
(exn-message e)
|
||||
(format "uncaught exception: ~s" e))
|
||||
(get-output ev)
|
||||
(get-error-output ev)))])
|
||||
(list (let ([v (do-plain-eval ev s #t)])
|
||||
(if (call-in-sandbox-context
|
||||
ev
|
||||
(lambda ()
|
||||
(let ([s (open-output-string)])
|
||||
(parameterize ([current-output-port s])
|
||||
(map (current-print) v))
|
||||
(get-output-string s)))))))
|
||||
(get-output ev)
|
||||
(get-error-output ev)))])
|
||||
(when expect
|
||||
(let ([expect (do-plain-eval ev (car expect) #t)])
|
||||
(unless (equal? (car r) expect)
|
||||
(raise-syntax-error 'eval "example result check failed" s))))
|
||||
r)])))
|
||||
(let ([cp (current-print)])
|
||||
(lambda ()
|
||||
(and (eq? (current-print) cp)
|
||||
(print-as-expression)))))
|
||||
(make-reader-graph (copy-value v (make-hasheq)))
|
||||
(box
|
||||
(call-in-sandbox-context
|
||||
ev
|
||||
(lambda ()
|
||||
(let ([s (open-output-string)])
|
||||
(parameterize ([current-output-port s])
|
||||
(map (current-print) v))
|
||||
(get-output-string s)))))))
|
||||
(get-output ev)
|
||||
(get-error-output ev)))])
|
||||
(when expect
|
||||
(let ([expect (do-plain-eval ev (car expect) #t)])
|
||||
(unless (equal? (car r) expect)
|
||||
(raise-syntax-error 'eval "example result check failed" s))))
|
||||
r)
|
||||
(values (list (list (void)) "" "")))))
|
||||
|
||||
|
||||
(define (install ht v v2)
|
||||
|
@ -337,9 +343,11 @@
|
|||
(define-syntax-rule (quote-expr e) 'e)
|
||||
|
||||
(define (do-interaction-eval ev e)
|
||||
(parameterize ([current-command-line-arguments #()])
|
||||
(do-plain-eval (or ev (make-base-eval)) e #f))
|
||||
"")
|
||||
(let-values ([(e expect) (extract-to-evaluate e)])
|
||||
(when e
|
||||
(parameterize ([current-command-line-arguments #()])
|
||||
(do-plain-eval (or ev (make-base-eval)) e #f)))
|
||||
""))
|
||||
|
||||
(define-syntax interaction-eval
|
||||
(syntax-rules ()
|
||||
|
|
|
@ -86,22 +86,18 @@ To avoid creating multiple brushes with the same characteristics, use
|
|||
@xmethod[dc<%> set-brush].
|
||||
|
||||
|
||||
@defconstructor*/make[(()
|
||||
([color (is-a?/c color%)]
|
||||
[style (one-of/c 'transparent 'solid 'opaque
|
||||
'xor 'hilite 'panel
|
||||
'bdiagonal-hatch 'crossdiag-hatch
|
||||
'fdiagonal-hatch 'cross-hatch
|
||||
'horizontal-hatch 'vertical-hatch)])
|
||||
([color-name string?]
|
||||
[style (one-of/c 'transparent 'solid 'opaque
|
||||
'xor 'hilite 'panel
|
||||
'bdiagonal-hatch 'crossdiag-hatch
|
||||
'fdiagonal-hatch 'cross-hatch
|
||||
'horizontal-hatch 'vertical-hatch)]))]{
|
||||
@defconstructor[([color (or/c string? (is-a?/c color%)) "black"]
|
||||
[style (one-of/c 'transparent 'solid 'opaque
|
||||
'xor 'hilite 'panel
|
||||
'bdiagonal-hatch 'crossdiag-hatch
|
||||
'fdiagonal-hatch 'cross-hatch
|
||||
'horizontal-hatch 'vertical-hatch)
|
||||
'solid]
|
||||
[stipple (or/c #f (is-a?/c bitmap%))
|
||||
#f])]{
|
||||
|
||||
When no argument are provided, the result is a solid black brush.
|
||||
Otherwise, the result is a brush with the given color and style. For
|
||||
Otherwise, the result is a brush with the given color, style, and stipple. For
|
||||
the case that the color is specified using a name, see
|
||||
@scheme[color-database<%>] for information about color names; if the
|
||||
name is not known, the brush's color is black.
|
||||
|
|
|
@ -11,12 +11,35 @@
|
|||
@racketmodname[racket/draw] library provides all of the class,
|
||||
interface, and procedure bindings defined in this manual.}
|
||||
|
||||
For an overview of the drawing library, see @secref["draw" #:doc
|
||||
'(lib "scribblings/guide/guide.scrbl")].
|
||||
|
||||
@table-of-contents[]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
@include-section["guide.scrbl"]
|
||||
@include-section["reference.scrbl"]
|
||||
@include-section["bitmap-class.scrbl"]
|
||||
@include-section["bitmap-dc-class.scrbl"]
|
||||
@include-section["brush-class.scrbl"]
|
||||
@include-section["brush-list-class.scrbl"]
|
||||
@include-section["color-class.scrbl"]
|
||||
@include-section["color-database-intf.scrbl"]
|
||||
@include-section["dc-intf.scrbl"]
|
||||
@include-section["dc-path-class.scrbl"]
|
||||
@include-section["font-class.scrbl"]
|
||||
@include-section["font-list-class.scrbl"]
|
||||
@include-section["font-name-directory-intf.scrbl"]
|
||||
@include-section["gl-config-class.scrbl"]
|
||||
@include-section["gl-context-intf.scrbl"]
|
||||
@include-section["pdf-dc-class.scrbl"]
|
||||
@include-section["pen-class.scrbl"]
|
||||
@include-section["pen-list-class.scrbl"]
|
||||
@include-section["point-class.scrbl"]
|
||||
@include-section["post-script-dc-class.scrbl"]
|
||||
@include-section["ps-setup-class.scrbl"]
|
||||
@include-section["region-class.scrbl"]
|
||||
@include-section["draw-funcs.scrbl"]
|
||||
@include-section["draw-unit.scrbl"]
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,227 +0,0 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/eval
|
||||
"common.ss")
|
||||
|
||||
@title[#:tag "overview"]{Overview}
|
||||
|
||||
Drawing with @racketmodname[racket/draw] uses a @deftech{device context}
|
||||
(@deftech{DC}), which is an instance of the @scheme[dc<%>]
|
||||
interface. For example, the @racket[post-script-dc%] class implements
|
||||
a @racket[dc<%>] for drawing to a PostScript file, while @racket[bitmap-dc%]
|
||||
draws to a bitmap. When using the @racketmodname[racket/gui] library for GUIs,
|
||||
the @method[canvas<%> get-dc] method of a
|
||||
canvas returns a @scheme[dc<%>] instance for drawing into the canvas
|
||||
window.
|
||||
|
||||
Tools that are used for drawing include the following: @scheme[pen%]
|
||||
objects for drawing lines and shape outlines, @scheme[brush%]
|
||||
objects for filling shapes, @scheme[bitmap%] objects for storing
|
||||
bitmaps, and @scheme[dc-path%] objects for describing paths to draw
|
||||
and fill.
|
||||
|
||||
The following example uses the GUI library as well as the drawing
|
||||
library. It creates a frame with a drawing canvas, and then draws a
|
||||
round, blue face with square, yellow eyes and a smiling, red mouth:
|
||||
|
||||
@schemeblock[
|
||||
(code:comment @#,t{Make some pens and brushes})
|
||||
(define no-pen (make-object pen% "BLACK" 1 'transparent))
|
||||
(define no-brush (make-object brush% "BLACK" 'transparent))
|
||||
(define blue-brush (make-object brush% "BLUE" 'solid))
|
||||
(define yellow-brush (make-object brush% "YELLOW" 'solid))
|
||||
(define red-pen (make-object pen% "RED" 2 'solid))
|
||||
|
||||
(code:comment @#,t{Define a procedure to draw a face})
|
||||
(define (draw-face dc)
|
||||
(send dc #,(:: dc<%> set-pen) no-pen)
|
||||
(send dc #,(:: dc<%> set-brush) blue-brush)
|
||||
(send dc #,(:: dc<%> draw-ellipse) 50 50 200 200)
|
||||
|
||||
(send dc #,(:: dc<%> set-brush) yellow-brush)
|
||||
(send dc #,(:: dc<%> draw-rectangle) 100 100 10 10)
|
||||
(send dc #,(:: dc<%> draw-rectangle) 200 100 10 10)
|
||||
|
||||
(send dc #,(:: dc<%> set-brush) no-brush)
|
||||
(send dc #,(:: dc<%> set-pen) red-pen)
|
||||
(let ([-pi (atan 0 -1)])
|
||||
(send dc #,(:: dc<%> draw-arc) 75 75 150 150 (* 5/4 -pi) (* 7/4 -pi))))
|
||||
|
||||
(code:comment @#,t{Make a 300 x 300 frame})
|
||||
(define frame (new frame% [label "Drawing Example"]
|
||||
[width 300]
|
||||
[height 300]))
|
||||
(code:comment @#,t{Make the drawing area, and set its paint callback})
|
||||
(code:comment @#,t{to use the @racket[draw-face] function:})
|
||||
(define canvas (new canvas%
|
||||
[parent frame]
|
||||
[paint-callback (lambda (c dc) (draw-face dc))]))
|
||||
|
||||
(code:comment @#,t{Show the frame})
|
||||
(send frame #,(:: top-level-window<%> show) #t)
|
||||
]
|
||||
|
||||
Suppose that @scheme[draw-face] creates a particularly complex face that
|
||||
takes a long time to draw. We might want to draw the face once into
|
||||
an offscreen bitmap, and then have the paint callback copy the cached
|
||||
bitmap image onto the canvas whenever the canvas is updated. To draw
|
||||
into a bitmap, we first create a @scheme[bitmap%] object, and then
|
||||
we create a @scheme[bitmap-dc%] to direct drawing commands into the
|
||||
bitmap:
|
||||
|
||||
@schemeblock[
|
||||
(code:comment @#,t{... pens, brushes, and @scheme[draw-face] are the same as above ...})
|
||||
|
||||
(code:comment @#,t{Create a 300 x 300 bitmap})
|
||||
(define face-bitmap (make-object bitmap% 300 300))
|
||||
(code:comment @#,t{Create a drawing context for the bitmap})
|
||||
(define bm-dc (make-object bitmap-dc% face-bitmap))
|
||||
(code:comment @#,t{A bitmap's initial content is undefined; clear it before drawing})
|
||||
(send bm-dc #,(:: dc<%> clear))
|
||||
|
||||
(code:comment @#,t{Draw the face into the bitmap})
|
||||
(draw-face bm-dc)
|
||||
|
||||
(code:comment @#,t{Make a 300 x 300 frame})
|
||||
(define frame (new frame% [label "Drawing Example"]
|
||||
[width 300]
|
||||
[height 300]))
|
||||
|
||||
(code:comment @#,t{Make a drawing area whose paint callback copies the bitmap})
|
||||
(define canvas
|
||||
(new canvas% [parent frame]
|
||||
[paint-callback
|
||||
(lambda (canvas dc)
|
||||
(send dc #,(:: dc<%> draw-bitmap) face-bitmap 0 0))]))
|
||||
|
||||
(code:comment @#,t{Show the frame})
|
||||
(send frame #,(:: top-level-window<%> show) #t)
|
||||
]
|
||||
|
||||
For all types of DCs, the drawing origin is the top-left corner of the
|
||||
DC. When drawing to a window or bitmap, DC units initially correspond
|
||||
to pixels, but the @method[dc<%> set-scale] method changes the
|
||||
scale. When drawing to a PostScript or printer device, DC units
|
||||
initially correspond to points (1/72 of an inch).
|
||||
|
||||
More complex shapes are typically best implemented with
|
||||
@deftech{paths}. The following example uses paths to draw the
|
||||
Racket logo. It also enables smoothing, so that the logo's curves are
|
||||
anti-aliased when smoothing is available. (Smoothing is always
|
||||
available under Mac OS X, smoothing is available under Windows XP or
|
||||
when @filepath{gdiplus.dll} is installed, and smoothing is available
|
||||
under X when Cairo is installed before GRacket is compiled.)
|
||||
|
||||
@(begin
|
||||
#readerscribble/comment-reader
|
||||
[schemeblock
|
||||
(require racket/math) ; for @scheme[pi]
|
||||
|
||||
;; Construct paths for a 630 x 630 logo
|
||||
|
||||
(define left-lambda-path ;; left side of the lambda
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% move-to) 153 44)
|
||||
(send p #,(:: dc-path% line-to) 161.5 60)
|
||||
(send p #,(:: dc-path% curve-to) 202.5 49 230 42 245 61)
|
||||
(send p #,(:: dc-path% curve-to) 280.06 105.41 287.5 141 296.5 186)
|
||||
(send p #,(:: dc-path% curve-to) 301.12 209.08 299.11 223.38 293.96 244)
|
||||
(send p #,(:: dc-path% curve-to) 281.34 294.54 259.18 331.61 233.5 375)
|
||||
(send p #,(:: dc-path% curve-to) 198.21 434.63 164.68 505.6 125.5 564)
|
||||
(send p #,(:: dc-path% line-to) 135 572)
|
||||
p))
|
||||
|
||||
(define left-logo-path ;; left side of the lambda and circle
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% append) left-lambda-path)
|
||||
(send p #,(:: dc-path% arc) 0 0 630 630 (* 235/360 2 pi) (* 121/360 2 pi) #f)
|
||||
p))
|
||||
|
||||
(define bottom-lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% move-to) 135 572)
|
||||
(send p #,(:: dc-path% line-to) 188.5 564)
|
||||
(send p #,(:: dc-path% curve-to) 208.5 517 230.91 465.21 251 420)
|
||||
(send p #,(:: dc-path% curve-to) 267 384 278.5 348 296.5 312)
|
||||
(send p #,(:: dc-path% curve-to) 301.01 302.98 318 258 329 274)
|
||||
(send p #,(:: dc-path% curve-to) 338.89 288.39 351 314 358 332)
|
||||
(send p #,(:: dc-path% curve-to) 377.28 381.58 395.57 429.61 414 477)
|
||||
(send p #,(:: dc-path% curve-to) 428 513 436.5 540 449.5 573)
|
||||
(send p #,(:: dc-path% line-to) 465 580)
|
||||
(send p #,(:: dc-path% line-to) 529 545)
|
||||
p))
|
||||
|
||||
(define bottom-logo-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% append) bottom-lambda-path)
|
||||
(send p #,(:: dc-path% arc) 0 0 630 630 (* 314/360 2 pi) (* 235/360 2 pi) #f)
|
||||
p))
|
||||
|
||||
(define right-lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% move-to) 153 44)
|
||||
(send p #,(:: dc-path% curve-to) 192.21 30.69 233.21 14.23 275 20)
|
||||
(send p #,(:: dc-path% curve-to) 328.6 27.4 350.23 103.08 364 151)
|
||||
(send p #,(:: dc-path% curve-to) 378.75 202.32 400.5 244 418 294)
|
||||
(send p #,(:: dc-path% curve-to) 446.56 375.6 494.5 456 530.5 537)
|
||||
(send p #,(:: dc-path% line-to) 529 545)
|
||||
p))
|
||||
|
||||
(define right-logo-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% append) right-lambda-path)
|
||||
(send p #,(:: dc-path% arc) 0 0 630 630 (* 314/360 2 pi) (* 121/360 2 pi) #t)
|
||||
p))
|
||||
|
||||
(define lambda-path ;; the lambda by itself (no circle)
|
||||
(let ([p (new dc-path%)])
|
||||
(send p #,(:: dc-path% append) left-lambda-path)
|
||||
(send p #,(:: dc-path% append) bottom-lambda-path)
|
||||
(let ([t (make-object dc-path%)])
|
||||
(send t #,(:: dc-path% append) right-lambda-path)
|
||||
(send t #,(:: dc-path% reverse))
|
||||
(send p #,(:: dc-path% append) t))
|
||||
(send p #,(:: dc-path% close))
|
||||
p))
|
||||
|
||||
;; This function draws the paths with suitable colors:
|
||||
(define (paint-plt dc)
|
||||
;; Paint white lambda, no outline:
|
||||
(send dc #,(:: dc<%> set-pen) "BLACK" 0 'transparent)
|
||||
(send dc #,(:: dc<%> set-brush) "WHITE" 'solid)
|
||||
(send dc #,(:: dc<%> draw-path) lambda-path)
|
||||
;; Paint outline and colors...
|
||||
(send dc #,(:: dc<%> set-pen) "BLACK" 0 'solid)
|
||||
;; Draw red regions
|
||||
(send dc #,(:: dc<%> set-brush) "RED" 'solid)
|
||||
(send dc #,(:: dc<%> draw-path) left-logo-path)
|
||||
(send dc #,(:: dc<%> draw-path) bottom-logo-path)
|
||||
;; Draw blue region
|
||||
(send dc #,(:: dc<%> set-brush) "BLUE" 'solid)
|
||||
(send dc #,(:: dc<%> draw-path) right-logo-path))
|
||||
|
||||
;; Create a frame to display the logo on a light-purple background:
|
||||
(define f (new frame% [label "Racket Logo"]))
|
||||
(define c
|
||||
(new canvas%
|
||||
[parent f]
|
||||
[paint-callback
|
||||
(lambda (c dc)
|
||||
(send dc #,(:: dc<%> set-background) (make-object color% 220 200 255))
|
||||
(send dc #,(:: dc<%> clear))
|
||||
(send dc #,(:: dc<%> set-smoothing) 'smoothed)
|
||||
(send dc #,(:: dc<%> set-origin) 5 5)
|
||||
(send dc #,(:: dc<%> set-scale) 0.5 0.5)
|
||||
(paint-plt dc))]))
|
||||
(send c #,(:: canvas<%> min-client-width) (/ 650 2))
|
||||
(send c #,(:: canvas<%> min-client-height) (/ 650 2))
|
||||
(send f show #t)
|
||||
])
|
||||
|
||||
Drawing effects are not completely portable across platforms or across
|
||||
types of DC. Drawing in smoothed mode tends to produce more reliable
|
||||
and portable results than in unsmoothed mode, and drawing with paths
|
||||
tends to produce more reliable results even in unsmoothed
|
||||
mode. Drawing with a pen of width 0 or 1 in unsmoothed mode in an
|
||||
unscaled DC produces relatively consistent results for all platforms,
|
||||
but a pen width of 2 or drawing to a scaled DC looks significantly
|
||||
different in unsmoothed mode on different platforms and destinations.
|
|
@ -89,27 +89,24 @@ A pen of size @scheme[0] uses the minimum line size for the
|
|||
|
||||
|
||||
|
||||
@defconstructor*/make[(()
|
||||
([color (is-a?/c color%)]
|
||||
[width (real-in 0 255)]
|
||||
[style (one-of/c 'transparent 'solid 'xor 'hilite
|
||||
'dot 'long-dash 'short-dash 'dot-dash
|
||||
'xor-dot 'xor-long-dash 'xor-short-dash
|
||||
'xor-dot-dash)]
|
||||
[cap-style (one-of/c 'round 'projecting 'butt)]
|
||||
[join-style (one-of/c 'round 'bevel 'miter)])
|
||||
([color-name string?]
|
||||
[width (real-in 0 255)]
|
||||
[style (one-of/c 'transparent 'solid 'xor 'dot 'hilite
|
||||
'long-dash 'short-dash 'dot-dash
|
||||
'xor-dot 'xor-long-dash 'xor-short-dash
|
||||
'xor-dot-dash)]
|
||||
[cap-style (one-of/c 'round 'projecting 'butt)]
|
||||
[join-style (one-of/c 'round 'bevel 'miter)]))]{
|
||||
@defconstructor[([color (or/c string? (is-a?/c color%)) "black"]
|
||||
[width (real-in 0 255) 0]
|
||||
[style (one-of/c 'transparent 'solid 'xor 'hilite
|
||||
'dot 'long-dash 'short-dash 'dot-dash
|
||||
'xor-dot 'xor-long-dash 'xor-short-dash
|
||||
'xor-dot-dash)
|
||||
'solid]
|
||||
[cap (one-of/c 'round 'projecting 'butt)
|
||||
'round]
|
||||
[join (one-of/c 'round 'bevel 'miter)
|
||||
'round]
|
||||
[stipple (or/c #f (is-a?/c bitmap%))
|
||||
#f])]{
|
||||
|
||||
When no argument are provided, the result is a solid black pen of
|
||||
width @scheme[0]. Otherwise, the result is a pen with the given
|
||||
color, width, style, cap style, and join style. For the case that the color is specified
|
||||
color, width, style, cap style, join style, and stipple.
|
||||
For the case that the color is specified
|
||||
using a name, see @scheme[color-database<%>] for information about
|
||||
color names; if the name is not known, the pen's color is black.
|
||||
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
#lang scribble/doc
|
||||
@(require "common.ss")
|
||||
|
||||
@title[#:style '(toc reveal)]{Reference}
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@include-section["bitmap-class.scrbl"]
|
||||
@include-section["bitmap-dc-class.scrbl"]
|
||||
@include-section["brush-class.scrbl"]
|
||||
@include-section["brush-list-class.scrbl"]
|
||||
@include-section["color-class.scrbl"]
|
||||
@include-section["color-database-intf.scrbl"]
|
||||
@include-section["dc-intf.scrbl"]
|
||||
@include-section["dc-path-class.scrbl"]
|
||||
@include-section["font-class.scrbl"]
|
||||
@include-section["font-list-class.scrbl"]
|
||||
@include-section["font-name-directory-intf.scrbl"]
|
||||
@include-section["gl-config-class.scrbl"]
|
||||
@include-section["gl-context-intf.scrbl"]
|
||||
@include-section["pdf-dc-class.scrbl"]
|
||||
@include-section["pen-class.scrbl"]
|
||||
@include-section["pen-list-class.scrbl"]
|
||||
@include-section["point-class.scrbl"]
|
||||
@include-section["post-script-dc-class.scrbl"]
|
||||
@include-section["ps-setup-class.scrbl"]
|
||||
@include-section["region-class.scrbl"]
|
||||
@include-section["draw-funcs.scrbl"]
|
||||
@include-section["draw-unit.scrbl"]
|
1125
collects/scribblings/gui/dc-intf.scrbl
Normal file
1125
collects/scribblings/gui/dc-intf.scrbl
Normal file
File diff suppressed because it is too large
Load Diff
642
collects/scribblings/guide/draw.scrbl
Normal file
642
collects/scribblings/guide/draw.scrbl
Normal file
|
@ -0,0 +1,642 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
"guide-utils.ss"
|
||||
scribble/eval
|
||||
scribble/racket
|
||||
(for-syntax racket/base)
|
||||
(for-label racket/draw
|
||||
racket/math
|
||||
racket/gui))
|
||||
|
||||
@(define draw-eval (make-base-eval))
|
||||
@interaction-eval[#:eval draw-eval (require racket/class
|
||||
racket/draw)]
|
||||
@interaction-eval[#:eval draw-eval (define (copy-bitmap bm0)
|
||||
(let ([w (send bm0 get-width)]
|
||||
[h (send bm0 get-height)])
|
||||
(let ([bm (make-bitmap w h)])
|
||||
(let ([dc (make-object bitmap-dc% bm)])
|
||||
(send dc draw-bitmap bm0 0 0)
|
||||
(send dc set-bitmap #f))
|
||||
bm)))]
|
||||
@interaction-eval[#:eval draw-eval (define (line-bitmap mode)
|
||||
(let* ([bm (make-bitmap 30 4)]
|
||||
[dc (make-object bitmap-dc% bm)])
|
||||
(send dc set-smoothing mode)
|
||||
(send dc draw-line 0 2 30 2)
|
||||
(send dc set-bitmap #f)
|
||||
bm))]
|
||||
@interaction-eval[#:eval draw-eval (define (path-bitmap zee join brush?)
|
||||
(let* ([bm (make-bitmap 40 40)]
|
||||
[dc (new bitmap-dc% [bitmap bm])])
|
||||
(send dc set-smoothing 'aligned)
|
||||
(send dc set-pen (new pen% [width 5] [join join]))
|
||||
(if brush?
|
||||
(send dc set-brush blue-brush)
|
||||
(send dc set-brush "white" 'transparent))
|
||||
(send dc draw-path zee 5 5)
|
||||
(send dc set-bitmap #f)
|
||||
bm))]
|
||||
|
||||
@(define-syntax-rule (define-linked-method name interface)
|
||||
(define-syntax name
|
||||
(make-element-id-transformer
|
||||
(lambda (stx)
|
||||
#'(method interface name)))))
|
||||
@(define-linked-method draw-line dc<%>)
|
||||
@(define-linked-method draw-rectangle dc<%>)
|
||||
@(define-linked-method set-pen dc<%>)
|
||||
@(define-linked-method set-font dc<%>)
|
||||
@(define-linked-method set-clipping-region dc<%>)
|
||||
@(define-linked-method set-alpha dc<%>)
|
||||
@(define-linked-method get-pen dc<%>)
|
||||
@(define-linked-method set-brush dc<%>)
|
||||
@(define-linked-method get-brush dc<%>)
|
||||
@(define-linked-method set-smoothing dc<%>)
|
||||
@(define-linked-method draw-path dc<%>)
|
||||
@(define-linked-method draw-ellipse dc<%>)
|
||||
@(define-linked-method draw-text dc<%>)
|
||||
@(define-linked-method draw-bitmap dc<%>)
|
||||
@(define-linked-method get-text-extent dc<%>)
|
||||
@(define-linked-method set-text-foreground dc<%>)
|
||||
@(define-linked-method draw-arc dc<%>)
|
||||
@(define-linked-method erase dc<%>)
|
||||
@(define-linked-method set-stipple brush%)
|
||||
@(define-linked-method line-to dc-path%)
|
||||
@(define-linked-method curve-to dc-path%)
|
||||
@(define-linked-method move-to dc-path%)
|
||||
@(define-linked-method append dc-path%)
|
||||
@(define-linked-method arc dc-path%)
|
||||
@(define-linked-method reverse dc-path%)
|
||||
@(define-linked-method ellipse dc-path%)
|
||||
@(define-linked-method translate dc<%>)
|
||||
@(define-linked-method scale dc<%>)
|
||||
@(define-linked-method rotate dc<%>)
|
||||
@(define-linked-method set-path region%)
|
||||
|
||||
@title[#:tag "draw"]{Drawing}
|
||||
|
||||
The @racketmodname[racket/draw] library provides a drawing API that is
|
||||
based on the PostScript drawing model. It supports line drawing, shape
|
||||
filling, bitmap copying, alpha blending, and affine transformations
|
||||
(i.e., scale, rotation, and translation).
|
||||
|
||||
@guideother{See @secref["classes"] for an introduction to classes and
|
||||
interfaces in Racket.}
|
||||
|
||||
Drawing with @racketmodname[racket/draw] requires a @deftech{drawing context}
|
||||
(@deftech{DC}), which is an instance of the @scheme[dc<%>]
|
||||
interface. For example, the @racket[post-script-dc%] class implements
|
||||
a @racket[dc<%>] for drawing to a PostScript file, while @racket[bitmap-dc%]
|
||||
draws to a bitmap. When using the @racketmodname[racket/gui] library for GUIs,
|
||||
the @method[canvas<%> get-dc] method of a
|
||||
canvas returns a @scheme[dc<%>] instance for drawing into the canvas
|
||||
window.
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Lines and Simple Shapes}
|
||||
|
||||
To draw into a bitmap, first create the bitmap with
|
||||
@racket[make-bitmap], and then create a @racket[bitmap-dc%] that draws
|
||||
into the new bitmap:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define target (make-bitmap 30 30)) (code:comment "A 30x30 bitmap")
|
||||
(define dc (new bitmap-dc% [bitmap target]))
|
||||
]
|
||||
|
||||
Then, use methods like @method[dc<%> draw-line] on the @tech{DC} to draw
|
||||
into the bitmap. For example, the sequence
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc draw-rectangle
|
||||
0 10 (code:comment @#,t{Top-left at (0, 10), 10 pixels down from top-left})
|
||||
30 10) (code:comment @#,t{30 pixels wide and 10 pixels high})
|
||||
(send dc draw-line
|
||||
0 0 (code:comment @#,t{Start at (0, 0), the top-left corner})
|
||||
30 30) (code:comment @#,t{and draw to (30, 30), the bottom-right corner})
|
||||
(send dc draw-line
|
||||
0 30 (code:comment @#,t{Start at (0, 30), the bottom-left corner})
|
||||
30 0) (code:comment @#,t{and draw to (30, 0), the top-right corner})
|
||||
]
|
||||
|
||||
draws an ``X'' on top of a smaller rectangle into the bitmap @racket[target]. If
|
||||
you save the bitmap to a file with @racket[(send target #,(:: bitmap% save-file)
|
||||
"box.png" 'png)], the @filepath{box.png} contains the image
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
in PNG format.
|
||||
|
||||
A line-drawing drawing operation like @racket[draw-line] uses the
|
||||
@tech{DC}'s current @defterm{pen} to draw the line. A pen has a color,
|
||||
line width, and style, where pen styles include @racket['solid],
|
||||
@racket['long-dash], and @racket['transparent]. Enclosed-shape
|
||||
operations like @racket[draw-rectangle] use both the current pen and
|
||||
the @tech{DC}'s current @deftech{brush}. A brush has a color and style,
|
||||
where brush styles include @racket['solid], @racket['cross-hatch], and
|
||||
@racket['transparent].
|
||||
|
||||
@margin-note{In DrRacket, instead of saving @racket[target] to a file
|
||||
viewing the image from the file, you can use @racket[(require
|
||||
racket/gui)] and @racket[(make-object image-snip% target)] to view the
|
||||
bitmap in the DrRacket interactions window.}
|
||||
|
||||
For example, set the brush and pen before the drawing operations to
|
||||
draw a thick, red ``X'' on a green rectangle with a thin, blue border:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc set-brush "green" 'solid)
|
||||
(send dc set-pen "blue" 1 'solid)
|
||||
(send dc draw-rectangle 0 10 30 10)
|
||||
(send dc set-pen "red" 3 'solid)
|
||||
(send dc draw-line 0 0 30 30)
|
||||
(send dc draw-line 0 30 30 0)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
To draw a filled shape without an outline, set the pen to
|
||||
@racket['transparent] mode (with any color and line width). For
|
||||
example,
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc set-pen "white" 1 'transparent)
|
||||
(send dc set-brush "black" 'solid)
|
||||
(send dc draw-ellipse 5 5 20 20)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
By default, a @racket[bitmap-dc%] draws solid pixels without smoothing
|
||||
the boundaries of shapes. To enable smoothing, set the
|
||||
smoothing mode to either @racket['smoothed] or @racket['aligned]:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc set-smoothing 'aligned)
|
||||
(send dc set-brush "black" 'solid)
|
||||
(send dc draw-ellipse 4 4 22 22) (code:comment @#,t{a little bigger})
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
The difference between @racket['aligned] mode and @racket['smoothed]
|
||||
mode is related to the relatively coarse granularity of pixels in a
|
||||
bitmap. Conceptually, drawing coordinates correspond to the lines
|
||||
between pixels, and the pen is centered on the line. In
|
||||
@racket['smoothed] mode, drawing on a line causes the pen to draw at
|
||||
half strength on either side of the line, which produces the following
|
||||
result for a 1-pixel black pen:
|
||||
|
||||
@centered[@interaction-eval-show[#:eval draw-eval (line-bitmap 'smoothed)]]
|
||||
|
||||
but @racket['aligned] mode shifts drawing coordinates to make the pen
|
||||
fall on whole pixels, so a 1-pixel black pen draws a single line of
|
||||
pixels:
|
||||
|
||||
@centered[@interaction-eval-show[#:eval draw-eval (line-bitmap 'aligned)]]
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Pen, Brush, and Color Objects}
|
||||
|
||||
The @racket[set-pen] and @racket[set-brush] methods of a @tech{DC}
|
||||
accept @scheme[pen%] and @scheme[brush%] objects, which group
|
||||
together pen and brush settings.
|
||||
|
||||
@schemeblock+eval[
|
||||
#:eval draw-eval
|
||||
(require racket/math)
|
||||
|
||||
(define no-pen (new pen% [style 'transparent]))
|
||||
(define no-brush (new brush% [style 'transparent]))
|
||||
(define blue-brush (new brush% [color "blue"]))
|
||||
(define yellow-brush (new brush% [color "yellow"]))
|
||||
(define red-pen (new pen% [color "red"] [width 2]))
|
||||
|
||||
(define (draw-face dc)
|
||||
(send dc set-smoothing 'aligned)
|
||||
|
||||
(send dc set-pen no-pen)
|
||||
(send dc set-brush blue-brush)
|
||||
(send dc draw-ellipse 25 25 100 100)
|
||||
|
||||
(send dc set-brush yellow-brush)
|
||||
(send dc draw-rectangle 50 50 10 10)
|
||||
(send dc draw-rectangle 90 50 10 10)
|
||||
|
||||
(send dc set-brush no-brush)
|
||||
(send dc set-pen red-pen)
|
||||
(send dc draw-arc 37 37 75 75 (* 5/4 pi) (* 7/4 pi)))
|
||||
|
||||
(define target (make-bitmap 150 150))
|
||||
(define dc (new bitmap-dc% [bitmap target]))
|
||||
|
||||
(draw-face dc)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
The @racket[get-pen] and @racket[get-brush] methods return a
|
||||
@tech{DC}'s current pen and brush, so they can be restored after
|
||||
changing them temporarily for drawing.
|
||||
|
||||
Besides grouping settings, a @racket[pen%] or @racket[brush%] object
|
||||
includes extra settings that are not available by using
|
||||
@racket[set-pen] or @racket[set-brush] directly. For example, a pen or
|
||||
brush can have a @deftech{stipple}, which is a bitmap that is used
|
||||
instead of a solid color when drawing. For example, if
|
||||
@filepath{water.png} has the image
|
||||
|
||||
@centered{@image["water.png"]}
|
||||
|
||||
then it can be loaded with @racket[read-bitmap] and installed as the
|
||||
stipple for @racket[blue-brush]:
|
||||
|
||||
@schemeblock+eval[
|
||||
#:eval draw-eval
|
||||
(send blue-brush set-stipple (read-bitmap "water.png"))
|
||||
(send dc erase)
|
||||
(draw-face dc)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
Along similar lines, a @racket[color%] object lets you specify a color
|
||||
through its red, green, and blue components instead of a built-in
|
||||
color name. Due to the way that @racket[color%] initialization is
|
||||
overloaded, use @racket[make-object%] instead of @racket[new] to
|
||||
instantiate @racket[color%]:
|
||||
|
||||
@schemeblock+eval[
|
||||
#:eval draw-eval
|
||||
(define red-pen
|
||||
(new pen% [color (make-object color% 200 100 150)] [width 2]))
|
||||
(send dc erase)
|
||||
(draw-face dc)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Transformations}
|
||||
|
||||
Any coordinates or lengths supplied to drawing commends are
|
||||
transformed by a @tech{DC}'s current transformation matrix. The
|
||||
transformation matrix can scale an image, draw it at an offset, or
|
||||
rotate all drawing. The transformation can be set directly, or the
|
||||
current transformation can be transformed further with methods like
|
||||
@racket[scale], @racket[translate], or @racket[rotate]:
|
||||
|
||||
@schemeblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc erase)
|
||||
(send dc scale 0.5 0.5)
|
||||
(draw-face dc)
|
||||
(send dc rotate (/ pi 2))
|
||||
(send dc translate 0 150)
|
||||
(draw-face dc)
|
||||
(send dc translate 0 -150)
|
||||
(send dc rotate (/ pi 2))
|
||||
(send dc translate 150 150)
|
||||
(draw-face dc)
|
||||
(send dc translate -150 -150)
|
||||
(send dc rotate (/ pi 2))
|
||||
(send dc translate 150 0)
|
||||
(draw-face dc)
|
||||
]
|
||||
|
||||
Use the @method[dc<%> get-transformation] method to get a @tech{DC}'s
|
||||
current transformation, and restore a saved transformation (or any
|
||||
affine transformation) using @method[dc<%> set-transformation].
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap target)]}
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Drawing Paths}
|
||||
|
||||
Drawing functions like @racket[draw-line] and @racket[draw-rectangle]
|
||||
are actually convenience functions for the more general
|
||||
@racket[draw-path] operation. The @racket[draw-path] operation takes
|
||||
a @deftech{path}, which describes a set of line segments and curves
|
||||
to draw with the pen and---in the case of closed set of lines and
|
||||
curves---fill with the current brush.
|
||||
|
||||
An instance of @racket[dc-path%] holds a path. Conceptually, a path
|
||||
has a current pen position that is manipulated by methods like
|
||||
@racket[move-to], @racket[line-to], and @racket[curve-to]. The
|
||||
@racket[move-to] method starts a sub-path, and @racket[line-to] and
|
||||
@racket[curve-to] extend it. The @racket[close] method moves the pen
|
||||
from its current position in a straight line to its starting
|
||||
position, completing the sub-path and forming a closed path that can
|
||||
be filled with the brush. A @racket[dc-path%] object can have
|
||||
multiple closed sub-paths and one final open path, where the open
|
||||
path is drawn only with the pen.
|
||||
|
||||
For example,
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define zee (new dc-path%))
|
||||
(send zee move-to 0 0)
|
||||
(send zee line-to 30 0)
|
||||
(send zee line-to 0 30)
|
||||
(send zee line-to 30 30)
|
||||
]
|
||||
|
||||
creates an open path. Drawing this path with a black pen of width 5
|
||||
and a transparent brush produces
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (path-bitmap zee 'round #f)]}
|
||||
|
||||
Drawing a single path with three line segments is not the same as
|
||||
drawing three separate lines. When multiple line segments are drawn at
|
||||
once, the corner frm one line to the next is shaped according to the
|
||||
pen's join style. The image above uses the default @racket['round]
|
||||
join style. With @racket['miter], line lines are joined with sharp
|
||||
corners:
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (path-bitmap zee 'miter #f)]}
|
||||
|
||||
If the sub-path in @racket[zee] is closed with @racket[close], then
|
||||
all of the corners are joined, including the corner at the initial
|
||||
point:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send zee close)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (path-bitmap zee 'miter #f)]}
|
||||
|
||||
Using @racket[blue-brush] instead of a transparent brush causes the
|
||||
interior of the path to be filled:
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (path-bitmap zee 'miter #t)]}
|
||||
|
||||
When a sub-path is not closed, it is implicitly closed for brush
|
||||
filling, but left open for pen drawing. When both a pen and brush are
|
||||
available (i.e., not transparent), then the brush is used first, so
|
||||
that the pen draws on top of the brush.
|
||||
|
||||
At this point we can't resist showing an extended example using
|
||||
@racket[dc-path%] to draw the Racket logo:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define red-brush (new brush% [stipple (read-bitmap "fire.png")]))
|
||||
|
||||
(define left-lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p move-to 153 44)
|
||||
(send p line-to 161.5 60)
|
||||
(send p curve-to 202.5 49 230 42 245 61)
|
||||
(send p curve-to 280.06 105.41 287.5 141 296.5 186)
|
||||
(send p curve-to 301.12 209.08 299.11 223.38 293.96 244)
|
||||
(send p curve-to 281.34 294.54 259.18 331.61 233.5 375)
|
||||
(send p curve-to 198.21 434.63 164.68 505.6 125.5 564)
|
||||
(send p line-to 135 572)
|
||||
p))
|
||||
|
||||
(define left-logo-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p append left-lambda-path)
|
||||
(send p arc 0 0 630 630 (* 235/360 2 pi) (* 121/360 2 pi) #f)
|
||||
p))
|
||||
|
||||
(define bottom-lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p move-to 135 572)
|
||||
(send p line-to 188.5 564)
|
||||
(send p curve-to 208.5 517 230.91 465.21 251 420)
|
||||
(send p curve-to 267 384 278.5 348 296.5 312)
|
||||
(send p curve-to 301.01 302.98 318 258 329 274)
|
||||
(send p curve-to 338.89 288.39 351 314 358 332)
|
||||
(send p curve-to 377.28 381.58 395.57 429.61 414 477)
|
||||
(send p curve-to 428 513 436.5 540 449.5 573)
|
||||
(send p line-to 465 580)
|
||||
(send p line-to 529 545)
|
||||
p))
|
||||
|
||||
(define bottom-logo-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p append bottom-lambda-path)
|
||||
(send p arc 0 0 630 630 (* 314/360 2 pi) (* 235/360 2 pi) #f)
|
||||
p))
|
||||
|
||||
(define right-lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p move-to 153 44)
|
||||
(send p curve-to 192.21 30.69 233.21 14.23 275 20)
|
||||
(send p curve-to 328.6 27.4 350.23 103.08 364 151)
|
||||
(send p curve-to 378.75 202.32 400.5 244 418 294)
|
||||
(send p curve-to 446.56 375.6 494.5 456 530.5 537)
|
||||
(send p line-to 529 545)
|
||||
p))
|
||||
|
||||
(define right-logo-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p append right-lambda-path)
|
||||
(send p arc 0 0 630 630 (* 314/360 2 pi) (* 121/360 2 pi) #t)
|
||||
p))
|
||||
|
||||
(define lambda-path
|
||||
(let ([p (new dc-path%)])
|
||||
(send p append left-lambda-path)
|
||||
(send p append bottom-lambda-path)
|
||||
(let ([t (new dc-path%)])
|
||||
(send t append right-lambda-path)
|
||||
(send t reverse)
|
||||
(send p append t))
|
||||
(send p close)
|
||||
p))
|
||||
|
||||
(define (paint-racket dc)
|
||||
(send dc set-pen "black" 0 'transparent)
|
||||
(send dc set-brush "white" 'solid)
|
||||
(send dc draw-path lambda-path)
|
||||
|
||||
(send dc set-pen "black" 4 'solid)
|
||||
|
||||
(send dc set-brush red-brush)
|
||||
(send dc draw-path left-logo-path)
|
||||
(send dc draw-path bottom-logo-path)
|
||||
|
||||
(send dc set-brush blue-brush)
|
||||
(send dc draw-path right-logo-path))
|
||||
|
||||
(define racket-logo (make-bitmap 170 170))
|
||||
(define dc (new bitmap-dc% [bitmap racket-logo]))
|
||||
|
||||
(send dc set-smoothing 'smoothed)
|
||||
(send dc translate 5 5)
|
||||
(send dc scale 0.25 0.25)
|
||||
(paint-racket dc)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval racket-logo]}
|
||||
|
||||
In addition to the core @racket[move-to], @racket[line-to],
|
||||
@racket[curve-to], and @racket[close] methods, a @racket[dc-path%]
|
||||
includes many convenience methods, such as @racket[ellipse] for adding
|
||||
a closed elliptical sub-path to the path.
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Text}
|
||||
|
||||
Draw text using the @racket[draw-text] method, which takes a string to
|
||||
draw and a location for the top-left of the drawn text:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define text-target (make-bitmap 100 30))
|
||||
(define dc (new bitmap-dc% [bitmap text-target]))
|
||||
(send dc set-brush "white" 'transparent)
|
||||
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
(send dc draw-text "Hello, World!" 5 1)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap text-target)]}
|
||||
|
||||
The font used to draw text is determined by the @tech{DC}'s current
|
||||
font. A font is described by a @racket[font%] object and installed
|
||||
with @racket[set-font]. The color of drawn text which is separate from
|
||||
either the pen or brush, can be set using
|
||||
@racket[set-text-foreground].
|
||||
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc erase)
|
||||
(send dc set-font (make-object font% 14 'roman 'normal 'bold))
|
||||
(send dc set-text-foreground "blue")
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
(send dc draw-text "Hello, World!" 5 1)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap text-target)]}
|
||||
|
||||
To compute the size that will be used by drawn text, use
|
||||
@racket[get-text-extent], which returns four values: the total width,
|
||||
total height, difference between the baseline and total height, and
|
||||
extra space (if any) above the text in a line. For example, the result
|
||||
of @racket[get-text-extent] can be used to position text within the
|
||||
center of a box:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc erase)
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
(define-values (w h d a) (send dc get-text-extent "Hello, World!"))
|
||||
(send dc draw-text "Hello, World!" (/ (- 100 w) 2) (/ (- 30 h) 2))
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap text-target)]}
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Alpha Channels and Alpha Blending}
|
||||
|
||||
When you create or @racket[erase] a bitmap, the content is
|
||||
nothing. ``Nothing'' isn't the same as white; it's the absence of
|
||||
drawing. For example, if you take @racket[text-target] from the
|
||||
previous section and copy it onto another @tech{DC} using
|
||||
@racket[draw-bitmap], then the black rectangle and blue text is
|
||||
transferred, and the background is left alone:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define new-target (make-bitmap 100 30))
|
||||
(define dc (new bitmap-dc% [bitmap new-target]))
|
||||
(send dc set-pen "black" 1 'transparent)
|
||||
(send dc set-brush "pink" 'solid)
|
||||
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
(send dc draw-bitmap text-target 0 0)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap new-target)]}
|
||||
|
||||
The information about which pixels of a bitmap are drawn (as opposed
|
||||
to ``nothing'') is the bitmap's @deftech{alpha channel}. Not all
|
||||
@tech{DC}s keep an alpha channel, but bitmaps created with
|
||||
@racket[make-bitmap] keep an alpha channel by default. Bitmaps loaded
|
||||
with @racket[read-bitmap] preserve transparency in the image file
|
||||
through the bitmap's alpha channel.
|
||||
|
||||
An alpha channel isn't all or nothing. When the edges text is
|
||||
anti-aliased by @racket[draw-text], for example, the pixels are
|
||||
partially transparent. When the pixels are transferred to another
|
||||
@tech{DC}, the partially transparent pixel is blended with the target
|
||||
pixel in a process called @deftech{alpha blending}. Furthermore, a
|
||||
@tech{DC} has an alpha value that is applied to all drawing
|
||||
operations; an alpha value of @racket[1.0] corresponds to solid
|
||||
drawing, an alpha value of @racket[0.0] makes the drawing have no
|
||||
effect, and values in between make the drawing translucent.
|
||||
|
||||
For example, setting the @tech{DC}'s alpha to @racket[0.25] before
|
||||
calling @racket[draw-bitmap] causes the blue and black of the ``Hello,
|
||||
World!'' bitmap to be quarter strength as it is blended with the
|
||||
destination image:
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(send dc erase)
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
(send dc set-alpha 0.25)
|
||||
(send dc draw-bitmap text-target 0 0)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap new-target)]}
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Clipping}
|
||||
|
||||
In addition to tempering the opacity of drawing operations, a
|
||||
@tech{DC} has a @deftech{clipping region} that constrains all drawing to
|
||||
inside the region. In the simplest case, a clipping region corresponds
|
||||
to a closed path, but it can also be the union, intersection,
|
||||
subtraction, or exclusive-or of two paths.
|
||||
|
||||
For example, a clipping region could be set to three circles to clip
|
||||
the drawing of a rectangle (with the 0.25 alpha still in effect):
|
||||
|
||||
@racketblock+eval[
|
||||
#:eval draw-eval
|
||||
(define r (new region%))
|
||||
(let ([p (new dc-path%)])
|
||||
(send p ellipse 00 0 35 30)
|
||||
(send p ellipse 35 0 30 30)
|
||||
(send p ellipse 65 0 35 30)
|
||||
(send r set-path p))
|
||||
(send dc set-clipping-region r)
|
||||
(send dc set-brush "green" 'solid)
|
||||
(send dc draw-rectangle 0 0 100 30)
|
||||
]
|
||||
|
||||
@centered{@interaction-eval-show[#:eval draw-eval (copy-bitmap new-target)]}
|
||||
|
||||
The clipping region can be viewed as a convenient alternative to path
|
||||
filling or drawing with stipples. Conversely, stippled drawing can be
|
||||
viewed as a convenience alternative to clipping repeated calls of
|
||||
@racket[draw-bitmap].
|
||||
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
@section{Portability}
|
||||
|
||||
Drawing effects are not completely portable across platforms or across
|
||||
types of DC. For example. drawing to a bitmap produced by
|
||||
@racket[make-bitmap] may produce slightly different results than
|
||||
drawing to one produced by @racketmodname[racket/gui]'s
|
||||
@racket[make-screen-bitmap], but drawing to a bitmap from
|
||||
@racket[make-screen-bitmap] should be the same as drawing to an
|
||||
onscreen @racket[canvas%]. Fonts and text, especially, can vary across
|
||||
platforms and types of @tech{DC}, but so can the precise set of pixels
|
||||
touched by drawing a line.
|
BIN
collects/scribblings/guide/fire.png
Normal file
BIN
collects/scribblings/guide/fire.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
53
collects/scribblings/guide/graphics.scrbl
Normal file
53
collects/scribblings/guide/graphics.scrbl
Normal file
|
@ -0,0 +1,53 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
"guide-utils.ss")
|
||||
|
||||
@title[#:tag "graphics" #:style 'toc]{Graphics and GUIs}
|
||||
|
||||
Racket provides many libraries for graphics and graphical user
|
||||
interfaces (GUIs):
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{The @racketmodname[racket/draw] library provides basic drawing
|
||||
tools, including @tech{drawing contexts} such as bitmaps and
|
||||
PostScript files.
|
||||
|
||||
See @secref["draw"] for an overview.}
|
||||
|
||||
@item{The @racketmodname[racket/gui] library provides GUI widgets
|
||||
such as windows, buttons, checkboxes, and text fields. The
|
||||
library also includes a sophisticated and extensible text
|
||||
editor.}
|
||||
|
||||
@item{The @racketmodname[slideshow/pict] library provides a more
|
||||
functional abstraction layer over @racketmodname[racket/draw].
|
||||
This layer is especially useful for creating slide
|
||||
presentations with @seclink[#:doc '(lib
|
||||
"scribblings/slideshow/slideshow.scrbl") "top"]{Slideshow}, but
|
||||
it is also useful for creating images for @seclink[#:doc '(lib
|
||||
"scribblings/scribble/scribble.scrbl") "top"]{Scribble}
|
||||
documents or other drawing tasks. Pictures created with the
|
||||
@racketmodname[slideshow/pict] library can be rendered to any
|
||||
@tech{drawing context}.
|
||||
|
||||
See @other-doc['(lib "scribblings/slideshow/slideshow.scrbl")]
|
||||
for more information.}
|
||||
|
||||
@item{The @racket[2htdp/image] library is similar to
|
||||
@racketmodname[slideshow/pict]. It is more streamlined for
|
||||
pedagogical use, but also slightly more specific to screen and
|
||||
bitmap drawing.
|
||||
|
||||
See @racket[2htdp/image] for more information.}
|
||||
|
||||
@item{The @racketmodname[sgl] library provides OpenGL for 3-D
|
||||
graphics. The context for rendering OpenGL can be a window or
|
||||
bitmap created with @racketmodname[racket/gui].
|
||||
|
||||
See @other-doc['(lib "sgl/scribblings/sgl.scrbl")] for more
|
||||
information.}
|
||||
|
||||
]
|
||||
|
||||
@include-section["draw.scrbl"]
|
|
@ -52,6 +52,8 @@ precise details to @|Racket| and other reference manuals.
|
|||
|
||||
@include-section["languages.scrbl"]
|
||||
|
||||
@include-section["graphics.scrbl"]
|
||||
|
||||
@include-section["performance.scrbl"]
|
||||
|
||||
@include-section["running.scrbl"]
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
|
||||
@title{More Libraries}
|
||||
|
||||
@other-manual['(lib "scribblings/gui/gui.scrbl")] describes the Racket
|
||||
graphics toolbox, whose core is implemented by the @exec{gracket}
|
||||
executable.
|
||||
|
||||
@other-manual['(lib "scribblings/foreign/foreign.scrbl")] describes
|
||||
tools for using Racket to access libraries that are normally used by C
|
||||
programs.
|
||||
|
|
BIN
collects/scribblings/guide/water.png
Normal file
BIN
collects/scribblings/guide/water.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
Loading…
Reference in New Issue
Block a user