(module rpn-gui mzscheme (require (lib "mred.ss" "mred") (lib "class.ss") (lib "list.ss") "rpn.ss" "simple-grid.ss" "simple-layouts.ss") (provide ugly-gui% less-ugly-gui%) (define calculator-model% (class object% (super-new) (define a-calc (new-calc)) (define listeners empty) (define/public (send-command-to-model! cmd) (set! a-calc (eval-command a-calc cmd)) (notify-listeners!)) (define/public (add-listener! new-listener) (set! listeners (cons new-listener listeners))) (define (notify-listeners!) (for-each (lambda (f) (f (calc-x-reg a-calc))) listeners)))) (define less-ugly-gui% (class frame% (super-new) (define model (new calculator-model%)) (send model add-listener! (lambda (xreg) (send text-field set-value (format "~a" xreg)))) (define/public (send-command-to-model! cmd) (send model send-command-to-model! cmd)) (define (make-command-button label cmd parent) (new button% [label label] [parent parent] [callback (lambda (button evt) (send-command-to-model! cmd))])) (define text-field (new text-field% [label #f] [parent this] [enabled #f])) (make-command-button "Reset" 'Reset this) (let ([grid (new simple-grid-panel% [parent (new horizontal-panel% [parent this] [alignment '(center center)])])]) (for-each (lambda (cmd) (make-command-button (format "~a" cmd) cmd grid)) (list 7 8 9 4 5 6 1 2 3 0 '+ '*))) (make-command-button "Enter" 'Enter this) (send-command-to-model! 'Reset))) (define rpn-controller% (class object% [init model] [init view] (super-new) (define current-model model) (define (update-view!) (send (send view get-text-field) set-value (format "~a" (calc-x-reg current-model)))) (send view set-on-button-pressed! (lambda (cmd) (set! current-model (eval-command current-model cmd)) (update-view!))) (update-view!))) (define ugly-view% (class frame% (super-new) (define (on-button-pressed cmd) (void)) (define/public (set-on-button-pressed! f) (set! on-button-pressed f)) (define (make-command-button label cmd) (new button% [label label] [parent this] [callback (lambda (button evt) (on-button-pressed cmd))])) (define text-field (new text-field% [label #f] [parent this] [enabled #f])) (define/public (get-text-field) text-field) (let* ([cmds '(Reset 0 1 2 3 4 5 6 7 8 9 + * Enter)] [labels (map (lambda (c) (format "~a" c)) cmds)]) (for-each make-command-button labels cmds)))) (define (test-rpn-gui) (let ([model (new-calc)] [view (new ugly-view% [label "ugly!"])]) (let ([controller (new rpn-controller% [model model] [view view])]) (send view show #t)))) (define ugly-gui% (class frame% (super-new) (define my-calculator (new-calc)) (define (sync-text-field-with-calc) (send text-field set-value (format "~a" (calc-x-reg my-calculator)))) (define (make-command-button label cmd) (new button% [label label] [parent this] [callback (lambda (button evt) (set! my-calculator (eval-command my-calculator cmd)) (sync-text-field-with-calc))])) ;; GUI widgets below: (define text-field (new text-field% [label #f] [parent this] [enabled #f])) (make-command-button "Reset" 'Reset) (for-each (lambda (digit) (make-command-button (number->string digit) digit)) '(0 1 2 3 4 5 6 7 8 9)) (make-command-button "+" '+) (make-command-button "*" '*) (make-command-button "Enter" 'Enter) (sync-text-field-with-calc))))