Draw something on the screen... and interact with it!
Summary of the previous episodes: 10 days ago Richard Jones complained about the difficulties to achieve simple tasks (drawing a function graph on the screen) on modern computers with modern programming languages; the day after Erik de Castro Lopo replied with a post in which he used GTK and Cairo (better: the OCaml bindings) to achieve the result to draw a simple function on the screen. Yesterday Matias Giovannini added some pepper to this argument using SDL to draw the Newton fractal.
So, what can be added to all this? With a perfect graphic toy you can draw on a window with simple commands, of course, but you also want to interact with the objects you drew. So I elaborated Erik example to add some keyboard and mouse interaction with the graphics on the screen.
Downloading and compiling
First of all, download the source code or, if you want the latest version, clone my GIT repository:
$ git clone https://www.ex-nunc.org/projects/pdonadeo/cairo_toy.git cairo_toy.git
To compile the program you need:
- OCaml (I have version 3.10.2, but probably 3.10.0 or 3.10.1 are ok);
- Lablgtk2, the OCaml binding to GTK2;
- the OCaml binding to libcairo.
All these packages are available in any recent Linux distribution; on Debian/Ubuntu:
$ aptitude install ocaml liblablgtk2-ocaml-dev libcairo-ocaml-dev
To compile instruct this command inside the program directory:
$ ocamlbuild demo_toy.native
The code
The program is very simple and is essentially derived from Erik's code: the core is the functor Toy_maker.Make which accepts, as input, a module with the following signature INTERACTOR:
module type INTERACTOR = sig type state val init_state : state val win_title : string val init_width : int val init_height : int val cmd_line_handler : state -> string array -> state val keyboard_callback : state -> GdkEvent.Key.t -> state * bool val pointer_buttons_callback : state -> GdkEvent.Button.t -> state * bool val pointer_motion_callback : state -> GdkEvent.Motion.t -> state * bool val pointer_scroll_callback : state -> GdkEvent.Scroll.t -> state * bool val repaint : state -> Cairo.t -> int -> int -> state * bool end
In this module the user must provide a type state, which contains the application state, some initialization values, a command line handler (in case you need) and 4 event handlers for the following events:
- keyboard;
- mouse motion;
- mouse buttons;
- mouse wheel event (scroll events in GTK).
The user also provides a repaint function, which takes care of repainting the Cairo context.
As a demo I wrote a simple My_interactor module implementing the following simple features:
- left click on the gray background creates a new circle;
- left click inside an existing circle moves it around;
- right click inside a circle deletes it;
- the mouse wheel zooms (in and out);
- middle click is used to pan;
Here is the result.
Yes, it's somewhat dull, but it does its job. Have fun!
1 September 2008, 18:58
This is off-topic, but i think your two-colour background makes the code quite hard to read. It looks like a list of unrelated lines, while it isn't, wich is a bit disturbing.
If you want to make the line number easy to associate with the corresponding code line, you could try a hover mechanism (highlighting the line under the mouse) instead.