(module mrtextfield racket/base (require racket/class racket/list (prefix-in wx: "kernel.rkt") "lock.rkt" "const.rkt" "check.rkt" "helper.rkt" "wx.rkt" "wxtextfield.rkt" "mrcontainer.rkt" "mritem.rkt" "mrmenu.rkt" "mrpopup.rkt") (provide text-field% combo-field%) (define combo-flag (gensym)) (define (check-text-field-args cwho label choices? choices parent callback init-value style req-styles font) (check-label-string/false cwho label) (when choices? (unless (and (list? choices) (andmap label-string? choices)) (raise-argument-error (who->name cwho) "(listof label-string?)" choices))) (check-container-parent cwho parent) (check-callback cwho callback) (check-string cwho init-value) (check-style cwho req-styles (append (if choices? null '(hscroll password)) '(vertical-label horizontal-label deleted)) (remq combo-flag style)) (check-font cwho font)) (define text-field% (class basic-control% (init label parent [callback (lambda (b e) (void))] [init-value ""] [style '(single)] ;; These are needed to ensure the order of init ;; args is correct (we pass them to the superclass below) ;; and so that this class can check the inits below. [font no-val] [enabled #t] [vert-margin no-val] [horiz-margin no-val] [min-width no-val] [min-height no-val] [stretchable-width no-val] [stretchable-height no-val]) (init-rest) (check-text-field-args '(constructor text-field) label #f #f parent callback init-value style '(single multiple) font) (define wx #f) (public* [set-field-background (lambda (c) (check-instance '(method text-field% set-field-color) wx:color% 'color% #f c) (send wx set-field-background c))] [get-field-background (lambda () (send wx get-field-background))] [get-editor (entry-point (lambda () (send wx get-editor)))] [get-value (lambda () (send wx get-value))] ; note: wx method doesn't expect as-entry [set-value (entry-point (lambda (v) (check-string '(method text-field% set-value) v) (send wx set-value v)))]) ;; Technically a bad way to change margin defaults, since it's ;; implemented with an update after creation: (when (eq? horiz-margin no-val) (set! horiz-margin 2)) (when (eq? vert-margin no-val) (set! vert-margin 2)) (as-entry (lambda () (super-new [mk-wx (lambda () (set! wx (make-object wx-text-field% this this (mred->wx-container parent) (wrap-callback callback) label init-value (if (memq combo-flag style) (cons 'combo (remq combo-flag style)) style) (no-val->#f font))) wx)] [mismatches (lambda () (let ([cwho '(constructor text-field)]) (check-container-ready cwho parent)))] [lbl label] [parent parent] [cb callback] [cursor ibeam] [font font] [enabled enabled] [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 combo-field% (class text-field% (init label choices parent [callback (lambda (b e) (void))] [init-value ""] [style '()] ;; this is handled by a superclass, but we put it here due to the check below [font no-val] [enabled #t] [vert-margin no-val] [horiz-margin no-val] [min-width no-val] [min-height no-val] [stretchable-width no-val] [stretchable-height no-val]) (init-rest) (inherit set-value popup-menu get-size focus get-editor) (check-text-field-args '(constructor combo-field) label #f choices parent callback init-value style #f font) (private* [prep-popup (lambda () (send menu on-demand) (let ([items (send menu get-items)] [wx (mred->wx this)]) (send wx clear-combo-items) (for-each (lambda (item) (unless (item . is-a? . separator-menu-item%) (send wx append-combo-item (send item get-plain-label) (lambda () (send item command (make-object wx:control-event% 'menu-popdown)))))) items)))]) (public* [on-popup (lambda (e) (void))] [get-menu (lambda () menu)] [append (lambda (item) (check-label-string '(method combo-field% append) item) (make-object menu-item% item menu (lambda (i e) (handle-selected item))))]) (private* [handle-selected (lambda (item) (focus) (set-value item) (let ([e (get-editor)]) (send e set-position 0 (send e last-position))) (send (as-entry (lambda () (mred->wx this))) command (make-object wx:control-event% 'text-field)))]) (define menu (new popup-menu% [font font])) (super-new [label label] [parent parent] [callback callback] [init-value init-value] [style (list* combo-flag 'single style)] [font font] [enabled enabled] [horiz-margin horiz-margin] [vert-margin vert-margin] [min-width min-width] [min-height min-height] [stretchable-width stretchable-width] [stretchable-height stretchable-height]) (send (mred->wx this) set-on-popup (lambda () (on-popup (make-object wx:control-event% 'menu-popdown)) (prep-popup))) (for-each (lambda (item) (append item)) choices))))