Windows Forms Menu (XNA Style :: Re-Release)

lxXTaCoXxl 0 Tallied Votes 164 Views Share

There only two glitches within this code that I can't seem to get 100% spot on. However, this will create a functioning menu (text based) on your form at runtime. I plan to develop an actual control exactly like it. It uses a custom class I developed called LocationBounceEffect that basically bounces an integer back and forth between two points (A start location and the provided offset on the provided axis). I'm using that class to bounce the selected menu item back and forth as I go through the menu items. For my implementation example I will be using a timer to update my bounce. I will fully comment the implementation source so that you understand what's going on and why.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Menu
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// This example shows how to use the menu classes I've created,
        /// and as well as why each line is important.
        /// 
        /// There are some optional lines (such as the LBE).
        /// 
        /// Thank you for using my code snippets, and just put a thanks to
        /// me into your disclaimer or credits.
        /// 
        /// Jamie K. Davis - Studio 41 Games (Owner/Head Developer)
        /// </summary>
        public Form1()
        {
            InitializeComponent();
        }

        // Declare a new menu object (setting the location of the menu at 15x 15y).
        //      You may optionally use the secondary constructor allowing you
        //          to change the selected item's forecolor from the default (white).
        Menu myMenu = new Menu(new Point(15, 15));

        // Declare a few menu entries to add to the menu;
        // They are all using the second constructor of the MenuEntry class.
        // The second constructor as you can see accepts a string for text,
        //          and a color for the forecolor.
        MenuEntry Entry1 = new MenuEntry("Play", Color.Red);
        MenuEntry Entry2 = new MenuEntry("Options", Color.Red);
        MenuEntry Entry3 = new MenuEntry("Credits", Color.Red);
        MenuEntry Entry4 = new MenuEntry("Exit", Color.Red);

        private void Form1_Load(object sender, EventArgs e)
        {
            // Add all 4 menu entries to the menu.
            myMenu.AddEntry(Entry1);
            myMenu.AddEntry(Entry2);
            myMenu.AddEntry(Entry3);
            myMenu.AddEntry(Entry4);

            // This is essential; using a loop go through and add
            //          each menu entry to the controls of the form
            //          (so they can be visible on the form).
            for (int i = 0; i < myMenu.Items.Count; i++)
                this.Controls.Add(myMenu.Items[i]);

            // Start the timer to update the bounce of the currently selected
            // Menu entry.
            Updater.Start();

            // Update the menu at runtime to allow selection color process to happen.
            myMenu.Update();
        }

        // Timer_Tick Event
        private void UpdateMenu(object sender, EventArgs e)
        {
            // Update the bounce of the selected menu item on timer tick.
            myMenu.UpdateBounce();
        }

        // Form_KeyDown Event
        private void NavigateMenu(object sender, KeyEventArgs e)
        {
            // Navigate through the menu using the keyboard.
            myMenu.Navigate(e);

            // Update the menu so the user can see the results of their
            //          navigation.
            myMenu.Update();
        }
    }
}

Enjoy,

Jamie - Studio 41 Games (Owner/Head Developer)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Menu
{
    public enum Axis
    {
        X, Y
    }

    public class LocationBounceEffect
    {
        public Axis BouncingAxis { get; private set; }

        public int Offset { get; private set; }
        public int Product { get; private set; }

        public int StartX { get; private set; }
        public int StartY { get; private set; }

        public int X { get; private set; }
        public int Y { get; private set; }

        private Point Location;
        private bool OffsetCompleted = false;

        public LocationBounceEffect(Point Location, int Offset, Axis AxisToModify)
        {
            this.Location = Location;
            this.StartX = Location.X;
            this.StartY = Location.Y;

            this.Offset = Offset;

            this.BouncingAxis = AxisToModify;
        }

        public void PerformBounce()
        {
            if (!OffsetCompleted)
            {
                if (BouncingAxis == Axis.X && StartX + Product < StartX + Offset || 
                    BouncingAxis == Axis.Y && StartY + Product < StartY + Offset)
                    Product++;

                else if (BouncingAxis == Axis.X && StartX + Product >= StartX + Offset ||
                    BouncingAxis == Axis.Y && StartY + Product >= StartY + Offset)
                    OffsetCompleted = true;
            }

            else
            {
                if (BouncingAxis == Axis.X && StartX + Product > StartX ||
                    BouncingAxis == Axis.Y && StartY + Product > StartY)
                    Product--;

                else if (BouncingAxis == Axis.X && StartX + Product <= StartX ||
                    BouncingAxis == Axis.Y && StartY + Product <= StartY)
                    OffsetCompleted = false;
            }

            if (BouncingAxis == Axis.X)
                Location = new Point(StartX + Product, Location.Y);

            else
                Location = new Point(Location.X, StartY + Product);

            this.X = Location.X;
            this.Y = Location.Y;
        }

        public void Reset()
        {
            this.Product = 0;

            Location = new Point(StartX, StartY);
            this.X = Location.X;
            this.Y = Location.Y;

            OffsetCompleted = false;
        }
    }

    public class MenuEntry
    {
        public string Text = "";

        public Point Location;
        public Color Color;
        public Font Font = new Font("OCR A Extended", 8.25f, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));

        public MenuEntry(string Text)
        {
            this.Text = Text;
            Color = Color.White;
        }

        public MenuEntry(string Text, Color Color)
        {
            this.Text = Text;
            this.Color = Color;
        }

        public MenuEntry(string Text, Font Font, Color Color)
        {
            this.Text = Text;
            this.Font = Font;
            this.Color = Color;
        }

        public MenuEntry(string Text, string FontName, float FontSize, Color Color)
        {
            this.Text = Text;
            this.Font = new Font(FontName, FontSize, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
            this.Color = Color;
        }
    }

    public class Menu
    {
        private LocationBounceEffect[] LBE = new LocationBounceEffect[50];

        private Input Input = new Input();
        private List<MenuEntry> MenuItems;

        public List<Label> Items { get; private set; }
        public Point Location { get; private set; }

        public int Length { get; private set; }
        public int SelectedIndex { get; private set; }

        public Color SelectionColor { get; private set; }

        public Menu(Point Location)
        {
            MenuItems = new List<MenuEntry>();

            this.Length = 0;
            this.SelectedIndex = 0;
            this.Location = Location;
            this.SelectionColor = Color.White;

            Items = new List<Label>();
        }

        public Menu(Point Location, Color SelectionColor)
        {
            MenuItems = new List<MenuEntry>();

            this.Length = 0;
            this.SelectedIndex = 0;
            this.Location = Location;
            this.SelectionColor = SelectionColor;

            this.Items = new List<Label>();
        }

        public void AddEntry(MenuEntry Entry)
        {
            MenuItems.Add(Entry);
            Items.Add(new Label());

            if (this.Length == 0)
                MenuItems[Length].Location = this.Location;

            else
                MenuItems[Length].Location = new Point(this.Location.X, MenuItems[Length - 1].Location.Y + Items[Length - 1].Size.Height + 5);

            Items[Length].BackColor = Color.Transparent;
            Items[Length].Text = Entry.Text;
            Items[Length].Font = Entry.Font;
            Items[Length].ForeColor = Entry.Color;
            Items[Length].Location = MenuItems[Length].Location;

            LBE[Length] = new LocationBounceEffect(Items[Length].Location, 10, Axis.X);

            Length++;
        }

        public void Navigate(KeyEventArgs e)
        {
            if (Input.NavigatingUp(e))
            {
                if (SelectedIndex <= 0)
                    SelectedIndex = MenuItems.Count;

                else
                    SelectedIndex--;
            }

            else if (Input.NavigatingDown(e))
            {
                if (SelectedIndex >= MenuItems.Count)
                    SelectedIndex = 0;

                else
                    SelectedIndex++;
            }
        }

        public void Update()
        {
            for (int i = 0; i < Items.Count; i++)
                Items[i].ForeColor = MenuItems[i].Color;

            Items[SelectedIndex].ForeColor = this.SelectionColor;

            LBE[SelectedIndex].Reset();
        }

        public void UpdateBounce()
        {
            LBE[SelectedIndex].PerformBounce();
            Items[SelectedIndex].Location = new Point(LBE[SelectedIndex].X, LBE[SelectedIndex].Y);
        }
    }

    public class Input
    {
        private bool Up = false;
        private bool Down = false;

        public bool NavigatingUp(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up)
            {
                Up = true;
                Thread.Sleep(10);
            }

            else
                Up = false;

            return Up;
        }

        public bool NavigatingDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Down)
            {
                Down = true;
                Thread.Sleep(10);
            }

            else
                Down = false;

            return Down;
        }
    }
}