-------------------------------------------------------------------
--           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 MSSyst.Windows.Forms;
use MSSyst.Windows.Forms;
with MSSyst.Drawing;
use MSSyst.Drawing;
with MSSyst.Drawing.Rectangle;
with MSSyst.Drawing.Color;
with MSSyst.Windows.Forms.Screen;
with MSSyst.Windows.Forms.Control;
with MSSyst.Windows.Forms.Cursors;
with MSSyst.Windows.Forms.Cursor;
with MSSyst.Object;
with MSSyst.Eventargs;
with Ada.Unchecked_Conversion;
with MSSyst.Windows.Forms.KeyEventArgs;
with MSSyst.Windows.Forms.MouseEventArgs;
with MSSyst.Windows.Forms.MouseButtons;
with MSSyst.Windows.Forms.KeyEventHandler;
with MSSyst.Windows.Forms.MouseEventHandler;
with MSSyst.ComponentModel;
use MSSyst.ComponentModel;
with MSSyst.ComponentModel.Component;
with Mcc.Gui.Container.Window;
package body Mcc.Gui is
   function Convert is new Ada.Unchecked_Conversion(
      MSSyst.Object.Ref, Sized_Object_Pointer);
   function Convert is new Ada.Unchecked_Conversion(
      Sized_Object_Pointer, MSSyst.Object.Ref);


   procedure Null_Key_Listener(
         Obj   : in out Sized_Object'Class;
         Event : in     Key_Event) is
   begin
      null;
   end Null_Key_Listener;
   
   procedure Null_Mouse_Listener(
         Obj   : in out Sized_Object'Class;
         Event : in     Mouse_Event) is
   begin
      null;
   end Null_Mouse_Listener;
   

   procedure Handle_Key(
         Sender : MSSyst.Object.Ref;
         Action : Key_Action_Type;
         E      : KeyEventArgs.Ref) is
      The_Peer : Control.Ref := Control.Ref(Sender);
      Rapid_Pointer : Sized_Object_Pointer;
      Tag : MSSyst.Object.Ref := The_Peer.Get_Tag;
      Event : Key_Event;
   begin
      Rapid_Pointer := Convert(Tag);
      if Rapid_Pointer.Key_Handler = null then
         return;
      end if;
      Event.Action := Action;
      Event.Key := Key_Type(E.Get_KeyValue);
      Rapid_Pointer.Key_Handler(
         Obj => Rapid_Pointer.all,
         Event => Event);
   end Handle_Key;

   procedure Dotnet_Keydown(
         Sender : MSSyst.Object.Ref;
         E      : KeyEventArgs.Ref) is
   begin
      Handle_Key(Sender,Press,E);
   end Dotnet_Keydown;

   procedure Dotnet_Keyup(
         Sender : MSSyst.Object.Ref;
         E      : KeyEventArgs.Ref) is
   begin
      Handle_Key(Sender,Release,E);
   end Dotnet_Keyup;
   
   procedure Handle_Mouse(
         Sender : MSSyst.Object.Ref;
         Action : Mouse_Action_Type;
         E      : MouseEventArgs.Ref) is
      The_Peer : Control.Ref := Control.Ref(Sender);
      Rapid_Pointer : Sized_Object_Pointer;
      Tag : MSSyst.Object.Ref := The_Peer.Get_Tag;
      Event : Mouse_Event;
      The_Button: MouseButtons.Valuetype;
      use type MouseButtons.Valuetype;
   begin
      The_Button := MouseButtons.Left;
      Rapid_Pointer := Convert(Tag);
      if Rapid_Pointer.Mouse_Handler = null then
         return;
      end if;
      Event.Action := Action;
      Event.X      := E.Get_X;
      Event.Y      := E.Get_Y;
      The_Button := E.Get_Button;
      if The_Button = MouseButtons.Left then
            Event.Button := Left;
      elsif The_Button = MouseButtons.Middle then 
            Event.Button := Middle;
      elsif The_Button = MouseButtons.None then
            Event.Button := None;
      elsif The_Button = MouseButtons.Right then
            Event.Button := Right;
      else
            Event.Button := None;
      end if;
      Rapid_Pointer.Mouse_Handler.all(
         Obj => Rapid_Pointer.all,
         Event => Event);
   end Handle_Mouse;

   procedure Dotnet_Mouseup(
         Sender : MSSyst.Object.Ref;
         E      : MouseEventArgs.Ref) is
   begin
      Handle_Mouse(Sender,Release,E);
   end Dotnet_Mouseup;
   
   procedure Dotnet_Mousedown(
         Sender : MSSyst.Object.Ref;
         E      : MouseEventArgs.Ref) is
      The_Button: MouseButtons.Valuetype;
      function Convert is new Ada.Unchecked_Conversion(
         mousebuttons.valuetype, integer);
   begin
      if E.get_Clicks mod 2 = 0 then
         Handle_Mouse(Sender,Double_Click,E);
      else
         Handle_Mouse(Sender,Press,E);
         The_Button := E.Get_Button;
      end if;
   end Dotnet_Mousedown;

   procedure Dotnet_MouseMove(
         Sender : MSSyst.Object.Ref;
         E      : MouseEventArgs.Ref) is
   begin
      Handle_Mouse(Sender,Move,E);
   end Dotnet_MouseMove;
   
   procedure Get_Screen_Dimensions(
      Width  : out Integer;
      Height : out Integer) is
      Bounds : Rectangle.Valuetype;   
      PrimaryScreen : Screen.Ref;
   begin
      PrimaryScreen := Screen.get_PrimaryScreen;
      Bounds := PrimaryScreen.Get_Bounds;
      Height := Rectangle.get_Height(Bounds);
      Width := Rectangle.get_Width(Bounds);
   end Get_Screen_Dimensions;
   
   procedure Get_Size(
      Obj    : in     Sized_Object;
      Width  :    out Integer;
      Height :    out Integer) is
      The_Peer : Control.Ref := Control.Ref(Get_Peer(Obj));
      Bounds : Rectangle.Valuetype;   
   begin
      Bounds := The_Peer.Get_Bounds;
      Height := Rectangle.get_Height(Bounds);
      Width := Rectangle.Get_Width(Bounds);
      if Sized_Object'Class(Obj) in Mcc.Gui.Container.Window.Window'Class then
         Height := Height - Peer.Title_Bar_Size;
      end if;
   end Get_Size;

   ----------
   -- Bell --
   ----------

   procedure Bell is
   begin
      null;
   end Bell;

   -------------
   -- Destroy --
   -------------

   procedure Destroy (Obj : in Object) is
      Obj_Peer : MSSyst.Object.Ref := Get_Peer(Obj);
      The_Peer : Component.Ref;
      use type MSSyst.Object.Ref;
      use type Control.Ref;
      -- ok, so this is a bit of a hack so I can modify Obj
      Ptr : Object_Pointer := Obj'Unrestricted_Access;
   begin
      if Obj_Peer /= null then
         The_Peer := Component.Ref (Obj_Peer);
         The_Peer.Dispose;
      end if;
      Ptr.My_Peer := null;
   end Destroy;

   ----------------------
   -- Get_Key_Listener --
   ----------------------

   function Get_Key_Listener
     (Obj : in Sized_Object'Class)
      return Key_Listener
   is
   begin
      if Obj.Key_Handler = Null_Key_Listener'access then
         return null;
      else
         return Obj.Key_Handler;
      end if;
   end Get_Key_Listener;

   ------------------------
   -- Get_Mouse_Listener --
   ------------------------

   function Get_Mouse_Listener
     (Obj : in Sized_Object'Class)
      return Mouse_Listener
   is
   begin
      if Obj.Mouse_Handler = Null_Mouse_Listener'access then
         return null;
      else
         return Obj.Mouse_Handler;
      end if;
   end Get_Mouse_Listener;

   --------------
   -- Get_Peer --
   --------------

   function Get_Peer (Obj : in Object) return Peer.Peer is
   begin
      return Obj.My_Peer;
   end Get_Peer;

   ----------
   -- Move --
   ----------

   procedure Move
     (Obj : in out Sized_Object;
      X   : in     Integer;
      Y   : in     Integer)
   is
      The_Peer : Control.Ref := Control.Ref(Get_Peer(Obj));
      Bounds : Rectangle.Valuetype;   
   begin
      Bounds := The_Peer.Get_Bounds;
      Rectangle.set_X(Bounds,X);
      Rectangle.set_Y(Bounds,Y);
      The_Peer.set_Bounds(Bounds);
   end Move;

   ------------
   -- Resize --
   ------------

   procedure Resize
     (Obj    : in out Sized_Object;
      Width  : in     Integer;
      Height : in     Integer)
   is
      The_Peer : Control.Ref := Control.Ref(Obj.My_Peer);
      Bounds : Rectangle.Valuetype;   
   begin
      Bounds := The_Peer.Get_Bounds;
      if Sized_Object'Class(Obj) in
         Mcc.Gui.Container.Window.Window'Class then
         Rectangle.Set_Height(Bounds,Height+Peer.Title_Bar_Size);
      else
         Rectangle.Set_Height(Bounds,Height);
      end if;
      Rectangle.set_Width(Bounds,Width);
      The_Peer.set_Bounds(Bounds);
   end Resize;

   --------------------------
   -- Set_Background_Color --
   --------------------------

   procedure Set_Background_Color
     (Obj       : in out Sized_Object;
      New_Color : in     Color)
   is
      The_Peer : Control.Ref := Control.Ref (Get_Peer(Obj)); 
      Msil_Color : MSSyst.Drawing.Color.Valuetype;       
   begin
      Msil_Color := MSSyst.Drawing.Color.FromArgb(
         Integer(New_Color.Red),
         Integer(New_Color.Green),
         Integer(New_Color.Blue));
      The_Peer.set_BackColor(Msil_Color);
   end Set_Background_Color;

   ----------------
   -- Set_Cursor --
   ----------------

   procedure Set_Cursor
     (Obj    : in Sized_Object;
      Cursor : in Cursor_Type)
   is
      The_Peer : Control.Ref := Control.Ref (Get_Peer(Obj));      
   begin
      case Cursor is
         when Default_Cursor =>
            The_Peer.set_Cursor(Cursors.get_Default);
         when Resize_NW|Resize_SE =>
            The_Peer.set_Cursor(Cursors.get_sizeNWSE);
         when Resize_N|Resize_S =>
            The_Peer.set_Cursor(Cursors.get_sizeNS);
         when Resize_NE|Resize_SW =>
            The_Peer.set_Cursor(Cursors.get_sizeNESW);
         when Resize_E|Resize_W =>
            The_Peer.set_Cursor(Cursors.get_sizeWE);
         when Move_Cursor =>
            The_Peer.set_Cursor(Cursors.get_sizeAll);
      end case;
   end Set_Cursor;

   ----------------------
   -- Set_Key_Listener --
   ----------------------

   procedure Set_Key_Listener
     (Obj      : in Sized_Object_Pointer;
      Listener : in Key_Listener)
   is
      The_Peer : Control.Ref := Control.Ref(Obj.My_Peer);         
   begin
      if Obj.Key_Handler = null then
         The_Peer.Set_Tag(Convert(Obj));
         The_Peer.Add_KeyDown(
            KeyEventHandler.New_KeyEventHandler(
               Object => MSSyst.Object.Ref(The_Peer),
               Method => Dotnet_Keydown'address));
         The_Peer.Add_KeyUp(
            KeyEventHandler.New_KeyEventHandler(
               Object => MSSyst.Object.Ref(The_Peer),
               Method => Dotnet_Keyup'address));
      end if;
      if Listener = null then
         Obj.Key_Handler := Null_Key_Listener'access;
      else
         Obj.Key_Handler := Listener;
      end if;
   end Set_Key_Listener;

   ------------------------
   -- Set_Mouse_Listener --
   ------------------------

   procedure Set_Mouse_Listener
     (Obj      : in Sized_Object_Pointer;
      Listener : in Mouse_Listener)
   is
      The_Peer : Control.Ref := Control.Ref(Obj.My_Peer);         
   begin
      if Obj.Mouse_Handler = null then
         The_Peer.Set_Tag(Convert(Obj));
         The_Peer.Add_MouseDown(
            MouseEventHandler.New_MouseEventHandler(
               Object => MSSyst.Object.Ref(The_Peer),
               Method => Dotnet_Mousedown'address));
         The_Peer.Add_MouseUp(
            MouseEventHandler.New_MouseEventHandler(
               Object => MSSyst.Object.Ref(The_Peer),
               Method => Dotnet_Mouseup'address));
         The_Peer.Add_MouseMove(
            MouseEventHandler.New_MouseEventHandler(
               Object => MSSyst.Object.Ref(The_Peer),
               Method => Dotnet_Mousemove'address));
      end if;
      if Listener = null then
         Obj.Mouse_Handler := Null_Mouse_Listener'access;
      else
         Obj.Mouse_Handler := Listener;
      end if;
   end Set_Mouse_Listener;

end Mcc.Gui;

