space-pew/Neoforce/ContextMenu.cs

576 lines
20 KiB
C#
Raw Normal View History

2015-12-04 10:23:49 +01:00
////////////////////////////////////////////////////////////////
// //
// Neoforce Controls //
// //
////////////////////////////////////////////////////////////////
// //
// File: ContextMenu.cs //
// //
// Version: 0.7 //
// //
// Date: 11/09/2010 //
// //
// Author: Tom Shane //
// //
////////////////////////////////////////////////////////////////
// //
// Copyright (c) by Tom Shane //
// //
////////////////////////////////////////////////////////////////
#region //// Using /////////////
////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
////////////////////////////////////////////////////////////////////////////
#endregion
namespace TomShane.Neoforce.Controls
{
public class ContextMenu: MenuBase
{
#region //// Fields ////////////
////////////////////////////////////////////////////////////////////////////
private long timer = 0;
private Control sender = null;
////////////////////////////////////////////////////////////////////////////
#endregion
#region //// Properties ////////
////////////////////////////////////////////////////////////////////////////
protected internal Control Sender { get { return sender; } set { sender = value; } }
////////////////////////////////////////////////////////////////////////////
#endregion
#region //// Construstors //////
////////////////////////////////////////////////////////////////////////////
public ContextMenu(Manager manager): base(manager)
{
Visible = false;
Detached = true;
StayOnBack = true;
Manager.Input.MouseDown += new MouseEventHandler(Input_MouseDown);
}
////////////////////////////////////////////////////////////////////////////
#endregion
#region //// Destructors ///////
////////////////////////////////////////////////////////////////////////////
protected override void Dispose(bool disposing)
{
if (disposing)
{
Manager.Input.MouseDown -= Input_MouseDown;
}
base.Dispose(disposing);
}
////////////////////////////////////////////////////////////////////////////
#endregion
#region //// Methods ///////////
////////////////////////////////////////////////////////////////////////////
public override void Init()
{
base.Init();
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected internal override void InitSkin()
{
base.InitSkin();
Skin = new SkinControl(Manager.Skin.Controls["ContextMenu"]);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void DrawControl(Renderer renderer, Rectangle rect, GameTime gameTime)
{
base.DrawControl(renderer, rect, gameTime);
SkinLayer l1 = Skin.Layers["Control"];
SkinLayer l2 = Skin.Layers["Selection"];
int vsize = LineHeight();
Color col = Color.White;
for (int i = 0; i < Items.Count; i++)
{
int mod = i > 0 ? 2 : 0;
int left = rect.Left + l1.ContentMargins.Left + vsize;
int h = vsize - mod - (i < (Items.Count - 1) ? 1 : 0);
int top = rect.Top + l1.ContentMargins.Top + (i * vsize) + mod;
if (Items[i].Separated && i > 0)
{
Rectangle r = new Rectangle(left, rect.Top + l1.ContentMargins.Top + (i * vsize), LineWidth() - vsize + 4, 1);
renderer.Draw(Manager.Skin.Controls["Control"].Layers[0].Image.Resource, r, l1.Text.Colors.Enabled);
}
if (ItemIndex != i)
{
if (Items[i].Enabled)
{
Rectangle r = new Rectangle(left, top, LineWidth() - vsize, h);
renderer.DrawString(this, l1, Items[i].Text, r, false);
col = l1.Text.Colors.Enabled;
}
else
{
Rectangle r = new Rectangle(left + l1.Text.OffsetX,
top + l1.Text.OffsetY,
LineWidth() - vsize, h);
renderer.DrawString(l1.Text.Font.Resource, Items[i].Text, r, l1.Text.Colors.Disabled, l1.Text.Alignment);
col = l1.Text.Colors.Disabled;
}
}
else
{
if (Items[i].Enabled)
{
Rectangle rs = new Rectangle(rect.Left + l1.ContentMargins.Left,
top,
Width - (l1.ContentMargins.Horizontal - Skin.OriginMargins.Horizontal),
h);
renderer.DrawLayer(this, l2, rs);
Rectangle r = new Rectangle(left,
top, LineWidth() - vsize, h);
renderer.DrawString(this, l2, Items[i].Text, r, false);
col = l2.Text.Colors.Enabled;
}
else
{
Rectangle rs = new Rectangle(rect.Left + l1.ContentMargins.Left,
top,
Width - (l1.ContentMargins.Horizontal - Skin.OriginMargins.Horizontal),
vsize);
renderer.DrawLayer(l2, rs, l2.States.Disabled.Color, l2.States.Disabled.Index);
Rectangle r = new Rectangle(left + l1.Text.OffsetX,
top + l1.Text.OffsetY,
LineWidth() - vsize, h);
renderer.DrawString(l2.Text.Font.Resource, Items[i].Text, r, l2.Text.Colors.Disabled, l2.Text.Alignment);
col = l2.Text.Colors.Disabled;
}
}
if (Items[i].Image != null)
{
Rectangle r = new Rectangle(rect.Left + l1.ContentMargins.Left + 3,
rect.Top + top + 3,
LineHeight() - 6,
LineHeight() - 6);
renderer.Draw(Items[i].Image, r, Color.White);
}
if (Items[i].Items != null && Items[i].Items.Count > 0)
{
renderer.Draw(Manager.Skin.Images["Shared.ArrowRight"].Resource, rect.Left + LineWidth() - 4, rect.Top + l1.ContentMargins.Top + (i * vsize) + 8, col);
}
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private int LineHeight()
{
int h = 0;
if (Items.Count > 0)
{
SkinLayer l = Skin.Layers["Control"];
h = (int)l.Text.Font.Resource.LineSpacing + 9;
}
return h;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private int LineWidth()
{
int w = 0;
SkinFont font = Skin.Layers["Control"].Text.Font;
if (Items.Count > 0)
{
for (int i = 0; i < Items.Count; i++)
{
int wx = (int)font.Resource.MeasureString(Items[i].Text).X + 16;
if (wx > w) w = wx;
}
}
w += 4 + LineHeight();
return w;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private void AutoSize()
{
SkinText font = Skin.Layers["Control"].Text;
if (Items != null && Items.Count > 0)
{
Height = (LineHeight() * Items.Count) + (Skin.Layers["Control"].ContentMargins.Vertical - Skin.OriginMargins.Vertical);
Width = LineWidth() + (Skin.Layers["Control"].ContentMargins.Horizontal - Skin.OriginMargins.Horizontal) + font.OffsetX;
}
else
{
Height = 16;
Width = 16;
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private void TrackItem(int x, int y)
{
if (Items != null && Items.Count > 0)
{
SkinText font = Skin.Layers["Control"].Text;
int h = LineHeight();
y -= Skin.Layers["Control"].ContentMargins.Top;
int i = (int)((float)y / h);
if (i < Items.Count)
{
if (i != ItemIndex && Items[i].Enabled)
{
if (ChildMenu != null)
{
this.HideMenu(false);
}
if (i >= 0 && i != ItemIndex)
{
Items[i].SelectedInvoke(new EventArgs());
}
Focused = true;
ItemIndex = i;
timer = (long)TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
}
else if (!Items[i].Enabled && ChildMenu == null)
{
ItemIndex = -1;
}
}
Invalidate();
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
TrackItem(e.Position.X, e.Position.Y);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected internal override void Update(GameTime gameTime)
{
base.Update(gameTime);
AutoSize();
long time = (long)TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
if (timer != 0 && time - timer >= Manager.MenuDelay && ItemIndex >= 0 && Items[ItemIndex].Items.Count > 0 && ChildMenu == null)
{
OnClick(new MouseEventArgs(new MouseState(), MouseButton.Left, Point.Zero));
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void OnMouseOut(MouseEventArgs e)
{
base.OnMouseOut(e);
if (!CheckArea(e.State.X, e.State.Y) && ChildMenu == null)
{
ItemIndex = -1;
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void OnClick(EventArgs e)
{
if (sender != null && !(sender is MenuBase)) sender.Focused = true;
base.OnClick(e);
timer = 0;
MouseEventArgs ex = (e is MouseEventArgs) ? (MouseEventArgs)e : new MouseEventArgs();
if (ex.Button == MouseButton.Left || ex.Button == MouseButton.None)
{
if (ItemIndex >= 0 && Items[ItemIndex].Enabled)
{
if (ItemIndex >= 0 && Items[ItemIndex].Items != null && Items[ItemIndex].Items.Count > 0)
{
if (ChildMenu == null)
{
ChildMenu = new ContextMenu(Manager);
(ChildMenu as ContextMenu).RootMenu = this.RootMenu;
(ChildMenu as ContextMenu).ParentMenu = this;
(ChildMenu as ContextMenu).sender = sender;
ChildMenu.Items.AddRange(Items[ItemIndex].Items);
(ChildMenu as ContextMenu).AutoSize();
}
int y = AbsoluteTop + Skin.Layers["Control"].ContentMargins.Top + (ItemIndex * LineHeight());
(ChildMenu as ContextMenu).Show(sender, AbsoluteLeft + Width - 1, y);
if (ex.Button == MouseButton.None) (ChildMenu as ContextMenu).ItemIndex = 0;
}
else
{
if (ItemIndex >= 0)
{
Items[ItemIndex].ClickInvoke(ex);
}
if (RootMenu is ContextMenu) (RootMenu as ContextMenu).HideMenu(true);
else if (RootMenu is MainMenu)
{
(RootMenu as MainMenu).HideMenu();
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void OnKeyPress(KeyEventArgs e)
{
base.OnKeyPress(e);
timer = 0;
if (e.Key == Keys.Down || (e.Key == Keys.Tab && !e.Shift))
{
e.Handled = true;
ItemIndex += 1;
}
if (e.Key == Keys.Up || (e.Key == Keys.Tab && e.Shift))
{
e.Handled = true;
ItemIndex -=1;
}
if (ItemIndex > Items.Count - 1) ItemIndex = 0;
if (ItemIndex < 0) ItemIndex = Items.Count - 1;
if (e.Key == Keys.Right && Items[ItemIndex].Items.Count > 0)
{
e.Handled = true;
OnClick(new MouseEventArgs(new MouseState(), MouseButton.None, Point.Zero));
}
if (e.Key == Keys.Left)
{
e.Handled = true;
if (ParentMenu != null && ParentMenu is ContextMenu)
{
(ParentMenu as ContextMenu).Focused = true;
(ParentMenu as ContextMenu).HideMenu(false);
}
}
if (e.Key == Keys.Escape)
{
e.Handled = true;
if (ParentMenu != null) ParentMenu.Focused = true;
HideMenu(true);
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
protected override void OnGamePadPress(GamePadEventArgs e)
{
timer = 0;
if (e.Button == GamePadButton.None) return;
if (e.Button == GamePadActions.Down || e.Button == GamePadActions.NextControl)
{
e.Handled = true;
ItemIndex += 1;
}
else if (e.Button == GamePadActions.Up || e.Button == GamePadActions.PrevControl)
{
e.Handled = true;
ItemIndex -= 1;
}
if (ItemIndex > Items.Count - 1) ItemIndex = 0;
if (ItemIndex < 0) ItemIndex = Items.Count - 1;
if (e.Button == GamePadActions.Right && Items[ItemIndex].Items.Count > 0)
{
e.Handled = true;
OnClick(new MouseEventArgs(new MouseState(), MouseButton.None, Point.Zero));
}
if (e.Button == GamePadActions.Left)
{
e.Handled = true;
if (ParentMenu != null && ParentMenu is ContextMenu)
{
(ParentMenu as ContextMenu).Focused = true;
(ParentMenu as ContextMenu).HideMenu(false);
}
}
base.OnGamePadPress(e);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
public virtual void HideMenu(bool hideCurrent)
{
if (hideCurrent)
{
Visible = false;
ItemIndex = -1;
}
if (ChildMenu != null)
{
(ChildMenu as ContextMenu).HideMenu(true);
ChildMenu.Dispose();
ChildMenu = null;
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
public override void Show()
{
Show(null, Left, Top);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
public virtual void Show(Control sender, int x, int y)
{
AutoSize();
base.Show();
if (!Initialized) Init();
if (sender != null && sender.Root != null && sender.Root is Container)
{
(sender.Root as Container).Add(this, false);
}
else
{
Manager.Add(this);
}
this.sender = sender;
if (sender != null && sender.Root != null && sender.Root is Container)
{
Left = x - Root.AbsoluteLeft;
Top = y - Root.AbsoluteTop;
}
else
{
Left = x;
Top = y;
}
if (AbsoluteLeft + Width > Manager.TargetWidth)
{
Left = Left - Width;
if (ParentMenu != null && ParentMenu is ContextMenu)
{
Left = Left - ParentMenu.Width + 2;
}
else if (ParentMenu != null)
{
Left = Manager.TargetWidth - (Parent != null ? Parent.AbsoluteLeft : 0) - Width - 2;
}
}
if (AbsoluteTop + Height > Manager.TargetHeight)
{
Top = Top - Height;
if (ParentMenu != null && ParentMenu is ContextMenu)
{
Top = Top + LineHeight();
}
else if (ParentMenu != null)
{
Top = ParentMenu.Top - Height - 1;
}
}
Focused = true;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private void Input_MouseDown(object sender, MouseEventArgs e)
{
if ((RootMenu is ContextMenu) && !(RootMenu as ContextMenu).CheckArea(e.Position.X, e.Position.Y) && Visible)
{
HideMenu(true);
}
else if ((RootMenu is MainMenu) && RootMenu.ChildMenu != null && !(RootMenu.ChildMenu as ContextMenu).CheckArea(e.Position.X, e.Position.Y) && Visible)
{
(RootMenu as MainMenu).HideMenu();
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
private bool CheckArea(int x, int y)
{
if (Visible)
{
if (x <= AbsoluteLeft ||
x >= AbsoluteLeft + Width ||
y <= AbsoluteTop ||
y >= AbsoluteTop + Height)
{
bool ret = false;
if (ChildMenu != null)
{
ret = (ChildMenu as ContextMenu).CheckArea(x, y);
}
return ret;
}
else
{
return true;
}
}
else
{
return false;
}
}
////////////////////////////////////////////////////////////////////////////
#endregion
}
}