Added unstable/gui/snip (provides snip-canvas%) and docs

Changed plot-frame to use snip-canvas%, so resizing the frame resizes the plot; added Escape handler (closes the frame)
This commit is contained in:
Neil Toronto 2012-03-03 12:33:49 -07:00
parent bf97780eda
commit 610280225c
5 changed files with 200 additions and 33 deletions

View File

@ -1,44 +1,34 @@
#lang racket/base
;; Extra GUI classes.
;; GUI helpers
(require racket/gui/base racket/class)
(require racket/gui/base racket/class unstable/gui/snip)
(provide (all-defined-out))
(define read-only-text%
(class text%
(define snip-frame%
(class frame%
(super-new)
(send this hide-caret #t)
(define writable? #t)
(define/public (set-writable w?) (set! writable? w?))
(define/augment (can-change-style? start len) writable?)
(define/augment (can-delete? start len) writable?)
(define/augment (can-insert? start len) writable?)
(define/augment (can-load-file? filename format) writable?)
(define/augment (can-save-file? filename format) writable?)
(define/override (can-do-edit-operation? op [recursive? #t])
(case op
[(copy select-all) #t]
[else writable?]))
(define/override (on-traverse-char event)
(define key-code (send event get-key-code))
(case key-code
[(escape) (send this show #f)]
[else (super on-traverse-char event)]))
))
(define (make-snip-frame snip width height label)
(define frame (new frame% [width width] [height height] [label label]))
(define text (new read-only-text%))
(define canvas (new editor-canvas% [parent frame] [editor text]
[horizontal-inset 0] [vertical-inset 0] [horiz-margin 0] [vert-margin 0]
[enabled #t] [style '(no-hscroll no-vscroll no-border)]))
(send text insert snip)
(send text set-writable #f)
(define (make-snip w h)
(send snip resize w h)
snip)
(define frame
(new snip-frame% [label label] [width (+ 10 width)] [height (+ 10 height)]))
(new snip-canvas%
[parent frame]
[make-snip make-snip]
[horiz-margin 5] [vert-margin 5]
[horizontal-inset 5] [vertical-inset 5])
frame)
(define (snip->canvas snip)
(let/ec return
(define admin (send snip get-admin))
(when (not admin) (return #f))
(define editor (send admin get-editor))
(send editor get-active-canvas)))

View File

@ -84,7 +84,7 @@ Use @(racket plot-bitmap) to create a @(racket bitmap%).
Use @(racket plot-frame) to create a @(racket frame%) regardless of the value of @(racket plot-new-window?). The frame is initially hidden.
Use @(racket plot-snip) to create an @(racket image-snip%) regardless of the value of @(racket plot-new-window?).
Use @(racket plot-snip) to create an interactive @(racket image-snip%) regardless of the value of @(racket plot-new-window?).
}
@doc-apply[plot/dc]{

View File

@ -0,0 +1,81 @@
#lang racket/base
(require racket/gui/base racket/class)
(provide snip-canvas%)
(define snip-canvas%
(class editor-canvas%
(init parent
make-snip
[style null]
[label #f]
[horizontal-inset 5]
[vertical-inset 5]
[enabled #t]
[vert-margin 0]
[horiz-margin 0]
[min-width 0]
[min-height 0]
[stretchable-width #t]
[stretchable-height #t])
(define snip #f)
(define text (new read-only-text%))
(send text set-writable #f)
(super-new [parent parent]
[editor text]
[horizontal-inset horizontal-inset]
[vertical-inset vertical-inset]
[label label]
[enabled enabled]
[style (list* 'no-hscroll 'no-vscroll style)]
[vert-margin vert-margin]
[horiz-margin horiz-margin]
[min-width min-width]
[min-height min-height]
[stretchable-width stretchable-width]
[stretchable-height stretchable-height])
(define/public (get-snip) snip)
(define/override (on-size w h)
(update-snip w h)
(super on-size w h))
(define (update-snip w h)
(define snip-w (max 0 (- w (* 2 horizontal-inset))))
(define snip-h (max 0 (- h (* 2 vertical-inset))))
(cond [snip (send snip resize snip-w snip-h)]
[else (set-snip (make-snip snip-w snip-h))]))
(define (set-snip s)
(unless (is-a? s snip%)
(raise-type-error 'set-snip "snip%" s))
(set! snip s)
(send text set-writable #t)
(send text erase)
(send text insert snip)
(send text set-writable #f))
))
(define read-only-text%
(class text%
(super-new)
(send this hide-caret #t)
(define writable? #t)
(define/public (set-writable w?) (set! writable? w?))
(define/augment (can-change-style? start len) writable?)
(define/augment (can-delete? start len) writable?)
(define/augment (can-insert? start len) writable?)
(define/augment (can-load-file? filename format) writable?)
(define/augment (can-save-file? filename format) writable?)
(define/override (can-do-edit-operation? op [recursive? #t])
(case op
[(copy select-all) #t]
[else writable?]))
))

View File

@ -12,3 +12,4 @@
@include-section["gui/pict.scrbl"]
@include-section["gui/slideshow.scrbl"]
@include-section["gui/pslide.scrbl"]
@include-section["gui/snip.scrbl"]

View File

@ -0,0 +1,95 @@
#lang scribble/manual
@(require "../utils.rkt"
(for-label racket/base
racket/class
racket/gui/base
unstable/gui/snip
racket/contract
plot))
@title[#:tag "snip"]{Snip Utilities}
@unstable[@author+email["Neil Toronto" "neil.toronto@gmail.com"]]
@defmodule[unstable/gui/snip]
@defclass[snip-canvas% editor-canvas% ()]{
A canvas that contains a single snip.
Snips cannot be placed directly on dialogs, frames and panels.
To use an interactive snip (such as one returned by @racket[plot-snip]) in a GUI,
it must be inserted into an editor, which itself must be placed on a special canvas, which can be placed in a GUI container.
To provide a seamless user experience, the editor should be enabled but not writable,
not be able to receive focus, not have scrollbars, and other small details.
The @racket[snip-canvas%] class handles these details, making it easy to use interactive snips as normal GUI elements.
@defconstructor[([parent (or/c (is-a?/c frame%) (is-a?/c dialog%)
(is-a?/c panel%) (is-a?/c pane%))]
[make-snip ((integer-in 0 10000) (integer-in 0 10000) . -> . snip%)]
[style (listof (one-of/c 'no-border 'control-border 'combo
'resize-corner 'no-focus 'deleted
'transparent)) null]
[label (or/c label-string? false/c) #f]
[horizontal-inset (integer-in 0 1000) 5]
[vertical-inset (integer-in 0 1000) 5]
[enabled any/c #t]
[vert-margin (integer-in 0 1000) 0]
[horiz-margin (integer-in 0 1000) 0]
[min-width (integer-in 0 10000) 0]
[min-height (integer-in 0 10000) 0]
[stretchable-width any/c #t]
[stretchable-height any/c #t])]{
Unlike instances of @racket[editor-canvas%], each instance of this class creates and manages its own editor.
The editor contains one object: a @racket[snip%] instance created by @racket[make-snip].
The @racket[make-snip] function receives the requested width and height of the snip, which are calculated from the size of the snip canvas.
It is called the first time the snip canvas is resized, which most likely coincides with the first time the snip canvas is shown.
The snip is thus created @italic{lazily}: only when needed, at the size needed.
See @method[snip-canvas% on-size] for more details and an example.
The @racket[style] list is prepended with @racket['no-hscroll] and @racket['no-vscroll] before being passed to the @racket[editor-canvas%] constructor.
The other constructor arguments are passed untouched.
}
@defmethod[(get-snip) (or/c (is-a?/c snip%) #f)]{
Returns the wrapped snip, or @racket[#f] if @racket[make-snip] has not been called yet.
}
@defmethod[#:mode override
(on-size [width (integer-in 0 10000)]
[height (integer-in 0 10000)])
void?]{
This is called when the snip canvas is resized.
On the first call, @method[snip-canvas% on-size] calls @racket[make-snip] with width and height arguments
respectively @racket[(max 0 (- width (* 2 horizontal-inset)))] and @racket[(max 0 (- height (* 2 vertical-inset)))].
It then inserts the resulting snip into its editor.
On subsequent calls, @method[snip-canvas% on-size] calls the snip's @method[snip% resize] method, calculating the width and height arguments the same way.
When a @racket[snip-canvas%] instance is intended to wrap an existing @racket[snip%] instance, @racket[make-snip] should simply resize it and return it.
Example: @racket[plot-frame] and @racket[plot3d-frame] create snips and call a function similar to the following to place them in a frame:
@racketblock[
(define (make-snip-frame snip w h label)
(define (make-snip width height)
(send snip resize width height)
snip)
(define frame
(new frame%
[label label]
[width (+ 5 5 5 5 w)]
[height (+ 5 5 5 5 h)]))
(new snip-canvas%
[parent frame]
[make-snip make-snip]
[horiz-margin 5] [vert-margin 5]
[horizontal-inset 5] [vertical-inset 5])
frame)]
}
} @; defclass snip-canvas%