Diagrams + Cairo + Gtk + Mouse picking

Diagrams is the best library for drawing diagrams in Haskell. But can it be used as part of a user interface so you can interact with parts of a diagram?

The answer is: yes.





In this article we walk through a simple example that combines Diagrams, its Cairo backend and Gtk, to show a diagram and determine which parts of the diagram the mouse is over.

The full source code for this example is at the bottom of this article, but we’ll also look at some excerpts in detail.

Let’s start with the diagram to be shown. It’s a simple picture of a house that a child might draw. The only special thing we do here is tag parts of the diagram with the value function. Each part – the wall, door, handle, roof, chimney and smoke – has a single string attached to it.

Now we can query the points in the diagram to see what’s there.

With this we’re actually most of the way there. However, the coordinate system of the diagram is not the same as the mouse coordinates we’ll get from Gtk. We could take the mouse coordinates and transform them into diagram coordinates, but let’s do it the other way around and make the diagram coordinates as close to the mouse coordinates as possible.

Gtk’s mouse coordinates have the origin (0,0) at the top left of the canvas. So first we move the diagram’s origin to the top left:

Then we scale the diagram so that it’s the same width as the canvas:

(The freeze makes the line widths scale up too.)

Now we are almost done: our mouse and diagram coordinates are the same size. The last wrinkle is that in diagrams-land positive Y-coordinates go up, but in Gtk-land positive Y-coordinates go down. We could reflect the diagram before we sample from it, but I found it easier just to negate the Y-coordinate.

And we’re done! The rest of the program is basically just Gtk plumbing.

Here’s the whole program.

Christopher Mears, 20 February 2014