Simple Scheme で電卓をつくってみる(5)
数を入力できるようになりました。
入力した数は、整数部分と小数部分をそれぞれトップレベル変数で保持するようになっています。画面に表示するときはこれらの変数から直接数値を取り出してイメージに変換して表示しています。
しかし、この方法では入力した数値以外の数を表示できません。
そこで、表示するデータを保持する、window
という変数を別に作ることにしました。
数字を表示するときは、まず表示したい数をwindow
へ代入することになります。
代入を簡単にするために、structureを使って、整数部分と小数部分を1つにまとめることにしました。
(define-struct num (sign i f)) (define input (make-num " " '(0) '())) (define window input) (define result #f) (define memory input)
数を保持するstructureの型名はnum
です。num
には整数部分と小数部分だけでなく符号も加えました。入力内容が負数になることはありませんが、計算結果やメモリの中身が負数になることがあるからです*1。
数字ボタンをタップするとinput-number
内で生成された関数が起動します。この関数の最後にwindow
への代入処理を追加しました。
*2
(define (rcons xs x) (append xs (list x))) (define which-part 'int) (define (input-number n) (lambda () (and (< (+ (length (num-i input)) (length (num-f input))) max-ndigits) (begin (if (symbol=? which-part 'int) (if (and (null? (cdr (num-i input))) (= 0 (car (num-i input)))) (set! input (make-num " " (list n) (num-f input))) (set! input (make-num " " (rcons (num-i input) n) (num-f input)))) (set! input (make-num " " (num-i input) (rcons (num-f input) n)))) (set! window input)))))
(define (overlay-window scn) (let* ((lis (map number->string (append (num-i window) (num-f window)))) (wdx (* width (/ 3/4 (+ max-ndigits 1/2)))) (iwdx (round wdx)) (wconv-x (lambda (x) (round (+ (* width 1/8) (* wdx (+ x (- max-ndigits (length lis)) 1)))))) (y (/ width 8))) (foldl (lambda (x scn) (place-image (text (car x) iwdx "black") (cadr x) y scn)) (place-image (text "." iwdx "black") (wconv-x (- (length (num-i window)) 0.5)) y (place-image (text (num-sign window) iwdx "black") (wconv-x -0.8) y scn)) (build-list (length lis) (lambda (i) (list (list-ref lis i) (wconv-x i)))))))
入力した数字の表示部分を少し広げ、数字のサイズを少し小さくしました。
また、数字の表示位置を少し右にずらしました。
これらの変更の目的は、符号を表示するための場所を空けることです。
*3
→古いバージョンの数字のサイズ(wdx
)と数字位置決定関数(wconv-x
)
枠をつけました。この場合keyboard
がバインドしているのは電源オフ状態の電卓のイメージですね。じゃあkeyboardという名前をやめろってなりますけど、どうしましょう。また今度考えます。
(define keyboard (place-image (round-rectangle (round (* 27/34 width)) 150 5 "outline" "gray") (/ width 2) (/ width 7) (place-buttons 0 0 buttons (empty-scene))))
続きます。