Simple Scheme で電卓をつくってみる(3)

Simple Schemeで電卓を作っています。前回までで、ボタンを押したら反応するようになりました

今度はボタンごとに異なる反応を返すようにしてみましょう。

押したボタンの上に、ボタンの文字と同じ色の円盤を重ね、その上に白抜きでボタンの文字を拡大表示します。

そのためには、どのボタンが押されたかを、タップされた位置の座標から求めなければなりません。
ボタンの文字については、文字のリストがすでにあるので、画面上の座標をキーボード上の座標に変換して、さらに添字に変換すれば求められます。

(define button-labels
  '("%"  "7" "8" "9" "÷" "MR"
    "√"  "4" "5" "6" "×" "M-"
    "C"  "1" "2" "3" "-" "M+"
    "AC" "0" "." "=" "+"))

(list-ref button-labels (+ (iconv-x x) (* 6 (iconv-y y))) ;(x,y)の位置にあるボタンのラベルをこれで取得できる

文字以外の情報(サイズと色)を含めたレコード型を定義してそのリストを作りましょう。

(define-struct button (label size color))
(define buttons
  (letrec ((find (lambda (lis b)
                   (let ((bc (car lis)))
                     (if (ormap (lambda (l) (string=? b l))
                                (button-category-labels bc))
                         (make-button b (button-category-size bc)
                                      (button-category-color bc))
                         (find (cdr lis) b))))))
    (map (lambda (l) (find button-categories l)) button-labels)))

これでタップされた位置のボタンの、文字以外の情報も取得できるようになりました。

(big-bang keyboard
          (on-draw (lambda (b) b))
          (on-mouse
           (lambda (_ x y what)
             (if (string=? what "button-down")
                 (let ((x (iconv-x x)) (y (iconv-y y)))
                   (let ((i (+ x (* 6 y))))
                     (if (and (<= 0 x) (< x 6) (<= 0 i) (< i 23))
                         (let ((b (list-ref buttons i))
                               (x (conv-x x)) (y (conv-y y)))
                           (place-image
                            (text (button-label b) (/ (* 4 (button-size b)) 3)
                                  "white")
                            x y
                            (place-image (circle 100 "solid" (button-color b)) x y
                                         keyboard)))
                         keyboard)))
                 keyboard))))

*1

続きます。

(ここまでのコード)*2*3*4

*1:Schemeなのでこのようにできそうですができませんでした。Simple Schemeでは<の3つめ以降の引数は無視されるようです。そのためキーボードよりも下の部分をタップしたときもbuttonsにアクセスしようとするのですが、範囲外なので強制終了してしまいます。
また、添字だけで範囲を指定するのは処理系に関係なく普通に間違いです。例えば(-1,2)の位置にM-があるとみなされたりするので。

*2:マジックナンバーが多いのなんとかしたほうがいいかな?

*3:キーボードのイメージを生成するコードもbuttonsを使って少し変えました

*4:以前と同じ英語の間違いをしていたので修正しました。