271 lines
8.2 KiB
Scheme
271 lines
8.2 KiB
Scheme
|
|
(module multiple-choice mzscheme
|
|
(require (prefix mred: mred)
|
|
mzlib/class
|
|
mzlib/file
|
|
mzlib/pretty
|
|
mzlib/etc
|
|
mzlib/list
|
|
"utils.ss"
|
|
"base.ss"
|
|
"feature.ss")
|
|
|
|
(define gb:make-item-list-snip%
|
|
(lambda (cl)
|
|
(class cl
|
|
(inherit gb-need-recalc-size)
|
|
(private*
|
|
[delete
|
|
(lambda (l p)
|
|
(let loop ([l l][p p])
|
|
(cond
|
|
[(null? l) l]
|
|
[(zero? p) (cdr l)]
|
|
[else (cons (car l) (loop (cdr l) (sub1 p)))])))])
|
|
(public*
|
|
[get-items
|
|
(lambda ()
|
|
items)]
|
|
[init-items (lambda () null)]
|
|
[get-item-height
|
|
(lambda (dc)
|
|
(let-values ([(w h d a) (send dc get-text-extent "Xj")])
|
|
h))]
|
|
[get-max-item-width
|
|
(lambda (dc)
|
|
(let loop ([l items][mw 0])
|
|
(if (null? l)
|
|
mw
|
|
(let-values ([(w h d a) (send dc get-text-extent (car l))])
|
|
(loop (cdr l) (max mw w))))))]
|
|
|
|
[items-install
|
|
(lambda (l)
|
|
(set! items l))])
|
|
(override*
|
|
[get-frame%
|
|
(lambda ()
|
|
(class (super get-frame%)
|
|
(inherit-field controls)
|
|
(super-new)
|
|
(public*
|
|
[user-item (lambda (v)
|
|
(mred:get-text-from-user "Item name:" "List Item Name" #f v))])
|
|
(private-field
|
|
[items-panel (make-object mred:vertical-panel% controls)]
|
|
[items-list (make-object mred:list-box%
|
|
"Items:"
|
|
items
|
|
items-panel
|
|
(lambda (l e)
|
|
(when (eq? 'list-box-dclick (send e get-event-type))
|
|
(let ([pos (send items-list get-selection)])
|
|
(unless (negative? pos)
|
|
(let ([v (user-item (list-ref items pos))])
|
|
(when v
|
|
(send items-list set-string pos v)
|
|
(set! items (let loop ([items items][pos pos])
|
|
(if (zero? pos)
|
|
(cons v (cdr items))
|
|
(cons (car items)
|
|
(loop (cdr items) (sub1 pos))))))
|
|
(gb-need-recalc-size))))))))]
|
|
[item-buttons-panel (let ([v (make-object mred:horizontal-panel% items-panel)])
|
|
(send v stretchable-width #f)
|
|
v)]
|
|
[add-item (make-object mred:button% "Add Item" item-buttons-panel
|
|
(lambda (b e)
|
|
(let ([v (user-item (format
|
|
"Item~a"
|
|
(send items-list get-number)))])
|
|
(when v
|
|
(send items-list append v)
|
|
(set! items (append items (list v)))
|
|
(gb-need-recalc-size)))))]
|
|
[delete-item (make-object mred:button% "Delete Item" item-buttons-panel
|
|
(lambda (b e)
|
|
(let loop ([ls (reverse (send items-list get-selections))])
|
|
(unless (null? ls)
|
|
(send items-list delete (car ls))
|
|
(set! items (delete items (car ls)))
|
|
(loop (cdr ls))))
|
|
(gb-need-recalc-size)))])))]
|
|
[gb-instantiate-arguments
|
|
(lambda ()
|
|
(cons
|
|
`[choices ',(get-items)]
|
|
(super gb-instantiate-arguments)))]
|
|
[copy
|
|
(lambda ()
|
|
(let ([o (super copy)])
|
|
(send o items-install items)
|
|
o))]
|
|
[write
|
|
(lambda (stream)
|
|
(super write stream)
|
|
(stream-write-list stream items))]
|
|
[read
|
|
(lambda (stream version)
|
|
(super read stream version)
|
|
(items-install (stream-read-list stream version)))])
|
|
(private-field
|
|
[items (init-items)])
|
|
(super-new))))
|
|
|
|
(define gb:make-list-box-snip%
|
|
(lambda (cl cn)
|
|
(class cl
|
|
(inherit-field w h)
|
|
(inherit get-callback-names get-items get-item-height)
|
|
(field
|
|
[min-body-width 50]
|
|
[sb-width 10]
|
|
[min-item-count 3])
|
|
(override*
|
|
[get-classname (lambda () cn)]
|
|
[init-name (lambda () (new-name "listbox"))]
|
|
[init-y-stretch? (lambda () #t)]
|
|
[init-x-stretch? (lambda () #t)]
|
|
[get-min-body-size
|
|
(lambda (dc)
|
|
(let ([y (get-item-height dc)])
|
|
(values min-body-width (* min-item-count y))))]
|
|
[draw-body
|
|
(lambda (dc x y w h)
|
|
(send dc draw-rectangle x y w h)
|
|
(send dc draw-line
|
|
(+ w x (- sb-width)) y
|
|
(+ w x (- sb-width)) (+ y h))
|
|
(with-clipping-region
|
|
dc x y (- w sb-width) h
|
|
(lambda ()
|
|
(let ([ih (get-item-height dc)])
|
|
(let loop ([l (get-items)][iy (add1 y)])
|
|
(unless (or (>= iy (+ y h)) (null? l))
|
|
(send dc draw-text (car l) (+ 2 x) iy)
|
|
(loop (cdr l) (+ iy ih))))))))]
|
|
[get-callback-kinds (lambda ()
|
|
(list "-select-callback" "-double-select-callback"))]
|
|
[gb-get-default-class (lambda () 'list-box%)]
|
|
[gb-get-style
|
|
(lambda ()
|
|
(cons 'single
|
|
(super gb-get-style)))]
|
|
[gb-get-unified-callback
|
|
(lambda ()
|
|
(let-values ([(sel dbl) (apply values (get-callback-names))])
|
|
`(lambda (b e)
|
|
(case (send e get-event-type)
|
|
[(list-box) (,sel b e)]
|
|
[(list-box-dclick) (,dbl b e)]))))])
|
|
(super-new))))
|
|
|
|
|
|
(define gb:list-box-snip% (gb:make-list-box-snip%
|
|
(gb:make-item-list-snip%
|
|
(gb:make-callback-snip%
|
|
(gb:make-text-labelled-snip% gb:atomic-snip%
|
|
"List")))
|
|
"gb:listbox"))
|
|
|
|
(register-class gb:list-box-snip% "gb:listbox")
|
|
|
|
|
|
(define gb:make-radio-box-snip%
|
|
(lambda (cl cn)
|
|
(class cl
|
|
(inherit-field w h vertical-layout?)
|
|
(inherit get-item-height get-max-item-width get-items
|
|
gb-need-recalc-size)
|
|
(private-field
|
|
[circle-size 10]
|
|
[margin 2])
|
|
(override*
|
|
[get-classname (lambda () cn)]
|
|
[init-name (lambda () (new-name "radiobox"))]
|
|
[init-items (lambda () (list "First" "Second"))]
|
|
[get-min-body-size
|
|
(lambda (dc)
|
|
(let ([h (max (get-item-height dc) circle-size)]
|
|
[w (get-max-item-width dc)]
|
|
[l (length (get-items))])
|
|
(let-values ([(x-l y-l) (if vertical-layout?
|
|
(values 1 l)
|
|
(values l 1))])
|
|
(values (* (+ circle-size margin w) x-l)
|
|
(* h y-l)))))]
|
|
[draw-body
|
|
(lambda (dc x y w h)
|
|
(let ([ih (max (get-item-height dc) circle-size)]
|
|
[iw (+ (get-max-item-width dc) circle-size margin)])
|
|
(let loop ([l (get-items)][iy y][ix x])
|
|
(unless (null? l)
|
|
(send dc draw-ellipse ix (+ iy (/ (- ih circle-size) 2)) circle-size circle-size)
|
|
(send dc draw-text (car l) (+ circle-size margin ix) iy)
|
|
(if vertical-layout?
|
|
(loop (cdr l) (+ iy ih) ix)
|
|
(loop (cdr l) iy (+ ix iw)))))))]
|
|
[gb-get-default-class (lambda () 'radio-box%)])
|
|
(super-new))))
|
|
|
|
|
|
(define gb:radio-box-snip% (gb:make-radio-box-snip%
|
|
(gb:make-item-list-snip%
|
|
(gb:make-layout-snip%
|
|
(gb:make-callback-snip%
|
|
(gb:make-text-labelled-snip% gb:atomic-snip%
|
|
"Radiobox"))))
|
|
"gb:radiobox"))
|
|
|
|
(register-class gb:radio-box-snip% "gb:radiobox")
|
|
|
|
|
|
(define gb:make-choice-snip%
|
|
(lambda (cl cn)
|
|
(class cl
|
|
(inherit-field w h)
|
|
(inherit get-item-height get-max-item-width get-items
|
|
gb-need-recalc-size)
|
|
(field
|
|
[arrow-size 10]
|
|
[lmargin 2]
|
|
[amargin 2]
|
|
[rmargin 2]
|
|
[arrow (list (make-object mred:point% 0 0)
|
|
(make-object mred:point% arrow-size 0)
|
|
(make-object mred:point% (quotient arrow-size 2) (quotient arrow-size 2)))])
|
|
(override*
|
|
[get-classname (lambda () cn)]
|
|
[init-name (lambda () (new-name "choice"))]
|
|
[init-items (lambda () (list "First"))]
|
|
[get-min-body-size
|
|
(lambda (dc)
|
|
(let ([h (get-item-height dc)]
|
|
[w (get-max-item-width dc)])
|
|
(values (+ lmargin arrow-size amargin w rmargin 3) (+ 3 h))))]
|
|
[draw-body
|
|
(lambda (dc x y w h)
|
|
(send dc draw-rectangle x y (sub1 w) (sub1 h))
|
|
(send dc draw-line (sub1 (+ x w)) (add1 y) (sub1 (+ x w)) (+ y h))
|
|
(send dc draw-line (add1 x) (sub1 (+ y h)) (+ x w) (sub1 (+ y h)))
|
|
(send dc draw-polygon arrow (+ 1 lmargin x) (+ y (/ (- h (/ arrow-size 2)) 2)))
|
|
(let ([l (get-items)])
|
|
(unless (null? l)
|
|
(send dc draw-text (car l) (+ 1 lmargin arrow-size amargin x) (add1 y)))))]
|
|
[gb-get-default-class (lambda () 'choice%)])
|
|
(super-new))))
|
|
|
|
|
|
(define gb:choice-snip% (gb:make-choice-snip%
|
|
(gb:make-item-list-snip%
|
|
(gb:make-callback-snip%
|
|
(gb:make-text-labelled-snip% gb:atomic-snip%
|
|
"Choice")))
|
|
"gb:choice"))
|
|
|
|
(register-class gb:choice-snip% "gb:choice")
|
|
|
|
(provide gb:list-box-snip%
|
|
gb:radio-box-snip%
|
|
gb:choice-snip%))
|