This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
gwen-dotnet/Gwen/Control/Base.cs

2128 lines
65 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
////using System.Drawing;
//using System.Windows.Forms;
using Gwen.Anim;
using Gwen.DragDrop;
using Gwen.Input;
using Gwen.Extensions;
namespace Gwen.Control
{
/// <summary>
/// Base control class.
/// </summary>
public class Base : IDisposable
{
// this REALLY needs to be replaced with control-specific events
/// <summary>
/// Delegate used for all control event handlers.
/// </summary>
/// <param name="control">Event source.</param>
public delegate void GwenEventHandler(Base control);
private bool m_Disposed;
private Base m_Parent;
/// <summary>
/// This is the panel's actual parent - most likely the logical
/// parent's InnerPanel (if it has one). You should rarely need this.
/// </summary>
private Base m_ActualParent;
/// <summary>
/// If the innerpanel exists our children will automatically become children of that
/// instead of us - allowing us to move them all around by moving that panel (useful for scrolling etc).
/// </summary>
protected Base m_InnerPanel;
private Base m_ToolTip;
private Skin.Base m_Skin;
private Rectangle m_Bounds;
private Rectangle m_RenderBounds;
private Rectangle m_InnerBounds;
private Padding m_Padding;
private Margin m_Margin;
private String m_Name;
private bool m_RestrictToParent;
private bool m_Disabled;
private bool m_Hidden;
private bool m_MouseInputEnabled;
private bool m_KeyboardInputEnabled;
private bool m_DrawBackground;
private Pos m_Dock;
//private Cursor m_Cursor;
private bool m_Tabable;
private bool m_NeedsLayout;
private bool m_CacheTextureDirty;
private bool m_CacheToTexture;
private Package m_DragAndDrop_Package;
private object m_UserData;
private bool m_DrawDebugOutlines;
/// <summary>
/// Real list of children.
/// </summary>
private readonly List<Base> m_Children;
/// <summary>
/// Invoked when mouse pointer enters the control.
/// </summary>
public event GwenEventHandler HoverEnter;
/// <summary>
/// Invoked when mouse pointer leaves the control.
/// </summary>
public event GwenEventHandler HoverLeave;
/// <summary>
/// Invoked when control's bounds have been changed.
/// </summary>
public event GwenEventHandler BoundsChanged;
/// <summary>
/// Accelerator map.
/// </summary>
private readonly Dictionary<String, GwenEventHandler> m_Accelerators;
public const int MaxCoord = 4096; // added here from various places in code
/// <summary>
/// Logical list of children. If InnerPanel is not null, returns InnerPanel's children.
/// </summary>
public List<Base> Children
{
get
{
if (m_InnerPanel != null)
return m_InnerPanel.Children;
return m_Children;
}
}
/// <summary>
/// The logical parent. It's usually what you expect, the control you've parented it to.
/// </summary>
public Base Parent
{
get { return m_Parent; }
set
{
if (m_Parent == value)
return;
if (m_Parent != null)
{
m_Parent.RemoveChild(this, false);
}
m_Parent = value;
m_ActualParent = null;
if (m_Parent != null)
{
m_Parent.AddChild(this);
}
}
}
// todo: ParentChanged event?
/// <summary>
/// Dock position.
/// </summary>
public Pos Dock
{
get { return m_Dock; }
set
{
if (m_Dock == value)
return;
m_Dock = value;
Invalidate();
InvalidateParent();
}
}
/// <summary>
/// Current skin.
/// </summary>
public Skin.Base Skin
{
get
{
if (m_Skin != null)
return m_Skin;
if (m_Parent != null)
return m_Parent.Skin;
throw new InvalidOperationException("GetSkin: null");
}
}
/// <summary>
/// Current tooltip.
/// </summary>
public Base ToolTip
{
get { return m_ToolTip; }
set
{
m_ToolTip = value;
if (m_ToolTip != null)
{
m_ToolTip.Parent = this;
m_ToolTip.IsHidden = true;
}
}
}
/// <summary>
/// Indicates whether this control is a menu component.
/// </summary>
internal virtual bool IsMenuComponent
{
get
{
if (m_Parent == null)
return false;
return m_Parent.IsMenuComponent;
}
}
/// <summary>
/// Determines whether the control should be clipped to its bounds while rendering.
/// </summary>
protected virtual bool ShouldClip { get { return true; } }
/// <summary>
/// Current padding - inner spacing.
/// </summary>
public Padding Padding
{
get { return m_Padding; }
set
{
if (m_Padding == value)
return;
m_Padding = value;
Invalidate();
InvalidateParent();
}
}
/// <summary>
/// Current margin - outer spacing.
/// </summary>
public Margin Margin
{
get { return m_Margin; }
set
{
if (m_Margin == value)
return;
m_Margin = value;
Invalidate();
InvalidateParent();
}
}
/// <summary>
/// Indicates whether the control is on top of its parent's children.
/// </summary>
public virtual bool IsOnTop { get { return this == Parent.m_Children.First(); } } // todo: validate
/// <summary>
/// User data associated with the control.
/// </summary>
public object UserData { get { return m_UserData; } set { m_UserData = value; } }
/// <summary>
/// Indicates whether the control is hovered by mouse pointer.
/// </summary>
public virtual bool IsHovered { get { return InputHandler.HoveredControl == this; } }
/// <summary>
/// Indicates whether the control has focus.
/// </summary>
public bool HasFocus { get { return InputHandler.KeyboardFocus == this; } }
/// <summary>
/// Indicates whether the control is disabled.
/// </summary>
public bool IsDisabled { get { return m_Disabled; } set { m_Disabled = value; } }
/// <summary>
/// Indicates whether the control is hidden.
/// </summary>
public virtual bool IsHidden { get { return m_Hidden; } set { if (value == m_Hidden) return; m_Hidden = value; Invalidate(); } }
/// <summary>
/// Determines whether the control's position should be restricted to parent's bounds.
/// </summary>
public bool RestrictToParent { get { return m_RestrictToParent; } set { m_RestrictToParent = value; } }
/// <summary>
/// Determines whether the control receives mouse input events.
/// </summary>
public bool MouseInputEnabled { get { return m_MouseInputEnabled; } set { m_MouseInputEnabled = value; } }
/// <summary>
/// Determines whether the control receives keyboard input events.
/// </summary>
public bool KeyboardInputEnabled { get { return m_KeyboardInputEnabled; } set { m_KeyboardInputEnabled = value; } }
/*
/// <summary>
/// Gets or sets the mouse cursor when the cursor is hovering the control.
/// </summary>
public Cursor Cursor { get { return m_Cursor; } set { m_Cursor = value; } }
*/
/// <summary>
/// Indicates whether the control is tabable (can be focused by pressing Tab).
/// </summary>
public bool IsTabable { get { return m_Tabable; } set { m_Tabable = value; } }
/// <summary>
/// Indicates whether control's background should be drawn during rendering.
/// </summary>
public bool ShouldDrawBackground { get { return m_DrawBackground; } set { m_DrawBackground = value; } }
/// <summary>
/// Indicates whether the renderer should cache drawing to a texture to improve performance (at the cost of memory).
/// </summary>
public bool ShouldCacheToTexture { get { return m_CacheToTexture; } set { m_CacheToTexture = value; /*Children.ForEach(x => x.ShouldCacheToTexture=value);*/ } }
/// <summary>
/// Gets or sets the control's internal name.
/// </summary>
public String Name { get { return m_Name; } set { m_Name = value; } }
/// <summary>
/// Control's size and position relative to the parent.
/// </summary>
public Rectangle Bounds { get { return m_Bounds; } }
/// <summary>
/// Bounds for the renderer.
/// </summary>
public Rectangle RenderBounds { get { return m_RenderBounds; } }
/// <summary>
/// Bounds adjusted by padding.
/// </summary>
public Rectangle InnerBounds { get { return m_InnerBounds; } }
/// <summary>
/// Size restriction.
/// </summary>
public Point MinimumSize { get { return m_MinimumSize; } set { m_MinimumSize = value; } }
/// <summary>
/// Size restriction.
/// </summary>
public Point MaximumSize { get { return m_MaximumSize; } set { m_MaximumSize = value; } }
private Point m_MinimumSize = new Point(1, 1);
private Point m_MaximumSize = new Point(MaxCoord, MaxCoord);
/// <summary>
/// Determines whether hover should be drawn during rendering.
/// </summary>
protected bool ShouldDrawHover { get { return InputHandler.MouseFocus == this || InputHandler.MouseFocus == null; } }
protected virtual bool AccelOnlyFocus { get { return false; } }
protected virtual bool NeedsInputChars { get { return false; } }
/// <summary>
/// Indicates whether the control and its parents are visible.
/// </summary>
public bool IsVisible
{
get
{
if (IsHidden)
return false;
if (Parent != null)
return Parent.IsVisible;
return true;
}
}
/// <summary>
/// Leftmost coordinate of the control.
/// </summary>
public int X { get { return m_Bounds.X; } set { SetPosition(value, Y); } }
/// <summary>
/// Topmost coordinate of the control.
/// </summary>
public int Y { get { return m_Bounds.Y; } set { SetPosition(X, value); } }
// todo: Bottom/Right includes margin but X/Y not?
public int Width { get { return m_Bounds.Width; } set { SetSize(value, Height); } }
public int Height { get { return m_Bounds.Height; } set { SetSize(Width, value); } }
public int Bottom { get { return m_Bounds.Bottom + m_Margin.Bottom; } }
public int Right { get { return m_Bounds.Right + m_Margin.Right; } }
/// <summary>
/// Determines whether margin, padding and bounds outlines for the control will be drawn. Applied recursively to all children.
/// </summary>
public bool DrawDebugOutlines
{
get { return m_DrawDebugOutlines; }
set
{
if (m_DrawDebugOutlines == value)
return;
m_DrawDebugOutlines = value;
foreach (Base child in Children)
{
child.DrawDebugOutlines = value;
}
}
}
public Color PaddingOutlineColor { get; set; }
public Color MarginOutlineColor { get; set; }
public Color BoundsOutlineColor { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Base"/> class.
/// </summary>
/// <param name="parent">Parent control.</param>
public Base(Base parent = null)
{
m_Children = new List<Base>();
m_Accelerators = new Dictionary<string, GwenEventHandler>();
Parent = parent;
m_Hidden = false;
m_Bounds = new Rectangle(0, 0, 10, 10);
m_Padding = Padding.Zero;
m_Margin = Margin.Zero;
RestrictToParent = false;
MouseInputEnabled = true;
KeyboardInputEnabled = false;
Invalidate();
//Cursor = Cursors.Default;
//ToolTip = null;
IsTabable = false;
ShouldDrawBackground = true;
m_Disabled = false;
m_CacheTextureDirty = true;
m_CacheToTexture = false;
BoundsOutlineColor = Color.Red;
MarginOutlineColor = Color.Green;
PaddingOutlineColor = Color.Blue;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public virtual void Dispose()
{
//Debug.Print("Control.Base: Disposing {0} {1:X}", this, GetHashCode());
if (m_Disposed)
{
#if DEBUG
throw new ObjectDisposedException(String.Format("Control.Base [{1:X}] disposed twice: {0}", this, GetHashCode()));
#else
return;
#endif
}
if (InputHandler.HoveredControl == this)
InputHandler.HoveredControl = null;
if (InputHandler.KeyboardFocus == this)
InputHandler.KeyboardFocus = null;
if (InputHandler.MouseFocus == this)
InputHandler.MouseFocus = null;
DragAndDrop.ControlDeleted(this);
Gwen.ToolTip.ControlDeleted(this);
Animation.Cancel(this);
foreach (Base child in m_Children)
child.Dispose();
m_Children.Clear();
m_Disposed = true;
GC.SuppressFinalize(this);
}
#if DEBUG
~Base()
{
throw new InvalidOperationException(String.Format("IDisposable object finalized [{1:X}]: {0}", this, GetHashCode()));
//Debug.Print(String.Format("IDisposable object finalized: {0}", GetType()));
}
#endif
/// <summary>
/// Detaches the control from canvas and adds to the deletion queue (processed in Canvas.DoThink).
/// </summary>
public void DelayedDelete()
{
GetCanvas().AddDelayedDelete(this);
}
public override string ToString()
{
if (this is MenuItem)
return "[MenuItem: " + (this as MenuItem).Text + "]";
if (this is Label)
return "[Label: " + (this as Label).Text + "]";
if (this is ControlInternal.Text)
return "[Text: " + (this as ControlInternal.Text).String + "]";
return GetType().ToString();
}
/// <summary>
/// Gets the canvas (root parent) of the control.
/// </summary>
/// <returns></returns>
public virtual Canvas GetCanvas()
{
Base canvas = m_Parent;
if (canvas == null)
return null;
return canvas.GetCanvas();
}
/// <summary>
/// Enables the control.
/// </summary>
public void Enable()
{
IsDisabled = false;
}
/// <summary>
/// Disables the control.
/// </summary>
public void Disable()
{
IsDisabled = true;
}
/// <summary>
/// Default accelerator handler.
/// </summary>
/// <param name="control">Event source.</param>
private void DefaultAcceleratorHandler(Base control)
{
OnAccelerator();
}
/// <summary>
/// Default accelerator handler.
/// </summary>
protected virtual void OnAccelerator()
{
}
/// <summary>
/// Hides the control.
/// </summary>
public virtual void Hide()
{
IsHidden = true;
}
/// <summary>
/// Shows the control.
/// </summary>
public virtual void Show()
{
IsHidden = false;
}
/// <summary>
/// Creates a tooltip for the control.
/// </summary>
/// <param name="text">Tooltip text.</param>
public virtual void SetToolTipText(String text)
{
Label tooltip = new Label(this);
tooltip.AutoSizeToContents = true;
tooltip.Text = text;
tooltip.TextColorOverride = Skin.Colors.TooltipText;
tooltip.Padding = new Padding(5, 3, 5, 3);
tooltip.SizeToContents();
ToolTip = tooltip;
}
/// <summary>
/// Invalidates the control's children (relayout/repaint).
/// </summary>
/// <param name="recursive">Determines whether the operation should be carried recursively.</param>
protected virtual void InvalidateChildren(bool recursive = false)
{
foreach (Base child in m_Children)
{
child.Invalidate();
if (recursive)
child.InvalidateChildren(true);
}
if (m_InnerPanel != null)
{
foreach (Base child in m_InnerPanel.m_Children)
{
child.Invalidate();
if (recursive)
child.InvalidateChildren(true);
}
}
}
/// <summary>
/// Invalidates the control.
/// </summary>
/// <remarks>
/// Causes layout, repaint, invalidates cached texture.
/// </remarks>
public virtual void Invalidate()
{
m_NeedsLayout = true;
m_CacheTextureDirty = true;
}
/// <summary>
/// Sends the control to the bottom of paren't visibility stack.
/// </summary>
public virtual void SendToBack()
{
if (m_ActualParent == null)
return;
if (m_ActualParent.m_Children.Count == 0)
return;
if (m_ActualParent.m_Children.First() == this)
return;
m_ActualParent.m_Children.Remove(this);
m_ActualParent.m_Children.Insert(0, this);
InvalidateParent();
}
/// <summary>
/// Brings the control to the top of paren't visibility stack.
/// </summary>
public virtual void BringToFront()
{
if (m_ActualParent == null)
return;
if (m_ActualParent.m_Children.Last() == this)
return;
m_ActualParent.m_Children.Remove(this);
m_ActualParent.m_Children.Add(this);
InvalidateParent();
Redraw();
}
public virtual void BringNextToControl(Base child, bool behind)
{
if (null == m_ActualParent)
return;
m_ActualParent.m_Children.Remove(this);
// todo: validate
int idx = m_ActualParent.m_Children.IndexOf(child);
if (idx == m_ActualParent.m_Children.Count - 1)
{
BringToFront();
return;
}
if (behind)
{
++idx;
if (idx == m_ActualParent.m_Children.Count - 1)
{
BringToFront();
return;
}
}
m_ActualParent.m_Children.Insert(idx, this);
InvalidateParent();
}
/// <summary>
/// Finds a child by name.
/// </summary>
/// <param name="name">Child name.</param>
/// <param name="recursive">Determines whether the search should be recursive.</param>
/// <returns>Found control or null.</returns>
public virtual Base FindChildByName(String name, bool recursive = false)
{
Base b = m_Children.Find(x => x.m_Name == name);
if (b != null)
return b;
if (recursive)
{
foreach (Base child in m_Children)
{
b = child.FindChildByName(name, true);
if (b != null)
return b;
}
}
return null;
}
/// <summary>
/// Attaches specified control as a child of this one.
/// </summary>
/// <remarks>
/// If InnerPanel is not null, it will become the parent.
/// </remarks>
/// <param name="child">Control to be added as a child.</param>
public virtual void AddChild(Base child)
{
if (m_InnerPanel != null)
{
m_InnerPanel.AddChild(child);
return;
}
m_Children.Add(child);
OnChildAdded(child);
child.m_ActualParent = this;
}
/// <summary>
/// Detaches specified control from this one.
/// </summary>
/// <param name="child">Child to be removed.</param>
/// <param name="dispose">Determines whether the child should be disposed (added to delayed delete queue).</param>
public virtual void RemoveChild(Base child, bool dispose)
{
// If we removed our innerpanel
// remove our pointer to it
if (m_InnerPanel == child)
{
m_Children.Remove(m_InnerPanel);
m_InnerPanel.DelayedDelete();
m_InnerPanel = null;
return;
}
if (m_InnerPanel != null && m_InnerPanel.Children.Contains(child))
{
m_InnerPanel.RemoveChild(child, dispose);
return;
}
m_Children.Remove(child);
OnChildRemoved(child);
if (dispose)
child.DelayedDelete();
}
/// <summary>
/// Removes all children (and disposes them).
/// </summary>
public virtual void DeleteAllChildren()
{
// todo: probably shouldn't invalidate after each removal
while (m_Children.Count > 0)
RemoveChild(m_Children[0], true);
}
/// <summary>
/// Handler invoked when a child is added.
/// </summary>
/// <param name="child">Child added.</param>
protected virtual void OnChildAdded(Base child)
{
Invalidate();
}
/// <summary>
/// Handler invoked when a child is removed.
/// </summary>
/// <param name="child">Child removed.</param>
protected virtual void OnChildRemoved(Base child)
{
Invalidate();
}
/// <summary>
/// Moves the control by a specific amount.
/// </summary>
/// <param name="x">X-axis movement.</param>
/// <param name="y">Y-axis movement.</param>
public virtual void MoveBy(int x, int y)
{
SetBounds(X + x, Y + y, Width, Height);
}
/// <summary>
/// Moves the control to a specific point.
/// </summary>
/// <param name="x">Target x coordinate.</param>
/// <param name="y">Target y coordinate.</param>
public virtual void MoveTo(float x, float y)
{
MoveTo((int)x, (int)y);
}
/// <summary>
/// Moves the control to a specific point, clamping on paren't bounds if RestrictToParent is set.
/// </summary>
/// <param name="x">Target x coordinate.</param>
/// <param name="y">Target y coordinate.</param>
public virtual void MoveTo(int x, int y)
{
if (RestrictToParent && (Parent != null))
{
Base parent = Parent;
if (x - Padding.Left < parent.Margin.Left)
x = parent.Margin.Left + Padding.Left;
if (y - Padding.Top < parent.Margin.Top)
y = parent.Margin.Top + Padding.Top;
if (x + Width + Padding.Right > parent.Width - parent.Margin.Right)
x = parent.Width - parent.Margin.Right - Width - Padding.Right;
if (y + Height + Padding.Bottom > parent.Height - parent.Margin.Bottom)
y = parent.Height - parent.Margin.Bottom - Height - Padding.Bottom;
}
SetBounds(x, y, Width, Height);
}
/// <summary>
/// Sets the control position.
/// </summary>
/// <param name="x">Target x coordinate.</param>
/// <param name="y">Target y coordinate.</param>
public virtual void SetPosition(float x, float y)
{
SetPosition((int)x, (int)y);
}
/// <summary>
/// Sets the control position.
/// </summary>
/// <param name="x">Target x coordinate.</param>
/// <param name="y">Target y coordinate.</param>
public virtual void SetPosition(int x, int y)
{
SetBounds(x, y, Width, Height);
}
/// <summary>
/// Sets the control size.
/// </summary>
/// <param name="width">New width.</param>
/// <param name="height">New height.</param>
/// <returns>True if bounds changed.</returns>
public virtual bool SetSize(int width, int height)
{
return SetBounds(X, Y, width, height);
}
/// <summary>
/// Sets the control bounds.
/// </summary>
/// <param name="bounds">New bounds.</param>
/// <returns>True if bounds changed.</returns>
public virtual bool SetBounds(Rectangle bounds)
{
return SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height);
}
/// <summary>
/// Sets the control bounds.
/// </summary>
/// <param name="x">X.</param>
/// <param name="y">Y.</param>
/// <param name="width">Width.</param>
/// <param name="height">Height.</param>
/// <returns>
/// True if bounds changed.
/// </returns>
public virtual bool SetBounds(float x, float y, float width, float height)
{
return SetBounds((int)x, (int)y, (int)width, (int)height);
}
/// <summary>
/// Sets the control bounds.
/// </summary>
/// <param name="x">X position.</param>
/// <param name="y">Y position.</param>
/// <param name="width">Width.</param>
/// <param name="height">Height.</param>
/// <returns>
/// True if bounds changed.
/// </returns>
public virtual bool SetBounds(int x, int y, int width, int height)
{
if (m_Bounds.X == x &&
m_Bounds.Y == y &&
m_Bounds.Width == width &&
m_Bounds.Height == height)
return false;
Rectangle oldBounds = Bounds;
m_Bounds.X = x;
m_Bounds.Y = y;
m_Bounds.Width = width;
m_Bounds.Height = height;
OnBoundsChanged(oldBounds);
if (BoundsChanged != null)
BoundsChanged.Invoke(this);
return true;
}
/// <summary>
/// Positions the control inside its parent.
/// </summary>
/// <param name="pos">Target position.</param>
/// <param name="xpadding">X padding.</param>
/// <param name="ypadding">Y padding.</param>
public virtual void Position(Pos pos, int xpadding = 0, int ypadding = 0) // todo: a bit ambiguous name
{
int w = Parent.Width;
int h = Parent.Height;
Padding padding = Parent.Padding;
int x = X;
int y = Y;
if (0 != (pos & Pos.Left)) x = padding.Left + xpadding;
if (0 != (pos & Pos.Right)) x = w - Width - padding.Right - xpadding;
if (0 != (pos & Pos.CenterH))
x = (int)(padding.Left + xpadding + (w - Width - padding.Left - padding.Right) * 0.5f);
if (0 != (pos & Pos.Top)) y = padding.Top + ypadding;
if (0 != (pos & Pos.Bottom)) y = h - Height - padding.Bottom - ypadding;
if (0 != (pos & Pos.CenterV))
y = (int)(padding.Top + ypadding + (h - Height - padding.Bottom - padding.Top) * 0.5f);
SetPosition(x, y);
}
/// <summary>
/// Handler invoked when control's bounds change.
/// </summary>
/// <param name="oldBounds">Old bounds.</param>
protected virtual void OnBoundsChanged(Rectangle oldBounds)
{
//Anything that needs to update on size changes
//Iterate my children and tell them I've changed
//
if (Parent != null)
Parent.OnChildBoundsChanged(oldBounds, this);
if (m_Bounds.Width != oldBounds.Width || m_Bounds.Height != oldBounds.Height)
{
Invalidate();
}
Redraw();
UpdateRenderBounds();
}
/// <summary>
/// Handler invoked when control's scale changes.
/// </summary>
protected virtual void OnScaleChanged()
{
foreach (Base child in m_Children)
{
child.OnScaleChanged();
}
}
/// <summary>
/// Handler invoked when control children's bounds change.
/// </summary>
protected virtual void OnChildBoundsChanged(Rectangle oldChildBounds, Base child)
{
}
/// <summary>
/// Renders the control using specified skin.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void Render(Skin.Base skin)
{
}
/// <summary>
/// Renders the control to a cache using specified skin.
/// </summary>
/// <param name="skin">Skin to use.</param>
/// <param name="master">Root parent.</param>
protected virtual void DoCacheRender(Skin.Base skin, Base master)
{
Renderer.Base render = skin.Renderer;
Renderer.ICacheToTexture cache = render.CTT;
if (cache == null)
return;
Point oldRenderOffset = render.RenderOffset;
Rectangle oldRegion = render.ClipRegion;
if (this != master)
{
render.AddRenderOffset(Bounds);
render.AddClipRegion(Bounds);
}
else
{
render.RenderOffset = Point.Empty;
render.ClipRegion = new Rectangle(0, 0, Width, Height);
}
if (m_CacheTextureDirty && render.ClipRegionVisible)
{
render.StartClip();
if (ShouldCacheToTexture)
cache.SetupCacheTexture(this);
//Render myself first
//var old = render.ClipRegion;
//render.ClipRegion = Bounds;
//var old = render.RenderOffset;
//render.RenderOffset = new Point(Bounds.X, Bounds.Y);
Render(skin);
//render.RenderOffset = old;
//render.ClipRegion = old;
if (m_Children.Count > 0)
{
//Now render my kids
foreach (Base child in m_Children)
{
if (child.IsHidden)
continue;
child.DoCacheRender(skin, master);
}
}
if (ShouldCacheToTexture)
{
cache.FinishCacheTexture(this);
m_CacheTextureDirty = false;
}
}
render.ClipRegion = oldRegion;
render.StartClip();
render.RenderOffset = oldRenderOffset;
if (ShouldCacheToTexture)
cache.DrawCachedControlTexture(this);
}
/// <summary>
/// Rendering logic implementation.
/// </summary>
/// <param name="skin">Skin to use.</param>
internal virtual void DoRender(Skin.Base skin)
{
// If this control has a different skin,
// then so does its children.
if (m_Skin != null)
skin = m_Skin;
// Do think
Think();
Renderer.Base render = skin.Renderer;
if (render.CTT != null && ShouldCacheToTexture)
{
DoCacheRender(skin, this);
return;
}
RenderRecursive(skin, Bounds);
if (DrawDebugOutlines)
skin.DrawDebugOutlines(this);
}
/// <summary>
/// Recursive rendering logic.
/// </summary>
/// <param name="skin">Skin to use.</param>
/// <param name="clipRect">Clipping rectangle.</param>
protected virtual void RenderRecursive(Skin.Base skin, Rectangle clipRect)
{
Renderer.Base render = skin.Renderer;
Point oldRenderOffset = render.RenderOffset;
render.AddRenderOffset(clipRect);
RenderUnder(skin);
Rectangle oldRegion = render.ClipRegion;
if (ShouldClip)
{
render.AddClipRegion(clipRect);
if (!render.ClipRegionVisible)
{
render.RenderOffset = oldRenderOffset;
render.ClipRegion = oldRegion;
return;
}
render.StartClip();
}
//Render myself first
Render(skin);
if (m_Children.Count > 0)
{
//Now render my kids
foreach (Base child in m_Children)
{
if (child.IsHidden)
continue;
child.DoRender(skin);
}
}
render.ClipRegion = oldRegion;
render.StartClip();
RenderOver(skin);
RenderFocus(skin);
render.RenderOffset = oldRenderOffset;
}
/// <summary>
/// Sets the control's skin.
/// </summary>
/// <param name="skin">New skin.</param>
/// <param name="doChildren">Deterines whether to change children skin.</param>
public virtual void SetSkin(Skin.Base skin, bool doChildren = false)
{
if (m_Skin == skin)
return;
m_Skin = skin;
Invalidate();
Redraw();
OnSkinChanged(skin);
if (doChildren)
{
foreach (Base child in m_Children)
{
child.SetSkin(skin, true);
}
}
}
/// <summary>
/// Handler invoked when control's skin changes.
/// </summary>
/// <param name="newSkin">New skin.</param>
protected virtual void OnSkinChanged(Skin.Base newSkin)
{
}
/// <summary>
/// Handler invoked on mouse wheel event.
/// </summary>
/// <param name="delta">Scroll delta.</param>
protected virtual bool OnMouseWheeled(int delta)
{
if (m_ActualParent != null)
return m_ActualParent.OnMouseWheeled(delta);
return false;
}
/// <summary>
/// Invokes mouse wheeled event (used by input system).
/// </summary>
internal bool InputMouseWheeled(int delta)
{
return OnMouseWheeled(delta);
}
/// <summary>
/// Handler invoked on mouse moved event.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
/// <param name="dx">X change.</param>
/// <param name="dy">Y change.</param>
protected virtual void OnMouseMoved(int x, int y, int dx, int dy)
{
}
/// <summary>
/// Invokes mouse moved event (used by input system).
/// </summary>
internal void InputMouseMoved(int x, int y, int dx, int dy)
{
OnMouseMoved(x, y, dx, dy);
}
/// <summary>
/// Handler invoked on mouse click (left) event.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
/// <param name="down">If set to <c>true</c> mouse button is down.</param>
protected virtual void OnMouseClickedLeft(int x, int y, bool down)
{
}
/// <summary>
/// Invokes left mouse click event (used by input system).
/// </summary>
internal void InputMouseClickedLeft(int x, int y, bool down)
{
OnMouseClickedLeft(x, y, down);
}
/// <summary>
/// Handler invoked on mouse click (right) event.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
/// <param name="down">If set to <c>true</c> mouse button is down.</param>
protected virtual void OnMouseClickedRight(int x, int y, bool down)
{
}
/// <summary>
/// Invokes right mouse click event (used by input system).
/// </summary>
internal void InputMouseClickedRight(int x, int y, bool down)
{
OnMouseClickedRight(x, y, down);
}
/// <summary>
/// Handler invoked on mouse double click (left) event.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
protected virtual void OnMouseDoubleClickedLeft(int x, int y)
{
OnMouseClickedLeft(x, y, true); // [omeg] should this be called?
}
/// <summary>
/// Invokes left double mouse click event (used by input system).
/// </summary>
internal void InputMouseDoubleClickedLeft(int x, int y)
{
OnMouseDoubleClickedLeft(x, y);
}
/// <summary>
/// Handler invoked on mouse double click (right) event.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
protected virtual void OnMouseDoubleClickedRight(int x, int y)
{
OnMouseClickedRight(x, y, true); // [omeg] should this be called?
}
/// <summary>
/// Invokes right double mouse click event (used by input system).
/// </summary>
internal void InputMouseDoubleClickedRight(int x, int y)
{
OnMouseDoubleClickedRight(x, y);
}
/// <summary>
/// Handler invoked on mouse cursor entering control's bounds.
/// </summary>
protected virtual void OnMouseEntered()
{
if (HoverEnter != null)
HoverEnter.Invoke(this);
if (ToolTip != null)
Gwen.ToolTip.Enable(this);
else if (Parent != null && Parent.ToolTip != null)
Gwen.ToolTip.Enable(Parent);
Redraw();
}
/// <summary>
/// Invokes mouse enter event (used by input system).
/// </summary>
internal void InputMouseEntered()
{
OnMouseEntered();
}
/// <summary>
/// Handler invoked on mouse cursor leaving control's bounds.
/// </summary>
protected virtual void OnMouseLeft()
{
if (HoverLeave != null)
HoverLeave.Invoke(this);
if (ToolTip != null)
Gwen.ToolTip.Disable(this);
Redraw();
}
/// <summary>
/// Invokes mouse leave event (used by input system).
/// </summary>
internal void InputMouseLeft()
{
OnMouseLeft();
}
/// <summary>
/// Focuses the control.
/// </summary>
public virtual void Focus()
{
if (InputHandler.KeyboardFocus == this)
return;
if (InputHandler.KeyboardFocus != null)
InputHandler.KeyboardFocus.OnLostKeyboardFocus();
InputHandler.KeyboardFocus = this;
OnKeyboardFocus();
Redraw();
}
/// <summary>
/// Unfocuses the control.
/// </summary>
public virtual void Blur()
{
if (InputHandler.KeyboardFocus != this)
return;
InputHandler.KeyboardFocus = null;
OnLostKeyboardFocus();
Redraw();
}
/// <summary>
/// Control has been clicked - invoked by input system. Windows use it to propagate activation.
/// </summary>
public virtual void Touch()
{
if (Parent != null)
Parent.OnChildTouched(this);
}
protected virtual void OnChildTouched(Base control)
{
Touch();
}
/// <summary>
/// Gets a child by its coordinates.
/// </summary>
/// <param name="x">Child X.</param>
/// <param name="y">Child Y.</param>
/// <returns>Control or null if not found.</returns>
public virtual Base GetControlAt(int x, int y)
{
if (IsHidden)
return null;
if (x < 0 || y < 0 || x >= Width || y >= Height)
return null;
// todo: convert to linq FindLast
var rev = ((IList<Base>)m_Children).Reverse(); // IList.Reverse creates new list, List.Reverse works in place.. go figure
foreach (Base child in rev)
{
Base found = child.GetControlAt(x - child.X, y - child.Y);
if (found != null)
return found;
}
if (!MouseInputEnabled)
return null;
return this;
}
/// <summary>
/// Lays out the control's interior according to alignment, padding, dock etc.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void Layout(Skin.Base skin)
{
if (skin.Renderer.CTT != null && ShouldCacheToTexture)
skin.Renderer.CTT.CreateControlCacheTexture(this);
}
/// <summary>
/// Recursively lays out the control's interior according to alignment, margin, padding, dock etc.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void RecurseLayout(Skin.Base skin)
{
if (m_Skin != null)
skin = m_Skin;
if (IsHidden)
return;
if (m_NeedsLayout)
{
m_NeedsLayout = false;
Layout(skin);
}
Rectangle bounds = RenderBounds;
// Adjust bounds for padding
bounds.X += m_Padding.Left;
bounds.Width -= m_Padding.Left + m_Padding.Right;
bounds.Y += m_Padding.Top;
bounds.Height -= m_Padding.Top + m_Padding.Bottom;
foreach (Base child in m_Children)
{
if (child.IsHidden)
continue;
Pos dock = child.Dock;
if (0 != (dock & Pos.Fill))
continue;
if (0 != (dock & Pos.Top))
{
Margin margin = child.Margin;
child.SetBounds(bounds.X + margin.Left, bounds.Y + margin.Top,
bounds.Width - margin.Left - margin.Right, child.Height);
int height = margin.Top + margin.Bottom + child.Height;
bounds.Y += height;
bounds.Height -= height;
}
if (0 != (dock & Pos.Left))
{
Margin margin = child.Margin;
child.SetBounds(bounds.X + margin.Left, bounds.Y + margin.Top, child.Width,
bounds.Height - margin.Top - margin.Bottom);
int width = margin.Left + margin.Right + child.Width;
bounds.X += width;
bounds.Width -= width;
}
if (0 != (dock & Pos.Right))
{
// TODO: THIS MARGIN CODE MIGHT NOT BE FULLY FUNCTIONAL
Margin margin = child.Margin;
child.SetBounds((bounds.X + bounds.Width) - child.Width - margin.Right, bounds.Y + margin.Top,
child.Width, bounds.Height - margin.Top - margin.Bottom);
int width = margin.Left + margin.Right + child.Width;
bounds.Width -= width;
}
if (0 != (dock & Pos.Bottom))
{
// TODO: THIS MARGIN CODE MIGHT NOT BE FULLY FUNCTIONAL
Margin margin = child.Margin;
child.SetBounds(bounds.X + margin.Left,
(bounds.Y + bounds.Height) - child.Height - margin.Bottom,
bounds.Width - margin.Left - margin.Right, child.Height);
bounds.Height -= child.Height + margin.Bottom + margin.Top;
}
child.RecurseLayout(skin);
}
m_InnerBounds = bounds;
//
// Fill uses the left over space, so do that now.
//
foreach (Base child in m_Children)
{
Pos dock = child.Dock;
if (!(0 != (dock & Pos.Fill)))
continue;
Margin margin = child.Margin;
child.SetBounds(bounds.X + margin.Left, bounds.Y + margin.Top,
bounds.Width - margin.Left - margin.Right, bounds.Height - margin.Top - margin.Bottom);
child.RecurseLayout(skin);
}
PostLayout(skin);
if (IsTabable)
{
if (GetCanvas().FirstTab == null)
GetCanvas().FirstTab = this;
if (GetCanvas().NextTab == null)
GetCanvas().NextTab = this;
}
if (InputHandler.KeyboardFocus == this)
{
GetCanvas().NextTab = null;
}
}
/// <summary>
/// Checks if the given control is a child of this instance.
/// </summary>
/// <param name="child">Control to examine.</param>
/// <returns>True if the control is out child.</returns>
public bool IsChild(Base child)
{
return m_Children.Contains(child);
}
/// <summary>
/// Converts local coordinates to canvas coordinates.
/// </summary>
/// <param name="pnt">Local coordinates.</param>
/// <returns>Canvas coordinates.</returns>
public virtual Point LocalPosToCanvas(Point pnt)
{
if (m_Parent != null)
{
int x = pnt.X + X;
int y = pnt.Y + Y;
// If our parent has an innerpanel and we're a child of it
// add its offset onto us.
//
if (m_Parent.m_InnerPanel != null && m_Parent.m_InnerPanel.IsChild(this))
{
x += m_Parent.m_InnerPanel.X;
y += m_Parent.m_InnerPanel.Y;
}
return m_Parent.LocalPosToCanvas(new Point(x, y));
}
return pnt;
}
/// <summary>
/// Converts canvas coordinates to local coordinates.
/// </summary>
/// <param name="pnt">Canvas coordinates.</param>
/// <returns>Local coordinates.</returns>
public virtual Point CanvasPosToLocal(Point pnt)
{
if (m_Parent != null)
{
int x = pnt.X - X;
int y = pnt.Y - Y;
// If our parent has an innerpanel and we're a child of it
// add its offset onto us.
//
if (m_Parent.m_InnerPanel != null && m_Parent.m_InnerPanel.IsChild(this))
{
x -= m_Parent.m_InnerPanel.X;
y -= m_Parent.m_InnerPanel.Y;
}
return m_Parent.CanvasPosToLocal(new Point(x, y));
}
return pnt;
}
/// <summary>
/// Closes all menus recursively.
/// </summary>
public virtual void CloseMenus()
{
//Debug.Print("Base.CloseMenus: {0}", this);
// todo: not very efficient with the copying and recursive closing, maybe store currently open menus somewhere (canvas)?
var childrenCopy = m_Children.FindAll(x => true);
foreach (Base child in childrenCopy)
{
child.CloseMenus();
}
}
/// <summary>
/// Copies Bounds to RenderBounds.
/// </summary>
protected virtual void UpdateRenderBounds()
{
m_RenderBounds.X = 0;
m_RenderBounds.Y = 0;
m_RenderBounds.Width = m_Bounds.Width;
m_RenderBounds.Height = m_Bounds.Height;
}
/// <summary>
/// Sets mouse cursor to current cursor.
/// </summary>
public virtual void UpdateCursor()
{
//Platform.Neutral.SetCursor(m_Cursor);
}
// giver
public virtual Package DragAndDrop_GetPackage(int x, int y)
{
return m_DragAndDrop_Package;
}
// giver
public virtual bool DragAndDrop_Draggable()
{
if (m_DragAndDrop_Package == null)
return false;
return m_DragAndDrop_Package.IsDraggable;
}
// giver
public virtual void DragAndDrop_SetPackage(bool draggable, String name = "", object userData = null)
{
if (m_DragAndDrop_Package == null)
{
m_DragAndDrop_Package = new Package();
m_DragAndDrop_Package.IsDraggable = draggable;
m_DragAndDrop_Package.Name = name;
m_DragAndDrop_Package.UserData = userData;
}
}
// giver
public virtual bool DragAndDrop_ShouldStartDrag()
{
return true;
}
// giver
public virtual void DragAndDrop_StartDragging(Package package, int x, int y)
{
package.HoldOffset = CanvasPosToLocal(new Point(x, y));
package.DrawControl = this;
}
// giver
public virtual void DragAndDrop_EndDragging(bool success, int x, int y)
{
}
// receiver
public virtual bool DragAndDrop_HandleDrop(Package p, int x, int y)
{
DragAndDrop.SourceControl.Parent = this;
return true;
}
// receiver
public virtual void DragAndDrop_HoverEnter(Package p, int x, int y)
{
}
// receiver
public virtual void DragAndDrop_HoverLeave(Package p)
{
}
// receiver
public virtual void DragAndDrop_Hover(Package p, int x, int y)
{
}
// receiver
public virtual bool DragAndDrop_CanAcceptPackage(Package p)
{
return false;
}
/// <summary>
/// Resizes the control to fit its children.
/// </summary>
/// <param name="width">Determines whether to change control's width.</param>
/// <param name="height">Determines whether to change control's height.</param>
/// <returns>True if bounds changed.</returns>
public virtual bool SizeToChildren(bool width = true, bool height = true)
{
Point size = GetChildrenSize();
size.X += Padding.Right;
size.Y += Padding.Bottom;
return SetSize(width ? size.X : Width, height ? size.Y : Height);
}
/// <summary>
/// Returns the total width and height of all children.
/// </summary>
/// <remarks>Default implementation returns maximum size of children since the layout is unknown.
/// Implement this in derived compound controls to properly return their size.</remarks>
/// <returns></returns>
public virtual Point GetChildrenSize()
{
Point size = Point.Empty;
foreach (Base child in m_Children)
{
if (child.IsHidden)
continue;
size.X = Math.Max(size.X, child.Right);
size.Y = Math.Max(size.Y, child.Bottom);
}
return size;
}
/// <summary>
/// Handles keyboard accelerator.
/// </summary>
/// <param name="accelerator">Accelerator text.</param>
/// <returns>True if handled.</returns>
internal virtual bool HandleAccelerator(String accelerator)
{
if (InputHandler.KeyboardFocus == this || !AccelOnlyFocus)
{
if (m_Accelerators.ContainsKey(accelerator))
{
m_Accelerators[accelerator].Invoke(this);
return true;
}
}
return m_Children.Any(child => child.HandleAccelerator(accelerator));
}
/// <summary>
/// Adds keyboard accelerator.
/// </summary>
/// <param name="accelerator">Accelerator text.</param>
/// <param name="handler">Handler.</param>
public void AddAccelerator(String accelerator, GwenEventHandler handler)
{
accelerator = accelerator.Trim().ToUpperInvariant();
m_Accelerators[accelerator] = handler;
}
/// <summary>
/// Adds keyboard accelerator with a default handler.
/// </summary>
/// <param name="accelerator">Accelerator text.</param>
public void AddAccelerator(String accelerator)
{
m_Accelerators[accelerator] = DefaultAcceleratorHandler;
}
/// <summary>
/// Function invoked after layout.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void PostLayout(Skin.Base skin)
{
}
/// <summary>
/// Re-renders the control, invalidates cached texture.
/// </summary>
public virtual void Redraw()
{
UpdateColors();
m_CacheTextureDirty = true;
if (m_Parent != null)
m_Parent.Redraw();
}
/// <summary>
/// Updates control colors.
/// </summary>
/// <remarks>
/// Used in composite controls like lists to differentiate row colors etc.
/// </remarks>
public virtual void UpdateColors()
{
}
/// <summary>
/// Invalidates control's parent.
/// </summary>
public void InvalidateParent()
{
if (m_Parent != null)
{
m_Parent.Invalidate();
}
}
/// <summary>
/// Handler for keyboard events.
/// </summary>
/// <param name="key">Key pressed.</param>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyPressed(Key key, bool down = true)
{
bool handled = false;
switch (key)
{
case Key.Tab: handled = OnKeyTab(down); break;
case Key.Space: handled = OnKeySpace(down); break;
case Key.Home: handled = OnKeyHome(down); break;
case Key.End: handled = OnKeyEnd(down); break;
case Key.Return: handled = OnKeyReturn(down); break;
case Key.Backspace: handled = OnKeyBackspace(down); break;
case Key.Delete: handled = OnKeyDelete(down); break;
case Key.Right: handled = OnKeyRight(down); break;
case Key.Left: handled = OnKeyLeft(down); break;
case Key.Up: handled = OnKeyUp(down); break;
case Key.Down: handled = OnKeyDown(down); break;
case Key.Escape: handled = OnKeyEscape(down); break;
default: break;
}
if (!handled && Parent != null)
Parent.OnKeyPressed(key, down);
return handled;
}
/// <summary>
/// Invokes key press event (used by input system).
/// </summary>
internal bool InputKeyPressed(Key key, bool down = true)
{
return OnKeyPressed(key, down);
}
/// <summary>
/// Handler for keyboard events.
/// </summary>
/// <param name="key">Key pressed.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyReleaseed(Key key)
{
return OnKeyPressed(key, false);
}
/// <summary>
/// Handler for Tab keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyTab(bool down)
{
if (!down)
return true;
if (GetCanvas().NextTab != null)
{
GetCanvas().NextTab.Focus();
Redraw();
}
return true;
}
/// <summary>
/// Handler for Space keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeySpace(bool down) { return false; }
/// <summary>
/// Handler for Return keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyReturn(bool down) { return false; }
/// <summary>
/// Handler for Backspace keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyBackspace(bool down) { return false; }
/// <summary>
/// Handler for Delete keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyDelete(bool down) { return false; }
/// <summary>
/// Handler for Right Arrow keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyRight(bool down) { return false; }
/// <summary>
/// Handler for Left Arrow keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyLeft(bool down) { return false; }
/// <summary>
/// Handler for Home keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyHome(bool down) { return false; }
/// <summary>
/// Handler for End keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyEnd(bool down) { return false; }
/// <summary>
/// Handler for Up Arrow keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyUp(bool down) { return false; }
/// <summary>
/// Handler for Down Arrow keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyDown(bool down) { return false; }
/// <summary>
/// Handler for Escape keyboard event.
/// </summary>
/// <param name="down">Indicates whether the key was pressed or released.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnKeyEscape(bool down) { return false; }
/// <summary>
/// Handler for Paste event.
/// </summary>
/// <param name="from">Source control.</param>
protected virtual void OnPaste(Base from)
{
}
/// <summary>
/// Handler for Copy event.
/// </summary>
/// <param name="from">Source control.</param>
protected virtual void OnCopy(Base from)
{
}
/// <summary>
/// Handler for Cut event.
/// </summary>
/// <param name="from">Source control.</param>
protected virtual void OnCut(Base from)
{
}
/// <summary>
/// Handler for Select All event.
/// </summary>
/// <param name="from">Source control.</param>
protected virtual void OnSelectAll(Base from)
{
}
internal void InputCopy(Base from)
{
OnCopy(from);
}
internal void InputPaste(Base from)
{
OnPaste(from);
}
internal void InputCut(Base from)
{
OnCut(from);
}
internal void InputSelectAll(Base from)
{
OnSelectAll(from);
}
/// <summary>
/// Renders the focus overlay.
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void RenderFocus(Skin.Base skin)
{
if (InputHandler.KeyboardFocus != this)
return;
if (!IsTabable)
return;
skin.DrawKeyboardHighlight(this, RenderBounds, 3);
}
/// <summary>
/// Renders under the actual control (shadows etc).
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void RenderUnder(Skin.Base skin)
{
}
/// <summary>
/// Renders over the actual control (overlays).
/// </summary>
/// <param name="skin">Skin to use.</param>
protected virtual void RenderOver(Skin.Base skin)
{
}
/// <summary>
/// Called during rendering.
/// </summary>
public virtual void Think()
{
}
/// <summary>
/// Handler for gaining keyboard focus.
/// </summary>
protected virtual void OnKeyboardFocus()
{
}
/// <summary>
/// Handler for losing keyboard focus.
/// </summary>
protected virtual void OnLostKeyboardFocus()
{
}
/// <summary>
/// Handler for character input event.
/// </summary>
/// <param name="chr">Character typed.</param>
/// <returns>True if handled.</returns>
protected virtual bool OnChar(Char chr)
{
return false;
}
internal bool InputChar(Char chr)
{
return OnChar(chr);
}
public virtual void Anim_WidthIn(float length, float delay = 0.0f, float ease = 1.0f)
{
Animation.Add(this, new Anim.Size.Width(0, Width, length, false, delay, ease));
Width = 0;
}
public virtual void Anim_HeightIn(float length, float delay, float ease)
{
Animation.Add(this, new Anim.Size.Height(0, Height, length, false, delay, ease));
Height = 0;
}
public virtual void Anim_WidthOut(float length, bool hide, float delay, float ease)
{
Animation.Add(this, new Anim.Size.Width(Width, 0, length, hide, delay, ease));
}
public virtual void Anim_HeightOut(float length, bool hide, float delay, float ease)
{
Animation.Add(this, new Anim.Size.Height(Height, 0, length, hide, delay, ease));
}
}
}