From 8b3165d55b85cffbe3ad28be6d8bd4c218d21529 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 27 Nov 2010 15:53:49 -0700 Subject: [PATCH] move racket/draw overview to the Guide and expand it --- plus some minor collateral API improvements --- collects/racket/draw/private/brush.rkt | 48 +- collects/racket/draw/private/dc.rkt | 28 +- collects/racket/draw/private/pen.rkt | 82 +- collects/scribble/eval.rkt | 78 +- collects/scribblings/draw/brush-class.scrbl | 24 +- collects/scribblings/draw/draw.scrbl | 27 +- collects/scribblings/draw/guide.scrbl | 227 ---- collects/scribblings/draw/pen-class.scrbl | 33 +- collects/scribblings/draw/reference.scrbl | 29 - collects/scribblings/gui/dc-intf.scrbl | 1125 +++++++++++++++++++ collects/scribblings/guide/draw.scrbl | 642 +++++++++++ collects/scribblings/guide/fire.png | Bin 0 -> 3094 bytes collects/scribblings/guide/graphics.scrbl | 53 + collects/scribblings/guide/guide.scrbl | 2 + collects/scribblings/guide/other.scrbl | 4 - collects/scribblings/guide/water.png | Bin 0 -> 4345 bytes 16 files changed, 2017 insertions(+), 385 deletions(-) delete mode 100644 collects/scribblings/draw/guide.scrbl delete mode 100644 collects/scribblings/draw/reference.scrbl create mode 100644 collects/scribblings/gui/dc-intf.scrbl create mode 100644 collects/scribblings/guide/draw.scrbl create mode 100644 collects/scribblings/guide/fire.png create mode 100644 collects/scribblings/guide/graphics.scrbl create mode 100644 collects/scribblings/guide/water.png diff --git a/collects/racket/draw/private/brush.rkt b/collects/racket/draw/private/brush.rkt index d37775b201..f8c65ce1ce 100644 --- a/collects/racket/draw/private/brush.rkt +++ b/collects/racket/draw/private/brush.rkt @@ -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) diff --git a/collects/racket/draw/private/dc.rkt b/collects/racket/draw/private/dc.rkt index 320d880818..e11fe0c369 100644 --- a/collects/racket/draw/private/dc.rkt +++ b/collects/racket/draw/private/dc.rkt @@ -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))) diff --git a/collects/racket/draw/private/pen.rkt b/collects/racket/draw/private/pen.rkt index bd26946a1e..745aa29d14 100644 --- a/collects/racket/draw/private/pen.rkt +++ b/collects/racket/draw/private/pen.rkt @@ -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) diff --git a/collects/scribble/eval.rkt b/collects/scribble/eval.rkt index e204f0cb17..4fe429c5dc 100644 --- a/collects/scribble/eval.rkt +++ b/collects/scribble/eval.rkt @@ -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 () diff --git a/collects/scribblings/draw/brush-class.scrbl b/collects/scribblings/draw/brush-class.scrbl index 66a5caaf17..fcc7463411 100644 --- a/collects/scribblings/draw/brush-class.scrbl +++ b/collects/scribblings/draw/brush-class.scrbl @@ -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. diff --git a/collects/scribblings/draw/draw.scrbl b/collects/scribblings/draw/draw.scrbl index 3787105685..247cc879ae 100644 --- a/collects/scribblings/draw/draw.scrbl +++ b/collects/scribblings/draw/draw.scrbl @@ -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"] @;------------------------------------------------------------------------ diff --git a/collects/scribblings/draw/guide.scrbl b/collects/scribblings/draw/guide.scrbl deleted file mode 100644 index d3e912ed6a..0000000000 --- a/collects/scribblings/draw/guide.scrbl +++ /dev/null @@ -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. diff --git a/collects/scribblings/draw/pen-class.scrbl b/collects/scribblings/draw/pen-class.scrbl index 7ca9b0a576..4e0b063f53 100644 --- a/collects/scribblings/draw/pen-class.scrbl +++ b/collects/scribblings/draw/pen-class.scrbl @@ -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. diff --git a/collects/scribblings/draw/reference.scrbl b/collects/scribblings/draw/reference.scrbl deleted file mode 100644 index e8e05d6811..0000000000 --- a/collects/scribblings/draw/reference.scrbl +++ /dev/null @@ -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"] diff --git a/collects/scribblings/gui/dc-intf.scrbl b/collects/scribblings/gui/dc-intf.scrbl new file mode 100644 index 0000000000..ec0de7440d --- /dev/null +++ b/collects/scribblings/gui/dc-intf.scrbl @@ -0,0 +1,1125 @@ +#lang scribble/doc +@(require "common.ss") + +@definterface/title[dc<%> ()]{ + +A @scheme[dc<%>] object is a drawing context for drawing graphics and + text. It represents output devices in a generic way; e.g., a canvas + has a drawing context, as does a printer. + + +@defmethod[(cache-font-metrics-key) + exact-integer?]{ + +Returns an integer that, if not @scheme[0], corresponds to a +particular kind of device and scaling factor, such that text-extent +information (from @method[dc<%> get-text-extent], @method[dc<%> +get-char-height], etc.) is the same. The key is valid across all +@scheme[dc<%>] instances, even among different classes. + +A @scheme[0] result indicates that the current configuration of +@this-obj[] does not fit into a common category, and so no key is +available for caching text-extent information.} + + +@defmethod[(clear) + void?]{ + +Clears the drawing region (fills it with the current background color, +as determined by @method[dc<%> get-background]). + +} + +@defmethod[(copy [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))] + [x2 real?] + [y2 real?]) + void?]{ + +Copies the rectangle defined by @racket[x], @racket[y], +@racket[width], and @racket[height] of the drawing context to the same +drawing context at the position specified by @racket[x2] and +@racket[y2]. + +The result is undefined if the source and destination rectangles +overlap.} + + +@defmethod[(draw-arc [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))] + [start-radians real?] + [end-radians real?]) + void?]{ + +Draws a counter-clockwise circular arc, a part of the ellipse + inscribed in the rectangle specified by @scheme[x] (left), @scheme[y] + (top), @scheme[width], and @scheme[height]. The arc starts at the angle + specified by @scheme[start-radians] (@scheme[0] is three o'clock and + half-pi is twelve o'clock) and continues counter-clockwise to + @scheme[end-radians]. If @scheme[start-radians] and @scheme[end-radians] are + the same, a full ellipse is drawn. + +The current pen is used for the arc. If the current brush is not + transparent, it is used to fill the wedge bounded by the arc plus + lines (not drawn) extending to the center of the inscribed ellipse. + +If both the pen and brush are non-transparent, the wedge is filled + with the brush before the arc is drawn with the pen. The wedge and + arc meet so that no space is left between them, but the precise + overlap between the wedge and arc is platform- and size-specific. + Typically, the regions drawn by the brush and pen overlap. More + generally, the pen is centered over the outline of the arc, rounding + toward the center in unsmoothed mode. + +@|DrawSizeNote| + +} + + +@defmethod[(draw-bitmap [source (is-a?/c bitmap%)] + [dest-x real?] + [dest-y real?] + [style (one-of/c 'solid 'opaque 'xor) 'solid] + [color (is-a?/c color%) (send the-color-database find-color "black")] + [mask (or/c (is-a?/c bitmap%) false/c) #f]) + boolean?]{ + +Displays a bitmap. The @scheme[dest-x] and @scheme[dest-y] arguments + are in DC coordinates. + +For color bitmaps, the drawing style and color arguments are + ignored. For monochrome bitmaps, @method[dc<%> draw-bitmap] uses the + style and color arguments in the same way that a brush uses its style + and color settings to draw a monochrome stipple (see @scheme[brush%] + for more information). + +If a mask bitmap is supplied, it must have the same width and height + as the bitmap to display, and its @method[bitmap% ok?] must return + true, otherwise @|MismatchExn|. The bitmap to draw and the mask + bitmap can be the same object, but if the drawing context is a + @scheme[bitmap-dc%] object, both bitmaps must be distinct from the + destination bitmap, otherwise @|MismatchExn|. + +If the mask bitmap is monochrome, drawing occurs in the target + @scheme[dc<%>] only where the mask bitmap contains black pixels. + +If the mask bitmap is grayscale and the bitmap to draw is not + monochrome, then the blackness of each mask pixel controls the + opacity of the drawn pixel (i.e., the mask acts as an inverted alpha + channel). If a mask bitmap is color, the component values of a given + pixel are averaged to arrive at a gray value for the pixel. + +The current brush, current pen, current text, and current alpha + settings for the DC have no effect on how the bitmap is drawn, but + the bitmap is scaled if the DC has a scale. + +For @scheme[post-script-dc%] output, the mask bitmap is currently + ignored, and the @scheme['solid] style is treated the same as + @scheme['opaque]. (However, mask bitmaps and @scheme['solid] drawing + may become supported for @scheme[post-script-dc%] in the future.) + +The result is @scheme[#t] if the bitmap is successfully drawn, + @scheme[#f] otherwise (possibly because the bitmap's @method[bitmap% + ok?] method returns @scheme[#f]). + +See also @method[dc<%> draw-bitmap-section]. + +@|DrawSizeNote| + +} + +@defmethod[(draw-bitmap-section [source (is-a?/c bitmap%)] + [dest-x real?] + [dest-y real?] + [src-x real?] + [src-y real?] + [src-width (and/c real? (not/c negative?))] + [src-height (and/c real? (not/c negative?))] + [style (one-of/c 'solid 'opaque 'xor) 'solid] + [color (is-a?/c color%) (send the-color-database find-color "black")] + [mask (or/c (is-a?/c bitmap%) false/c) #f]) + boolean?]{ + +Displays part of a bitmap. + +The @scheme[src-x], @scheme[src-y], @scheme[src-width], and + @scheme[src-height] arguments specify a rectangle in the source + bitmap to copy into this drawing context. + +See @method[dc<%> draw-bitmap] for information about @scheme[dest-x], + @scheme[dest-y], @scheme[style], @scheme[color], and @scheme[mask]. + +} + +@defmethod[(draw-ellipse [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))]) + void?]{ + +Draws an ellipse contained in a rectangle with the given top-left + corner and size. The current pen is used for the outline, and the + current brush is used for filling the shape. + +If both the pen and brush are non-transparent, the ellipse is filled + with the brush before the outline is drawn with the pen. The filling + and outline meet so that no space is left between them, but the + precise overlap between the filling and outline is platform- and + size-specific. Typically, the regions drawn by the brush and pen + overlap. More generally, the pen is centered over the outline of the + ellipse, rounding toward the center in unsmoothed mode. + +@|DrawSizeNote| + +} + +@defmethod[(draw-line [x1 real?] + [y1 real?] + [x2 real?] + [y2 real?]) + void?]{ + +Draws a line from one point to another. The current pen is used for + drawing the line. + +In unsmoothed mode, the points correspond to pixels, and the line + covers both the start and end points. For a pen whose scaled width is + larger than @scheme[1], the line is drawn centered over the start and + end points. + +See also @method[dc<%> set-smoothing] for information on the +@scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + +@defmethod[(draw-lines [points (listof (is-a?/c point%))] + [xoffset real? 0] + [yoffset real? 0]) + void?]{ + +Draws lines using a list of @scheme[points], adding @scheme[xoffset] + and @scheme[yoffset] to each point. The current pen is used for + drawing the lines. + +See also @method[dc<%> set-smoothing] for information on the + @scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + +@defmethod[(draw-path [path (is-a?/c dc-path%)] + [xoffset real? 0] + [yoffset real? 0] + [fill-style (one-of/c 'odd-even 'winding) 'odd-even]) + void?]{ + +Draws the sub-paths of the given @scheme[dc-path%] object, adding + @scheme[xoffset] and @scheme[yoffset] to each point. (See + @scheme[dc-path%] for general information on paths and sub-paths.) + The current pen is used for drawing the path as a line, and the + current brush is used for filling the area bounded by the path. + +If both the pen and brush are non-transparent, the path is filled with + the brush before the outline is drawn with the pen. The filling and + outline meet so that no space is left between them, but the precise + overlap between the filling and outline is platform- and + size-specific. Thus, the regions drawn by the brush and pen may + overlap. More generally, the pen is centered over the path, rounding + left and down in unsmoothed mode. + +The @scheme[fill-style] argument specifies the fill rule: + @scheme['odd-even] or @scheme['winding]. In @scheme['odd-even] mode, a + point is considered enclosed within the path if it is enclosed by an + odd number of sub-path loops. In @scheme['winding] mode, a point is + considered enclosed within the path if it is enclosed by more or less + clockwise sub-path loops than counter-clockwise sub-path loops. + +See also @method[dc<%> set-smoothing] for information on the + @scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + +@defmethod[(draw-point [x real?] + [y real?]) + void?]{ + +Plots a single point using the current pen. + +@|DrawSizeNote| + +} + +@defmethod[(draw-polygon [points (listof (is-a?/c point%))] + [xoffset real? 0] + [yoffset real? 0] + [fill-style (one-of/c 'odd-even 'winding) 'odd-even]) + void?]{ + +Draw a filled polygon using a list of @scheme[points], adding + @scheme[xoffset] and @scheme[yoffset] to each point. The polygon is + automatically closed, so the first and last point can be + different. The current pen is used for drawing the outline, and the + current brush for filling the shape. + +If both the pen and brush are non-transparent, the polygon is filled + with the brush before the outline is drawn with the pen. The filling + and outline meet so that no space is left between them, but the + precise overlap between the filling and outline is platform- and + shape-specific. Thus, the regions drawn by the brush and pen may + overlap. More generally, the pen is centered over the polygon lines, + rounding left and down in unsmoothed mode. + +The @scheme[fill-style] argument specifies the fill rule: + @scheme['odd-even] or @scheme['winding]. In @scheme['odd-even] mode, a + point is considered enclosed within the polygon if it is enclosed by + an odd number of loops. In @scheme['winding] mode, a point is + considered enclosed within the polygon if it is enclosed by more or + less clockwise loops than counter-clockwise loops. + +See also @method[dc<%> set-smoothing] for information on the + @scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + + +@defmethod[(draw-rectangle [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))]) + void?]{ + +Draws a rectangle with the given top-left corner and size. The + current pen is used for the outline and the current brush for filling + the shape. + +If both the pen and brush are non-transparent, the rectangle is filled + with the brush before the outline is drawn with the pen. In + unsmoothed mode, when the pen is size 0 or 1, the filling precisely + overlaps the entire outline. As a result, if a rectangle is drawn + with a size-0 or size-1 @scheme['xor] @scheme[pen%] and an + @scheme['xor] @scheme[brush%], the outline is xored twice (first by + the brush, then by the pen), leaving it unchanged. More generally, + the pen is centered over the outline of the rectangle, rounding + toward the center in unsmoothed mode. + +See also @method[dc<%> set-smoothing] for information on the +@scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + + +@defmethod[(draw-rounded-rectangle [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))] + [radius real? -0.25]) + void?]{ + +Draws a rectangle with the given top-left corner, and with the given + size. The corners are quarter-circles using the given radius. The + current pen is used for the outline and the current brush for filling + the shape. + +If @scheme[radius] is positive, the value is used as the radius of the + rounded corner. If @scheme[radius] is negative, the absolute value is + used as the @italic{proportion} of the smallest dimension of the + rectangle. + +If @scheme[radius] is less than @scheme[-0.5] or more than half of + @scheme[width] or @scheme[height], @|MismatchExn|. + +If both the pen and brush are non-transparent, the rectangle is filled + with the brush before the outline is drawn with the pen. The filling + and outline meet so that no space is left between them, but the + precise overlap between the filling and outline is platform- and + size-specific. Thus, the regions drawn by the brush and pen may + partially overlap. More generally, the pen is centered over the + outline of the rounded rectangle, rounding toward the center in + unsmoothed mode. + +See also @method[dc<%> set-smoothing] for information on the +@scheme['aligned] smoothing mode. + +@|DrawSizeNote| + +} + +@defmethod[(draw-spline [x1 real?] + [y1 real?] + [x2 real?] + [y2 real?] + [x3 real?] + [y3 real?]) + void?]{ + +@index['("drawing curves")]{Draws} a spline from (@scheme[x1], + @scheme[y1]) to (@scheme[x3], @scheme[y3]) using (@scheme[x2], + @scheme[y2]) as the control point. + +See also @method[dc<%> set-smoothing] for information on the + @scheme['aligned] smoothing mode. See also @scheme[dc-path%] and + @method[dc<%> draw-path] for drawing more complex curves. + +@|DrawSizeNote| + +} + +@defmethod[(draw-text [text string?] + [x real?] + [y real?] + [combine? any/c #f] + [offset exact-nonnegative-integer? 0] + [angle real? 0]) + void?]{ + +Draws a text string at a specified point, using the current text font, + and the current text foreground and background colors. For unrotated + text, the specified point is used as the starting top-left point for + drawing characters (e.g, if ``W'' is drawn, the point is roughly the + location of the top-left pixel in the ``W''). Rotated text is rotated + around this point. + +The @scheme[text] string is drawn starting from the @scheme[offset] + character, and continuing until the end of @scheme[text] or the first + null character. + +If @scheme[combine?] is @scheme[#t], then @scheme[text] may be + measured with adjacent characters combined to ligature glyphs, with + Unicode combining characters as a single glyph, with kerning, with + right-to-left rendering of characters, etc. If @scheme[combine?] is + @scheme[#f], then the result is the same as if each character is + measured separately, and Unicode control characters are ignored. + +The string is rotated by @scheme[angle] radians counter-clockwise. If + @scheme[angle] is not zero, then the text is always drawn in + transparent mode (see @method[dc<%> set-text-mode]). + +The current brush and current pen settings for the DC have no effect + on how the text is drawn. + +See @method[dc<%> get-text-extent] for information on the size of the + drawn text. + +See also @method[dc<%> set-text-foreground], @method[dc<%> + set-text-background], and @method[dc<%> set-text-mode]. + +@|DrawSizeNote| + +} + +@defmethod[(end-doc) + void?]{ + +Ends a document, relevant only when drawing to a printer or PostScript + device (including to a PostScript file). + +For printer or PostScript output, an exception is raised if +@scheme[end-doc] is called when the document is not started with +@method[dc<%> start-doc], when a page is currently started by +@method[dc<%> start-page] and not ended with @method[dc<%> end-page], +or when the document has been ended already. + +} + +@defmethod[(end-page) + void?]{ + +Ends a single page, relevant only when drawing to a printer or + PostScript device (including to a PostScript file). + +For printer or PostScript output, an exception is raised if +@scheme[end-page] is called when a page is not currently started by +@method[dc<%> start-page]. + +} + + +@defmethod[(flush) void?]{ + +Calls the @xmethod[canvas<%> flush] method for +@racket[canvas<%>] output, and has no effect for other kinds of +drawing contexts.} + + + +@defmethod[(get-alpha) + (real-in 0 1)]{ + +Gets the current opacity for drawing; see +@method[dc<%> set-alpha]. + +} + +@defmethod[(get-background) + (is-a?/c color%)]{ + +Gets the color used for painting the background. See also +@method[dc<%> set-background]. + +} + +@defmethod[(get-brush) + (is-a?/c brush%)]{ + +Gets the current brush. See also @method[dc<%> set-brush]. + +} + +@defmethod[(get-char-height) + (and/c real? (not/c negative?))]{ + +Gets the height of a character using the current font. + +Unlike most methods, this method can be called for a + @scheme[bitmap-dc%] object without a bitmap installed. + +} + +@defmethod[(get-char-width) + (and/c real? (not/c negative?))]{ + +Gets the average width of a character using the current font. + +Unlike most methods, this method can be called for a + @scheme[bitmap-dc%] object without a bitmap installed. + +} + +@defmethod[(get-clipping-region) + (or/c (is-a?/c region%) false/c)]{ + +Gets the current clipping region, returning @scheme[#f] if the drawing + context is not clipped (i.e., the clipping region is the entire + drawing region). + +} + +@defmethod[(get-font) + (is-a?/c font%)]{ + +Gets the current font. See also @method[dc<%> set-font]. + +} + +@defmethod[(get-gl-context) + (or/c (is-a?/c gl-context<%>) false/c)]{ + +Returns a @scheme[gl-context<%>] object for this drawing context + if it supports OpenGL, @scheme[#f] otherwise. + +See @scheme[gl-context<%>] for more information. + +} + +@defmethod[(get-initial-matrix) + (vector/c real? real? real? real? real? real?)]{ + +Returns a transformation matrix that converts logical coordinates to + device coordinates. The matrix applies before additional origin + offset, scaling, and rotation. + +The vector content corresponds to a transformation matrix in the +following order: + +@itemlist[ + + @item{@racket[_xx]: a scale from the logical @racket[_x] to the device @racket[_x]} + + @item{@racket[_xy]: a scale from the logical @racket[_x] added to the device @racket[_y]} + + @item{@racket[_yx]: a scale from the logical @racket[_y] added to the device @racket[_x]} + + @item{@racket[_yy]: a scale from the logical @racket[_y] to the device @racket[_y]} + + @item{@racket[_x0]: an additional amount added to the device @racket[_x]} + + @item{@racket[_y0]: an additional amount added to the device @racket[_y]} + +] + +See also @method[dc<%> set-initial-matrix] and @method[dc<%> get-transformation]. + +} + + +@defmethod[(get-origin) + (values real? real?)]{ + +Returns the device origin, i.e., the location in device coordinates of + @math{(0,0)} in logical coordinates. The origin offset applies after + the initial transformation matrix, but before scaling and rotation. + +See also @method[dc<%> set-origin] and @method[dc<%> get-transformation]. + +} + + +@defmethod[(get-pen) + (is-a?/c pen%)]{ + +Gets the current pen. See also @method[dc<%> set-pen]. + +} + +@defmethod[(get-rotation) real?]{ + +Returns the rotation of logical coordinates in radians to device +coordinates. Rotation applies after the initial transformation matrix, +origin offset, and scaling. + +See also @method[dc<%> set-rotation] and @method[dc<%> get-transformation]. + +} + +@defmethod[(get-scale) + (values real? real?)]{ + +Returns the scaling factor that maps logical coordinates to device +coordinates. Scaling applies after the initial transformation matrix +and origin offset, but before rotation. + +See also @method[dc<%> set-scale] and @method[dc<%> get-transformation]. + +} + +@defmethod[(get-size) + (values nonnegative-real? nonnegative-real?)]{ + +Gets the size of the destination drawing area. For a @scheme[dc<%>] + object obtained from a @scheme[canvas<%>], this is the (virtual + client) size of the destination window; for a @scheme[bitmap-dc%] + object, this is the size of the selected bitmap (or 0 if no bitmap is + selected); for a @scheme[post-script-dc%] or @scheme[printer-dc%] + drawing context, this gets the horizontal and vertical size of the + drawing area. + +} + +@defmethod[(get-smoothing) + (one-of/c 'unsmoothed 'smoothed 'aligned)]{ + +Returns the current smoothing mode. See @method[dc<%> set-smoothing]. + +} + +@defmethod[(get-text-background) + (is-a?/c color%)]{ + +Gets the current text background color. See also @method[dc<%> +set-text-background]. + +} + +@defmethod[(get-text-extent [string string?] + [font (or/c (is-a?/c font%) false/c) #f] + [combine? any/c #f] + [offset exact-nonnegative-integer? 0]) + (values nonnegative-real? + nonnegative-real? + nonnegative-real? + nonnegative-real?)]{ + + +Returns the size of @scheme[str] at it would be drawn in the drawing + context, starting from the @scheme[offset] character of @scheme[str], + and continuing until the end of @scheme[str] or the first null + character. The @scheme[font] argument specifies the font to use in + measuring the text; if it is @scheme[#f], the current font of the + drawing area is used. (See also @method[dc<%> set-font].) + +The result is four real numbers: + +@itemize[ + + @item{the total width of the text (depends on both the font and the + text);} + + @item{the total height of the font (depends only on the font);} + + @item{the distance from the baseline of the font to the bottom of the + descender (included in the height, depends only on the font); and} + + @item{extra vertical space added to the font by the font designer + (included in the height, and often zero; depends only on the font).} + +] + +The returned width and height define a rectangle is that guaranteed to + contain the text string when it is drawn, but the fit is not + necessarily tight. Some undefined number of pixels on the left, + right, top, and bottom of the drawn string may be ``whitespace,'' + depending on the whims of the font designer and the platform-specific + font-scaling mechanism. + +If @scheme[combine?] is @scheme[#t], then @scheme[text] may be drawn + with adjacent characters combined to ligature glyphs, with Unicode + combining characters as a single glyph, with kerning, with + right-to-left ordering of characters, etc. If @scheme[combine?] is + @scheme[#f], then the result is the same as if each character is + drawn separately, and Unicode control characters are ignored. + +Unlike most methods, this method can be called for a + @scheme[bitmap-dc%] object without a bitmap installed. + +} + + +@defmethod[(get-text-foreground) + (is-a?/c color%)]{ + +Gets the current text foreground color. See also @method[dc<%> +set-text-foreground]. + +} + + +@defmethod[(get-text-mode) + (one-of/c 'solid 'transparent)]{ +Reports how text is drawn; see +@method[dc<%> set-text-mode].} + + +@defmethod[(get-transformation) + (vector/c (vector/c real? real? real? real? real? real?) + real? real? real? real? real?)]{ + +Returns the current transformation setting of the drawing context in a +form that is suitable for restoration via @method[dc<%> +set-transformation]. + +The vector content is as follows: + +@itemlist[ + + @item{the initial transformation matrix; see @method[dc<%> + get-initial-matrix];} + + @item{the X and Y origin; see @method[dc<%> get-origin];} + + @item{the X and Y scale; see @method[dc<%> get-origin];} + + @item{a rotation; see @method[dc<%> get-rotation].} + +]} + + +@defmethod[(glyph-exists? [c char] + [font (or/c (is-a?/c font%) false/c) #f]) + boolean?]{ + +Returns @scheme[#t] if the given character has a corresponding glyph + for this drawing context, @scheme[#f] otherwise. + +Due to automatic font substitution when drawing or measuring text, the + result of this method does not depend on the given font, which merely + provides a hint for the glyph search. If the font is @scheme[#f], the + drawing context's current font is used. The result depends on the + type of the drawing context, but the result for @scheme[canvas%] + @scheme[dc<%>] instances and @scheme[bitmap-dc%] instances is always + the same for a given platform and a given set of installed fonts. + +See also @method[font% screen-glyph-exists?] . + +} + +@defmethod[(ok?) + boolean?]{ + +Returns @scheme[#t] if the drawing context is usable. + +} + + +@defmethod[(resume-flush) void?]{ + +Calls the @xmethod[canvas<%> resume-flush] method for +@racket[canvas<%>] output, and has no effect for other kinds of +drawing contexts.} + + +@defmethod[(rotate [angle real?]) void?]{ + +Adds a rotation of @racket[angle] radians to the drawing context's +current transformation. + +Afterward, the drawing context's transformation is represented in the +initial transformation matrix, and the separate origin, scale, and +rotation settings have their identity values. + +} + +@defmethod[(scale [x-scale real?] + [y-scale real?]) + void?]{ + +Adds a scaling of @racket[x-scale] in the X-direction and +@racket[y-scale] in the Y-direction to the drawing context's current +transformation. + +Afterward, the drawing context's transformation is represented in the +initial transformation matrix, and the separate origin, scale, and +rotation settings have their identity values. + +} + +@defmethod[(set-alpha [opacity (real-in 0 1)]) + void?]{ + +Determines the opacity of drawing. A value of @scheme[0.0] corresponds +to completely transparent (i.e., invisible) drawing, and @scheme[1.0] +corresponds to completely opaque drawing. For intermediate values, +drawing is blended with the existing content of the drawing context.} + + +@defmethod[(set-background [color (or/c (is-a?/c color%) string?)]) + void?]{ + +Sets the background color for drawing in this object (e.g., using +@method[dc<%> clear] or using a stippled @scheme[brush%] with the mode +@scheme['opaque]). For monochrome drawing, all non-black colors are +treated as white. + +} + +@defmethod*[([(set-brush [brush (is-a?/c brush%)]) + void?] + [(set-brush [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)]) + void?] + [(set-brush [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)]) + void?])]{ + +Sets the current brush for drawing in this object. While a brush is + selected into a drawing context, it cannot be modified. When a color + and style are given, the arguments are as for @xmethod[brush-list% + find-or-create-brush]. + +} + + +@defmethod[(set-clipping-rect [x real?] + [y real?] + [width (and/c real? (not/c negative?))] + [height (and/c real? (not/c negative?))]) + void?]{ + +Sets the clipping region to a rectangular region. + +See also @method[dc<%> set-clipping-region] and @method[dc<%> +get-clipping-region]. + +@|DrawSizeNote| + +} + +@defmethod[(set-clipping-region [rgn (or/c (is-a?/c region%) false/c)]) + void?]{ + +Sets the clipping region for the drawing area, turning off all + clipping within the drawing region if @scheme[#f] is provided. + +The clipping region must be reset after changing a @scheme[dc<%>] + object's origin or scale (unless it is @scheme[#f]); see + @scheme[region%] for more information. + +See also @method[dc<%> set-clipping-rect] and @method[dc<%> + get-clipping-region]. + +} + +@defmethod[(set-font [font (is-a?/c font%)]) + void?]{ + +Sets the current font for drawing text in this object. + +} + +@defmethod[(set-initial-matrix [m (vector/c real? real? real? real? real? real?)]) + void?]{ + +Set a transformation matrix that converts logical coordinates to + device coordinates. The matrix applies before additional origin + offset, scaling, and rotation. + +See @method[dc<%> get-initial-matrix] for information on the matrix as + represented by a vector @racket[m]. + +See also @method[dc<%> transform], which adds a transformation to the + current transformation, instead of changing the transformation + composition in the middle. + +@|DrawSizeNote| + +} + +@defmethod[(set-origin [x real?] + [y real?]) + void?]{ + +Sets the device origin, i.e., the location in device coordinates of + @math{(0,0)} in logical coordinates. The origin offset applies after + the initial transformation matrix, but before scaling and rotation. + +See also @method[dc<%> translate], which adds a translation to the + current transformation, instead of changing the transformation + composition in the middle. + +@|DrawSizeNote| + +} + +@defmethod*[([(set-pen [pen (is-a?/c pen%)]) + void?] + [(set-pen [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)]) + void?] + [(set-pen [color-name string?] + [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)]) + void?])]{ + +Sets the current pen for this object. When a color, width, and style + are given, the arguments are as for @xmethod[pen-list% + find-or-create-pen]. + +The current pen does not affect text drawing; see also @method[dc<%> + set-text-foreground]. + +While a pen is selected into a drawing context, it cannot be modified. + +} + +@defmethod[(set-rotation [angle real?]) void?]{ + +Set the rotation of logical coordinates in radians to device +coordinates. Rotation applies after the initial transformation matrix, +origin offset, and scaling. + +See also @method[dc<%> rotate], which adds a rotation to the current + transformation, instead of changing the transformation composition. + +@|DrawSizeNote| + +} + +@defmethod[(set-scale [x-scale real?] + [y-scale real?]) + void?]{ + +Sets a scaling factor that maps logical coordinates to device + coordinates. Scaling applies after the initial transformation matrix + and origin offset, but before rotation. Negative scaling factors have + the effect of flipping. + +See also @method[dc<%> scale], which adds a scale to the current + transformation, instead of changing the transformation composition in + the middle. + +@|DrawSizeNote| + +} + +@defmethod[(set-smoothing [mode (one-of/c 'unsmoothed 'smoothed 'aligned)]) + void?]{ + +Enables or disables anti-aliased smoothing for drawing. (Text + smoothing is not affected by this method, and is instead controlled + through the @scheme[font%] object.) + +The smoothing mode is either @scheme['unsmoothed], @scheme['smoothed], + or @scheme['aligned]. Both @scheme['aligned] and @scheme['smoothed] + are smoothing modes. + +In @scheme['smoothed] mode for a canvas or bitmap drawing context, + integer drawing coordinates correspond to the boundary between + pixels, and pen-based drawing is centered over a given line or + curve. Thus, drawing with pen width @scheme[1] from @math{(0, 10)} to + @math{(10, 10)} draws a 2-pixel wide line with @math{50%} opacity. + +The @scheme['aligned] smoothing mode is like @scheme['smoothed], but + it paints pixels more like @scheme['unsmoothed] mode. Since it aligns + shapes to pixel boundaries, @scheme['aligned] mode often produces + better results than @scheme['smoothed], but the results depend on the + application. The @scheme['aligned] mode is defined in terms of + @scheme['smoothed] mode, except that drawing coordinates are rounded + down (via @scheme[floor], after scaling and origin translation). For + line drawing, coordinates are then shifted right and down by the + @scheme[floor] of half a pen width. In addition, for pen drawing + through @method[dc<%> draw-rectangle], @method[dc<%> draw-ellipse], + @method[dc<%> draw-rounded-rectangle], and @method[dc<%> draw-arc], + the given width and height are each decreased by @math{1.0}. + +In either smoothing mode, brush and pen stipples are ignored (except + for PostScript drawing), and @scheme['hilite] and @scheme['xor] + drawing modes are treated as @scheme['solid]. If smoothing is not + supported, then attempting to set the smoothing mode to + @scheme['smoothed] or @scheme['aligned] will have no effect, and + @method[dc<%> get-smoothing] will always return + @scheme['unsmoothed]. Similarly, @method[dc<%> get-smoothing] for a + @scheme[post-script-dc%] always returns @scheme['smoothed]. + +} + +@defmethod[(set-text-background [color (or/c (is-a?/c color%) string?)]) + void?]{ + +Sets the current text background color for this object. The text + background color is painted behind text that is drawn with + @method[dc<%> draw-text], but only for the @scheme['solid] text mode + (see @method[dc<%> set-text-mode]). + +For monochrome drawing, all non-white colors are treated as black. + +} + +@defmethod[(set-text-foreground [color (or/c (is-a?/c color%) string?)]) + void?]{ + +Sets the current text foreground color for this object, used for + drawing text with +@method[dc<%> draw-text]. + +For monochrome drawing, all non-black colors are treated as + white. + +} + +@defmethod[(set-text-mode [mode (one-of/c 'solid 'transparent)]) + void?]{ + +Determines how text is drawn: + +@itemize[ + + @item{@scheme['solid] --- Before text is drawn, the destination area + is filled with the text background color (see @method[dc<%> + set-text-background]).} + + @item{@scheme['transparent] --- Text is drawn directly over any + existing image in the destination, as if overlaying text + written on transparent film.} + +] + +} + + +@defmethod[(set-transformation + [t (vector/c (vector/c real? real? real? real? real? real?) + real? real? real? real? real?)]) + void?]{ + +Sets the draw context's transformation. See @method[dc<%> +get-transformation] for information about @racket[t].} + + +@defmethod[(start-doc [message string?]) + boolean?]{ + +Starts a document, relevant only when drawing to a printer or + PostScript device (including to a PostScript file). For some + platforms, the @scheme[message] string is displayed in a dialog until + @method[dc<%> end-doc] is called. + +For printer or PostScript output, an exception is raised if + @scheme[start-doc] has been called already (even if @method[dc<%> + end-doc] has been called as well). Furthermore, drawing methods raise + an exception if not called while a page is active as determined by + @method[dc<%> start-doc] and @method[dc<%> start-page]. + +} + +@defmethod[(start-page) + void?]{ + +Starts a page, relevant only when drawing to a printer or PostScript + device (including to a PostScript file). + +For printer or PostScript output, an exception is raised if + @scheme[start-page] is called when a page is already started, or when + @method[dc<%> start-doc] has not been called, or when @method[dc<%> + end-doc] has been called already. In addition, in the case of + PostScript output, Encapsulated PostScript (EPS) cannot contain + multiple pages, so calling @scheme[start-page] a second time for a + @scheme[post-script-dc%] instance raises an exception; to create + PostScript output with multiple pages, supply @scheme[#f] as the + @scheme[as-eps] initialization argument for @scheme[post-script-dc%]. + +} + + +@defmethod[(suspend-flush) void?]{ + +Calls the @xmethod[canvas<%> suspend-flush] method for +@racket[canvas<%>] output, and has no effect for other kinds of +drawing contexts.} + + +@defmethod[(transform [m (vector/c real? real? real? real? real? real?)]) + void?]{ + +Adds a transformation by @racket[m] to the drawing context's current +transformation. + +See @method[dc<%> get-initial-matrix] for information on the matrix as + represented by a vector @racket[m]. + +Afterward, the drawing context's transformation is represented in the +initial transformation matrix, and the separate origin, scale, and +rotation settings have their identity values. + +} + +@defmethod[(translate [dx real?] + [dy real?]) + void?]{ + +Adds a scaling of @racket[dx] in the X-direction and @racket[dy] in +the Y-direction to the drawing context's current transformation. + +Afterward, the drawing context's transformation is represented in the +initial transformation matrix, and the separate origin, scale, and +rotation settings have their identity values. + +} + + +@defmethod[(try-color [try (is-a?/c color%)] + [result (is-a?/c color%)]) + void?]{ + +Determines the actual color used for drawing requests with the given + color. The @scheme[result] color is set to the RGB values that are + actually produced for this drawing context to draw the color + @scheme[try]. + +}} diff --git a/collects/scribblings/guide/draw.scrbl b/collects/scribblings/guide/draw.scrbl new file mode 100644 index 0000000000..5b4ebc268f --- /dev/null +++ b/collects/scribblings/guide/draw.scrbl @@ -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. diff --git a/collects/scribblings/guide/fire.png b/collects/scribblings/guide/fire.png new file mode 100644 index 0000000000000000000000000000000000000000..102b047c7b3939875c07e7b31938bf5ca1dfd938 GIT binary patch literal 3094 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 literal 0 HcmV?d00001