# 2D on a screen: GUI canvases Everything so far drew to a file. This chapter draws to a **window**: an interactive canvas that repaints, responds to the mouse and keyboard, and can animate. Every GUI toolkit works the same way in outline: you create a window, you give it a paint handler that draws its contents, and the toolkit calls that handler whenever the window needs redrawing. Drawing inside the handler uses primitives that are, by now, familiar: lines, ellipses, polygons, fills. The Perl GUI landscape has a clear best option for graphics and several others with tradeoffs. This chapter leads with `Prima`, because it is actively maintained, self-contained, and has a real graphics core; then covers `Tk` and `Gtk3` for when you have a reason to prefer them; and is honest about `Wx`, which is no longer a healthy choice. ## Prima: the self-contained option `Prima` is a GUI toolkit written for Perl with its own graphics engine. It does not wrap an external toolkit you have to install and match versions with; it draws natively (on X11 on Linux) and ships its own primitives, image handling, and fonts. It is maintained, and it is the recommendation for new graphics-heavy GUI work in Perl. A minimal window with a paint handler: ```perl use Prima qw(Application); my $win = Prima::MainWindow->new( text => 'Prima demo', size => [400, 300], onPaint => sub { my ($self, $canvas) = @_; # the handler gets a canvas $canvas->color(cl::White); $canvas->bar(0, 0, $canvas->size); # bar is a filled rectangle $canvas->color(cl::Red); $canvas->fill_ellipse(200, 150, 120, 90); $canvas->color(cl::Black); $canvas->line(0, 0, 400, 300); }, ); Prima->run; ``` Two naming notes that catch newcomers. Prima’s **filled rectangle** is `bar`; plain `rectangle` draws the outline. The polygon fill is `fillpoly` (one word), taking an array reference of coordinates. Colors come from the `cl::` constants (`cl::Red`, `cl::White`, and so on) or a packed RGB integer, and are set as the drawing state with `color` before you draw, rather than passed to each primitive. The `Prima::Drawable` primitives are the full set you expect: `line`, `ellipse` and `fill_ellipse`, `arc`, `sector` and `fill_sector`, `polyline`, `fillpoly`, `bar`, `rectangle`, `flood_fill`, and `put_image` for blitting a bitmap. Drawing state includes `color`, `backColor`, `lineWidth`, and fill patterns. ### Offscreen drawing and saving The same primitives work on a `Prima::Image`, an offscreen surface, so you can draw without a window and save the result. This is how a Prima program exports what it drew: ```perl my $img = Prima::Image->new(width => 200, height => 200, type => im::RGB); $img->begin_paint; $img->color(cl::Blue); $img->fill_ellipse(100, 100, 80, 80); $img->end_paint; $img->save('out.png'); ``` `begin_paint` and `end_paint` bracket drawing onto the offscreen image, and `save` writes it in a format inferred from the extension. This dual nature (same drawing code for the screen and for a file) is why the [capstone chapters](capstone-drawing-app.md) build on Prima. ## Tk: the classic Canvas `Tk` (Perl/Tk) is the long-standing option, and its `Canvas` widget has a different model worth knowing: it is **retained-mode**. Instead of a paint handler that redraws everything, you create canvas items (a line, an oval, a polygon) that the widget remembers and redraws for you, and you move or reconfigure them by their id. This suits diagrams and editors where objects persist and get manipulated. ```perl use Tk; my $mw = MainWindow->new; my $canvas = $mw->Canvas(-width => 400, -height => 300)->pack; $canvas->createLine(0, 0, 400, 300, -fill => 'blue', -width => 2); my $oval = $canvas->createOval(160, 100, 240, 180, -fill => 'red'); $canvas->createPolygon(50, 10, 150, 10, 100, 90, -fill => 'green'); # move the remembered oval later, by id $canvas->move($oval, 20, 0); MainLoop; ``` `Tk` is stable and works, though it is in maintenance rather than active development and carries a few inherited CVEs in its bundled Tcl/libpng. For a persistent-object diagram or a quick classic GUI it is a reasonable pick; for a redraw-every-frame animation the immediate-mode Prima model fits better. ## Gtk3: drawing through Cairo `Gtk3` binds GTK 3 through GObject introspection. Its drawing story is that a `Gtk3::DrawingArea` widget emits a `draw` signal handed a [Cairo](vector-cairo-svg.md) context, so you draw with the Cairo API from the vector chapter inside the handler. If your application is already a GTK application, this is the natural way to add custom graphics; if it is not, pulling in the whole GTK stack (the GTK 3 development libraries and GObject introspection data) is a large dependency for graphics alone. ```perl use Gtk3 -init; my $window = Gtk3::Window->new('toplevel'); my $area = Gtk3::DrawingArea->new; $window->add($area); $window->set_default_size(400, 300); $area->signal_connect(draw => sub { my ($widget, $cr) = @_; # $cr is a Cairo context $cr->set_source_rgb(0.2, 0.4, 0.9); $cr->arc(200, 150, 80, 0, 6.28318); $cr->fill; return 0; }); $window->show_all; Gtk3->main; ``` Everything you know about Cairo applies unchanged inside that handler. `Gtk3` is usable but in slow maintenance, and the dependency weight means it earns its place mainly when GTK is already in the picture. ## Wx: mention, not recommendation You will find `Wx` (wxPerl) referenced as the way to build native-looking cross-platform GUIs in Perl, and historically it was. It is included here so its current state is clear: `Wx` and its `Alien::wxWidgets` build dependency have not had a release in years, and a large fraction of automated build reports fail against current wxWidgets. It is not a choice for new work. If you need a GUI with custom drawing today, `Prima` is the maintained self-contained option and `Tk` the maintained classic; reach for either of those instead. ## Choosing | You want … | Reach for | |----------------------------------------------------|-------------| | Maintained, self-contained, graphics-heavy new GUI | `Prima` | | A retained-mode canvas of persistent objects | `Tk` | | Custom drawing inside an existing GTK application | `Gtk3` | | Per-frame animation and a realtime loop | `Prima` | With a window and a paint handler in hand, the toolkit arc is complete. The [next arc](ffi-graphics-primer.md) goes further than any single CPAN module: it uses pperl’s native FFI to reach C graphics libraries directly, and then spends everything in the guide on two projects you can run, both built on the Prima foundation from this chapter.