--------------------------------------------------------------------------------
--                                                                            --
-- Copyright (C) 2004, RISC OS Ada Library (RASCAL) developers.               --
--                                                                            --
-- This library is free software; you can redistribute it and/or              --
-- modify it under the terms of the GNU Lesser General Public                 --
-- License as published by the Free Software Foundation; either               --
-- version 2.1 of the License, or (at your option) any later version.         --
--                                                                            --
-- This library is distributed in the hope that it will be useful,            --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of             --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           --
-- Lesser General Public License for more details.                            --
--                                                                            --
-- You should have received a copy of the GNU Lesser General Public           --
-- License along with this library; if not, write to the Free Software        --
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    --
--                                                                            --
--------------------------------------------------------------------------------

-- $Author$
-- $Date$
-- $Revision$

with RASCAL.OS;
with RASCAL.Memory;     use RASCAL.Memory;
with RASCAL.Sprite;     use RASCAL.Sprite;
with RASCAL.Utility;    use RASCAL.Utility;

with Interfaces.C;      use Interfaces.C;
with Kernel;            use Kernel;


package body RASCAL.ToolboxTreeView is

   -- SWIs
   Toolbox_ObjectMiscOp                 : constant := 16#44EC6#;

   -- Reason codes
   TreeView_SetState                    : constant := 16#4028#;
   TreeView_GetState                    : constant := 16#4029#;
   TreeView_AddNode                     : constant := 16#402a#;
   TreeView_GetNodeID                   : constant := 16#402b#;
   TreeView_SetNodeText                 : constant := 16#402c#;
   TreeView_SetNodeSprite               : constant := 16#402d#;
   TreeView_SetNodePrivateWord          : constant := 16#402e#;
   TreeView_GetNodeText                 : constant := 16#402f#;
   TreeView_GetNodeSprite               : constant := 16#4030#;
   TreeView_GetNodePrivateWord          : constant := 16#4031#;
   TreeView_MoveTo                      : constant := 16#4032#;
   TreeView_MoveNext                    : constant := 16#4033#;
   TreeView_MovePrevious                : constant := 16#4034#;
   TreeView_MoveChild                   : constant := 16#4035#;
   TreeView_MoveParent                  : constant := 16#4036#;
   TreeView_DeleteNode                  : constant := 16#4037#;
   TreeView_DeleteAll                   : constant := 16#4038#;
   TreeView_UpdateDisplay               : constant := 16#4039#;
   TreeView_MoveFirstSelected           : constant := 16#403a#;
   TreeView_MoveNextSelected            : constant := 16#403b#;


   --

   procedure Set_State (Window    : in Object_ID;
                        Component : in Component_ID;
                        State     : in System.Unsigned_Types.unsigned;
                        Flags     : in System.Unsigned_Types.unsigned :=0) is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_SetState;
      Register.R(3) := int(Component);
      Register.R(4) := int(Unsigned_to_Int(State));

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Set_State: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_State;

   --

   function Get_State (Window    : in Object_ID;
                       Component : in Component_ID;
                       Flags     : in System.Unsigned_Types.unsigned := 0) return System.Unsigned_Types.unsigned is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_GetState;
      Register.R(3) := int(Component);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Get_State: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return 0;
      else
         return System.Unsigned_Types.unsigned(Register.R(0));
      end if;
   end Get_State;
  
   --

   function Add_Node (Window    : in Object_ID;
                      Component : in Component_ID;
                      Text      : in String;
                      Flags     : in System.Unsigned_Types.unsigned := 0) return integer is

      Text_0         : String := Text & ASCII.NUL;
      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_AddNode;
      Register.R(3) := int(Component);
      Register.R(4) := Adr_To_Int(Text_0'Address);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Add_Node: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Add_Node;

   --

   function Get_NodeID (Window    : in Object_ID;
                        Component : in Component_ID;
                        Flags     : in System.Unsigned_Types.unsigned := 0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_GetNodeID;
      Register.R(3) := int(Component);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Get_NodeID: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Get_NodeID;
   
   --

   procedure Set_NodeText (Window    : in Object_ID;
                           Component : in Component_ID;
                           Text      : in String;
                           Flags     : in System.Unsigned_Types.unsigned := 0) is

      Text_0         : String := Text & ASCII.NUL;
      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_SetNodeText;
      Register.R(3) := int(Component);
      Register.R(4) := Adr_To_Int(Text_0'Address);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Set_NodeText: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_NodeText;

   --

   procedure Set_NodeSprite (Window      : in Object_ID;
                             Component   : in Component_ID;
                             Name        : in String;
                             Exp_Name    : in String := "";
                             Sprite_Area : in Sprite_Area_Ptr := null;
                             Flags       : in System.Unsigned_Types.unsigned := 0) is

      Name_0     : String := Name & ASCII.NUL;
      Exp_Name_0 : String := Exp_Name & ASCII.NUL;
      Register   : aliased Kernel.swi_regs;
      Error      : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_SetNodeSprite;
      Register.R(3) := int(Component);
      if Sprite_Area = null then
         Register.R(4) := 1;
      end if;
      Register.R(5) := Adr_To_Int(Name_0'Address);
      if Exp_Name'Length = 0 then
         Register.R(6) := 0;
      else
         Register.R(6) := Adr_To_Int(Exp_Name_0'Address);
      end if;
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);
      if Error /= null then
         Report("ToolboxTreeView.Set_NodeSprite: " & To_Ada(Error.ErrMess));
      end if;
   end Set_NodeSprite;

   --

   procedure Set_NodePrivateWord (Window    : in Object_ID;
                                  Component : in Component_ID;
                                  Word      : in integer;
                                  Flags     : in System.Unsigned_Types.unsigned := 0) is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_SetNodePrivateWord;
      Register.R(3) := int(Component);
      Register.R(4) := int(Word);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Set_NodePrivateWord: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_NodePrivateWord;

   --

   function Get_NodeText (Window    : in Object_ID;
                          Component : in Component_ID;
                          Flags     : in System.Unsigned_Types.unsigned := 0) return String is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
      Buffer_Size    : integer := 0;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_GetNodeText;
      Register.R(3) := int(Component);
      Register.R(4) := 0;
      Register.R(5) := 0;
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Get_NodeText: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return "";
      end if;

      Buffer_Size := integer(Register.R(5));

      declare
         Buffer : String(1..Buffer_Size + 1);
      begin
         Register.R(0) := int(Unsigned_to_Int(Flags));
         Register.R(1) := int(Window);
         Register.R(2) := TreeView_GetNodeText;
         Register.R(3) := int(Component);
         Register.R(4) := Adr_To_Int(Buffer'Address);
         Register.R(5) := int(Buffer_Size + 1);
         Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxTreeView.Get_NodeText: " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;

         return MemoryToString(Buffer'Address);
      end;
   end Get_NodeText;

   --

   function Get_NodeSprite (Window    : in Object_ID;
                            Component : in Component_ID;
                            Flags     : in System.Unsigned_Types.unsigned := 0) return String is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
      Buffer_Size    : integer := 0;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_GetNodeSprite;
      Register.R(3) := int(Component);
      Register.R(4) := 0;
      Register.R(5) := 0;
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Get_NodeSprite: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return "";
      end if;

      Buffer_Size := integer(Register.R(5));

      declare
         Buffer : String(1..Buffer_Size + 1);
      begin
         Register.R(0) := int(Unsigned_to_Int(Flags));
         Register.R(1) := int(Window);
         Register.R(2) := TreeView_GetNodeSprite;
         Register.R(3) := int(Component);
         Register.R(4) := Adr_To_Int(Buffer'Address);
         Register.R(5) := int(Buffer_Size + 1);
         Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxTreeView.Get_NodeSprite: " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;

         return MemoryToString(Buffer'Address);
      end;
   end Get_NodeSprite;

   --

   function Get_NodePrivateWord (Window    : in Object_ID;
                                 Component : in Component_ID;
                                 Flags     : in System.Unsigned_Types.unsigned := 0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_GetNodePrivateWord;
      Register.R(3) := int(Component);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Get_NodePrivateWord: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return 0;
      else
         return integer(Register.R(0));
      end if;
   end Get_NodePrivateWord;

   --

   procedure Move_To (Window    : in Object_ID;
                      Component : in Component_ID;
                      Node      : in Integer;
                      Flags     : in System.Unsigned_Types.unsigned :=0) is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveTo;
      Register.R(3) := int(Component);
      Register.R(4) := int(Node);

      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Move_To: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Move_To;

   --

   function Move_Next (Window    : in Object_ID;
                       Component : in Component_ID;
                       Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveNext;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_Next;

   --

   function Move_Previous (Window    : in Object_ID;
                           Component : in Component_ID;
                           Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MovePrevious;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_Previous;

   --

   function Move_Child (Window    : in Object_ID;
                        Component : in Component_ID;
                        Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveChild;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_Child;

   --

   function Move_Parent (Window    : in Object_ID;
                         Component : in Component_ID;
                         Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveParent;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_Parent;

   --
  
   function Delete_Node (Window    : in Object_ID;
                         Component : in Component_ID;
                         Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_DeleteNode;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Delete_Node: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Delete_Node;

   --

   procedure Delete_All (Window    : in Object_ID;
                         Component : in Component_ID;
                         Flags     : in System.Unsigned_Types.unsigned :=0) is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_DeleteAll;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Delete_All: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Delete_All;

   --

   procedure Update_Display (Window    : in Object_ID;
                             Component : in Component_ID;
                             Flags     : in System.Unsigned_Types.unsigned := 0) is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_UpdateDisplay;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxTreeView.Update_Display: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Update_Display;

   --

   function Move_FirstSelected (Window    : in Object_ID;
                                Component : in Component_ID;
                                Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveFirstSelected;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_FirstSelected;

   --

   function Move_NextSelected (Window    : in Object_ID;
                               Component : in Component_ID;
                               Flags     : in System.Unsigned_Types.unsigned :=0) return integer is

      Register       : aliased Kernel.swi_regs;
      Error          : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := TreeView_MoveNextSelected;
      Register.R(3) := int(Component);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         return -1;
      else
         return integer(Register.R(0));
      end if;
   end Move_NextSelected;

   --

   function Is_Empty (Window    : in Object_ID;
                      Component : in Component_ID;
                      Flags     : in System.Unsigned_Types.unsigned :=0) return boolean is

      Current_Node : constant Integer := Get_NodeID(Window,Component);
   begin
      return Current_Node = 0;
   end Is_Empty;

   --

   function Is_Selection (Window    : in Object_ID;
                          Component : in Component_ID;
                          Flags     : in System.Unsigned_Types.unsigned :=0) return Boolean is

      Current_Node : Integer := Get_NodeID(Window,Component);
      Selected     : Integer;
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;
      Selected := Move_FirstSelected(Window,Component);
      Move_To(Window,Component,Current_Node);
      if Selected = -1 then
         return false;
      end if;
      return true;
   end Is_Selection;

   --

   function Count_Selections (Window    : in Object_ID;
                             Component : in Component_ID;
                             Flags     : in System.Unsigned_Types.unsigned :=0) return Integer is

      Current_Node : Integer := Get_NodeID(Window,Component);
      Selections   : Integer := 0;
      Selected     : Integer;
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;

      Selected := Move_FirstSelected(Window,Component);
      loop
         exit when Selected = -1;
         Selections := Selections + 1;
         Selected   := Move_NextSelected (Window,Component,Flags);
      end loop;
      Move_To(Window,Component,Current_Node);
      return Selections;
   end Count_Selections;

   --

   function Get_Selections (Window    : in Object_ID;
                            Component : in Component_ID;
                            Flags     : in System.Unsigned_Types.unsigned :=0) return Node_list_Type is

      Current_Node : Integer := Get_NodeID(Window,Component);
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;

      declare
         Nr       : Integer := Count_Selections(Window,Component,Flags);
         Index    : Integer := 1;
         Nodes    : Node_List_Type(1..Nr);
         Selected : Integer := Move_FirstSelected(Window,Component);
      begin
         loop
            exit when Selected = -1;
   
            Nodes(Index) := Selected;
            Index        := Index + 1;
            Selected     := Move_NextSelected (Window,Component,Flags);
         end loop;
         Move_To(Window,Component,Current_Node);
         return Nodes;
      end;
   end Get_Selections;

   --

   function Count_Children (Window    : in Object_ID;
                            Component : in Component_ID;
                            Node      : in Integer;
                            Flags     : in System.Unsigned_Types.unsigned :=0) return Integer is
      Nr : Integer := 0;
      Child_Node   : Integer;
      Current_Node : Integer := Get_NodeID(Window,Component);
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;

      if Node = -1 then
         return 0;
      end if;
      Move_To(Window,Component,Node,Flags);
      Child_Node := Move_Child(Window,Component);
      while Child_Node /= -1 loop
         Nr := Nr + 1;
         Child_Node := Move_Child(Window,Component);
         while Child_Node = -1 loop
            Child_Node := Move_Next(Window,Component);
            if Child_Node = -1 then
               Child_Node := Move_Parent(Window,Component);
               if Child_Node = Node then
                  return Nr;
               end if;
               Child_Node := Move_Next(Window,Component);
            end if;
         end loop;
      end loop;
      Move_To(Window,Component,Current_Node);
      return Nr;
   end Count_Children;

   --

   function Get_Children (Window    : in Object_ID;
                          Component : in Component_ID;
                          Node      : in Integer;
                          Flags     : in System.Unsigned_Types.unsigned :=0) return Node_List_Type is

      Current_Node : Integer := Get_NodeID(Window,Component);
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;
      declare
         Nr           : Integer := Count_Children(Window,Component,Node,Flags);
         Index        : Integer := 1;
         Child_Node   : Integer;
         Nodes        : Node_List_Type(1..Nr);
      begin
         if Nr = 0 then
            return Nodes;
         end if;
         Nodes(1) := Node;
         Move_To(Window,Component,Node,Flags);
         Child_Node := Move_Child(Window,Component);
         while Child_Node /= -1 and Index <= Nr loop
            Index        := Index + 1;
            Nodes(Index) := Child_Node;
            Child_Node := Move_Child(Window,Component);
            while Child_Node = -1 loop
               Child_Node := Move_Next(Window,Component);
               if Child_Node = -1 then
                  Child_Node := Move_Parent(Window,Component);
                  if Child_Node = Node then
                     return Nodes;
                  end if;
                  Child_Node := Move_Next(Window,Component);
               end if;
            end loop;
         end loop;
         Move_To(Window,Component,Current_Node);
         return Nodes;
      end;
   end Get_Children;

   --

   function Get_Root (Window    : in Object_ID;
                      Component : in Component_ID;
                      Flags     : in System.Unsigned_Types.Unsigned :=0) return Integer is

      Old_Node : Integer := Get_NodeID(Window,Component,Flags);
      Parent   : Integer;
   begin
      if Old_Node = 0 then
         raise Empty_Tree;
      end if;

      Move_To(Window,Component,Old_Node,Flags);
      Parent := Move_Parent(Window,Component,Flags);
      while Parent /= Old_Node loop
         Old_Node := Parent;
         Move_To(Window,Component,Old_Node,Flags);
         Parent := Move_Parent(Window,Component,Flags);
      end loop;
   
      Old_Node := Move_Previous(Window,Component,Flags);
      while Old_Node /= -1 loop
            Old_Node := Move_Previous(Window,Component,Flags);
      end loop;
   
      return Get_NodeID(Window,Component,Flags);
   end Get_Root;

   --

   function Is_Root (Window    : in Object_ID;
                     Component : in Component_ID;
                     Flags     : in System.Unsigned_Types.Unsigned :=0) return Boolean is

      Old_Node : Integer := Get_NodeID(Window,Component,Flags);
      Parent   : Integer;      
   begin
      if Is_Empty (Window,Component,Flags) then
         raise Empty_Tree;
      end if;

      Move_To(Window,Component,Old_Node,Flags);
      Parent := Move_Parent(Window,Component,Flags);
      if Parent = Old_Node then
         Parent := Move_Previous(Window,Component,Flags);
         if Parent = -1 then
            Move_To(Window,Component,Old_Node,Flags);
            return true;
         end if;
      end if;
      Move_To(Window,Component,Old_Node,Flags);
      return false;
   end Is_Root;

   --

end RASCAL.ToolboxTreeView;
