/Scenes/UserInterfaces/Controls/Panel.cs
C# | 613 lines | 391 code | 74 blank | 148 comment | 25 complexity | 7511b11eabd10194129000fd1e23522c MD5 | raw file
Possible License(s): Apache-2.0
- using System.Collections.Generic;
- using Delta.Engine;
- using Delta.InputSystem;
- using Delta.Rendering.Basics.Fonts;
- using Delta.Scenes.Enums;
- using Delta.Scenes.UserInterfaces.Designs;
- using Delta.Utilities;
- using Delta.Utilities.Datatypes;
- using Delta.Utilities.Datatypes.Advanced;
- using NUnit.Framework;
-
- namespace Delta.Scenes.UserInterfaces.Controls
- {
- /// <summary>
- /// Panel
- /// </summary>
- public class Panel : BaseControl
- {
- #region Padding (Public)
- /// <summary>
- /// Defines the padding for the inner content / controls of the panel.
- /// Note: NOT SUPPORTED YET
- /// </summary>
- /// <returns>Spacing</returns>
- public Margin Padding
- {
- get;
- set;
- }
- #endregion
-
- #region Protected
-
- #region FallbackDesign (Protected)
- /// <summary>
- /// Defines the theme which will be used if no "Theme" was set explicitely.
- /// </summary>
- protected override ControlDesign FallbackDesign
- {
- get
- {
- return Theme.Current.PanelDesign;
- } // get
- }
- #endregion
-
- #endregion
-
- #region Private
-
- #region horizontalScrollbar (Private)
- private readonly Scrollbar horizontalScrollbar;
- #endregion
-
- #region needCheckForScrollbars (Private)
- private bool needCheckForScrollbars;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create panel
- /// </summary>
- public Panel()
- {
- horizontalScrollbar = new Scrollbar(this);
- Add(horizontalScrollbar);
- horizontalScrollbar.State = ElementState.Invisible;
- needCheckForScrollbars = false;
- }
- #endregion
-
- #region Dispose (Public)
- /// <summary>
- /// Disposes the whole control (inclusive children).
- /// </summary>
- public override void Dispose()
- {
- // At first we need to destroy all Children of us
- List<BaseControl> rememberToRemove = new List<BaseControl>();
- foreach (BaseControl child in Children)
- {
- rememberToRemove.Add(child);
- } // foreach
- foreach (BaseControl child in rememberToRemove)
- {
- child.Dispose();
- } // foreach
-
- base.Dispose();
- }
- #endregion
-
- #region Add (Public)
- /// <summary>
- /// Add
- /// </summary>
- /// <param name="newChild">New child</param>
- public override bool Add(AlignableElement newChild)
- {
- bool wasControlAdded = base.Add(newChild);
-
- // We need to recheck if the scrollbar are needed now if a new control
- // was added because maybe it doesn't fit (fully) in the visible panel
- // space anymore or if a scrollbar is already shown then the available
- // "scroll space" needs to be updated anyway
- if (wasControlAdded)
- {
- // Note:
- // We only modify that flag for "successful actions" to avoid
- // "delete" this flag in the case that series of controls would be
- // added in one frame and the last one was a "bad" one
- needCheckForScrollbars = true;
- } // if
-
- return wasControlAdded;
- }
- #endregion
-
- #region Remove (Public)
- /// <summary>
- /// Remove
- /// </summary>
- /// <param name="childControl">Child control</param>
- public override bool Remove(AlignableElement childControl)
- {
- bool wasControlRemoved = base.Remove(childControl);
-
- // We need to recheck if the scrollbar are needed now if a control was
- // removed again because if the scrollbar is shown already the current
- // "scroll space" need to be updated or maybe the remaining control fit
- // now (fully) in the visible panel space and the scrollbar is not needed
- // anymore
- if (wasControlRemoved)
- {
- // Note:
- // We only modify that flag for "successful actions" to avoid
- // "delete" this flag in the case that series of controls would be
- // removed in one frame and the last one was a "bad" one
- needCheckForScrollbars = true;
- } // if
-
- return wasControlRemoved;
- }
- #endregion
-
- #region GetChildrenOfType (Public)
- /// <summary>
- /// Get children of type
- /// Recursive search for all children of Type T in this panel and all
- /// subpanels.
- /// </summary>
- /// <returns>List</returns>
- public List<T> GetChildrenOfType<T>() where T : class
- {
- List<T> foundChildren = new List<T>();
- for (int i = 0; i < Children.Count; i++)
- {
- if (Children[i] as Panel != null)
- {
- foundChildren.AddRange((Children[i] as Panel).GetChildrenOfType<T>());
- } // if
- else if ((Children[i] as T) != null)
- {
- foundChildren.Add(Children[i] as T);
- } // else if
- } // for
- return foundChildren;
- }
- #endregion
-
- #region GetScrolledOffset (Public)
- /// <summary>
- /// Get scrolled offset
- /// </summary>
- public float GetScrolledOffset()
- {
- return horizontalScrollbar.CurrentScrollOffset;
- }
- #endregion
-
- #region ScrollForeward (Public)
- /// <summary>
- /// Scroll foreward
- /// </summary>
- public void ScrollForeward()
- {
- //float horizontalContentWidth = GetContentWidth();
-
- //if (horizontalContentWidth <= Size.Width)
- //{
- // // It only make sense to scroll if the content area is bigger than the
- // // panel area
- // return;
- //} // if
-
- //float newScrollOffset = horizontalScrollbar.CurrentScrollOffset +
- // horizontalScrollbar.ScrollWidth;
- //if ((newScrollOffset + Size.Width) < horizontalContentWidth)
- //{
- // horizontalScrollbar.CurrentScrollOffset = newScrollOffset;
- //} // if
- //else
- //{
- // horizontalScrollbar.CurrentScrollOffset = horizontalContentWidth -
- // horizontalScrollbar.ScrollWidth;
- //} // else
- horizontalScrollbar.ScrollForewards();
- }
- #endregion
-
- #region Methods (Private)
-
- #region GetAlignmentArea
- /// <summary>
- /// Get alignment area
- /// </summary>
- /// <param name="totalArea">Total area</param>
- /// <param name="areaToAlign">Area to align</param>
- /// <param name="wishedAlignment">Wished alignment</param>
- internal static Rectangle GetAlignmentArea(Size totalArea, Size areaToAlign,
- Alignment wishedAlignment) //LOOK ?:, float borderThickness = 0.0f)
- {
- Point areaPos = Point.Zero;
- switch (wishedAlignment)
- {
- case Alignment.BottomLeft:
- areaPos.Y = totalArea.Height - areaToAlign.Height;
- break;
-
- case Alignment.Bottom:
- areaPos.X = totalArea.Width * 0.5f - areaToAlign.Width * 0.5f;
- areaPos.Y = totalArea.Height - areaToAlign.Height;
- break;
-
- case Alignment.BottomRight:
- areaPos.X = totalArea.Width - areaToAlign.Width;
- areaPos.Y = totalArea.Height - areaToAlign.Height;
- break;
-
- default:
- Log.Warning("Sorry, the Alignment '" + wishedAlignment +
- "' isn't supported yet.");
- break;
- } // switch
-
- return new Rectangle(areaPos, areaToAlign);
- }
- #endregion
-
- #region UpdateDrawData
- /// <summary>
- /// Updates all data of this element which are required for the following
- /// draw call.
- /// </summary>
- /// <remarks>
- /// This method will only be called if the element is in an enabled state.
- /// </remarks>
- protected override void UpdateDrawData()
- {
- base.UpdateDrawData();
-
- //return;
- if (needCheckForScrollbars)
- {
- horizontalScrollbar.State = (GetContentWidth() > Size.Width)
- ? ElementState.Enabled
- : ElementState.Invisible;
- } // if
- }
- #endregion
-
- #region DrawData
- /// <summary>
- /// Draws all data of this Panel which needs to be visualized.
- /// </summary>
- /// <remarks>
- /// This method will only be called if the Panel is in a visible state.
- /// </remarks>
- protected override void DrawData()
- {
- base.DrawData();
-
- //horizontalScrollbar.Run();
- }
- #endregion
-
- #region OnSizeChanging
- /// <summary>
- /// On size changing
- /// </summary>
- /// <param name="oldSize">Old size</param>
- /// <returns>
- /// 'True' if the new value can be used or 'false' if the change should be
- /// aborted.
- /// </returns>
- protected override bool OnSizeChanging(Size oldSize)
- {
- if (base.OnSizeChanging(oldSize))
- {
- // Notify the scrollbar that the size has changed
- horizontalScrollbar.LocalArea = GetAlignmentArea(Size,
- new Size(Size.Width, horizontalScrollbar.Size.Height),
- Alignment.Bottom);
-
- return true;
- } // if
-
- return false;
- }
- #endregion
-
- #region GetScrolledControls
- /// <summary>
- /// Get scrolled controls
- /// </summary>
- internal List<BaseControl> GetScrolledControls()
- {
- List<BaseControl> visibleControls = new List<BaseControl>();
-
- List<BaseControl> leftPartialControls = new List<BaseControl>();
- List<BaseControl> rightPartialControls = new List<BaseControl>();
-
- Rectangle visibleScrollArea = horizontalScrollbar.VisibleScrollArea;
- foreach (BaseControl element in Children)
- {
- Rectangle childLocalArea = element.LocalArea;
-
- // Checking which control is fully visible in the current scrolled
- // panel section
- if (childLocalArea.Left >= visibleScrollArea.Left &&
- childLocalArea.Right <= visibleScrollArea.Right)
- {
- visibleControls.Add(element);
- } // if
-
- // but still check for the other controls that aren't fully visible
- // because maybe some elements are at least partial visible
-
- // -> at least partial visible on the left side
- else if (childLocalArea.Left < visibleScrollArea.Left &&
- childLocalArea.Right > visibleScrollArea.Left)
- {
- leftPartialControls.Add(element);
- // Test:
- //visibleControls.Add(element);
- } // else if
-
- // -> at least partial visible on the right side
- else if (childLocalArea.Left < visibleScrollArea.Right &&
- childLocalArea.Right > visibleScrollArea.Right)
- {
- rightPartialControls.Add(element);
- // Test:
- //visibleControls.Add(element);
- } // else if
- } // foreach
-
- return visibleControls;
- }
- #endregion
-
- #region GetContentWidth
- /// <summary>
- /// Get content width
- /// </summary>
- internal float GetContentWidth()
- {
- float horizontalContentWidth = 0.0f;
- foreach (BaseControl element in Children)
- {
- if (element.LocalArea.Right > horizontalContentWidth)
- {
- horizontalContentWidth = element.LocalArea.Right;
- } // if
- } // foreach
-
- return horizontalContentWidth;
- }
- #endregion
-
- #endregion
-
- /// <summary>
- /// Tests for Panel controls
- /// </summary>
- [Category("Visual")]
- internal class PanelTests
- {
- #region Helpers
-
- #region DisplayTwoPanelsWithChildren
- /// <summary>
- /// This test shows two panel with several children, one where the
- /// children completely fit in the panel and no scrollbar is necessary and
- /// one panel where the children controls need more space than the panel
- /// has and a scrollbar is required.
- /// </summary>
- public static void DisplayTwoPanelsWithChildren()
- {
- Screen testScene = new Screen();
-
- Margin panelPadding = new Margin(0.01f);
-
- Panel fittingPanel = new Panel
- {
- //LocalArea = Rectangle.FromCenter(0.35f, 0.4f, 0.5f, 0.2f),
- LocalArea = new Rectangle(0.2f, 0.3f, 0.3f, 0.15f),
- CustomDesign = new ControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Yellow),
- },
- Padding = panelPadding,
- };
- testScene.Add(fittingPanel);
-
- Label singleItem = new Label
- {
- LocalArea = new Rectangle(panelPadding.Left, panelPadding.Top, 0.1f,
- 0.1f),
- CustomDesign = new TextControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Green),
- TextFont = new Font(Font.Default, Color.Brown),
- },
- Text = "Lonely Label",
- };
- fittingPanel.Add(singleItem);
-
- Panel toSmallPanel = new Panel
- {
- //LocalArea = Rectangle.FromCenter(0.35f, 0.4f, 0.5f, 0.2f),
- LocalArea = new Rectangle(0.2f, 0.5f, 0.3f, 0.15f),
- CustomDesign = new ControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Yellow),
- },
- Padding = panelPadding,
- };
- testScene.Add(toSmallPanel);
-
- BaseControl lastControl = null;
- for (int index = 0; index < 5; index++)
- {
- Label panelItem = new Label
- {
- LocalArea = new Rectangle(panelPadding.Left, panelPadding.Top, 0.1f,
- 0.1f),
- CustomDesign = new TextControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Green),
- TextFont = new Font(Font.Default, Color.Brown),
- },
- Text = "Label " + (index + 1),
- };
-
- if (lastControl != null)
- {
- panelItem.LocalArea = new Rectangle(panelItem.LocalArea.Left +
- lastControl.LocalArea.Right,
- panelItem.LocalArea.Top,
- panelItem.LocalArea.Width, panelItem.LocalArea.Height);
- } // if
-
- toSmallPanel.Add(panelItem);
- lastControl = panelItem;
- } // for
-
- // Open now the scene to "activate" for the test
- testScene.Open();
-
- //Font infoFont = Font.Default;
- Application.Start(delegate
- {
- if (Input.Keyboard.SpaceReleased)
- {
- toSmallPanel.ScrollForeward();
- } // if
- });
- }
- #endregion
-
- #endregion
-
- #region DisplayPanelWithChildren (Static)
- /// <summary>
- /// Display panel with children
- /// </summary>
- [Test]
- public static void DisplayPanelWithChildren()
- {
- Panel testPanel = new Panel
- {
- //LocalArea = Rectangle.FromCenter(0.35f, 0.4f, 0.5f, 0.2f),
- LocalArea = new Rectangle(0.2f, 0.3f, 0.3f, 0.15f),
- CustomDesign = new ControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Yellow),
- },
- //Padding =
- };
-
- float leftBorder = 0.01f;
- float topBorder = leftBorder;
- BaseControl lastControl = null;
- for (int index = 0; index < 7; index++)
- {
- Label panelItem = new Label
- {
- LocalArea = new Rectangle(leftBorder, topBorder, 0.1f, 0.1f),
- CustomDesign = new TextControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Green),
- TextFont = new Font(Font.Default, Color.Brown),
- },
- Text = "Label " + (index + 1),
- };
-
- if (lastControl != null)
- {
- panelItem.LocalArea = new Rectangle(panelItem.LocalArea.Left +
- lastControl.LocalArea.Right,
- panelItem.LocalArea.Top,
- panelItem.LocalArea.Width, panelItem.LocalArea.Height);
- } // if
-
- testPanel.Add(panelItem);
- lastControl = panelItem;
- } // for
-
- Screen testScene = new Screen();
- testScene.Add(testPanel);
-
- // Open now the scene to "activate" for the test
- testScene.Open();
-
- //Font infoFont = Font.Default;
- Application.Start(delegate
- {
- if (Input.Keyboard.SpaceReleased)
- {
- testPanel.ScrollForeward();
- } // if
- });
- }
- #endregion
-
- #region DisplayPanelWithButtons (Static)
- /// <summary>
- /// Display panel with children
- /// </summary>
- [Test]
- public static void DisplayPanelWithButtons()
- {
- Panel testPanel = new Panel
- {
- CustomDesign = new ControlDesign
- {
- Background = BaseTheme.GetUIMaterial(
- new Color(1.0f, 1.0f, 1.0f, 0.5f))
- },
- //Size = new Size(0.18f, 0.1f),
- //LocalPosition = new Point(0.5f, 0.5f),
- LocalArea = new Rectangle(0.2f, 0.3f, 0.3f, 0.15f),
- };
-
- // Create add and remove emitter buttons with some basic props.
- Button addEmitterButton = new Button
- {
- CustomDesign = new TextControlDesign
- {
- //Background = null,
- Background = BaseTheme.GetUIMaterial(Color.Black),
- TextFont = Font.Default,
- },
- State = ElementState.Enabled,
- Text = "A Test Button",
- LocalArea = new Rectangle(0.0f, 0.0f, 0.18f, 0.05f),
- };
-
- Button removeEmitterButton = new Button
- {
- CustomDesign = new TextControlDesign
- {
- Background = BaseTheme.GetUIMaterial(Color.Black),
- TextFont = Font.Default,
- },
- Text = "TEST ABC",
- LocalArea = new Rectangle(0.0f, addEmitterButton.Size.Height, 0.18f, 0.05f),
- };
-
- testPanel.Add(addEmitterButton);
- testPanel.Add(removeEmitterButton);
-
- testPanel.State = ElementState.Enabled;
- Screen testScene = new Screen();
-
- testScene.Add(testPanel);
-
- // Open now the scene to "activate" for the test
- testScene.Open();
-
- //Font infoFont = Font.Default;
- Application.Start(delegate
- {
- });
- }
- #endregion
- }
- }
- }
-