GuiSystem.cs :  » Game » RealmForge » CrayzEdsGui » Base » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Game » RealmForge 
RealmForge » CrayzEdsGui » Base » GuiSystem.cs
#region LGPL License

/*************************************************************************
    Crazy Eddie's GUI System (http://crayzedsgui.sourceforge.net)
    Copyright (C)2004 Paul D Turner (crayzed@users.sourceforge.net)
  
  C# Port developed by Chris McGuirk (leedgitar@latenitegames.com)
  Compatible with the Axiom 3D Engine (http://axiomengine.sf.net)

    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
*************************************************************************/

#endregion LGPL License

#region Using directives

using System;
using System.Text;

#endregion

namespace CrayzEdsGui.Base{

/// <summary>
///    This class is the CEGUI class that provides access to all other elements in this system.
/// </summary>
/// <remarks>
///    This object must be created by the client application.  The GuiSystem object requires that you pass it
///    an initialized <see cref="Renderer"/> object which it can use to interface to whatever rendering system will be
///    used to display the GUI imagery.
/// </remarks>
  public class GuiSystem {
    #region Constants

    /// <summary>
    ///    Default timeout for generation of single click events.
    /// </summary>
    const float DefaultSingleClickTimeout = 0.2f;
    /// <summary>
    ///    Default timeout for generation of multi-click events.
    /// </summary>
    const float DefaultMultiClickTimeout = 0.33f;
    /// <summary>
    ///    Default allowable mouse movement for multi-click event generation.
    /// </summary>
    public readonly Size DefaultMultiClickAreaSize = new Size(12, 12);
      
    #endregion Constants

    #region Fields

    /// <summary>
    ///    The active GUI sheet (root window)
    /// </summary>
    protected Window activeSheet;
    /// <summary>
    ///    Reference to the window that currently contains the mouse.
    /// </summary>
    protected Window windowWithMouse;
    /// <summary>
    ///    True if GUI should be re-drawn, false if render should re-use last times queue.
    /// </summary>
    protected bool guiRedraw;
    /// <summary>
    ///    Holds a reference to the default GUI font.
    /// </summary>
    protected Font defaultFont;
    /// <summary>
    ///    Holds a reference to the default mouse cursor.
    /// </summary>
    protected Image defaultMouseCursor;
    /// <summary>
    /// Holds the reference to the Renderer object given to us in the constructor.
    /// </summary>
    protected Renderer renderer;

    /// <summary>
    ///    Timeout value, in seconds, used to generate a single-click (button down then up).
    /// </summary>
    protected float clickTimeout;
    /// <summary>
    ///    Timeout value, in seconds, used to generate multi-click events (botton down, then up, then down, and so on).
    /// </summary>
    protected float doubleClickTimeout;
    /// <summary>
    ///    Size of area the mouse can move and still make multi-clicks.
    /// </summary>
    protected Size doubleClickSize;
    /// <summary>
    ///    Structs used to keep track of mouse button click generation.
    /// </summary>
    protected MouseClickTracker[] clickTrackers = new MouseClickTracker[(int)MouseButton.Count];
    /// <summary>
    ///    System keys that are currently pressed.
    /// </summary>
    protected SystemKey sysKeys;

    /// <summary>
    ///    State of the left control key.
    /// </summary>
    protected bool leftCtrl;
    /// <summary>
    ///    State of the left shift key.
    /// </summary>
    protected bool leftShift;
    /// <summary>
    ///    State of the right control key.
    /// </summary>
    protected bool rightCtrl;
    /// <summary>
    ///    State of the right shift key.
    /// </summary>
    protected bool rightShift;

    #endregion Fields

    #region Singleton Implementation

    /// <summary>
    ///    Singlton instance of this class.
    /// </summary>
    private static GuiSystem instance;

    /// <summary>
    /// Default constructor.
    /// </summary>
    /// <param name="renderer">Reference to the valid Renderer object that will be used to render GUI imagery</param>
    public GuiSystem(Renderer renderer) {
      // only create once instance
      if (instance == null) {
        // store off the renderer instance
        this.renderer = renderer;

        // mouse input timing defaults
        clickTimeout    = DefaultSingleClickTimeout;
        doubleClickTimeout  = DefaultMultiClickTimeout;
        doubleClickSize    = DefaultMultiClickAreaSize;

        for(int i = 0; i < clickTrackers.Length - 1; i++) {
          clickTrackers[i] = new MouseClickTracker();
        }

        instance = this;

        // first thing to do is create logger
        new Logger("CEGUI.log");

        Logger.Instance.LogEvent("---- Begining CEGUI System initialisation ----");

        // cause creation of other singleton objects
        new ImagesetManager();
        new FontManager();
        new WindowManager();
        new SchemeManager();
        new MouseCursor();

        // register the GuiSheet widget by default since it is part of the core
// njk-patch
//        WindowManager.Instance.RegisterType(typeof(GuiSheet), GetType().Assembly);
//        WindowManager.Instance.RegisterType(typeof(Widgets.StaticImage), GetType().Assembly);
      }
    }

    /// <summary>
    ///    Gets the singleton class instance.
    /// </summary>
    /// <value></value>
    public static GuiSystem Instance {
      get {
        return instance;
      }
    }

  #endregion Singleton Implementation

    #region Properties

    /// <summary>
    ///    Return a reference to the default <see cref="Font"/> for the GUI system.
    /// </summary>
    /// <value>Reference to a <see cref="Font"/> object that is the default font in the system.</value>
    public Font DefaultFont {
      get {
        return defaultFont;
      }
    }

    /// <summary>
    ///    Return the currently set default mouse cursor image.
    /// </summary>
    /// <value>
    ///    Reference to the current default image used for the mouse cursor.  May return null if default cursor has not been set,
    ///    or has intentionally been set to NULL - which results in a blank default cursor.
    /// </value>
    public Image DefaultMouseCursor {
      get {
        return defaultMouseCursor;
      }
    }

    /// <summary>
    ///    Gets/Sets the active GUI sheet (root) window.
    /// </summary>
    /// <value>Reference to the <see cref="Window"/> object that has been set as the GUI root element.</value>
    public Window GuiSheet {
      get {
        return activeSheet;
      }
      set {
        activeSheet = value;
      }
    }

    /// <summary>
    ///    Gets a reference to the <see cref="Renderer"/> object being used by the system.
    /// </summary>
    /// <value>Reference to the <see cref="Renderer"/> object being used by the system.</value>
    public Renderer Renderer {
      get {
        return renderer;
      }
    }

    /// <summary>
    ///    Return the Window object that the mouse is presently within.
    /// </summary>
    /// <value>Reference to the Window object that currently contains the mouse cursor, or 'null' if none.</value>
    public Window WindowContainingMouse {
      get {
        return windowWithMouse;
      }
    }

  #endregion Properties

    #region Methods

    /// <summary>
    ///    Render the GUI.
    /// </summary>
    /// <remarks>
    ///    Depending upon the internal state, this may either re-use rendering from last time, 
    ///    or trigger a full re-draw from all elements.
    /// </remarks>
    public void RenderGui() {
      //////////////////////////////////////////////////////////////////////////
      // This makes use of some tricks the Renderer can do so that we do not
      // need to do a full redraw every frame - only when some UI element has
      // changed.
      //
      // Since the mouse is likely to move very often, and in order not to
      // short-circuit the above optimisation, the mouse is not queued, but is
      // drawn directly to the display every frame.
      //////////////////////////////////////////////////////////////////////////
      if(guiRedraw) {
        renderer.ResetZValue();
        renderer.QueueingEnabled = true;
        renderer.ClearRenderList();

        if(activeSheet != null) {
          activeSheet.Render();
        }

        guiRedraw = false;
      }

      // Render queued objects
      renderer.DoRender();

      renderer.QueueingEnabled = false;
      MouseCursor.Instance.Draw();
    }

    /// <summary>
    ///    Set the default font to be used by the system.
    /// </summary>
    /// <param name="name">Name of the default font to be used by the system.</param>
    public void SetDefaultFont(string name) {
      if(name == null || name.Length == 0) {
        Font tmp = null;
        SetDefaultFont(tmp);
      }
      else {
        SetDefaultFont(FontManager.Instance.GetFont(name));
      }
    }

    /// <summary>
    ///    Set the default font to be used by the system.
    /// </summary>
    /// <param name="font">Reference to the default font to be used by the system.</param>
    public void SetDefaultFont(Font font) {
      defaultFont = font;

      // TODO: Add a 'system default font' changed event and fire it here.
    }

    /// <summary>
    ///    Set the image to be used as the default mouse cursor.
    /// </summary>
    /// <param name="imagesetName">The name of the Imageset  that contains the image to be used.</param>
    /// <param name="imageName">The name of the Image on <paramref name="imageset"/> that is to be used.</param>
    public void SetDefaultMouseCursor(string imagesetName, string imageName) {
      defaultMouseCursor = ImagesetManager.Instance.GetImageset(imagesetName).GetImage(imageName);
    }

    /// <summary>
    ///    Set the image to be used as the default mouse cursor.
    /// </summary>
    /// <param name="image">
    ///    Reference to an image object that is to be used as the default mouse cursor.  To have no cursor rendered by default, you
    ///    can specify null here.
    /// </param>
    public void SetDefaultMouseCursor(Image image) {
      defaultMouseCursor = image;
    }

    /// <summary>
    ///    Causes a full re-draw next time <see cref="RenderGui"/> is called.
    /// </summary>
    public void SignalRedraw() {
      guiRedraw = true;
    }

    #endregion Methods

    #region Input Injection Methods

    /// <summary>
    ///    Method that injects a typed character into the system.
    /// </summary>
    /// <param name="c">Character that was typed.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectChar(char c) {
      if(activeSheet != null) {
        KeyEventArgs e = new KeyEventArgs();
        e.Character = c;
        e.Modifiers = sysKeys;

        Window destWindow = activeSheet.ActiveChild;

        while((destWindow != null) && !e.Handled) {
          destWindow.OnCharacter(e);
          destWindow = destWindow.Parent;
        }

        return e.Handled;
      }

      return false;
    }

    /// <summary>
    ///    Injects a key down event into the system.
    /// </summary>
    /// <param name="keyCode">Keyboard key pressed.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectKeyDown(KeyCodes keyCode) {
      // update sys keys
      sysKeys |= KeyCodeToSysKey(keyCode, true);

      if(activeSheet != null) {
        KeyEventArgs e = new KeyEventArgs();
        e.KeyCode = keyCode;
        e.Modifiers = sysKeys;

        Window destWindow = activeSheet.ActiveChild;

        while((destWindow != null) && !e.Handled) {
          destWindow.OnKeyDown(e);
          destWindow = destWindow.Parent;
        }

        return e.Handled;
      }

      return false;
    }

    /// <summary>
    ///    Injects a key up event into the system.
    /// </summary>
    /// <param name="keyCode">Keyboard key pressed.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectKeyUp(KeyCodes keyCode) {
      // update sys keys
      sysKeys &= ~KeyCodeToSysKey(keyCode, true);

      if(activeSheet != null) {
        KeyEventArgs e = new KeyEventArgs();
        e.KeyCode = keyCode;
        e.Modifiers = sysKeys;

        Window destWindow = activeSheet.ActiveChild;

        while((destWindow != null) && !e.Handled) {
          destWindow.OnKeyUp(e);
          destWindow = destWindow.Parent;
        }

        return e.Handled;
      }

      return false;
    }

    /// <summary>
    ///    Injects a mouse down event into the system.
    /// </summary>
    /// <param name="button">Mouse button being pressed.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectMouseDown(MouseButton button) {
      MouseEventArgs e = new MouseEventArgs();
      e.Position = MouseCursor.Instance.Position;
      e.MoveDelta = new Point(0, 0);
      e.Button = button;
      bool handled = false;

      Window destWindow = GetTargetWindow(e.Position);

      Window eventWindow = destWindow;

      while(!e.Handled && (eventWindow != null)) {
        eventWindow.OnMouseButtonDown(e);
        eventWindow = eventWindow.Parent;
      }

      // Double/Triple click
      MouseClickTracker tracker = clickTrackers[(int)button];

      tracker.clickCount++;

      if(  tracker.timer.Elapsed > doubleClickTimeout ||
        !tracker.clickArea.IsPointInRect(e.Position) ||
        tracker.clickCount > 3) {

        // single down event
        tracker.clickCount = 1;

        // build allowable area for multi-clicks
        tracker.clickArea.Position = e.Position;
        tracker.clickArea.Size = doubleClickSize;
        tracker.clickArea.Offset(new Point(-(doubleClickSize.width * 0.5f), -(doubleClickSize.height * 0.5f)));
      }

      // reuse same event args from earlier
      handled = e.Handled;
      e.Handled = false;

      switch(tracker.clickCount) {
        case 2:
          eventWindow = destWindow;

          while(!e.Handled && (eventWindow != null)) {
            eventWindow.OnMouseDoubleClicked(e);
            eventWindow = eventWindow.Parent;
          }

          break;

        case 3:
          eventWindow = destWindow;

          while(!e.Handled && (eventWindow != null)) {
            eventWindow.OnMouseTripleClicked(e);
            eventWindow = eventWindow.Parent;
          }

          break;
      }

      // reset timer for this button
      tracker.timer.Restart();

      return (handled || e.Handled);
    }

    /// <summary>
    ///    Injects a mouse up event into the system.
    /// </summary>
    /// <param name="button">Mouse button being pressed.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectMouseUp(MouseButton button) {
      MouseEventArgs e = new MouseEventArgs();
      e.Position = MouseCursor.Instance.Position;
      e.MoveDelta = new Point(0, 0);
      e.Button = button;

      Window destWindow = GetTargetWindow(e.Position);

      Window eventWindow = destWindow;

      while(!e.Handled && (eventWindow != null)) {
        eventWindow.OnMouseButtonUp(e);
        eventWindow = eventWindow.Parent;
      }
      
      // check timer for 'button' to see if this up event also constitutes a single click
      if(clickTrackers[(int)button].timer.Elapsed <= clickTimeout) {
        e.Handled = false;
        destWindow = GetTargetWindow(e.Position);

        while(!e.Handled && (destWindow != null)) {
          destWindow.OnMouseClicked(e);
          destWindow = destWindow.Parent;
        }
      }

      return e.Handled;
    }

    /// <summary>
    ///    Method that injects a mouse movement event into the system.
    /// </summary>
    /// <param name="deltaX">Amount the mouse moved on the x axis.</param>
    /// <param name="deltaY">Amount the mouse moved on the y axis.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectMouseMove(int deltaX, int deltaY) {
      MouseCursor mouse = MouseCursor.Instance;

      MouseEventArgs e = new MouseEventArgs();

      e.MoveDelta.x = (float)deltaX;
      e.MoveDelta.y = (float)deltaY;

      // move the mouse cursor
      mouse.OffsetPosition(e.MoveDelta);
      e.Position = mouse.Position;

      Window destWindow = GetTargetWindow(e.Position);

      // if there is no GUI sheet, then there is nowhere to send input
      // TODO: keep an eye on passing the same args around
      if(destWindow != null) {
        if(destWindow != windowWithMouse) {
          if(windowWithMouse != null) {
            windowWithMouse.OnMouseLeaves(e);
          }

          windowWithMouse = destWindow;
          destWindow.OnMouseEnters(e);
        }

        while(!e.Handled && (destWindow != null)) {
          destWindow.OnMouseMove(e);
          destWindow = destWindow.Parent;
        }
      }

      return e.Handled;
    }

    /// <summary>
    ///    Method that injects a mouse wheel scroll event into the system.
    /// </summary>
    /// <param name="delta">Amount that the mouse wheel was moved.</param>
    /// <returns>Returns true if the event was handled, and false if it is not.</returns>
    public bool InjectMouseWheel(int delta) {
      MouseEventArgs e = new MouseEventArgs();
      e.WheelDelta = delta;
      e.Position = MouseCursor.Instance.Position;

      Window destWindow = GetTargetWindow(e.Position);

      if(destWindow != null) {
        destWindow.OnMouseWheel(e);
      }

      return e.Handled;
    }

    #endregion Input Injection Methods

    #region Private Helper Methods

    /// <summary>
    ///    Given <paramref name="point"/>, return a reference to the <see cref="Window"/> that should receive a 
    ///    mouse input if <paramref name="point"/> is the mouse location.
    /// </summary>
    /// <param name="point">Screen location (in pixels).</param>
    /// <returns>
    ///    Reference to a <see cref="Window"/> object at mouse locatioj <paramref name="point"/> that
    ///    is to receive input.
    /// </returns>
    private Window GetTargetWindow(Point point) {
      Window destWindow = null;

      // if there is no GUI sheet, then there is nowhere to send input
      if (activeSheet != null) {
        destWindow = Window.CaptureWindow;

        if (destWindow == null) {
          destWindow = activeSheet.GetChildAtPosition(point);

          if (destWindow == null) {
            destWindow = activeSheet;
          }
        }
        else {
          Window childWindow = destWindow.GetChildAtPosition(point);

          if(childWindow != null) {
            destWindow = childWindow;
          }
        }
      }

      return destWindow;
    }

    /// <summary>
    ///    Converts the specified keycode into a system key value.
    /// </summary>
    /// <param name="key">KeyCode to consider.</param>
    /// <param name="direction">True if down, false if coming back up.</param>
    /// <returns>System key associated with the specified keycode.</returns>
    private SystemKey KeyCodeToSysKey(KeyCodes key, bool direction) {
      switch(key) {
        case KeyCodes.LeftShift:
          leftShift = direction;

          if(!rightShift) {
            return SystemKey.Shift;
          }

          break;

        case KeyCodes.RightShift:
          rightShift = direction;

          if(!leftShift) {
            return SystemKey.Shift;
          }

          break;

        case KeyCodes.LeftControl:
          leftCtrl = direction;

          if(!rightCtrl) {
            return SystemKey.Control;
          }

          break;

        case KeyCodes.RightControl:
          rightCtrl = direction;

          if(!leftCtrl) {
            return SystemKey.Control;
          }

          break;
      }

      // if not a system key or the state hasn't changed, return None
      return SystemKey.None;
    }

    #endregion Private Helper Methods

    #region Nested Classes

    /// <summary>
    ///    Structure to use for tracking mouse click timing for a single button.
    /// </summary>
    /// <remarks>
    ///    This would be a struct, but we need to be able to create the timer here.
    /// </remarks>
    public class MouseClickTracker {
      /// <summary>
      ///    Timer to use for timing mouse clicks.
      /// </summary>
      public Timer timer = new Timer();
      /// <summary>
      ///    Number of times the button has been clicked.
      /// </summary>
      public int clickCount;
      /// <summary>
      ///    Area where the mouse was last clicked (with tolerance).
      /// </summary>
      public Rect clickArea;
    }

    /// <summary>
    ///    Simple class for tracking elasped time (in milliseconds).
    /// </summary>
    public class Timer {
      /// <summary>
      ///    Elapsed time since the last call to <see cref="Restart"/>.
      /// </summary>
      private float elapsed;

      /// <summary>
      ///    Constructor.
      /// </summary>
      public Timer() {
        Restart();
      }

      /// <summary>
      ///    Gets the elapsed time (in milliseconds) since the last call to <see cref="Restart"/>.
      /// </summary>
      public float Elapsed {
        get {
          return (Environment.TickCount - elapsed) / 1000;
        }
      }

      /// <summary>
      ///    Restarts the timer.
      /// </summary>
      public void Restart() {
        // tick count is more than sufficient for our purposes
        elapsed = Environment.TickCount;
      }
    }

    #endregion Nested Classes
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.