//////////////////////////////////////////////////////////////// // // // Neoforce Controls // // // //////////////////////////////////////////////////////////////// // // // File: ListBox.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.Input; //////////////////////////////////////////////////////////////////////////// #endregion namespace TomShane.Neoforce.Controls { #region //// Classes /////////// //////////////////////////////////////////////////////////////////////////// /// public class ListBox : Control { #region //// Fields //////////// //////////////////////////////////////////////////////////////////////////// private List items = new List(); private ScrollBar sbVert = null; private ClipBox pane = null; private int itemIndex = -1; private bool hotTrack = false; private int itemsCount = 0; private bool hideSelection = true; //////////////////////////////////////////////////////////////////////////// #endregion #region //// Properties //////// //////////////////////////////////////////////////////////////////////////// public virtual List Items { get { return items; } internal set { items = value; } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// public virtual bool HotTrack { get { return hotTrack; } set { if (hotTrack != value) { hotTrack = value; if (!Suspended) OnHotTrackChanged(new EventArgs()); } } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// public virtual int ItemIndex { get { return itemIndex; } set { //if (itemIndex != value) { if (value >= 0 && value < items.Count) { itemIndex = value; } else { itemIndex = -1; } ScrollTo(itemIndex); if (!Suspended) OnItemIndexChanged(new EventArgs()); } } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// public virtual bool HideSelection { get { return hideSelection; } set { if (hideSelection != value) { hideSelection = value; Invalidate(); if (!Suspended) OnHideSelectionChanged(new EventArgs()); } } } //////////////////////////////////////////////////////////////////////////// #endregion #region //// Events //////////// //////////////////////////////////////////////////////////////////////////// public event EventHandler HotTrackChanged; public event EventHandler ItemIndexChanged; public event EventHandler HideSelectionChanged; //////////////////////////////////////////////////////////////////////////// #endregion #region //// Construstors ////// //////////////////////////////////////////////////////////////////////////// public ListBox(Manager manager) : base(manager) { Width = 64; Height = 64; MinimumHeight = 16; sbVert = new ScrollBar(Manager, Orientation.Vertical); sbVert.Init(); sbVert.Parent = this; sbVert.Left = Left + Width - sbVert.Width - Skin.Layers["Control"].ContentMargins.Right; sbVert.Top = Top + Skin.Layers["Control"].ContentMargins.Top; sbVert.Height = Height - Skin.Layers["Control"].ContentMargins.Vertical; sbVert.Anchor = Anchors.Top | Anchors.Right | Anchors.Bottom; sbVert.PageSize = 25; sbVert.Range = 1; sbVert.PageSize = 1; sbVert.StepSize = 10; pane = new ClipBox(manager); pane.Init(); pane.Parent = this; pane.Top = Skin.Layers["Control"].ContentMargins.Top; pane.Left = Skin.Layers["Control"].ContentMargins.Left; pane.Width = Width - sbVert.Width - Skin.Layers["Control"].ContentMargins.Horizontal - 1; pane.Height = Height - Skin.Layers["Control"].ContentMargins.Vertical; pane.Anchor = Anchors.All; pane.Passive = true; pane.CanFocus = false; pane.Draw += new DrawEventHandler(DrawPane); CanFocus = true; Passive = false; } //////////////////////////////////////////////////////////////////////////// #endregion #region //// Methods /////////// //////////////////////////////////////////////////////////////////////////// public override void Init() { base.Init(); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// public virtual void AutoHeight(int maxItems) { if (items != null && items.Count < maxItems) maxItems = items.Count; if (maxItems < 3) { //maxItems = 3; sbVert.Visible = false; pane.Width = Width - Skin.Layers["Control"].ContentMargins.Horizontal - 1; } else { pane.Width = Width - sbVert.Width - Skin.Layers["Control"].ContentMargins.Horizontal - 1; sbVert.Visible = true; } SkinText font = Skin.Layers["Control"].Text; if (items != null && items.Count > 0) { int h = (int)font.Font.Resource.MeasureString(items[0].ToString()).Y; Height = (h * maxItems) + (Skin.Layers["Control"].ContentMargins.Vertical);// - Skin.OriginMargins.Vertical); } else { Height = 32; } } //////////////////////////////////////////////////////////////////////////// public override int MinimumHeight { get { return base.MinimumHeight; } set { base.MinimumHeight = value; if (this.sbVert != null) this.sbVert.MinimumHeight = value; } } //////////////////////////////////////////////////////////////////////////// protected override void DrawControl(Renderer renderer, Rectangle rect, GameTime gameTime) { sbVert.Invalidate(); pane.Invalidate(); //DrawPane(this, new DrawEventArgs(renderer, rect, gameTime)); base.DrawControl(renderer, rect, gameTime); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// private void DrawPane(object sender, DrawEventArgs e) { if (items != null && items.Count > 0) { SkinText font = Skin.Layers["Control"].Text; SkinLayer sel = Skin.Layers["ListBox.Selection"]; int h = (int)font.Font.Resource.MeasureString(items[0].ToString()).Y; int v = (sbVert.Value / 10); int p = (sbVert.PageSize / 10); int d = (int)(((sbVert.Value % 10) / 10f) * h); int c = items.Count; int s = itemIndex; for (int i = v; i <= v + p + 1; i++) { if (i < c) { e.Renderer.DrawString(this, Skin.Layers["Control"], items[i].ToString(), new Rectangle(e.Rectangle.Left, e.Rectangle.Top - d + ((i - v) * h), e.Rectangle.Width, h), false); } } if (s >= 0 && s < c && (Focused || !hideSelection)) { int pos = -d + ((s - v) * h); if (pos > -h && pos < (p + 1) * h) { e.Renderer.DrawLayer(this, sel, new Rectangle(e.Rectangle.Left, e.Rectangle.Top + pos, e.Rectangle.Width, h)); e.Renderer.DrawString(this, sel, items[s].ToString(), new Rectangle(e.Rectangle.Left, e.Rectangle.Top + pos, e.Rectangle.Width, h), false); } } } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (e.Button == MouseButton.Left || e.Button == MouseButton.Right) { TrackItem(e.Position.X, e.Position.Y); } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// private void TrackItem(int x, int y) { if (items != null && items.Count > 0 && (pane.ControlRect.Contains(new Point(x, y)))) { SkinText font = Skin.Layers["Control"].Text; int h = (int)font.Font.Resource.MeasureString(items[0].ToString()).Y; int d = (int)(((sbVert.Value % 10) / 10f) * h); int i = (int)Math.Floor((sbVert.Value / 10f) + ((float)y / h)); if (i >= 0 && i < Items.Count && i >= (int)Math.Floor((float)sbVert.Value / 10f) && i < (int)Math.Ceiling((float)(sbVert.Value + sbVert.PageSize) / 10f)) ItemIndex = i; Focused = true; } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (hotTrack) { TrackItem(e.Position.X, e.Position.Y); } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected override void OnKeyPress(KeyEventArgs e) { if (e.Key == Keys.Down) { e.Handled = true; itemIndex += sbVert.StepSize / 10; } else if (e.Key == Keys.Up) { e.Handled = true; itemIndex -= sbVert.StepSize / 10; } else if (e.Key == Keys.PageDown) { e.Handled = true; itemIndex += sbVert.PageSize / 10; } else if (e.Key == Keys.PageUp) { e.Handled = true; itemIndex -= sbVert.PageSize / 10; } else if (e.Key == Keys.Home) { e.Handled = true; itemIndex = 0; } else if (e.Key == Keys.End) { e.Handled = true; itemIndex = items.Count - 1; } if (itemIndex < 0) itemIndex = 0; else if (itemIndex >= Items.Count) itemIndex = Items.Count - 1; ItemIndex = itemIndex; base.OnKeyPress(e); } //////////////////////////////////////////////////////////////////////////// /// /// Handles mouse scroll events for the list box. /// /// protected override void OnMouseScroll(MouseEventArgs e) { Focused = true; if (e.ScrollDirection == MouseScrollDirection.Down) { e.Handled = true; itemIndex += sbVert.StepSize / 10; } else if (e.ScrollDirection == MouseScrollDirection.Up) { e.Handled = true; itemIndex -= sbVert.StepSize / 10; } // Wrap index in collection range. if (itemIndex < 0) itemIndex = 0; else if (itemIndex >= Items.Count) itemIndex = Items.Count - 1; ItemIndex = itemIndex; base.OnMouseScroll(e); } //////////////////////////////////////////////////////////////////////////// protected override void OnGamePadPress(GamePadEventArgs e) { if (e.Button == GamePadActions.Down) { e.Handled = true; itemIndex += sbVert.StepSize / 10; } else if (e.Button == GamePadActions.Up) { e.Handled = true; itemIndex -= sbVert.StepSize / 10; } if (itemIndex < 0) itemIndex = 0; else if (itemIndex >= Items.Count) itemIndex = Items.Count - 1; ItemIndex = itemIndex; base.OnGamePadPress(e); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// private void ItemsChanged() { if (items != null && items.Count > 0) { SkinText font = Skin.Layers["Control"].Text; int h = (int)font.Font.Resource.MeasureString(items[0].ToString()).Y; int sizev = Height - Skin.Layers["Control"].ContentMargins.Vertical; sbVert.Range = items.Count * 10; sbVert.PageSize = (int)Math.Floor((float)sizev * 10 / h); Invalidate(); } else if (items == null || items.Count <= 0) { sbVert.Range = 1; sbVert.PageSize = 1; Invalidate(); } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected override void OnResize(ResizeEventArgs e) { base.OnResize(e); ItemsChanged(); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// public virtual void ScrollTo(int index) { ItemsChanged(); if ((index * 10) < sbVert.Value) { sbVert.Value = index * 10; } else if (index >= (int)Math.Floor(((float)sbVert.Value + sbVert.PageSize) / 10f)) { sbVert.Value = ((index + 1) * 10) - sbVert.PageSize; } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected internal override void Update(GameTime gameTime) { base.Update(gameTime); if (Visible && items != null && items.Count != itemsCount) { itemsCount = items.Count; ItemsChanged(); } } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected virtual void OnItemIndexChanged(EventArgs e) { if (ItemIndexChanged != null) ItemIndexChanged.Invoke(this, e); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected virtual void OnHotTrackChanged(EventArgs e) { if (HotTrackChanged != null) HotTrackChanged.Invoke(this, e); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// protected virtual void OnHideSelectionChanged(EventArgs e) { if (HideSelectionChanged != null) HideSelectionChanged.Invoke(this, e); } //////////////////////////////////////////////////////////////////////////// #endregion } //////////////////////////////////////////////////////////////////////////// #endregion }