1. ----------------------------------------------------------------------- 
  2. --               GtkAda - Ada95 binding for Gtk+/Gnome               -- 
  3. --                                                                   -- 
  4. --                 Copyright (C) 2003-2013, AdaCore                  -- 
  5. --                                                                   -- 
  6. -- This library is free software; you can redistribute it and/or     -- 
  7. -- modify it under the terms of the GNU General Public               -- 
  8. -- License as published by the Free Software Foundation; either      -- 
  9. -- version 2 of the License, or (at your option) any later version.  -- 
  10. --                                                                   -- 
  11. -- This library is distributed in the hope that it will be useful,   -- 
  12. -- but WITHOUT ANY WARRANTY; without even the implied warranty of    -- 
  13. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -- 
  14. -- General Public License for more details.                          -- 
  15. --                                                                   -- 
  16. -- You should have received a copy of the GNU General Public         -- 
  17. -- License along with this library; if not, write to the             -- 
  18. -- Free Software Foundation, Inc., 59 Temple Place - Suite 330,      -- 
  19. -- Boston, MA 02111-1307, USA.                                       -- 
  20. --                                                                   -- 
  21. -- As a special exception, if other files instantiate generics from  -- 
  22. -- this unit, or you link this unit with other files to produce an   -- 
  23. -- executable, this  unit  does not  by itself cause  the resulting  -- 
  24. -- executable to be covered by the GNU General Public License. This  -- 
  25. -- exception does not however invalidate any other reasons why the   -- 
  26. -- executable file  might be covered by the  GNU Public License.     -- 
  27. ----------------------------------------------------------------------- 
  28.  
  29. --  <description> 
  30. --  This widget implements a multi-paned widget, similar to the standard 
  31. --  Gtk_Paned widget, but which can contain several children side to side. 
  32. --  This widget can mix vertical and horizontal splits 
  33. --  </description> 
  34. --  <group>Layout containers</group> 
  35. --  <testgtk>create_splittable.adb</testgtk> 
  36.  
  37. with Glib;       use Glib; 
  38. with Gdk.Cursor; 
  39. with Gdk.GC; 
  40. with Gtk.Enums; 
  41. with Gtk.Fixed; 
  42. with Gtk.Widget; 
  43.  
  44. package Gtkada.Multi_Paned is 
  45.    type Gtkada_Multi_Paned_Record is new Gtk.Fixed.Gtk_Fixed_Record 
  46.      with private; 
  47.    type Gtkada_Multi_Paned is access all Gtkada_Multi_Paned_Record'Class; 
  48.  
  49.    Handle_Width : constant := 6; 
  50.    --  Width, in pixels, of the resizing handles. 
  51.    --  ??? Should be read from theme with 
  52.    --     gtk_widget_style_get (gtk_paned, "handle_size", &handle_size, NULL) 
  53.  
  54.    type Pane is private; 
  55.    --  An area of the window, which can is splitted either horizontally or 
  56.    --  vertically. It can contain one or several children, next to each other, 
  57.    --  or on top of one another. 
  58.  
  59.    Root_Pane : constant Pane; 
  60.    --  The root pane. If you split this one, the newly added window will be 
  61.    --  next to all other windows. For instance, if you split vertically with 
  62.    --  the main_pane the following window, you will get: 
  63.    --     +-----+------+        +-----+------+ 
  64.    --     |  1  |      |        |  1  |      | 
  65.    --     +-----+  3   |    =>  +-----+  3   | 
  66.    --     |  2  |      |        |  2  |      | 
  67.    --     +-----+------+        +-----+------+ 
  68.    --                           |     4      | 
  69.    --                           +------------+ 
  70.  
  71.    procedure Gtk_New (Win : out Gtkada_Multi_Paned); 
  72.    procedure Initialize (Win : access Gtkada_Multi_Paned_Record'Class); 
  73.    --  Create a new paned window. 
  74.  
  75.    procedure Set_Opaque_Resizing 
  76.      (Win : access Gtkada_Multi_Paned_Record; Opaque : Boolean); 
  77.    --  Whether resizing of the widgets should be opaque or not. The default 
  78.    --  is not to do opaque resizing for efficiency reasons 
  79.  
  80.    procedure Add_Child 
  81.      (Win           : access Gtkada_Multi_Paned_Record; 
  82.       New_Child     : access Gtk.Widget.Gtk_Widget_Record'Class; 
  83.       Orientation   : Gtk.Enums.Gtk_Orientation := 
  84.         Gtk.Enums.Orientation_Horizontal; 
  85.       Fixed_Size    : Boolean := False; 
  86.       Width, Height : Glib.Gint := -1; 
  87.       After         : Boolean := True); 
  88.    --  Add new child, splitting as needed. 
  89.    --  This should be used when there is no child yet 
  90.    --  The window is splitted in two by default. However, if Width and Height 
  91.    --  are specified (or left to -1 for automatic computation), the window is 
  92.    --  splitted so that amount of screen space is left to the widget 
  93.    --  (leaving some minimum amount of space to other children as needed). 
  94.    --  If Fixed_Size is true, then the size of the dock will not change when 
  95.    --  Win is resized. Otherwise, it will keep its relative size (x% of the 
  96.    --  total size of Win). This Fixed_Size setting will be reset to False 
  97.    --  as soon as the user has resized a pane with the mouse. 
  98.  
  99.    procedure Split 
  100.      (Win           : access Gtkada_Multi_Paned_Record; 
  101.       Ref_Widget    : access Gtk.Widget.Gtk_Widget_Record'Class; 
  102.       New_Child     : access Gtk.Widget.Gtk_Widget_Record'Class; 
  103.       Orientation   : Gtk.Enums.Gtk_Orientation; 
  104.       Fixed_Size    : Boolean := False; 
  105.       Width, Height : Glib.Gint := -1; 
  106.       After         : Boolean := True); 
  107.    --  Split the pane containing Ref_Widget, and add New_Child 
  108.    --  in the new pane (on the right or at the bottom if After is True, on the 
  109.    --  left or at the top if After is False). 
  110.  
  111.    procedure Set_Size 
  112.      (Win           : access Gtkada_Multi_Paned_Record; 
  113.       Widget        : access Gtk.Widget.Gtk_Widget_Record'Class; 
  114.       Width, Height : Glib.Gint := -1; 
  115.       Fixed_Size    : Boolean := False); 
  116.    --  Force a specific size for Widget 
  117.  
  118.    function Splitted_Area 
  119.      (Win           : access Gtkada_Multi_Paned_Record; 
  120.       Ref_Widget    : access Gtk.Widget.Gtk_Widget_Record'Class; 
  121.       Orientation   : Gtk.Enums.Gtk_Orientation; 
  122.       After         : Boolean := True) return Gtk.Widget.Gtk_Widget; 
  123.    --  Return the widget in the splitted area next to Ref_Widget if any exist. 
  124.    --  Orientation and After define which splitted area we are looking at. 
  125.    --  null is returned if there are no such splitted area. 
  126.  
  127.    function Get_Pane 
  128.      (Win    : access Gtkada_Multi_Paned_Record; 
  129.       Widget : access Gtk.Widget.Gtk_Widget_Record'Class) return Pane; 
  130.    function Get_Pane (Current_Pane : Pane) return Pane; 
  131.    --  Return the pane that contains the widget. See comment for Split below. 
  132.  
  133.    procedure Split 
  134.      (Win           : access Gtkada_Multi_Paned_Record; 
  135.       Ref_Pane      : Pane; 
  136.       New_Child     : access Gtk.Widget.Gtk_Widget_Record'Class; 
  137.       Orientation   : Gtk.Enums.Gtk_Orientation; 
  138.       Fixed_Size    : Boolean := False; 
  139.       Width, Height : Glib.Gint := -1; 
  140.       After         : Boolean := True); 
  141.    --  Split Ref_Pane to display New_Child to one of its sides. 
  142.    --  See the comments for Root_Pane above. 
  143.    --  The examples below assume that you are using one of the two split 
  144.    --  procedures, either with a Ref_Pane or a Ref_Widget. In the former case, 
  145.    --  the pane is obtained with a call to Get_Pane(Ref_Widget). 
  146.    --  As you will see, the results are different (although they might appear 
  147.    --  similar sometimes on this simple example. 
  148.    --  In all these examples, we split either vertically or horizontally, and 
  149.    --  add a new widget "4". 
  150.    -- 
  151.    --  Given the following setup: 
  152.    --     +---+---+ 
  153.    --     | 1 |   | 
  154.    --     +---+ 3 | 
  155.    --     | 2 |   | 
  156.    --     +---+---+ 
  157.    -- 
  158.    --  Ref_Pane = Get_Pane ("1")              Ref_Widget = "1" 
  159.    --  Split vertically 
  160.    --    After=True  After=False        After=True   After=False 
  161.    --    +---+---+   +---+---+          +---+---+    +---+---+ 
  162.    --    | 1 | 3 |   | 4 | 3 |          | 1 | 3 |    | 4 | 3 | 
  163.    --    +---+   |   +---+   |          +---+   |    +---+   | 
  164.    --    | 2 |   |   | 1 |   |          | 4 |   |    | 1 |   | 
  165.    --    +---+   |   +---+   |          +---+   |    +---+   | 
  166.    --    | 4 |   |   | 2 |   |          | 2 |   |    | 2 |   | 
  167.    --    +---+---+   +---+---+          +---+---+    +---+---+ 
  168.    -- 
  169.    --  Split horizontally 
  170.    --    After=True     After=False     After=True     After=False 
  171.    --    +---+---+---+  +---+---+---+   +---+---+---+  +---+---+---+ 
  172.    --    | 1 | 4 | 3 |  | 4 | 1 | 3 |   | 1 | 4 | 3 |  | 4 | 1 | 3 | 
  173.    --    +---+   |   |  |   +---+   |   +---+---+   |  +---+---+   | 
  174.    --    | 2 |   |   |  |   | 2 |   |   |   2   |   |  |   2   |   | 
  175.    --    +---+---+---+  +---+---+---+   +-------+---+  +-------+---+ 
  176.    -- 
  177.    -- 
  178.    --  Ref_Pane = Get_Pane ("3")             Ref_Widget = "3" 
  179.    --  Split vertically 
  180.    --    After=True   After=False       After=True     After=False 
  181.    --    +---+---+    +-------+         +---+---+      +---+---+ 
  182.    --    | 1 | 3 |    |   4   |         | 1 | 3 |      | 1 | 4 | 
  183.    --    +---+   |    +---+---+         +---+---+      +---+---+ 
  184.    --    | 2 |   |    | 1 | 3 |         | 2 | 4 |      | 2 | 3 | 
  185.    --    +---+---+    +---+   |         +---+---+      +---+---+ 
  186.    --    |   4   |    | 2 |   | 
  187.    --    +-------+    +---+---+ 
  188.    -- 
  189.    --  Split horizontally 
  190.    --    After=True     After=False     After=True     After=False 
  191.    --    +---+---+---+  +---+---+---+   +---+---+---+  +---+---+---+ 
  192.    --    | 1 | 3 | 4 |  | 4 | 1 | 3 |   | 1 | 3 | 4 |  | 1 | 4 | 3 | 
  193.    --    +---+   |   |  |   +---+   |   +---+   |   |  +---+   |   | 
  194.    --    | 2 |   |   |  |   | 2 |   |   | 2 |   |   |  | 2 |   |   | 
  195.    --    +---+---+---+  +---+---+---+   +---+---+---+  +---+---+---+ 
  196.  
  197.    procedure Freeze (Win : access Gtkada_Multi_Paned_Record); 
  198.    --  Freeze the window, ie when a child is inserted, no computation of its 
  199.    --  size is done, and will not generate immediate resizing. 
  200.    --  You only need to call this procedure when restoring Win to a previously 
  201.    --  state saved, and never if you are using the GtkAda.MDI which takes care 
  202.    --  of it on its own. 
  203.  
  204.    procedure Thaw (Win : access Gtkada_Multi_Paned_Record); 
  205.    --  Opposite of Freeze. You should call Size_Allocate on Win afterward to 
  206.    --  force a recomputation of the size 
  207.  
  208.    --------------- 
  209.    -- Iterators -- 
  210.    --------------- 
  211.  
  212.    type Child_Iterator is private; 
  213.  
  214.    function Start 
  215.      (Win : access Gtkada_Multi_Paned_Record) return Child_Iterator; 
  216.    --  Return an iterator to the first child of the window. This also returns 
  217.    --  children which are not widget, but are used to organize the window into 
  218.    --  horizontal and vertical panes 
  219.  
  220.    function At_End (Iter : Child_Iterator) return Boolean; 
  221.    --  True if there is no more child to be returned 
  222.  
  223.    procedure Next (Iter : in out Child_Iterator); 
  224.    --  Move to the next child of Iterator 
  225.  
  226.    function Get_Widget (Iter : Child_Iterator) return Gtk.Widget.Gtk_Widget; 
  227.    --  Return the widget embedded in the current child. This returns null if 
  228.    --  the current child is only used as a pane separator (horizontal or 
  229.    --  vertical). You mustn't remove the widget from the paned widget, or the 
  230.    --  iterator becomes invalid. 
  231.  
  232.    function Get_Orientation 
  233.      (Iter : Child_Iterator) return Gtk.Enums.Gtk_Orientation; 
  234.    --  Return the orientation of the current child. This is only relevant if 
  235.    --  the child doesn't contain a widget (and therefore Get_Widget has 
  236.    --  returned null). 
  237.  
  238.    function Get_Depth (Iter : Child_Iterator) return Natural; 
  239.    --  Return the depth of the current child (0 means the child is at the 
  240.    --  toplevel, 1 that this is a child directly underneath,...). 
  241.    --  This can be used to detect when the Iter has finished traversing one 
  242.    --  of the panes. 
  243.  
  244.    procedure Get_Size 
  245.      (Iter                        : Child_Iterator; 
  246.       Width, Height               : out Gint; 
  247.       Parent_Width, Parent_Height : out Gint; 
  248.       Parent_Orientation          : out Gtk.Enums.Gtk_Orientation); 
  249.    --  Return the size of the current element (pane or widget), as well as the 
  250.    --  parent's pane (the resizable area that contains notebooks or other 
  251.    --  panes). The parent size is the total size devoted to its children, 
  252.    --  omitting the size occupied by resize handles. 
  253.  
  254.    procedure Dump (Split : access Gtkada_Multi_Paned_Record'Class); 
  255.    --  Dump the configuration of Split to stdout. This is only intended for 
  256.    --  testing purposes. If you want to save and restore this configuration, 
  257.    --  you should look at Gtkada.MDI instead, which contains all the 
  258.    --  subprograms needed to handle desktops. 
  259.  
  260. private 
  261.    type Child_Description; 
  262.    type Child_Description_Access is access Child_Description; 
  263.  
  264.    type Pane is new Child_Description_Access; 
  265.    Root_Pane : constant Pane := null; 
  266.  
  267.    type Child_Iterator is record 
  268.       Current : Child_Description_Access; 
  269.       Depth   : Natural := 0; 
  270.    end record; 
  271.  
  272.    type Gtkada_Multi_Paned_Record is new Gtk.Fixed.Gtk_Fixed_Record with record 
  273.       Frozen      : Boolean := False; 
  274.       Children    : Child_Description_Access; 
  275.       GC          : Gdk.GC.Gdk_GC; 
  276.  
  277.       Initial_Pos  : Gint; 
  278.       Selected     : Child_Description_Access; 
  279.       Selected_Pos : Gtk.Widget.Gtk_Allocation; 
  280.  
  281.       Cursor_Double_H_Arrow : Gdk.Cursor.Gdk_Cursor; 
  282.       Cursor_Double_V_Arrow : Gdk.Cursor.Gdk_Cursor; 
  283.  
  284.       Opaque_Resizing        : Boolean := False; 
  285.    end record; 
  286.  
  287. end Gtkada.Multi_Paned;