//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynter.Engine.Menus { #region Using Statements using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Content; using DarkWynter.Engine.Globals; using DarkWynter.Stream; #endregion /// /// Wrapper class for Game Menu Elements. /// public class GameMenuElement { /// /// Game menu title. /// protected string title = "Untitled"; /// /// Element type from Enums_Engine.MenuElementType. /// protected Enums_Engine.MenuElementType type; /// /// Current visibility state of element. /// protected bool visible = true; /// /// Current x scale of element. /// protected float scaleX = 1.0f; /// /// Current y scale of element. /// protected float scaleY = 1.0f; /// /// Font used in this element. /// protected SpriteFont font = Statics_Stream.Fonts.ComicSans; /// /// Set to red by default, to provide easily noticable default color. /// protected Color color = Color.Red; /// /// Game Menu Element constructor. /// public GameMenuElement() { type = Enums_Engine.MenuElementType.NONE; } /// /// Accessor for element type. /// /// This element's type. public Enums_Engine.MenuElementType GetElementType() { return type; } /// /// Sets the element's scale. /// /// X scale value /// Y scale value public void SetScale(float scaleX, float scaleY) { this.scaleX = scaleX; this.scaleY = scaleY; } /// /// Gets the color of the SpriteFont /// /// public Color GetColor() { return color; } public void SetColor(Color fontColor) { color = fontColor; } /// /// Gets the element's current font. /// /// Return's current spritefont public SpriteFont GetFont() { return font; } /// /// Sets the element's current font. /// /// SpriteFont to use. public void SetFont(SpriteFont font) { this.font = font; } /// /// Gets the element's current x scale. /// /// Current X scale of element.. public float GetScaleX() { return scaleX; } /// /// Gets the element's current y scale. /// /// Current Y scale of element. public float GetScaleY() { return scaleY; } /// /// Sets the element's title. /// /// Title of element. public void SetTitle(string title) { this.title = title; } /// /// Gets the element's title. /// /// Title of element. public string GetTitle() { return title; } /// /// Hides this element from view. /// public void Hide() { visible = false; } /// /// Makes this element visible. /// public void Show() { visible = true; } /// /// Checks to see if element is currently visible. /// /// True if visible public bool isVisible() { return visible; } } /// /// 2D Label /// public class GameMenuLabel : GameMenuElement { /// /// Game Menu Lable constructor /// public GameMenuLabel() { type = Enums_Engine.MenuElementType.LABEL; } /// /// Game Menu Lable constructor with title. /// /// Title of the element. public GameMenuLabel(string title) { type = Enums_Engine.MenuElementType.LABEL; this.title = title; } /// /// Game Menu Lable constructor with title. /// /// Title of the element. public GameMenuLabel(string title, Color textColor) { type = Enums_Engine.MenuElementType.LABEL; this.color = textColor; this.title = title; } } /// /// 2D Image display /// public class GameMenuRandomImageDisplay : GameMenuElement { private List images = new List(); private int selectedIndex = 0; private List used = new List(); Random rand = new Random(); /// /// Random Image Display constructor. /// public GameMenuRandomImageDisplay() { type = Enums_Engine.MenuElementType.IMAGE_DISPLAY; } /// /// Random Image Display constructor with title. /// /// Title of the Random Image Display. public GameMenuRandomImageDisplay(string title) { type = Enums_Engine.MenuElementType.IMAGE_DISPLAY; this.title = title; } /// /// Add's an image to the Random Image Display. /// /// Image to add. public void AddImage(Texture2D img) { images.Add(img); } /// /// Selects a random image to use. /// public void RandomIndex() { if (used.Count == images.Count) { used.Clear(); } do { selectedIndex = rand.Next(images.Count); } while (used.Contains(selectedIndex)); used.Add(selectedIndex); } /// /// Gets the current image being used. /// /// Image currently being used. public Texture2D GetCurrentTexture() { if (selectedIndex >= 0 && selectedIndex < images.Count) { return images[selectedIndex]; } return null; } } /// /// 2D Button /// public class GameMenuButton : GameMenuElement { /// /// Game Menu Button constructor. /// public GameMenuButton() { type = Enums_Engine.MenuElementType.BUTTON; } /// /// Game Menu Button with title. /// /// Title of this Game Menu Button. public GameMenuButton(string title) { this.title = title; type = Enums_Engine.MenuElementType.BUTTON; } } /// /// 2D Renderable /// public class GameMenuValueInput : GameMenuElement { private int value = 0; private int maxValue = 0; private int minValue = 0; private int valueIncrement = 1; private float valueRatio = 0.0f; /// /// Constructor for Game Menu Value Input. /// public GameMenuValueInput() { type = Enums_Engine.MenuElementType.VALUE; } /// /// Constructor for Game Menu Value Input with predefined values. /// /// Title of this component. /// Minimum value of this component. /// Maximum value of this component. /// Initial/Default value of this component. /// Increment rate of this componenet. public GameMenuValueInput(string title, int minValue, int maxValue, int defaultValue, int increment) { this.title = title; this.minValue = minValue; this.maxValue = maxValue; this.value = defaultValue; this.valueIncrement = increment; valueRatio = (float)this.value / (float)(this.maxValue - this.minValue); type = Enums_Engine.MenuElementType.VALUE; } /// /// Get current value of componenet. /// /// Current value. public int GetValue() { return value; } /// /// Set range of this componenet. /// /// Minimum allowed value. /// Maximum allowed value. public void SetRange(int min, int max) { maxValue = max; minValue = min; UpdateValueRatio(); } /// /// Manually set the value of this component. /// /// Value to set this component to. public void SetValue(int val) { if (val <= maxValue && val >= minValue) { value = val; UpdateValueRatio(); } } private void UpdateValueRatio() { if (maxValue == minValue) { valueRatio = 1.0f; } else { valueRatio = ((float)this.value - this.minValue) / ((float)(this.maxValue - this.minValue)); } } /// /// Ratio between minumum and maximum value of this component. /// /// Ratio of max and min values. public float GetValueRatio() { return valueRatio; } /// /// Increment value of component using predefined increment amount. /// public void Increment() { value += valueIncrement; if (value > maxValue) { value = maxValue; } UpdateValueRatio(); } /// /// Decrement value of component using predefined increment amount. /// public void Decrement() { value -= valueIncrement; if (value < minValue) { value = minValue; } UpdateValueRatio(); } } /// /// 2D Value Scroller /// public class GameMenuOption : GameMenuElement { private List options = new List(); private int activeOptionIndex = 0; /// /// Constructor for Option selector. /// public GameMenuOption() { type = Enums_Engine.MenuElementType.OPTION; } /// /// Constructor for Option selector with title. /// /// Title of this component. public GameMenuOption(string title) { this.title = title; type = Enums_Engine.MenuElementType.OPTION; } /// /// Add an option to this option selector. /// /// Displayed text. public void AddOption(string option) { options.Add(option); } /// /// Add a list of options to this option selector. /// /// List of displayed text. public void SetOption(List optionList) { options = optionList; } /// /// Set currently displayed option text. /// /// Index of option to display. public void SetCurrentIndex(int index) { activeOptionIndex = index; } /// /// Select the previous option in the list. /// public void PreviousOption() { activeOptionIndex--; if (activeOptionIndex < 0) { activeOptionIndex = 0; } } /// /// Select the next option in the list. /// public void NextOption() { activeOptionIndex++; if (activeOptionIndex >= options.Count) { activeOptionIndex = options.Count - 1; } } /// /// Get the current option's text. /// /// Current option's text. public string GetActiveOption() { return options[activeOptionIndex]; } /// /// Get the current option's index. /// /// Current option's index. public int GetActiveIndex() { return activeOptionIndex; } } /// /// Image with multiple selectable components. /// public class GameMenuImageScroller : GameMenuElement { /// /// An image scrolling item /// public struct ImageScrollItem { /// /// Inactive image /// public Texture2D offImage; /// /// Active image /// public Texture2D onImage; /// /// Screen X position of image /// public int x; /// /// Screen Y position of image /// public int y; /// /// Name of the Item /// public string name; }; private int maxVisibleAtATime = 0; List items = new List(); private int activeItemIndex = 0; /// /// Default Constructor /// public GameMenuImageScroller() { type = Enums_Engine.MenuElementType.IMAGE_SCROLL; } /// /// Constructor /// /// The title of the Menu /// The number of visible lines? public GameMenuImageScroller(string title, int numVisible) { maxVisibleAtATime = numVisible; this.title = title; type = Enums_Engine.MenuElementType.IMAGE_SCROLL; } private void AddNew(string name, Texture2D onImage, Texture2D offImage, int x, int y) { ImageScrollItem item = new ImageScrollItem(); item.name = name; item.onImage = onImage; item.offImage = offImage; item.x = x; item.y = y; items.Add(item); } private void AddNew(string name, Texture2D onImage, Texture2D offImage) { ImageScrollItem item = new ImageScrollItem(); item.name = name; item.onImage = onImage; item.offImage = offImage; item.x = -1; item.y = -1; items.Add(item); } /// /// Retrieve the Item at index location /// /// Location /// ImageScrollItem public ImageScrollItem GetItemAt(int index) { if (index >= 0 && index < items.Count) { return items[index]; } return new ImageScrollItem(); } /// /// Returns the number of items in the Menu /// /// Number of items in the Menu public int GetNumItems() { return items.Count; } /// /// Returns the maximum number of visible items in a Menu /// /// Maximum number of visible items in a Menu public int GetMaxItemsVisible() { return maxVisibleAtATime; } private void Clear() { activeItemIndex = 0; items.Clear(); } /// /// Sets the previous item as the current one /// public void PreviousItem() { activeItemIndex--; if (activeItemIndex < 0) { activeItemIndex = items.Count - 1; } } /// /// Sets the next item as the current one /// public void NextItem() { activeItemIndex++; if (activeItemIndex >= items.Count) { activeItemIndex = 0; } } private ImageScrollItem GetActiveItem() { return items[activeItemIndex]; } /// /// Returns the index of the active item /// /// Index of active item public int GetActiveIndex() { return activeItemIndex; } /// /// Sets the item at index to the current one /// /// Location public void SetCurrentIndex(int index) { if (index >= 0 || index < items.Count) { activeItemIndex = index; } } } /// /// GameMenu is used by a GameScreen. /// It contains a list of GameMenuElements such as Buttons, Options, and Scrollers /// that are defined by classes that override GameScreen. /// public class GameMenu { private string title = "Untitled Menu"; private List menuElements = new List(); private int selectedElementIndex = 0; private Vector2 position = new Vector2(); private const int SLIDER_WIDTH = 150; private const int SLIDER_HEIGHT = 30; private bool drawMenuTitle = true; private Texture2D sliderBackground; /// /// Constructor /// /// Name of the Menu /// Screen X position /// Screen Y positiong public GameMenu(string title, float positionX, float positionY) { this.title = title; position.X = positionX; position.Y = positionY; sliderBackground = Statics_Engine.SystemSettings.content.Load("Content/_textures/SliderImproved"); } /// /// Sets whether the menu is drawn or not /// /// Yes or No public void SetDrawMenuTitle(bool draw) { drawMenuTitle = draw; } /// /// Sets the menu title /// /// Name public void SetTitle(string title) { this.title = title; } /// /// Sets the position where the menu will be drawn /// /// X /// Y public void SetPosition(float x, float y) { position.X = x; position.Y = y; } /// /// Adds a new menu Button /// /// To draw or not to draw /// Name public void AddMenuButton(bool visible, string title) { AddMenuButton(title); if (!visible) { GetMenuElement(title).Hide(); } } /// /// Adds a new menu Button /// /// Name public void AddMenuButton(string title) { menuElements.Add(new GameMenuButton(title)); } /// /// Adds a new Menu Option Item /// /// To draw or not to draw /// Name /// String array of options public void AddMenuOption(bool visible, string title, params string[] options) { AddMenuOption(title,options); if (!visible) { GetMenuElement(title).Hide(); } } /// /// Adds a new Menu Option Item /// /// Name /// String array of options public void AddMenuOption(string title, params string[] options) { GameMenuOption element = new GameMenuOption(title); foreach (string s in options) { element.AddOption(s); } menuElements.Add(element); } /// /// Adds a new image display which randomly displays a different image /// /// Name /// Array of images public void AddRandomImageDisplay(string title, params Texture2D[] images) { GameMenuRandomImageDisplay element = new GameMenuRandomImageDisplay(title); foreach (Texture2D image in images) { element.AddImage(image); } menuElements.Add(element); } /// /// Sets the list of options for a particular Menu option item /// /// New list of options /// Index of menu option item public void SetMenuOption(List optionList, int optionNumber) { GameMenuOption menuOptions = (GameMenuOption)menuElements[optionNumber]; menuOptions.SetOption(optionList); } private void AddValueInput(bool visible, string title, int minValue, int maxValue, int defaultValue, int increment) { AddValueInput(title, minValue, maxValue, defaultValue, increment); if (!visible) { GetMenuElement(title).Hide(); } } /// /// Adds a new Menu value-based item /// /// Name /// Minimum Value /// Maximum Value /// Default value /// Increments public void AddValueInput(string title, int minValue, int maxValue, int defaultValue, int increment) { GameMenuValueInput valueInput = new GameMenuValueInput(title, minValue, maxValue, defaultValue, increment); menuElements.Add(valueInput); } /// /// Adds a new Menu image scroller item /// /// Name /// Number of visible lines? public void AddImageScroller(string title, int numVisible) { GameMenuImageScroller element = new GameMenuImageScroller(title, numVisible); menuElements.Add(element); } /// /// Adds a new Menu Label item /// /// Name public void AddLabel(string title, Color textColor) { GameMenuLabel label = new GameMenuLabel(title, textColor); menuElements.Add(label); } /// /// Adds a new Menu Label item /// /// Name public void AddLabel(string title) { GameMenuLabel label = new GameMenuLabel(title); menuElements.Add(label); } /// /// Sets the current menu element to the previous menu element /// public void PreviousMenuElement() { selectedElementIndex--; if (selectedElementIndex < 0) { selectedElementIndex = 0; } if (GetActiveMenuElement().isVisible() == false) { PreviousMenuElement(); } if (GetActiveMenuElement().GetElementType() == Enums_Engine.MenuElementType.LABEL) { if (selectedElementIndex == 0) { NextMenuElement(); } else { PreviousMenuElement(); } } } /// /// Sets the current menu element to the next menu element /// public void NextMenuElement() { selectedElementIndex++; if (selectedElementIndex >= menuElements.Count) { selectedElementIndex = menuElements.Count - 1; } if (GetActiveMenuElement().isVisible() == false) { NextMenuElement(); } if (GetActiveMenuElement().GetElementType() == Enums_Engine.MenuElementType.LABEL) { if (selectedElementIndex == menuElements.Count - 1) { PreviousMenuElement(); } else { NextMenuElement(); } } } /// /// Returns the Name of the current Game Menu /// /// String name of current Game Menu public string GetTitle() { return title; } /// /// Returns the current active menu element /// /// Menu Element public GameMenuElement GetActiveMenuElement() { return menuElements[selectedElementIndex]; } /// /// Returns the index of the current active menu element /// /// Index of the current active menu element public int GetActiveIndex() { return selectedElementIndex; } /// /// Returns the Menu element at index /// /// Index of element to retrieve /// Menu Element public GameMenuElement GetMenuElement(int index) { return menuElements[index]; } /// /// Returns the first Menu element which has a matching title /// /// Search name /// Menu Element public GameMenuElement GetMenuElement(string title) { foreach (GameMenuElement element in menuElements) { if (element.GetTitle() == title) { return element; } } return new GameMenuElement(); } /// /// Returns the first Menu element found with a matching title after the starting index /// /// Search name /// Search index start /// Menu Element public GameMenuElement GetMenuElement(string title, int fromIndex) { for (int i = fromIndex; i < menuElements.Count; i++) { if (menuElements[i].GetTitle() == title) { return menuElements[i]; } } return new GameMenuElement(); } /// /// Sets the font for all menu items /// /// Font public void SetFont(SpriteFont font) { for (int i = 0; i < menuElements.Count; i++) { menuElements[i].SetFont(font); } } /// /// Draw function /// /// Spritebatch public void Draw(SpriteBatch spriteBatch) { float yPosition = position.Y; int titleLength = 0; float scaleX = (Statics_Stream.RenderSettings.GAME_WINDOW_WIDTH / 1280.0f); float scaleY = (Statics_Stream.RenderSettings.GAME_WINDOW_HEIGHT / 1024.0f); // Draw Header if (drawMenuTitle) { spriteBatch.DrawString(Statics_Stream.Fonts.ComicSans, title, new Vector2(position.X, position.Y), Color.White); Vector2 size = Statics_Stream.Fonts.ComicSans.MeasureString(title); //Extra padding below the big font yPosition += size.Y; } // Draw menu elements for (int i = 0; i < menuElements.Count; i++) { if (menuElements[i].isVisible() == true) { spriteBatch.DrawString(menuElements[i].GetFont(), menuElements[i].GetTitle(), new Vector2(position.X, yPosition), menuElements[i].GetColor()); Vector2 stringSize = menuElements[i].GetFont().MeasureString(menuElements[i].GetTitle()); titleLength = (int)(stringSize.X) + 10; // Option Selectors if (menuElements[i].GetElementType() == Enums_Engine.MenuElementType.OPTION) { GameMenuOption option = (GameMenuOption)menuElements[i]; spriteBatch.DrawString(menuElements[i].GetFont(), option.GetActiveOption(), new Vector2(position.X + titleLength, yPosition), Color.White); } // Value Selectors if (menuElements[i].GetElementType() == Enums_Engine.MenuElementType.VALUE) { GameMenuValueInput valueSlider = (GameMenuValueInput)menuElements[i]; spriteBatch.Draw(sliderBackground, new Rectangle((int)(position.X) + titleLength, (int)(yPosition), SLIDER_WIDTH, SLIDER_HEIGHT), Color.Honeydew); //Draw the actual slider value here spriteBatch.Draw(sliderBackground, new Rectangle((int)(position.X) + titleLength, (int)(yPosition), (int)(SLIDER_WIDTH * valueSlider.GetValueRatio()), SLIDER_HEIGHT), Color.DarkRed); spriteBatch.DrawString(menuElements[i].GetFont(), "" + valueSlider.GetValue(), new Vector2(position.X + titleLength + (SLIDER_WIDTH / 2), yPosition - 3), Color.Black); } // Image Displays if (menuElements[i].GetElementType() == Enums_Engine.MenuElementType.IMAGE_DISPLAY) { GameMenuRandomImageDisplay imageDisplay = (GameMenuRandomImageDisplay)menuElements[i]; Texture2D image = imageDisplay.GetCurrentTexture(); //yPosition += (160 * scaleY); if (image != null) { spriteBatch.Draw(image, new Rectangle((int)(position.X), (int)(yPosition), (int)(image.Width * imageDisplay.GetScaleX() * scaleX), (int)(image.Height * imageDisplay.GetScaleY() * scaleY)), Color.White); yPosition += (image.Height + 50) * scaleY; } } #region Image Scrollers if (menuElements[i].GetElementType() == Enums_Engine.MenuElementType.IMAGE_SCROLL) { GameMenuImageScroller scroller = (GameMenuImageScroller)menuElements[i]; int numItems = scroller.GetNumItems(); int maxItems = scroller.GetMaxItemsVisible(); int activeIndex = scroller.GetActiveIndex(); yPosition += 8; //if the window is smaller than the list.. start with the active one for (int index = (maxItems < numItems) ? activeIndex : 0; index < ((maxItems < numItems)? activeIndex+maxItems : maxItems); index++) { if (index >= numItems) { break; } GameMenuImageScroller.ImageScrollItem item = scroller.GetItemAt(index); float x, y; if (item.x == -1){x = position.X;} else{x = item.x;} if (item.y == -1){y = yPosition;} else{y = item.y;} if (scroller.GetActiveIndex() == index) { if (item.onImage != null) { // Draw Selected Button Image spriteBatch.Draw(item.onImage, new Rectangle((int)(x), (int)(y), (int)(item.onImage.Width * scroller.GetScaleX() * scaleX), (int)(item.onImage.Height * scroller.GetScaleY() * scaleY)), Color.White); } } else { if (item.offImage != null) { // Draw Deselected Button Image spriteBatch.Draw(item.offImage, new Rectangle((int)(x), (int)(y), (int)(item.offImage.Width * scroller.GetScaleX() * scaleX), (int)(item.offImage.Height * scroller.GetScaleY() * scaleY)), Color.White); } } int heightOffset = 0; if (item.offImage != null) { heightOffset = item.offImage.Height; } yPosition += (heightOffset + 50) * scaleY; } } #endregion yPosition += stringSize.Y + 20; } } } } }