Blame examples_labltk/calc.ml

Packit bd2e5d
(***********************************************************************)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*                 MLTk, Tcl/Tk interface of OCaml                     *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*    Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis    *)
Packit bd2e5d
(*               projet Cristal, INRIA Rocquencourt                    *)
Packit bd2e5d
(*            Jacques Garrigue, Kyoto University RIMS                  *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(*  Copyright 2002 Institut National de Recherche en Informatique et   *)
Packit bd2e5d
(*  en Automatique and Kyoto University.  All rights reserved.         *)
Packit bd2e5d
(*  This file is distributed under the terms of the GNU Library        *)
Packit bd2e5d
(*  General Public License, with the special exception on linking      *)
Packit bd2e5d
(*  described in file LICENSE found in the OCaml source tree.          *)
Packit bd2e5d
(*                                                                     *)
Packit bd2e5d
(***********************************************************************)
Packit bd2e5d
Packit bd2e5d
(* $Id$ *)
Packit bd2e5d
Packit bd2e5d
(* A simple calculator demonstrating OO programming with O'Labl
Packit bd2e5d
   and LablTk.
Packit bd2e5d
Packit bd2e5d
   LablTk itself is not OO, but it is good to wrap complex
Packit bd2e5d
   structures in objects. Even if the absence of initializers
Packit bd2e5d
   makes things a little bit awkward.
Packit bd2e5d
*)
Packit bd2e5d
Packit bd2e5d
open StdLabels
Packit bd2e5d
open Tk
Packit bd2e5d
Packit bd2e5d
let mem_string ~elt:c s =
Packit bd2e5d
  try
Packit bd2e5d
    for i = 0 to String.length s -1 do
Packit bd2e5d
      if s.[i] = c then raise Exit
Packit bd2e5d
    done; false
Packit bd2e5d
  with Exit -> true
Packit bd2e5d
Packit bd2e5d
let ops = ['+',(+.); '-',(-.); '*',( *.); '/',(/.)]
Packit bd2e5d
Packit bd2e5d
(* The abstract calculator class.
Packit bd2e5d
   Does not use Tk (only Textvariable) *)
Packit bd2e5d
Packit bd2e5d
class calc () = object (calc)
Packit bd2e5d
  val variable = Textvariable.create ()
Packit bd2e5d
  val mutable x = 0.0
Packit bd2e5d
  val mutable op = None
Packit bd2e5d
  val mutable displaying = true
Packit bd2e5d
Packit bd2e5d
  method set = Textvariable.set variable
Packit bd2e5d
  method get = Textvariable.get variable
Packit bd2e5d
  method insert s = calc#set (calc#get ^ s)
Packit bd2e5d
  method get_float = float_of_string (calc#get)
Packit bd2e5d
Packit bd2e5d
  method command s =
Packit bd2e5d
    if s <> "" then match s.[0] with
Packit bd2e5d
      '0'..'9' ->
Packit bd2e5d
        if displaying then (calc#set ""; displaying <- false);
Packit bd2e5d
        calc#insert s
Packit bd2e5d
    | '.' ->
Packit bd2e5d
        if displaying then
Packit bd2e5d
          (calc#set "0."; displaying <- false)
Packit bd2e5d
        else
Packit bd2e5d
          if not (mem_string ~elt:'.' calc#get) then calc#insert s
Packit bd2e5d
    | '+'|'-'|'*'|'/' as c ->
Packit bd2e5d
        displaying <- true;
Packit bd2e5d
        begin match op with
Packit bd2e5d
          None ->
Packit bd2e5d
            x <- calc#get_float;
Packit bd2e5d
            op <- Some (List.assoc c ops)
Packit bd2e5d
        | Some f ->
Packit bd2e5d
            x <- f x (calc#get_float);
Packit bd2e5d
            op <- Some (List.assoc c ops);
Packit bd2e5d
            calc#set (Printf.sprintf "%g" x)
Packit bd2e5d
        end
Packit bd2e5d
    | '='|'\n'|'\r' ->
Packit bd2e5d
        displaying <- true;
Packit bd2e5d
        begin match op with
Packit bd2e5d
          None -> ()
Packit bd2e5d
        | Some f ->
Packit bd2e5d
            x <- f x (calc#get_float);
Packit bd2e5d
            op <- None;
Packit bd2e5d
            calc#set (Printf.sprintf "%g" x)
Packit bd2e5d
        end
Packit bd2e5d
    | 'q' -> closeTk (); exit 0
Packit bd2e5d
    | _ -> ()
Packit bd2e5d
end
Packit bd2e5d
Packit bd2e5d
(* Buttons for the calculator *)
Packit bd2e5d
Packit bd2e5d
let m =
Packit bd2e5d
  [|["7";"8";"9";"+"];
Packit bd2e5d
    ["4";"5";"6";"-"];
Packit bd2e5d
    ["1";"2";"3";"*"];
Packit bd2e5d
    ["0";".";"=";"/"]|]
Packit bd2e5d
Packit bd2e5d
(* The physical calculator. Inherits from the abstract one *)
Packit bd2e5d
Packit bd2e5d
class calculator ~parent = object
Packit bd2e5d
  inherit calc () as calc
Packit bd2e5d
Packit bd2e5d
  val label = Label.create ~anchor:`E ~relief:`Sunken ~padx:10 parent
Packit bd2e5d
  val frame = Frame.create parent
Packit bd2e5d
Packit bd2e5d
  initializer
Packit bd2e5d
    let buttons =
Packit bd2e5d
      Array.map ~f:
Packit bd2e5d
        (List.map ~f:
Packit bd2e5d
           (fun text ->
Packit bd2e5d
             Button.create ~text ~command:(fun () -> calc#command text) frame))
Packit bd2e5d
        m
Packit bd2e5d
    in
Packit bd2e5d
    Label.configure ~textvariable:variable label;
Packit bd2e5d
    calc#set "0";
Packit bd2e5d
    bind ~events:[`KeyPress] ~fields:[`Char]
Packit bd2e5d
      ~action:(fun ev -> calc#command ev.ev_Char)
Packit bd2e5d
      parent;
Packit bd2e5d
    for i = 0 to Array.length m - 1 do
Packit bd2e5d
      Grid.configure ~row:i buttons.(i)
Packit bd2e5d
    done;
Packit bd2e5d
    pack ~side:`Top ~fill:`X [label];
Packit bd2e5d
    pack ~side:`Bottom ~fill:`Both ~expand:true [frame];
Packit bd2e5d
end
Packit bd2e5d
Packit bd2e5d
(* Finally start everything *)
Packit bd2e5d
Packit bd2e5d
let top = openTk ()
Packit bd2e5d
Packit bd2e5d
let applet = new calculator ~parent:top
Packit bd2e5d
Packit bd2e5d
let _ = mainLoop ()