(* The widget interface will consist of a type composed of a function that processes events (signature: fun mouse_x mouse_y mouse_button key_pressed -> returns a new widget) and a function to draw the widget itself. *) type widget = { process_event : (int -> int -> bool -> char -> widget); draw_self : (unit -> unit) } (* Two different types of button: *) (* A rectangular fixed-position button *) let rec make_button left top width height col = let ds () = Graphics.set_color col; Graphics.draw_rect left top width height and pe x y b k = let pt_in_box x y left top width height = if ((x >= left) && (x < (left + width)) && (y >= top) && (y < (top + height))) then true else false in if (pt_in_box x y left top width height) then make_button left top width height Graphics.red (* The button has the focus; create a new Red button *) else make_button left top width height Graphics.black (* The button does not have the focus; create a new Black button *) in { process_event = pe; draw_self = ds; } (* And a circular 'draggable' button *) let rec make_circle_button cx cy cr col = let ds () = Graphics.set_color col; Graphics.draw_circle cx cy cr and pe x y b k = let pt_in_circle x y cx cy cr = let foi = float_of_int and iof = int_of_float in let l = iof (sqrt (foi ((cx - x)*(cx - x) + (cy - y) * (cy - y)))) in if l < cr then true else false in if (pt_in_circle x y cx cy cr) then if b = true then make_circle_button x y cr Graphics.yellow (* The button has the focus *and* is being dragged; create a new Yellow button *) else make_circle_button cx cy cr Graphics.red (* The button has the focus; create a new Red button *) else make_circle_button cx cy cr Graphics.black (* The button does not have the focus; create a new Black button *) in { process_event = pe; draw_self = ds; } (* Put them together *) let rec do_events w = let x, y = Graphics.mouse_pos () and b = Graphics.button_down () and k = if Graphics.key_pressed () then Graphics.read_key () else char_of_int 0 in if k = char_of_int 27 then exit 0 else (* ESC exits program *) let w' = Array.map (fun a -> a.process_event x y b k) w in Array.iter (fun a -> a.draw_self ()) w'; do_events w';; (* Place all parent buttons in a list. Each parent button is the ancestor of a linear family tree of buttons *) let get_events () = try do_events [|(make_circle_button 80 80 25 Graphics.black); (make_button 10 10 40 40 Graphics.black); (make_circle_button 180 140 25 Graphics.black); (make_button 10 80 40 40 Graphics.black)|] with _ -> () (*************** test framework ********************) let width = 320 let height = 200 let main () = let init_string = (Printf.sprintf " %dx%d" width height) in Graphics.open_graph init_string ; let _ = get_events () in try while true do () done; exit 0; with _ -> print_string "Exception"; Graphics.close_graph (); exit 0 ;; main ();;