Friday, March 21, 2014

Getting Started with GtkAda - Packing

When creating an application, you'll want to put more than one widget inside a window. Our first helloworld example only used one widget so we could simply use Add call to "pack" the widget into the window. But when you want to put more than one widget into a window, it it becomes important to control how each widget is positioned and sized. This is where packing comes in.

GtkAda comes with a large variety of layout containers whose purpose it is to control the layout of the child widgets that are added to them. You could see the Gtk+ Layout Containers for an overview. GtkAda has all the containers and normally has the form of Gtk_<Container_Name>

The following example shows how the Gtk_Grid container lets you arrange several buttons. It follows the same directory structure in the helloworld example.

src/grid.adb:
with Gtk.Main;
with Gtk.Window;      use Gtk.Window;
with Gtk.Grid;        use Gtk.Grid;
with Gtk.Button;      use Gtk.Button;
with Gtkada.Handlers; use Gtkada.Handlers;

with grid_cb; use grid_cb;

procedure Grid is
   Win    : Gtk_Window;
   Grid   : Gtk_Grid;
   Button : Gtk_Button;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- create a top level window
   Gtk_New (Win);
   Win.Set_Title ("Grid");
   -- set the border width of the window
   Win.Set_Border_Width (10);
   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   -- Here we construct the container that is going pack our buttons
   Gtk_New (Grid);

   -- Packed the container in the Window
   Win.Add (Grid);

   -- create a button with label
   Gtk_New (Button, "Button 1");
   -- connect the click signal
   Button.On_Clicked (button_clicked'Access);

   -- Place the first button in the grid cell (0, 0), and make it fill
   -- just 1 cell horizontally and vertically (ie no spanning)
   Grid.Attach (Button, 0, 0, 1, 1);

   -- create another button with label
   Gtk_New (Button, "Button 2");
   Button.On_Clicked (button_clicked'Access);

   -- Place the second button in the grid cell (1, 0), and make it fill
   -- just 1 cell horizontally and vertically (ie no spanning)
   Grid.Attach (Button, 1, 0, 1, 1);

   -- create the quit button
   Gtk_New (Button, "Quit");
   -- connect the "clicked" signal of the button to destroy function
   Widget_Callback.Object_Connect
     (Button,
      "clicked",
      Widget_Callback.To_Marshaller (button_quit'Access),
      Win);
   -- Place the Quit button in the grid cell (0, 1), and make it
   -- span 2 columns.
   Grid.Attach (Button, 0, 1, 2, 1);

   -- Now that we are done packing our widgets, we show them all
   -- in one go, by calling Win.Show_All.
   -- This call recursively calls Show on all widgets
   -- that are contained in the window, directly or indirectly.
   Win.Show_All;

   -- All GTK applications must have a Gtk.Main.Main. Control ends here
   -- and waits for an event to occur (like a key press or a mouse event),
   -- until Gtk.Main.Main_Quit is called.
   Gtk.Main.Main;
end Grid;
src/grid_cb.ads:
with Gtk.Widget;  use Gtk.Widget;
with Gtk.Button;  use Gtk.Button;
with Glib.Object;

with Gdk.Event;

package grid_cb is
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean;
   procedure main_quit (Self : access Gtk_Widget_Record'Class);
   procedure button_clicked (Self : access Gtk_Button_Record'Class);
   procedure button_quit (Self : access Gtk_Widget_Record'Class);
end grid_cb;
src/grid_cb.adb:
with Ada.Text_IO; use Ada.Text_IO;

with Gtk.Main;

package body grid_cb is
   -- If you return false in the "delete_event" signal handler,
   -- GTK will emit the "destroy" signal. Returning true means
   -- you don't want the window to be destroyed.
   --
   -- This is useful for popping up 'are you sure you want to quit?'
   -- type dialogs.
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean
   is
   begin
      Put_Line ("Delete event encounter.");
      return True;
   end main_del;

   procedure main_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Gtk.Main.Main_Quit;
   end main_quit;

   procedure button_clicked (Self : access Gtk_Button_Record'Class) is
   begin
      Put_Line ("Hello clicked");
   end button_clicked;

   procedure button_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Put_Line ("buttion_quit is called");
      Destroy (Self);
   end button_quit;

end grid_cb;
grid.gpr
with "gtkada";

project Grid is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("grid.adb");

   --  Enable Ada 2005.
   package Compiler is
      for Default_Switches ("ada") use ("-gnat05");
   end Compiler;

end Grid
To compile the program:
gprbuild -P grid

You may notice the callback functions are exactly the same as helloworld, you could reuse it by just rename the packages or simple using the same hello_cb package and in grid.adb with and use it with hello_cb; use hello_cb;, then you don't need to change anything on the call backs.

No comments: