1110 lines
35 KiB
Racket
1110 lines
35 KiB
Racket
#lang scribble/doc
|
|
@(require scribble/manual
|
|
(for-label scheme/base
|
|
scheme/contract
|
|
"../graphics.ss"))
|
|
|
|
@title{Legacy Graphics Library}
|
|
|
|
@table-of-contents[]
|
|
|
|
@section[#:style 'toc]{Viewport Graphics}
|
|
|
|
The viewport graphics library is a relatively simple toolbox of
|
|
graphics commands. The library is not very powerful; it is intended as
|
|
a simplified alternative to @schememodname[scheme/gui]'s full
|
|
graphical toolbox.
|
|
|
|
The graphics library originated as SIXlib, a library of X Windows
|
|
commands available within Chez Scheme at Rice University. The
|
|
functionality of that library has been reproduced (with backward
|
|
compatibility) in this version.
|
|
|
|
@defmodule[graphics/graphics]
|
|
|
|
@local-table-of-contents[]
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@subsection{Basic Commands}
|
|
|
|
@defproc[(open-graphics) void?]{
|
|
|
|
Initializes the library's graphics routines. It must be called before
|
|
any other graphics operations.}
|
|
|
|
@defproc[(close-graphics) void?]{
|
|
|
|
Closes all of the windows. Until @scheme[open-graphics] is called
|
|
again, no graphics routines will work.}
|
|
|
|
@defproc*[([(open-viewport [name string?]
|
|
[horiz exact-nonnegative-integer?]
|
|
[vert exact-nonnegative-integer?])
|
|
viewport?]
|
|
[(open-viewport [name string?]
|
|
[dimensions posn?])
|
|
viewport?])]{
|
|
|
|
Creates a new window called @scheme[name]. The window is
|
|
@scheme[horiz] pixels wide and @scheme[vert] pixels high. For
|
|
backward compatibility, a single @scheme[posn] value can be submitted
|
|
in the place of @scheme[horiz] and @scheme[vert]. The result is a
|
|
viewport descriptor.}
|
|
|
|
|
|
@defproc*[([(open-pixmap [name string?]
|
|
[horiz exact-nonnegative-integer?]
|
|
[vert exact-nonnegative-integer?])
|
|
viewport?]
|
|
[(open-pixmap [name string?]
|
|
[dimensions posn?])
|
|
viewport?])]{
|
|
|
|
Like @scheme[open-viewport], but the resulting viewport is not
|
|
displayed on the screen. Offscreen pixmaps are useful for executing a
|
|
sequence of drawing commands and displaying them all at once with
|
|
@scheme[copy-viewport].
|
|
|
|
Offscreen pixmaps are also useful in conjunction with viewport->snip
|
|
(see below). This allows functions to compute with graphical objects
|
|
and view the graphics when results are returned to the interactions
|
|
window.}
|
|
|
|
|
|
@defproc[(close-viewport [viewport viewport?]) void?]{
|
|
|
|
Removes the viewport from the screen and makes subsequent operations
|
|
dealing with the viewport illegal.}
|
|
|
|
|
|
@defproc[(viewport? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a viewport (i.e., a destination
|
|
for drawing), @scheme[#f] otherwise.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@subsection{Position Operations}
|
|
|
|
A position is a pixel location within a viewport. The upper-left
|
|
corner is pixel @math{(0, 0)}, and positions increase to the left and
|
|
down.
|
|
|
|
|
|
@defstruct[posn ([x real?][y real?])]{
|
|
|
|
Represents a positions.}
|
|
|
|
|
|
@defproc[((get-pixel [viewport viewport?]) [p posn?]) (one-of/c 0 1)]{
|
|
|
|
Returns the color of the pixel at position @scheme[p] in
|
|
@scheme[viewport]; @scheme[0] denotes white and @scheme[1] denotes not
|
|
white.}
|
|
|
|
|
|
@defproc[((get-color-pixel [viewport viewport?]) [p posn?]) rgb?]{
|
|
|
|
Returns an @scheme[rgb] value for color of the pixel at position
|
|
@scheme[p] in @scheme[viewport].}
|
|
|
|
|
|
@defproc[((test-pixel [viewport viewport?]) [color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)])
|
|
rgb?]{
|
|
|
|
Returns the color that will actually be used if @scheme[color] is used
|
|
to draw.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@subsection{Color Operations}
|
|
|
|
A color can be represented in three ways: as a color index (an integer
|
|
in 0 to 299, inclusive), as a color name string, or as a @scheme[rgb]
|
|
value. All drawing functions which take a color argument accept colors
|
|
in any form. An @scheme[rgb] value is assigned to an index with
|
|
@scheme[change-color].
|
|
|
|
|
|
@defstruct[rgb ([red (real-in 0 1)][green (real-in 0 1)][blue (real-in 0 1)])]{
|
|
|
|
Takes three values in the range 0 (dark) to 1 (bright) and returns an
|
|
@scheme[rgb] (a color).}
|
|
|
|
|
|
@defproc[(change-color [index (integer-in 0 299)] [rgb rgb?])
|
|
void?]{
|
|
|
|
Changes the color at @scheme[index] in the color table to the
|
|
color specified in @scheme[rgb]. Only the first twenty-one indices
|
|
are initialized; a color index should not be used until it has
|
|
been initialized.}
|
|
|
|
|
|
@defproc[(default-display-is-color?) boolean?]{
|
|
|
|
Returns @scheme[#t] if the default display screen for viewports is in
|
|
color or @scheme[#f] otherwise.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@subsection{Draw, Clear, and Flip Operations}
|
|
|
|
The following are the basic graphics operations for drawing to a
|
|
viewport. Each function takes a viewport as its argument and returns
|
|
a function operating within that viewport. Further arguments, if any,
|
|
are curried. For example, @scheme[(draw-line _viewport)] returns a
|
|
function, that can then be applied to the proper arguments to draw a
|
|
line in the viewport corresponding to viewport descriptor
|
|
@scheme[_viewport].
|
|
|
|
In general, @schemeidfont{draw-} functions make pixels black or
|
|
colored, @schemeidfont{clear-} functions make them white, and
|
|
@schemeidfont{flip-} commands @deftech{invert} pixels (which makes
|
|
black white, white black, and is otherwise ill-defined).
|
|
|
|
@subsubsection{Viewports}
|
|
|
|
@defproc[((draw-viewport [viewport viewport?])
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Colors the entire contents of @scheme[viewport] with @scheme[color].}
|
|
|
|
@defproc[((clear-viewport [viewport viewport?]))
|
|
void?]{
|
|
|
|
Whitens the entire contents of @scheme[viewport].}
|
|
|
|
@defproc[((flip-viewport [viewport viewport?]))
|
|
void?]{
|
|
|
|
@tech{Inverts} the entire contents of @scheme[viewport].}
|
|
|
|
|
|
@defproc[(copy-viewport [source viewport?] [dest viewport?])
|
|
void?]{
|
|
|
|
Copies the content of @scheme[source] into @scheme[dest].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Pixels}
|
|
|
|
@defproc[((draw-pixel [viewport viewport?])
|
|
[p posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Colors the pixel in @scheme[viewport] at @scheme[p].}
|
|
|
|
@defproc[((clear-pixel [viewport viewport?])
|
|
[p posn?])
|
|
void?]{
|
|
|
|
Whitens the pixel in @scheme[viewport] at @scheme[p].}
|
|
|
|
@defproc[((flip-pixel [viewport viewport?])
|
|
[p posn?])
|
|
void?]{
|
|
|
|
@tech{Inverts} the pixel in @scheme[viewport] at @scheme[p].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Lines}
|
|
|
|
@defproc[((draw-line [viewport viewport?])
|
|
[p1 posn?]
|
|
[p2 posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a line in @scheme[viewport] connecting positions @scheme[p1] and
|
|
@scheme[p2].}
|
|
|
|
|
|
@defproc[((clear-line [viewport viewport?])
|
|
[p1 posn?]
|
|
[p2 posn?])
|
|
void?]{
|
|
|
|
Whitens a line in @scheme[viewport] connecting positions @scheme[p1]
|
|
and @scheme[p2].}
|
|
|
|
|
|
@defproc[((flip-line [viewport viewport?])
|
|
[p1 posn?]
|
|
[p2 posn?])
|
|
void?]{
|
|
|
|
@tech{Inverts} a line in @scheme[viewport] connecting positions
|
|
@scheme[p1] and @scheme[p2].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Rectangles}
|
|
|
|
@defproc[((draw-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a rectangle border in the @scheme[viewport] with the top-left of
|
|
the rectangle at the position @scheme[p] and with sides @scheme[width]
|
|
across and @scheme[height] tall.}
|
|
|
|
|
|
@defproc[((clear-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
Whitens a rectangle border in the @scheme[viewport], analogous to
|
|
@scheme[draw-rectangle].}
|
|
|
|
|
|
@defproc[((flip-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
@tech{Inverts} a rectangle border in the @scheme[viewport], analogous
|
|
to @scheme[draw-rectangle].}
|
|
|
|
|
|
@defproc[((draw-solid-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a solid rectangle in the @scheme[viewport] with the top-left of
|
|
the rectangle at the position @scheme[p] and with sides @scheme[width]
|
|
across and @scheme[height] tall.}
|
|
|
|
|
|
@defproc[((clear-solid-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
Whitens a rectangle border in the @scheme[viewport], analogous to
|
|
@scheme[draw-solid-rectangle].}
|
|
|
|
|
|
@defproc[((flip-solid-rectangle [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
@tech{Inverts} a rectangle border in the @scheme[viewport], analogous
|
|
to @scheme[draw-solid-rectangle].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Ellipses}
|
|
|
|
@defproc[((draw-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a ellipse border in the @scheme[viewport]. The ellipse is
|
|
inscribed with a rectangle whose top-left is at position @scheme[p]
|
|
and with sides @scheme[width] across and @scheme[height] tall.}
|
|
|
|
|
|
@defproc[((clear-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
Whitens a ellipse border in the @scheme[viewport], analogous to
|
|
@scheme[draw-ellipse].}
|
|
|
|
|
|
@defproc[((flip-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
@tech{Inverts} a ellipse border in the @scheme[viewport], analogous
|
|
to @scheme[draw-ellipse].}
|
|
|
|
|
|
@defproc[((draw-solid-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a solid ellipse in the @scheme[viewport]. The ellipse is
|
|
inscribed with a rectangle whose top-left is at position @scheme[p]
|
|
and with sides @scheme[width] across and @scheme[height] tall.}
|
|
|
|
|
|
@defproc[((clear-solid-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
Whitens a ellipse border in the @scheme[viewport], analogous to
|
|
@scheme[draw-solid-ellipse].}
|
|
|
|
|
|
@defproc[((flip-solid-ellipse [viewport viewport?])
|
|
[p posn?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
void?]{
|
|
|
|
@tech{Inverts} a ellipse border in the @scheme[viewport], analogous
|
|
to @scheme[draw-solid-ellipse].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Polygons}
|
|
|
|
@defproc[((draw-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a polygon border in @scheme[viewport] using @scheme[points] for
|
|
the polygon vertices and @scheme[offset] as an offset added to all
|
|
points.}
|
|
|
|
|
|
@defproc[((clear-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?])
|
|
void?]{
|
|
|
|
Whitens a polygon border in @scheme[viewport], analogous to
|
|
@scheme[draw-polygon].}
|
|
|
|
|
|
@defproc[((flip-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?])
|
|
void?]{
|
|
|
|
@tech{Inverts} a polygon border in @scheme[viewport], analogous to
|
|
@scheme[draw-polygon].}
|
|
|
|
|
|
@defproc[((draw-solid-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a solid polygon in @scheme[viewport] using @scheme[points] for
|
|
the polygon vertices and @scheme[offset] as an offset added to all
|
|
points.}
|
|
|
|
|
|
@defproc[((clear-solid-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?])
|
|
void?]{
|
|
|
|
Whitens a polygon border in @scheme[viewport], analogous to
|
|
@scheme[draw-solid-polygon].}
|
|
|
|
|
|
@defproc[((flip-solid-polygon [viewport viewport?])
|
|
[points (listof posn?)]
|
|
[offset posn?])
|
|
void?]{
|
|
|
|
@tech{Inverts} a polygon border in @scheme[viewport], analogous to
|
|
@scheme[draw-solid-polygon].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Strings}
|
|
|
|
@defproc[((draw-string [viewport viewport?])
|
|
[p posn?]
|
|
[str string?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a string at a specified location in the @scheme[viewport].
|
|
The lower left of the string begins at @scheme[p].}
|
|
|
|
|
|
@defproc[((clear-string [viewport viewport?])
|
|
[p posn?]
|
|
[str string?])
|
|
void?]{
|
|
|
|
Whitens a string at a specified location in the @scheme[viewport].
|
|
The lower left of the string begins at @scheme[p].}
|
|
|
|
@defproc[((flip-string [viewport viewport?])
|
|
[p posn?]
|
|
[str string?])
|
|
void?]{
|
|
|
|
@tech{Inverts} a string at a specified location in the
|
|
@scheme[viewport]. The lower left of the string begins at
|
|
@scheme[p].}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@subsubsection{Pixmaps}
|
|
|
|
@defproc[(((draw-pixmap-posn [file path-string?]
|
|
[type (one-of/c 'unknown 'unknown/mask
|
|
'gif 'gif/mask 'jpeg 'png 'png/mask
|
|
'xbm 'xpm 'bmp 'pict)
|
|
'unknown/mask])
|
|
[viewport viewport?])
|
|
[p posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Draws a pixmap into @scheme[viewport] with its upper left corner at
|
|
position @scheme[p]. If @scheme[type] is @scheme['unknown] or
|
|
@scheme['unknown/mask], then the content of the file is examined to
|
|
determine the type. All formats are supported on all platforms,
|
|
except @scheme['pict] which is only supported under Mac OS X. The
|
|
@scheme['gif/mask], @scheme['png/mask], and @scheme['unknown/mask]
|
|
types draw the bitmap with a transparent background if
|
|
@scheme[filename] refers to a GIF/PNG file with a transparent
|
|
background.
|
|
|
|
The argument @scheme[color] is only used when the loaded pixmap is
|
|
monochrome. In that case, the color is used instead of black in the
|
|
drawn image.}
|
|
|
|
@defproc[((draw-pixmap [viewport viewport?])
|
|
[file path-string?]
|
|
[p posn?]
|
|
[color (or/c (integer-in 0 299)
|
|
string?
|
|
rgb?)
|
|
"black"])
|
|
void?]{
|
|
|
|
Equivalent to @scheme[(((draw-pixmap-posn file) viewport) p color)].}
|
|
|
|
@defproc[((save-pixmap [viewport viewport?])
|
|
[file path-string?]
|
|
[type (one-of/c 'gif 'jpeg 'png 'xbm 'xpm 'bmp) 'xpm])
|
|
void?]{
|
|
|
|
Saves the current content of @scheme[viewport] to @scheme[file].
|
|
The @scheme[type] argument determines the kind of file that is written.}
|
|
|
|
@; ----------------------------------------
|
|
|
|
@;{
|
|
|
|
@subsection{World Operations}
|
|
|
|
Every canvas comes with an associated world. A client program can set the world,
|
|
start the world's clock, stop the world's clock, and deal with tick events (the
|
|
clock ticks) and keyboard inputs (keyevents).
|
|
|
|
@itemize{
|
|
@item{\Function{init-world}
|
|
@scheme[((init-world @scheme[viewport]) X)]
|
|
Takes a viewport descriptor. It returns a function whose input becomes the
|
|
initial value of the world associated with this canvas.}
|
|
|
|
@item{\Function{set-on-tick-event}
|
|
@scheme[((set-on-tick-event @scheme[viewport]) number @scheme[unary procedure])]
|
|
Takes a viewport descriptor. It returns a function whose first input is a
|
|
number and the second one is a function from worlds to worlds. The number
|
|
determines how frequently the clock ticks. The given function is called for
|
|
every clock tick on the current world; the result becomes the next world.}
|
|
|
|
@item{\Function{stop-tick}
|
|
@scheme[((stop-tick @scheme[viewport]))]
|
|
Takes a viewport descriptor. It returns a function of no arguments that can
|
|
stop the clock for this canvas's world.}
|
|
|
|
@item{\Function{set-on-key-event}
|
|
@scheme[((set-on-key-event @scheme[viewport]) unary-procedure)]
|
|
Takes a viewport descriptor. It returns a function whose input becomes the
|
|
keyevent callback function. This callback consumes the latest keyevent and the
|
|
current world and a keyevent; it produces the next world.}
|
|
}
|
|
|
|
@subsection{Miscellaneous Operations}
|
|
|
|
@itemize{
|
|
@item{\Function{get-string-size}
|
|
@scheme[((get-string-size @scheme[viewport]) string)]
|
|
Takes a viewport descriptor. It returns a
|
|
function that returns the size of a string as a list of two numbers:
|
|
the width and height.}
|
|
|
|
@item{\Function{viewport->snip}
|
|
@scheme[(viewport->snip @scheme[viewport])]
|
|
Takes a viewport descriptor. It returns an
|
|
object that can be inserted into an editor buffer to display the
|
|
current image in the viewport. (Subsequent drawing to the viewport
|
|
does not affect the snip's image.)
|
|
|
|
When snips are the results of computations in the interactions window, DrScheme will print show the contents of the viewport, right in the interactions window.}
|
|
|
|
@item{\Function{viewport-dc}
|
|
@scheme[(viewport-dc @scheme[viewport])]
|
|
Takes a viewport descriptor. It returns an
|
|
object that can be used with the primitive MrEd toolbox
|
|
functions to draw into the viewport's on-screen representation
|
|
(if any). Mirror all such drawing to the result of
|
|
@scheme[(viewport-offscreen-dc @scheme[viewport])], too.}
|
|
|
|
@item{\Function{viewport-offscreen-dc}
|
|
@scheme[(viewport-offscreen-dc @scheme[viewport])]
|
|
Takes a viewport descriptor. It returns an
|
|
object that can be used with the primitive MrEd toolbox
|
|
functions to draw into the viewport's off-screen representation.
|
|
Mirror all such drawing to the result of
|
|
@scheme[(viewport-dc @scheme[viewport])], too.}
|
|
}
|
|
|
|
@subsection{An Example}
|
|
|
|
@schemeblock[
|
|
(open-graphics)
|
|
;; nothing appears to happen, but the library is initialized...
|
|
|
|
(define w (open-viewport "practice" 300 300))
|
|
;; viewport appears
|
|
|
|
((draw-line w) (make-posn 30 30) (make-posn 100 100))
|
|
;; line appears
|
|
|
|
(close-viewport w)
|
|
;; viewport disappears
|
|
|
|
(close-graphics)
|
|
;; again, nothing appears to happen, but
|
|
;; unclosed viewports (if any) would disappear
|
|
]
|
|
|
|
@subsection{A More Complicated Example}
|
|
|
|
The use of multiple viewports, viewport descriptors, drawing
|
|
operations for multiple viewports is as easy as the use of a single
|
|
viewport:
|
|
|
|
@schemeblock[
|
|
(open-graphics)
|
|
(let* (;; @scheme[w1] and @scheme[w2] are viewport descriptors for different windows
|
|
[w1 (open-viewport "viewport 1" 300 300)]
|
|
[w2 (open-viewport "viewport 2" 200 500)]
|
|
;; d1 and d2 are functions that draw lines in different viewports
|
|
[d1 (draw-line w1)]
|
|
[d2 (draw-line w2)])
|
|
;; draws a line in viewport labeled "viewport 1"
|
|
(d1 (make-posn 100 5) (make-posn 5 100))
|
|
;; draws a line in viewport labeled "viewport 2"
|
|
(d2 (make-posn 100 100) (make-posn 101 400)))
|
|
|
|
;; we no longer have access to viewports 1 and 2,
|
|
;; since their descriptors did not escape the @scheme[let]
|
|
(close-graphics)
|
|
;; removes the viewports
|
|
]
|
|
|
|
@subsection{Protecting Graphics Operations}
|
|
|
|
To guarantee the proper closing of viewports in cases of errors,
|
|
especially when a program manages several viewports simultaneously, a
|
|
programmer should use @scheme[dynamic-wind:]
|
|
|
|
@schemeblock[
|
|
(let ([w (open-viewport "hello" 100 100)])
|
|
(dynamic-wind
|
|
;; what we want to happen first: nothing
|
|
void
|
|
;; the main program (errors constrained to this piece)
|
|
(lambda () (draw-pixel 13)) ; an error
|
|
;; what we would like to happen, whether the main program finishes
|
|
;; normally or not
|
|
(lambda () (close-viewport w))))
|
|
]
|
|
|
|
@subsection{Mouse Operations}
|
|
|
|
The graphics library contains functions that determine where the
|
|
mouse is, if there are any clicks, etc.
|
|
The functions @scheme[get-mouse-click] and @scheme[ready-mouse-click] first
|
|
return a ``mouse-click descriptor,'' and then other functions take
|
|
the descriptor and return the mouse's position, which button was
|
|
pushed, etc.
|
|
Mouse clicks are buffered and returned in the same order in which
|
|
they occurred.
|
|
Thus, the descriptors returned by @scheme[get-mouse-click] and
|
|
@scheme[ready-mouse-click] may be from clicks that occurred long
|
|
before these functions were called.
|
|
|
|
@itemize{
|
|
@item{\Function{get-mouse-click}
|
|
@scheme[(get-mouse-click @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
a mouse click descriptor.
|
|
It returns the next mouse click in the @scheme[viewport], waiting for a click
|
|
if necessary.}
|
|
|
|
@item{\Function{ready-mouse-click}
|
|
@scheme[(ready-mouse-click @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
either a mouse click descriptor, or else @scheme[#f] if none is available.
|
|
Unlike the previous function, @scheme[ready-mouse-click] returns immediately.}
|
|
|
|
@item{\Function{ready-mouse-release}
|
|
@scheme[(ready-mouse-release @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
either a click descriptor from a mouse-release (button-up) event,
|
|
or else @scheme[#f] if none is available.}
|
|
|
|
@item{\Function{query-mouse-posn}
|
|
@scheme[(query-mouse-posn @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
either the position of the mouse cursor within the @scheme[viewport],
|
|
or else @scheme[#f] if the cursor is currently outside the @scheme[viewport].}
|
|
|
|
@item{\Function{mouse-click-posn}
|
|
@scheme[(mouse-click-posn @scheme[mouse-click])]
|
|
Takes a mouse click descriptor and
|
|
returns the position of the pixel where the click occurred.}
|
|
|
|
@item{\Function{left-mouse-click?}
|
|
@scheme[(left-mouse-click?\ @scheme[mouse-click])]
|
|
Takes a mouse click descriptor and returns
|
|
@scheme[#t] if the click occurred with the left mouse button,
|
|
or else @scheme[#f].}
|
|
|
|
@item{\Function{middle-mouse-click?}
|
|
@scheme[(middle-mouse-click?\ @scheme[mouse-click])]
|
|
Similar to @scheme[left-mouse-click?].}
|
|
|
|
@item{\Function{right-mouse-click?}
|
|
@scheme[(right-mouse-click?\ @scheme[mouse-click])]
|
|
Similar to @scheme[left-mouse-click?].}
|
|
}
|
|
|
|
@subsection{Keyboard Operations}
|
|
|
|
The graphics library contains functions that report key presses from
|
|
the keyboard. The functions @scheme[get-key-press] and
|
|
@scheme[ready-key-press] return a ``key-press descriptor,'' and then
|
|
@scheme[key-value] takes the descriptor and returns a character or
|
|
symbol (usually a character) representing the key that was pressed.
|
|
Key presses are buffered and returned in the same order in which they
|
|
occurred. Thus, the descriptors returned by @scheme[get-key-press] and
|
|
@scheme[ready-key-press] may be from presses that occurred long before
|
|
these functions were called.
|
|
|
|
@itemize{
|
|
@item{\Function{get-key-press}
|
|
@scheme[(get-key-press @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
a key press descriptor.
|
|
It returns the next key press in the @scheme[viewport], waiting for a click
|
|
if necessary.}
|
|
|
|
@item{\Function{ready-key-press}
|
|
@scheme[(ready-key-press @scheme[viewport])]
|
|
Takes a viewport descriptor and returns
|
|
either a key press descriptor, or else @scheme[#f] if none is available.
|
|
Unlike the previous function, @scheme[ready-key-press] returns immediately.}
|
|
|
|
@item{\Function{key-value}
|
|
@scheme[(key-value @scheme[key-press])]
|
|
|
|
Takes a key press descriptor and returns a character or special
|
|
symbol for the key that was pressed. For example, the Enter key
|
|
generates \scmch{return}, and the up-arrow key generates @scheme['up].
|
|
For a complete list of possible return values, see {\MrEdManual}.}
|
|
}
|
|
|
|
@subsection{Flushing}
|
|
|
|
@itemize{
|
|
@item{\Function{viewport-flush-input}
|
|
@scheme[(viewport-flush-input @scheme[viewport])]
|
|
As noted above, key presses and mouse clicks are buffered.
|
|
@scheme[viewport-flush-input] takes a viewport descriptor
|
|
and empties the input buffer of mouse and keyboard events.}
|
|
}
|
|
|
|
@subsection{Unitized Graphics}
|
|
|
|
To use a unitized version of the graphics library (see {\MzLibManual}
|
|
for more information on units), get the signatures
|
|
\scmsigfirst{graphics}, \scmsigfirst{graphics:posn-less}, and
|
|
\scmsigfirst{graphics:posn} with:
|
|
|
|
@schemeblock[
|
|
(require (libKW "graphics-sig.ss" "graphics"))
|
|
]
|
|
|
|
The \scmsig{graphics} signature includes all of the names defined in
|
|
this chapter. The \scmsig{graphics:posn-less} signature contains
|
|
everything except the \scm{posn} structure information, and
|
|
\scmsig{graphics:posn} contains only the \scm{posn} structure.
|
|
|
|
To obtain \scmunitfirst{graphics}, which imports \scmsig{mred} (all of
|
|
the MrEd classes, functions, and constants) and exports
|
|
\scmsig{graphics}:
|
|
|
|
@schemeblock[
|
|
(require (libKW "graphics-unit.ss" "graphics"))
|
|
]
|
|
|
|
The @filepath{graphics-posn-less-unit.ss} library provides
|
|
\scmunit{graphics-posn-less}, which imports \scmsig{graphics:posn} in
|
|
addition to MrEd.
|
|
|
|
@; ======================================================================
|
|
|
|
@section[#:tag "misc:turtles"]{Turtles}
|
|
|
|
@subsection{Traditional Turtles}
|
|
|
|
There are two ways to use the turtles in DrScheme. You can
|
|
use it as a TeachPack (see the DrScheme manual for details
|
|
of TeachPacks) or as a library. Use the
|
|
@filepath{turtles.ss} TeachPack.
|
|
|
|
In the MrEd language or in a module, load turtles with
|
|
|
|
@schemeblock[
|
|
(require (libKW "turtles.ss" "graphics"))
|
|
]
|
|
|
|
The following are the turtle functions:
|
|
|
|
@itemize{
|
|
@item{{@scheme[(turtles b)]}\Function{turtles}
|
|
shows and hides the turtles window based on the boolean @scheme[b].
|
|
The parameter @scheme[b] is optional; if it is left out, it toggles the
|
|
state of the turtles.}
|
|
|
|
@item{{{@scheme[(move n)]}}\Function{move}
|
|
moves the turtle n pixels.}
|
|
|
|
@item{{{@scheme[(draw n)]}}\Function{draw}
|
|
moves the turtle n pixels and draws a line on that path.}
|
|
|
|
@item{{{@scheme[(erase n)]}}\Function{erase}
|
|
moves the turtle n pixels and erases along that path.
|
|
|
|
\Function{move-offset}
|
|
\Function{draw-offset}
|
|
\Function{erase-offset}}
|
|
@item{{{ @scheme[(move-offset h v)], @scheme[(draw-offset h v)], @scheme[(erase-offset h v)]}}
|
|
are just like move, draw and erase, except they take a horizontal and
|
|
vertical offset from the turtle's current position.}
|
|
|
|
@item{{ @scheme[(turn theta)]}\Function{turn}
|
|
turns the turtle theta degrees counter-clockwise.}
|
|
|
|
@item{{ @scheme[(turn/radians theta)]}\Function{turn/radians}
|
|
turns the turtle theta radians counter-clockwise.}
|
|
|
|
@item{{{@scheme[(clear)]}}\Function{clear}
|
|
erases the turtles window.}
|
|
}
|
|
|
|
Turtles also defines these syntactic forms:
|
|
|
|
@itemize{
|
|
@item{{{@scheme[(split E)]}}\Function{split}
|
|
spawns a new turtle where
|
|
the turtle is currently located. In order to distinguish the two turtles,
|
|
only the new one evaluates the expression E. For example, if you start
|
|
with a fresh turtle-window and type:
|
|
|
|
\begin{center}
|
|
\begin{schemebox}
|
|
(split (turn/radians (/ pi 2)))
|
|
\end{schemebox}
|
|
\end{center}
|
|
|
|
you will have two turtles, pointing at right angles to each other.
|
|
To see that, try this:
|
|
|
|
\begin{center}
|
|
\begin{schemebox}
|
|
(draw 100)
|
|
\end{schemebox}
|
|
\end{center}
|
|
|
|
You will see two lines. Now, if you evaluate those two expression
|
|
again, you will have four turtles, etc}
|
|
|
|
@item{{{@scheme[(split* E ...)]}}\Function{split*}
|
|
is similar to @scheme[(split E ...)], except it creates as many turtles as
|
|
there are expressions and each turtles does one of the expression. For
|
|
example, to create two turtles, one pointing at $\pi/2$ and one at
|
|
$\pi/3$, evaluate this:
|
|
|
|
\begin{center}
|
|
\begin{schemebox}
|
|
(split* (turn/radians (/ pi 3)) (turn/radians (/ pi 2)))
|
|
\end{schemebox}
|
|
\end{center}}
|
|
|
|
@item{{{@scheme[(tprompt E...)]}}\Function{tprompt}
|
|
provides a way to limit the splitting of the turtles. Before
|
|
the expression E is run, the state of the turtles (how many, their
|
|
positions and headings) is "checkpointed," then E is evaluated and
|
|
the state of the turtles is restored, but all drawing that may have
|
|
occurred during execution of E remains.
|
|
|
|
For example, if you do this:
|
|
|
|
\begin{center}
|
|
\begin{schemebox}
|
|
(tprompt (draw 100))
|
|
\end{schemebox}
|
|
\end{center}
|
|
|
|
the turtle will move forward 100 pixels, draw a line there and then
|
|
be immediately put back in it's original position. Also, if you do this:
|
|
|
|
\begin{center}
|
|
\begin{schemebox}
|
|
(tprompt (split (turn/radians (/ pi 2))))
|
|
\end{schemebox}
|
|
\end{center}
|
|
|
|
the turtle will split into two turtles, one will turn 90 degrees and then
|
|
the turtles will be put back into their original state -- as if the split
|
|
never took place.
|
|
|
|
The fern functions below demonstrate more advanced use of @scheme[tprompt].}
|
|
}
|
|
|
|
In the file @filepath{turtle-examples.ss} in the @filepath{graphics} library of your PLT
|
|
distribution, you will find these functions and values defined, as
|
|
example turtle programs. (The file is located in the @filepath{graphics}
|
|
subdirectory of the @filepath{collects} subdirectory of the PLT
|
|
distribution).
|
|
|
|
@itemize{
|
|
@item{{{@scheme[(regular-poly sides radius)]}}
|
|
draws a regular poly centered at the turtle with
|
|
sides @scheme[sides] and with radius @scheme[radius].}
|
|
|
|
@item{{{@scheme[(regular-polys sides s)]}}
|
|
draws s regular polys spaced evenly outwards with sides @scheme[sides].}
|
|
|
|
@item{{{@scheme[(radial-turtles n)]}}
|
|
places $2^n$ turtles spaced evenly pointing radially outward}
|
|
|
|
@item{{{@scheme[(spaced-turtles n)]}}
|
|
places $2^n$ turtles pointing in the same direction as the original turtle
|
|
evenly spaced in a line.}
|
|
|
|
@item{{{@scheme[(spokes)]}}
|
|
draws some spokes, using radial-turtles and spaced-turtles}
|
|
|
|
@item{{{@scheme[(spyro-gyra)]}}
|
|
draws a spyro-grya reminiscent shape}
|
|
|
|
@item{{{@scheme[(neato)]}}
|
|
as the name says\ldots}
|
|
|
|
@item{{{@scheme[(graphics-bexam)]}}
|
|
draws a fractal that came up on an exam I took.}
|
|
|
|
@item{{{@scheme[serp-size]}}
|
|
a constant which is a good size for the serp procedures
|
|
|
|
\index{Serpinski Triangle}}
|
|
@item{{@scheme[(serp serp-size)], @scheme[(serp-nosplit serp-size)]}
|
|
draws the Serpinski triangle in two different ways, the first using split
|
|
heavily. After running the first one, try executing
|
|
@scheme[(draw 10)].}
|
|
|
|
@item{{{@scheme[koch-size]}}
|
|
a constant which is a good size for the koch procedures
|
|
|
|
\index{Koch Snowflake}}
|
|
@item{{{@scheme[(koch-split koch-size)],@scheme[(koch-draw koch-size)]}}
|
|
draws the same koch snowflake in two different ways.
|
|
|
|
\index{Lorenz Attractor}
|
|
\index{Butterfly Attractor}}
|
|
@item{{{@scheme[(lorenz a b c)]}}
|
|
watch the lorenz "butterfly" attractor with initial values a b and c.}
|
|
|
|
@item{{{@scheme[(lorenz1)]}}
|
|
a good setting for the lorenz attractor
|
|
|
|
\index{Peano space-filling curve}}
|
|
@item{{@scheme[(peano1 peano-size)]}
|
|
|
|
This will draw the Peano space-filling curve, using split.}
|
|
|
|
@item{{@scheme[(peano2 peano-size)]}
|
|
|
|
This will draw the Peano space-filling curve, without using split.
|
|
|
|
\index{Fern Fractal}}
|
|
@item{{{@scheme[fern-size]}}
|
|
a good size for the fern functions}
|
|
|
|
@item{{{@scheme[(fern1 fern-size)]}}
|
|
You will probably want to point the turtle up before running
|
|
this one, with something like:
|
|
|
|
\begin{center}
|
|
@scheme[(turn/radians (- (/ pi 2)))]
|
|
\end{center}}
|
|
|
|
@item{{{@scheme[(fern2 fern-size)]}}
|
|
a fern -- you may need to backup a little for this one.}
|
|
|
|
}
|
|
|
|
@subsection{Value Turtles}
|
|
|
|
There are two ways to use the turtles in DrScheme. You can
|
|
use it as a TeachPack (see the DrScheme manual for details
|
|
of TeachPacks) or as a library. Use the
|
|
@filepathFirst{value-turtles.ss} TeachPack.
|
|
|
|
In the MrEd language or in a module, load turtles with
|
|
|
|
@schemeblock[
|
|
(require (libKW "value-turtles.ss" "graphics"))
|
|
]
|
|
|
|
|
|
The value turtles are a variation on the turtles library.
|
|
Rather than having just a single window where each operation
|
|
changes the state of that window, in this library, the
|
|
entire turtles window is treated as a value. This means
|
|
that each of the primitive operations accepts, in addition
|
|
to the usual arguments, a turtles window value and instead
|
|
of returning nothing, returns a turtles window value.
|
|
|
|
The following are the value turtle functions:
|
|
|
|
@itemize{
|
|
@item{{@scheme[(turtles number number [number number number])]}\FunctionK{turtles}{turtlesVal}
|
|
creates a new turtles window. The first two arguments are
|
|
the width and height of the turtles window. The remaining
|
|
arguments specify the x,y position of the initial turtle
|
|
and the angle. The default to a turtle in the middle of
|
|
the window, pointing to the right.}
|
|
|
|
@item{{{@scheme[(move n turtles)]}}\FunctionK{move}{moveVal}
|
|
moves the turtle n pixels, returning a new turtles window.}
|
|
|
|
@item{{{@scheme[(draw n turtles)]}}\FunctionK{draw}{drawVal}
|
|
moves the turtle n pixels and draws a line on that path,
|
|
returning a new turtles window.}
|
|
|
|
@item{{{@scheme[(erase n turtles)]}}\FunctionK{erase}{eraseVal}
|
|
moves the turtle n pixels and erases along that path,
|
|
returning a new turtles window.
|
|
|
|
\FunctionK{move-offset}{move-offsetVal}
|
|
\FunctionK{draw-offset}{draw-offsetVal}
|
|
\FunctionK{erase-offset}{erase-offsetVal}}
|
|
@item{{{@scheme[(move-offset h v turtles)],
|
|
@scheme[(draw-offset h v turtles)],
|
|
@scheme[(erase-offset h v turtles)]}}
|
|
are just like move, draw and erase, except they take a horizontal and
|
|
vertical offset from the turtle's current position.}
|
|
|
|
@item{{ @scheme[(turn theta turtles)]}\FunctionK{turn}{turnVal}
|
|
turns the turtle theta degrees counter-clockwise,
|
|
returning a new turtles window.}
|
|
|
|
@item{{ @scheme[(turn/radians theta)]}\FunctionK{turn/radians}{turn/radiansVal}
|
|
turns the turtle theta radians counter-clockwise,
|
|
returning a new turtles window.}
|
|
|
|
@item{{@scheme[(merge turtles turtles)]}\Function{merge}
|
|
|
|
The @scheme[split] and @scheme[tprompt] functionality
|
|
provided by the imperative turtles implementation aren't
|
|
needed for this, since the turtles window is itself a
|
|
value.
|
|
|
|
Instead, the @scheme[merge] accepts two turtles windows
|
|
and combines the state of the two turtles windows into a
|
|
single window. The new window contains all of the
|
|
turtles of the previous two windows, but only the line
|
|
drawings of the first turtles argument.}
|
|
|
|
}
|
|
|
|
In the file @filepath{value-turtles-examples.ss} in the
|
|
@filepath{graphics} library of your PLT distribution, you will
|
|
find these functions and values defined, as example turtle
|
|
programs. (The file is located in the @filepath{graphics}
|
|
subdirectory of the @filepath{collects} subdirectory of the PLT
|
|
distribution).
|
|
|
|
It contains a sampling of the examples from the normal
|
|
turtles implementation, but translated to use @scheme[merge]
|
|
and the values turtles.
|
|
|
|
}
|