add example snip%
subclass
This commit is contained in:
parent
7541838b78
commit
bb3265bad0
gui-doc/scribblings/gui
|
@ -172,7 +172,8 @@ The editor toolbox supports extensible and nestable editors by
|
||||||
or an interactive object (such as an embedded editor). In a text
|
or an interactive object (such as an embedded editor). In a text
|
||||||
editor, snips are constrained to fit on a single line and generally
|
editor, snips are constrained to fit on a single line and generally
|
||||||
contain data of a single type. The @racket[snip%] class implements a
|
contain data of a single type. The @racket[snip%] class implements a
|
||||||
basic snip. Other snip classes include @racket[string-snip%] for
|
basic snip and serves as the base for implementing new snips; see
|
||||||
|
@secref["snip-example"]. Other snip classes include @racket[string-snip%] for
|
||||||
managing text, @racket[image-snip%] for managing pictures, and
|
managing text, @racket[image-snip%] for managing pictures, and
|
||||||
@racket[editor-snip%] for managing embedded editors.}
|
@racket[editor-snip%] for managing embedded editors.}
|
||||||
|
|
||||||
|
@ -452,6 +453,9 @@ A snip class's name can also be just @racket["(lib ...)"], which is
|
||||||
form provides no information for the text-only @racketmodname[wxme]
|
form provides no information for the text-only @racketmodname[wxme]
|
||||||
reader.
|
reader.
|
||||||
|
|
||||||
|
For an example snip implementation and its associated snip-class
|
||||||
|
implementation, see @secref["snip-example"].
|
||||||
|
|
||||||
@subsubsection[#:tag "editordata"]{Editor Data}
|
@subsubsection[#:tag "editordata"]{Editor Data}
|
||||||
|
|
||||||
While a snip belongs to an editor, the editor may store extra
|
While a snip belongs to an editor, the editor may store extra
|
||||||
|
@ -556,6 +560,10 @@ For this reason, @techlink{position}-setting and
|
||||||
is filled with @racket[#t] if the position is ambiguous and it came
|
is filled with @racket[#t] if the position is ambiguous and it came
|
||||||
from a right-side location, or @racket[#f] otherwise.
|
from a right-side location, or @racket[#f] otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
@include-section["snip-example.scrbl"]
|
||||||
|
|
||||||
|
|
||||||
@section[#:tag "editorflattened"]{Flattened Text}
|
@section[#:tag "editorflattened"]{Flattened Text}
|
||||||
|
|
||||||
In plain text editors, there is a simple correlation between
|
In plain text editors, there is a simple correlation between
|
||||||
|
|
|
@ -7,28 +7,8 @@ Useful snip classes are defined by instantiating derived subclasses of
|
||||||
@racket[snip-class%]. A class derived from @racket[snip-class%]
|
@racket[snip-class%]. A class derived from @racket[snip-class%]
|
||||||
serves as a kind of ``meta-class'' for snips; each snip is associated
|
serves as a kind of ``meta-class'' for snips; each snip is associated
|
||||||
with an instance of @racket[snip-class%] as its snip class.
|
with an instance of @racket[snip-class%] as its snip class.
|
||||||
|
See @secref["snip-example"] for more information about deriving a new
|
||||||
In deriving a new @racket[snip-class%] class, override the
|
snip class.
|
||||||
@method[snip-class% read] method. Then, for each instance of the
|
|
||||||
derived class (where each instance corresponds to a single snip
|
|
||||||
class):
|
|
||||||
|
|
||||||
@itemize[
|
|
||||||
|
|
||||||
@item{Set the classname using @method[snip-class% set-classname].}
|
|
||||||
|
|
||||||
@item{Set the version using
|
|
||||||
@method[snip-class% set-version].}
|
|
||||||
|
|
||||||
@item{Install the class into the list returned by
|
|
||||||
@racket[get-the-snip-class-list] using the
|
|
||||||
@method[snip-class-list<%> add] method. Note that if the same
|
|
||||||
name is inserted into the same class list multiple times, all
|
|
||||||
but the first insertion is ignored.}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
See also @|snipclassdiscuss|.
|
|
||||||
|
|
||||||
|
|
||||||
@defconstructor[()]{
|
@defconstructor[()]{
|
||||||
|
|
|
@ -4,77 +4,9 @@
|
||||||
@defclass/title[snip% object% (equal<%>)]{
|
@defclass/title[snip% object% (equal<%>)]{
|
||||||
|
|
||||||
A direct instance of @racket[snip%] is uninteresting. Useful snips are
|
A direct instance of @racket[snip%] is uninteresting. Useful snips are
|
||||||
defined by instantiating derived subclasses, but this class defines
|
defined by instantiating derived subclasses, but the @racket[snip%] class defines
|
||||||
the basic functionality.
|
the basic functionality. See @secref["snip-example"] for more information about
|
||||||
|
deriving a new snip class.
|
||||||
In deriving a new snip class, these methods must be overridden to
|
|
||||||
create a useful snip:
|
|
||||||
|
|
||||||
@itemize[
|
|
||||||
|
|
||||||
@item{@method[snip% get-extent]}
|
|
||||||
|
|
||||||
@item{@method[snip% draw]}
|
|
||||||
|
|
||||||
@item{@method[snip% copy]}
|
|
||||||
|
|
||||||
@item{@method[snip% resize] if the snip can be resized by the user}
|
|
||||||
|
|
||||||
@item{@method[snip% partial-offset] if the snip can contain more than
|
|
||||||
one @techlink{item}}
|
|
||||||
|
|
||||||
@item{@method[snip% split] if the snip can contain more than one @techlink{item}}
|
|
||||||
|
|
||||||
@item{@method[snip% size-cache-invalid] if the snip caches the result to @method[snip% get-extent]}
|
|
||||||
|
|
||||||
@item{@method[snip% get-text] (not required)}
|
|
||||||
|
|
||||||
@item{@method[snip% find-scroll-step], @method[snip%
|
|
||||||
get-num-scroll-steps], and @method[snip%
|
|
||||||
get-scroll-step-offset] if the snip can contain more than one
|
|
||||||
scroll position}
|
|
||||||
|
|
||||||
@item{@method[snip% set-unmodified] if the snip's internal state can
|
|
||||||
be modified by the user, and call @method[snip-admin% modified]
|
|
||||||
in the snip's administrator when the state changes the first
|
|
||||||
time}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
If a snip can contain more than one @techlink{item}, then the snip's @techlink{count}
|
|
||||||
must be maintained as well.
|
|
||||||
|
|
||||||
To define a class of snips that can be saved or cut-and-pasted:
|
|
||||||
|
|
||||||
@itemize[
|
|
||||||
|
|
||||||
@item{Create an instance of @racket[snip-class%], implementing the
|
|
||||||
@method[snip-class% read] method. Export the
|
|
||||||
@racket[snip-class%] instance as @racket[snip-class] from a
|
|
||||||
module, and use a classname of the form @racket["(lib ...)"] as
|
|
||||||
described in @|snipclassdiscuss|.}
|
|
||||||
|
|
||||||
@item{For each instance of the snip class, set the snip's class object
|
|
||||||
with @method[snip% set-snipclass].}
|
|
||||||
|
|
||||||
@item{Override the @method[snip% copy] method.}
|
|
||||||
|
|
||||||
@item{Override the @method[snip% write] method.}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
To define a class of snips that read specially with
|
|
||||||
@racket[open-input-text-editor]:
|
|
||||||
|
|
||||||
@itemize[
|
|
||||||
|
|
||||||
@item{Make your @racket[snip%] class implement @racket[readable-snip<%>].}
|
|
||||||
|
|
||||||
@item{Implement the @method[readable-snip<%> read-special] method.}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@defconstructor[()]{
|
@defconstructor[()]{
|
||||||
|
|
||||||
|
|
166
gui-doc/scribblings/gui/snip-example.scrbl
Normal file
166
gui-doc/scribblings/gui/snip-example.scrbl
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require scribble/bnf "common.rkt")
|
||||||
|
|
||||||
|
@title[#:tag "snip-example"]{Implementing New Snips}
|
||||||
|
|
||||||
|
To support new kinds of content within an editor, derive a subclass of @racket[snip%]
|
||||||
|
to implement a new kind of @tech{snip}.
|
||||||
|
In deriving a new snip implementation, the following methods of @racket[snip%]
|
||||||
|
must be overridden to
|
||||||
|
create a useful snip:
|
||||||
|
|
||||||
|
@itemize[
|
||||||
|
|
||||||
|
@item{@method[snip% get-extent]}
|
||||||
|
|
||||||
|
@item{@method[snip% draw]}
|
||||||
|
|
||||||
|
@item{@method[snip% copy]}
|
||||||
|
|
||||||
|
@item{@method[snip% resize] if the snip can be resized by the user}
|
||||||
|
|
||||||
|
@item{@method[snip% partial-offset] if the snip can contain more than
|
||||||
|
one @techlink{item}}
|
||||||
|
|
||||||
|
@item{@method[snip% split] if the snip can contain more than one @techlink{item}}
|
||||||
|
|
||||||
|
@item{@method[snip% size-cache-invalid] if the snip caches the result to @method[snip% get-extent]}
|
||||||
|
|
||||||
|
@item{@method[snip% get-text] (not required)}
|
||||||
|
|
||||||
|
@item{@method[snip% find-scroll-step], @method[snip%
|
||||||
|
get-num-scroll-steps], and @method[snip%
|
||||||
|
get-scroll-step-offset] if the snip can contain more than one
|
||||||
|
scroll position}
|
||||||
|
|
||||||
|
@item{@method[snip% set-unmodified] if the snip's internal state can
|
||||||
|
be modified by the user, and call @method[snip-admin% modified]
|
||||||
|
in the snip's administrator when the state changes the first
|
||||||
|
time}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
If a snip can contain more than one @techlink{item}, then the snip's @techlink{count}
|
||||||
|
must be maintained as well.
|
||||||
|
|
||||||
|
To define a class of snips that can be saved or cut-and-pasted (see also
|
||||||
|
@|snipclassdiscuss|):
|
||||||
|
|
||||||
|
@itemize[
|
||||||
|
|
||||||
|
@item{Create an instance of @racket[snip-class%], implementing the
|
||||||
|
@method[snip-class% read] method. Export the
|
||||||
|
@racket[snip-class%] instance as @racket[snip-class] from a
|
||||||
|
module, and use a classname of the form @racket["(lib ...)"] as
|
||||||
|
described in @|snipclassdiscuss|.}
|
||||||
|
|
||||||
|
@item{For each instance of the snip class, set the snip's class object
|
||||||
|
with @method[snip% set-snipclass].}
|
||||||
|
|
||||||
|
@item{Override the @method[snip% copy] method.}
|
||||||
|
|
||||||
|
@item{Override the @method[snip% write] method.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
In deriving a new @racket[snip-class%] class:
|
||||||
|
|
||||||
|
@itemize[
|
||||||
|
|
||||||
|
@item{Set the classname using @method[snip-class% set-classname].}
|
||||||
|
|
||||||
|
@item{Set the version using
|
||||||
|
@method[snip-class% set-version].}
|
||||||
|
|
||||||
|
@item{Install the class into the list returned by
|
||||||
|
@racket[get-the-snip-class-list] using the
|
||||||
|
@method[snip-class-list<%> add] method. Note that if the same
|
||||||
|
name is inserted into the same class list multiple times, all
|
||||||
|
but the first insertion is ignored.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
To define a class of snips that read specially with
|
||||||
|
@racket[open-input-text-editor]:
|
||||||
|
|
||||||
|
@itemize[
|
||||||
|
|
||||||
|
@item{Make your @racket[snip%] class implement @racket[readable-snip<%>].}
|
||||||
|
|
||||||
|
@item{Implement the @method[readable-snip<%> read-special] method.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
As an example, the following module implements a snip that draws a
|
||||||
|
circle. Clicking on the snip causes the circle to grow. To enable
|
||||||
|
copying an instance of the snip from one program/eventspace to
|
||||||
|
another, the module should be @filepath{main.rkt} a
|
||||||
|
@filepath{circle-snip} directory that is installed as a
|
||||||
|
@filepath{circle-snip} package.
|
||||||
|
|
||||||
|
@codeblock{
|
||||||
|
#lang racket/base
|
||||||
|
(require racket/class
|
||||||
|
racket/snip
|
||||||
|
racket/format)
|
||||||
|
|
||||||
|
(provide circle-snip%
|
||||||
|
(rename-out [circle-snip-class snip-class]))
|
||||||
|
|
||||||
|
(define circle-snip%
|
||||||
|
(class snip%
|
||||||
|
(inherit set-snipclass
|
||||||
|
get-flags set-flags
|
||||||
|
get-admin)
|
||||||
|
(init-field [size 20.0])
|
||||||
|
|
||||||
|
(super-new)
|
||||||
|
(set-snipclass circle-snip-class)
|
||||||
|
(send (get-the-snip-class-list) add circle-snip-class)
|
||||||
|
(set-flags (cons 'handles-events (get-flags)))
|
||||||
|
|
||||||
|
(define/override (get-extent dc x y
|
||||||
|
[w #f]
|
||||||
|
[h #f]
|
||||||
|
[descent #f]
|
||||||
|
[space #f]
|
||||||
|
[lspace #f]
|
||||||
|
[rspace #f])
|
||||||
|
(define (maybe-set-box! b v) (when b (set-box! b v)))
|
||||||
|
(maybe-set-box! w (+ 2.0 size))
|
||||||
|
(maybe-set-box! h (+ 2.0 size))
|
||||||
|
(maybe-set-box! descent 1.0)
|
||||||
|
(maybe-set-box! space 1.0)
|
||||||
|
(maybe-set-box! lspace 1.0)
|
||||||
|
(maybe-set-box! rspace 1.0))
|
||||||
|
|
||||||
|
(define/override (draw dc x y left top right bottom dx dy draw-caret)
|
||||||
|
(send dc draw-ellipse (+ x 1.0) (+ y 1.0) size size))
|
||||||
|
|
||||||
|
(define/override (copy)
|
||||||
|
(new circle-snip% [size size]))
|
||||||
|
|
||||||
|
(define/override (write f)
|
||||||
|
(send f put size))
|
||||||
|
|
||||||
|
(define/override (on-event dc x y editorx editory e)
|
||||||
|
(when (send e button-down?)
|
||||||
|
(set! size (+ 1.0 size))
|
||||||
|
(define admin (get-admin))
|
||||||
|
(when admin
|
||||||
|
(send admin resized this #t))))))
|
||||||
|
|
||||||
|
(define circle-snip-class%
|
||||||
|
(class snip-class%
|
||||||
|
(inherit set-classname)
|
||||||
|
|
||||||
|
(super-new)
|
||||||
|
(set-classname (~s '(lib "main.rkt" "circle-snip")))
|
||||||
|
|
||||||
|
(define/override (read f)
|
||||||
|
(define size-b (box 0.0))
|
||||||
|
(send f get size-b)
|
||||||
|
(new circle-snip% [size (unbox size-b)]))))
|
||||||
|
|
||||||
|
(define circle-snip-class (new circle-snip-class%))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user