(**************************************) (* The main type of graphics contexts *) (* HW06: You will need to modify this type definition for Task 5. *) type t = { x:int; y:int; (* offset from (0,0) in local coordinates *) color:Graphics.color; (* the current pen color *) } (*************************) (* Basic Gctx operations *) (*************************) (* Creates a fresh Gctx.t *) let create () : t = {x=0; y=0; color=Graphics.black; } (* Shifts the gctx by (dx,dy) *) let translate (g:t) ((dx,dy):int*int) : t = {g with x=g.x+dx; y=g.y+dy} (*******************************) (* Coordinates Transformations *) (*******************************) (* ALWAYS call these functions before passing widget-local points to the native Graphics module or vice-versa. *) (* This function takes widget-local coordinates (x,y) to OCaml graphics coordinates, relative to the graphics context. *) let ocaml_coords (g:t) ((x,y):int*int) : (int*int) = (g.x + x, Graphics.size_y()-(g.y + y)) (* This function takes OCaml Graphics coordinates (x,y) to widget-local graphics coordinates, relative to the graphics context *) let local_coords (g:t) ((x,y):int*int) : (int*int) = (x - g.x, (Graphics.size_y() - y) - g.y) (**********) (* Colors *) (**********) type color = Graphics.color let (black,white,red,green) = (Graphics.black,Graphics.white,Graphics.red,Graphics.green) let (blue,yellow,cyan,magenta) = (Graphics.blue,Graphics.yellow,Graphics.cyan,Graphics.magenta) (* Produce a new Gctx.t with a different pen color *) let set_color (g:t) (c:color) : t = {g with color=c} (* Set the OCaml graphics library's internal state so that it agrees with the Gctx settings. Initially, this just sets the current pen color. *) (* HW06: You will need to modify this type definition for Task 5. *) let set_graphics_state (g:t) : unit = Graphics.set_color g.color (***********) (* Drawing *) (***********) (* Each of these functions takes inputs in widget-local coordinates, converts them to OCaml coordinates, and then draws the appropriate shape. *) let draw_line (g:t) (p1:int*int) (p2:int*int) : unit = set_graphics_state g; let (x1,y1) = ocaml_coords g p1 in let (x2,y2) = ocaml_coords g p2 in Graphics.moveto x1 y1; Graphics.lineto x2 y2 let draw_string (g:t) (p:int*int) (s:string) : unit = set_graphics_state g; let (_, height) = Graphics.text_size s in let (x,y) = ocaml_coords g p in Graphics.moveto x (y - height); (* subtract: working with Ocaml coordinates *) Graphics.draw_string s let fill_rect (g:t) (p1:int*int) (w,h:int*int) : unit = set_graphics_state g; let (x,y) = ocaml_coords g p1 in Graphics.fill_rect x y w h let text_size (g:t) (s:string) : int*int = set_graphics_state g; Graphics.text_size s (* HW06: You will need to add several "wrapped" versions of ocaml graphics functions here for Tasks 2, 4, and possibly 5 and 6 *) (******************) (* Event Handling *) (******************) type event = Graphics.status (* Waits for a mouse or key event *) let wait_for_event (g:t) : event = Graphics.wait_next_event [Graphics.Mouse_motion; Graphics.Button_down; Graphics.Button_up; Graphics.Key_pressed] (* Determine whether the event has the button pressed *) let button_pressed (g:t) (e:event) : bool = e.Graphics.button (* Get the widget-local coordinates of an event *) let event_pos (g:t) (e:event) : int * int = local_coords g (e.Graphics.mouse_x, e.Graphics.mouse_y) (* Determine whether the event has a key pressed *) let is_keypressed (g:t) (e:event) : bool = e.Graphics.keypressed (* Get the keyboard character associated with an event *) let get_key (g:t) (e:event) : char = e.Graphics.key