-------------------------------------------------------------------
--           RAPID - RAPID ADA PORTABLE INTERFACE DESIGNER         
--           MCC GUI PACKAGE LIBRARY                               
--           Copyright (C) 1999 Martin C. Carlisle.                
--                                                                 
-- RAPID is free software; you can redistribute it and/or modify
-- it under terms of the GNU General Public License as published  
-- by the Free Software Foundation; either version 2, or (at your
-- option) any later version.  RAPID 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 General Public License for more details.  
-- You should have received a copy of the GNU General Public License
-- distributed with RAPID; see file COPYING.  If not, write to the 
-- Free Software Foundation,  59 Temple Place - Suite 330,  Boston, 
-- MA 02111-1307, USA.                                                 
--                                                                     
-- As a special exception, if other files instantiate generics from
-- this unit, or you link this unit with other files to produce an 
-- executable, this unit does not by itself cause the resulting 
-- executable to be covered by the GNU General Public License.  
-- This exception does not however invalidate any other reasons 
-- why the executable file might be covered by the GNU Public 
-- License.  This exception does not apply to executables which
-- are GUI design tools, or that could act as a replacement
-- for RAPID.
------------------------------------------------------------------------------

with Mcc.Gui.Container.Window;
with Mcc.Gui.Container.Frame;
with Ada.Characters.Handling;
with Ada.Unchecked_Conversion;
with MSSyst.Windows.Forms.Shortcut;
use  MSSyst.Windows.Forms.Shortcut;
with MSSyst.Windows.Forms;
use  MSSyst.Windows.Forms;
with MSSyst.Windows.Forms.Form;
with MSSyst.Windows.Forms.GroupBox;
with MSSyst.Windows.Forms.MainMenu;
with MSSyst.Windows.Forms.MenuItem;
with MSSyst.Windows.Forms.Menu;
with MSSyst.Windows.Forms.Menu.MenuItemCollection;
with MSSyst.ComponentModel;
use  MSSyst.ComponentModel;
with MSSyst.ComponentModel.IContainer;
with MSSyst.ComponentModel.IComponent;
with MSSyst.Windows.Forms.Control;
with MSSyst.Windows.Forms.Control.ControlCollection;
with MSSyst.Object;
with MSSyst.EventArgs;
with MSSyst.EventHandler;
with MSSyst.String;
use MSSyst.String;
with Menuitem_Peer;
with Ada.Text_Io;

package body Mcc.Gui.Menu is
   -- needed to set parent pointer
   type Parent_Menu is access constant Menu'Class;
   function Convert is new Ada.Unchecked_Conversion(
      Parent_Menu,Menu_Pointer);

   function Convert is new Ada.Unchecked_Conversion(
      MSSyst.Object.Ref, Menu_Callback);
   function Convert is new Ada.Unchecked_Conversion(
      Menu_Callback, MSSyst.Object.Ref);
      
   -----------------------------------------------------
   -- we assume we've stored the function pointer in the
   -- tag of the menuitem
   -----------------------------------------------------
   procedure Dotnet_Click(
         Sender : MSSyst.Object.Ref;
         E      : MSSyst.EventArgs.Ref) is
      The_Peer : MenuItem_Peer.Ref := MenuItem_Peer.Ref(Sender);
   begin
      if The_Peer.Callback /= null then
         The_Peer.Callback.all;
      end if;
   end Dotnet_Click;

   function Get_Keystroke(Accelerator : in String) return
      MSSyst.Windows.Forms.Shortcut.ValueType is
      function Convert is new Ada.Unchecked_Conversion(
         MSSyst.Windows.Forms.Shortcut.Valuetype, Integer);
      
      function Get_Keycode(Key : in String) return Integer is
         Result : Integer;
      begin
         if Ada.Characters.Handling.To_Upper(Key(Key'First)) = 'F' and
               Key'Length > 1 then
            Result := Integer'Value(Key(Key'First+1..Key'Last));
            Result := Result +
               Convert(MSSyst.Windows.Forms.Shortcut.F1)-1;
            return result;
         else
            return (Character'Pos(Key(Key'First)));
         end if;
      end Get_Keycode;
      
      Modifier : Integer;
      Keycode  : Integer;
      function Convert is new Ada.Unchecked_Conversion(
         Integer, MSSyst.Windows.Forms.Shortcut.Valuetype);
      Shift_Mask : constant := 16#00010000#;
      Ctrl_Mask  : constant := 16#00020000#;
      Alt_Mask   : constant := 16#00040000#;
   begin
      if accelerator'length > 5 and then Ada.Characters.Handling.To_Lower(
         Accelerator(Accelerator'First..Accelerator'First+4)) = "ctrl+" then
         Modifier := Ctrl_Mask;
         Keycode := Get_Keycode(
            Accelerator(Accelerator'First+5..Accelerator'Last));
      elsif accelerator'length > 4 and then Ada.Characters.Handling.To_Lower(
         Accelerator(Accelerator'First..Accelerator'First+3)) = "alt+" then
         Modifier := Alt_Mask;
         Keycode := Get_Keycode(
            Accelerator(Accelerator'First+4..Accelerator'Last));
      elsif accelerator'length > 2 and then Ada.Characters.Handling.To_Lower(
         Accelerator(Accelerator'First..Accelerator'First+2)) = "del" then
         Modifier := 0;
         Keycode := Convert(MSSyst.Windows.Forms.Shortcut.DEL);
      elsif accelerator'length > 2 and then Ada.Characters.Handling.To_Lower(
         Accelerator(Accelerator'First..Accelerator'First+2)) = "ins" then
         Modifier := 0;
         Keycode := Convert(MSSyst.Windows.Forms.Shortcut.INS);
      else
         Modifier := 0;
         Keycode := Get_Keycode(Accelerator);
      end if;
      
      return Convert(Keycode+Modifier);
   end Get_Keystroke;
   
   ----------------
   -- Add_Choice --
   ----------------

   procedure Add_Choice
     (Obj         : in out Choice;
      To_Menu     : in     Menu'Class;
      Text        : in     String;
      Action      : in     Menu_Callback;
      Underline   : in     Natural;
      Accelerator : in     String := "")
   is
   begin
      Add_Choice(Obj, To_Menu, Text, Action, Underline,
         Natural'Last, Accelerator);
   end Add_Choice;

   ----------------
   -- Add_Choice --
   ----------------

   procedure Add_Choice
     (Obj         : in out Choice;
      To_Menu     : in     Menu'Class;
      Text        : in     String;
      Action      : in     Menu_Callback;
      Underline   : in     Natural;
      Location    : in     Natural;
      Accelerator : in     String := "")
   is
      Menu_Peer : MenuItem.Ref := MenuItem.Ref(To_Menu.My_Peer); 
      Items     : MSSyst.Windows.Forms.Menu.MenuItemCollection.Ref; 
      New_Peer  : MenuItem_Peer.Ref;  
      Ignore    : Integer;  
   begin
      Items := Menu_Peer.Get_MenuItems;
      New_Peer := MenuItem_Peer.New_MenuItem;
      if Underline = 0 then
         New_Peer.set_Text(Text);
      else
         declare
            New_Text : String(1..Text'Length+1);
         begin
            New_Text(1..Underline-1) := Text(Text'First..
               Text'First+Underline-2);
            New_Text(Underline) := '&';
            New_Text(Underline+1..New_Text'Last) :=
               Text(Underline..Text'Last);
            New_Peer.set_Text(New_Text);
         end;
      end if;
      if Accelerator /= "" then
         New_Peer.Set_Shortcut(Get_Keystroke(Accelerator));
      end if;
      New_Peer.Callback := Action;
      New_Peer.add_Click(
         MSSyst.EventHandler.New_EventHandler(
            object => mssyst.object.ref(New_Peer),
            Method => Dotnet_Click'Address));
      if Location = Natural'Last then
         Ignore := Items.Add(Menuitem.Ref(New_Peer));
      else
         Ignore := Items.Add(Location,Menuitem.Ref(New_Peer));
      end if;
      Obj.My_Peer := MSSyst.Object.Ref(New_Peer);
   end Add_Choice;


   -----------------
   -- Add_Submenu --
   -----------------

   procedure Add_Submenu
     (Obj         : in out Submenu;
      Text        : in     String;
      Underline   : in     Natural;
      Parent_Menu : in     Menu'Class;
      On_Post     : in     Menu_Callback := null)
   is
   begin
      Add_Submenu(Obj, Text, Underline, Parent_Menu, 
         Location => Natural'Last, On_Post => On_Post);
   end Add_Submenu;

   -----------------
   -- Add_Submenu --
   -----------------

   procedure Add_Submenu
     (Obj         : in out Submenu;
      Text        : in     String;
      Underline   : in     Natural;
      Parent_Menu : in     Menu'Class;
      Location    : in     Natural;
      On_Post     : in     Menu_Callback := null)
   is
      Peer_Ref  : MenuItem.Ref;
      Menu_Peer : MSSyst.Windows.Forms.Menu.Ref;
      Items     : MSSyst.Windows.Forms.Menu.MenuItemCollection.Ref; 
      New_Peer  : MenuItem_Peer.Ref;  
      Ignore    : Integer;  
   begin
      Menu_Peer := MSSyst.Windows.Forms.Menu.Ref(Parent_Menu.My_Peer); 
      Items := Menu_Peer.Get_MenuItems;
      
      New_Peer := MenuItem_Peer.New_MenuItem;
      if Underline = 0 then
         New_Peer.set_Text(Text);
      else
         declare
            New_Text : String(1..Text'Length+1);
         begin
            New_Text(1..Underline-1) := Text(Text'First..
               Text'First+Underline-2);
            New_Text(Underline) := '&';
            New_Text(Underline+1..New_Text'Last) :=
               Text(Underline..Text'Last);
            New_Peer.set_Text(New_Text);
         end;
      end if;
                                                      
      New_Peer.Callback := On_Post;
      New_Peer.add_Popup(
         MSSyst.EventHandler.New_EventHandler(
            object => mssyst.object.ref(New_Peer),
            Method => Dotnet_Click'Address));
      if Location = Natural'Last then
         Ignore := Items.Add(Menuitem.Ref(New_Peer));
      else
         Ignore := Items.Add(Location,Menuitem.Ref(New_Peer));
      end if;
      Obj.My_Peer := MSSyst.Object.Ref(New_Peer);
            
   end Add_Submenu;

   ------------
   -- Create --
   ------------

   procedure Create
     (Obj    : in out Window_Menu;
      Window : in     Mcc.Gui.Container.Container'Class)
   is
      Peer_Ref : MainMenu.Ref;         
   begin
      Peer_Ref := MainMenu.new_MainMenu;
      if Window in Mcc.Gui.Container.Window.Window'Class then
         declare
            The_Peer : Form.Ref;
         begin
            The_Peer := Form.Ref(
               Mcc.Gui.Container.Get_Peer(Window));
            The_Peer.Set_Menu(Peer_Ref);
         end;
      elsif Window in Mcc.Gui.Container.Frame.Frame'Class then
         declare
            The_Peer : GroupBox.Ref;
            The_Container : IContainer.Ref;
         begin
            The_Peer := Groupbox.Ref(
               Mcc.Gui.Container.Get_Peer(Window));
            The_Container := The_Peer.Get_Container;
--            The_Container.Add(Peer_Ref.I_IComponent);
         end;
      else
         raise Unimplemented;
      end if;
      Obj.My_Peer := MSSyst.Object.Ref(Peer_Ref);
   end Create;

   ------------
   -- Delete --
   ------------

   procedure Delete (Obj : in out Menu_Item) is
      Parent_Menu : MSSyst.Windows.Forms.Menu.Ref;
      The_Peer    : MenuItem.Ref := MenuItem.Ref(Obj.My_Peer);
      Items       : MSSyst.Windows.Forms.Menu.MenuItemCollection.Ref;
   begin
      Parent_Menu := The_Peer.Get_Parent;
      Items := Parent_Menu.Get_MenuItems;
      Items.Remove(The_Peer);
   end Delete;

   -------------
   -- Disable --
   -------------

   procedure Disable (Obj : in out Choice) is
   begin
      MenuItem.set_Enabled(
         MenuItem.Ref(Obj.My_Peer),
         false);
   end Disable;

   ------------
   -- Enable --
   ------------

   procedure Enable (Obj : in out Choice) is
   begin
      MenuItem.set_Enabled(
         MenuItem.Ref(Obj.My_Peer),
         true);
   end Enable;

   procedure Add_Separator(
      Obj         : in out Separator;
      To_Menu     : in     Menu'Class) is
   begin
      Add_Separator(Obj, To_Menu, Natural'Last);
   end Add_Separator;
   
   procedure Add_Separator(
      Obj         : in out Separator;
      To_Menu     : in     Menu'Class;
      Location    : in     Natural) is
      Menu_Peer : MenuItem.Ref := MenuItem.Ref(To_Menu.My_Peer); 
      Items     : MSSyst.Windows.Forms.Menu.MenuItemCollection.Ref; 
      New_Peer  : MenuItem_Peer.Ref;  
      Ignore    : Integer;  
   begin
      Items := Menu_Peer.Get_MenuItems;
      New_Peer := MenuItem_Peer.New_MenuItem;
      New_Peer.set_Text("-");
      if Location = Natural'Last then
         Ignore := Items.Add(Menuitem.Ref(New_Peer));
      else
         Ignore := Items.Add(Location,Menuitem.Ref(New_Peer));
      end if;
      Obj.My_Peer := MSSyst.Object.Ref(New_Peer);
   end Add_Separator;

end Mcc.Gui.Menu;

