using RecrownedAthenaeum.Input; using RecrownedAthenaeum.Graphics.Render; using RecrownedAthenaeum.Types; using RecrownedAthenaeum.UI.SkinSystem; using RecrownedAthenaeum.UI.SkinSystem.Definitions; using System; namespace RecrownedAthenaeum.UI.Modular.Modules { public class UIScrollable : UIModule { BasicScissor basicScissor; Rectangle viewport; UIModuleGroup group; Color scrollBarColor = Color.White; float opacityOfBar = 1f; bool showingBars; private bool mouseWasPressed; private bool horizontalSelected; private Vector2 mouseRelativePosition; float shiftX, shiftY; public float XScrollPosition { get { return (Width - horizontalScrollBarBounds.Width) * (-shiftX / (group.Width - viewport.Width)); } set { if (value > Width - verticalScrollBarBounds.Height) { value = Width - verticalScrollBarBounds.Height; } if (value < 0) value = 0; shiftX = -(group.Width - viewport.Width) * (value / (Width - horizontalScrollBarBounds.Width)); WidthOrXChange(true); } } public float YScrollPosition { get { return (Height - verticalScrollBarBounds.Height) * (-shiftY / (group.Height - viewport.Height)); } set { if (value > Height - verticalScrollBarBounds.Height) { value = Height - verticalScrollBarBounds.Height; } if (value < 0) value = 0; shiftY = -(group.Height - viewport.Height) * (value / (Height - verticalScrollBarBounds.Height)); HeightOrYChange(true); } } UIModule furthestXModule, furthestYMod; bool horScrollAvailable, vertScrollAvailable; Rectangle horizontalScrollBarBounds, verticalScrollBarBounds; /// /// How fast the bars fade away in opacity (0 to 254) per second. /// public float barFadeSpeed = 250; ISpecialDrawable horizontalScrollBar, verticalScrollBar; ISpecialDrawable background, horizontalBarTrack, verticalBarTrack; private int topPadding, bottomPadding, leftPadding, rightPadding; /// /// /// public int PadTop { get { return topPadding; } set { topPadding = value; HeightOrYChange(); } } public int PadBottom { get { return bottomPadding; } set { bottomPadding = value; HeightOrYChange(); } } public int PadLeft { get { return leftPadding; } set { leftPadding = value; WidthOrXChange(); } } public int PadRight { get { return rightPadding; } set { rightPadding = value; WidthOrXChange(); } } /// /// The minimum bar length for the scroll bar. /// public int minimumBarLength = 16; public int HorizontalBarThickness { get { return horizontalScrollBarBounds.Height; } set { horizontalScrollBarBounds.Height = value; HeightOrYChange(); } } public int VerticalBarThickness { get { return verticalScrollBarBounds.Width; } set { verticalScrollBarBounds.Width = value; WidthOrXChange(); } } bool hideScrollBars; /// /// Whether or not to hide scroll bars. /// public bool HideScrollBars { get { return hideScrollBars; } set { hideScrollBars = value; WidthOrXChange(true); HeightOrYChange(true); if (!value) { opacityOfBar = 1f; scrollBarColor = color * opacityOfBar; } } } /// /// Set to true to change from the normal position to the new position. /// public bool verticalBarLeftPosition, horizontalBarTopPosition; public override int Width { get { return base.Width; } set { base.Width = value; WidthOrXChange(); } } public override int Height { get { return base.Height; } set { base.Height = value; HeightOrYChange(); } } public override int X { get { return base.X; } set { WidthOrXChange(true); base.X = value; } } public override int Y { get { return base.Y; } set { HeightOrYChange(true); base.Y = value; } } public UIScrollable(ISpecialDrawable horizontalScrollBar, ISpecialDrawable verticalScrollBar, ISpecialDrawable horizontalBarTrack = null, ISpecialDrawable verticalBarTrack = null, ISpecialDrawable background = null) { this.horizontalScrollBar = horizontalScrollBar; this.verticalScrollBar = verticalScrollBar; this.horizontalBarTrack = horizontalBarTrack; this.verticalBarTrack = verticalBarTrack; this.background = background; basicScissor = new BasicScissor(); group = new UIModuleGroup(); HorizontalBarThickness = 12; VerticalBarThickness = 12; } public UIScrollable(ISkin skin, string definition = null) : this(skin.GetTextureAtlasRegion(skin.ObtainDefinition().horizontalBar, true), skin.GetTextureAtlasRegion(skin.ObtainDefinition().verticalBar, true), skin.GetTextureAtlasRegion(skin.ObtainDefinition().horizontalBarTrack), skin.GetTextureAtlasRegion(skin.ObtainDefinition().verticalBarTrack), skin.GetTextureAtlasRegion(skin.ObtainDefinition().background)) { } public override void Update(GameTime gameTime) { if (hideScrollBars) { if (!showingBars && !mouseWasPressed) { if (opacityOfBar > 0f) { opacityOfBar -= (barFadeSpeed / 255f) * (float)gameTime.ElapsedGameTime.TotalSeconds; } } else { opacityOfBar = 1f; } scrollBarColor = color * opacityOfBar; } if (horScrollAvailable) { horizontalScrollBarBounds.X = (int)XScrollPosition; } if (vertScrollAvailable) { verticalScrollBarBounds.Y = (int)YScrollPosition; } base.Update(gameTime); } public override void Draw(ConsistentSpriteBatch spriteBatch) { background?.Draw(spriteBatch, Boundaries, color, origin: origin); spriteBatch.End(); basicScissor.Begin(viewport, spriteBatch); group.Draw(spriteBatch); basicScissor.End(); spriteBatch.Begin(); if (horScrollAvailable) { horizontalScrollBar.Draw(spriteBatch, horizontalScrollBarBounds, scrollBarColor); } if (vertScrollAvailable) { horizontalScrollBar.Draw(spriteBatch, verticalScrollBarBounds, scrollBarColor); } base.Draw(spriteBatch); } public void AddModules(params UIModule[] addModules) { group.AddModules(addModules); for (int i = 0; i < addModules.Length; i++) { UIModule m = addModules[i]; int mFurthestX = m.Boundaries.X + m.Boundaries.Width; int mFurthestY = m.Boundaries.Y + m.Boundaries.Height; if (mFurthestX > group.Width) { furthestXModule = m; group.Width = mFurthestX; } if (mFurthestY > group.Height) { furthestYMod = m; group.Height = mFurthestY; } } WidthOrXChange(); HeightOrYChange(); } public void RemoveModule(UIModule module) { group.RemoveModule(module); if (module == furthestXModule) { group.Width = 0; UIModule[] modules = group.GetCopyOfModules(); for (int i = 0; i < modules.Length; i++) { UIModule m = modules[i]; int mFurthestX = m.Boundaries.X + m.Boundaries.Width; if (mFurthestX > group.Width) { furthestXModule = m; group.Width = mFurthestX; } } } if (module == furthestYMod) { group.Height = 0; UIModule[] modules = group.GetCopyOfModules(); for (int i = 0; i < modules.Length; i++) { UIModule m = modules[i]; int mFurthestY = m.Boundaries.Y + m.Boundaries.Height; if (mFurthestY > group.Height) { furthestYMod = m; group.Height = mFurthestY; } } } } private void WidthOrXChange(bool onlyXChange = false) { group.X = X + leftPadding + (int)shiftX; if (!onlyXChange) { viewport.X = X + leftPadding; viewport.Width = Width - rightPadding - leftPadding; if (Width < group.Width) { horScrollAvailable = true; horizontalScrollBarBounds.Width = (int)(Width * ((float)Width / group.Width)); horizontalScrollBarBounds.Width = Math.Max(horizontalScrollBarBounds.Width, minimumBarLength); } else { horScrollAvailable = false; } verticalScrollBarBounds.X = X; if (!hideScrollBars) { viewport.Width -= VerticalBarThickness; if (!verticalBarLeftPosition) { verticalScrollBarBounds.X += viewport.Width; } } else { if (!verticalBarLeftPosition) { verticalScrollBarBounds.X += viewport.Width - verticalScrollBarBounds.Width; } } } } private void HeightOrYChange(bool onlyYChange = false) { group.Y = Y + bottomPadding + (int)shiftY; if (!onlyYChange) { viewport.Y = Y + bottomPadding; viewport.Height = Height - bottomPadding - topPadding; if (Height < group.Height) { vertScrollAvailable = true; verticalScrollBarBounds.Height = (int)(Height * ((float)Height / group.Height)); verticalScrollBarBounds.Height = Math.Max(verticalScrollBarBounds.Height, minimumBarLength); } else { vertScrollAvailable = false; } horizontalScrollBarBounds.Y = Y; if (!hideScrollBars) { viewport.Height -= HorizontalBarThickness; if (!horizontalBarTopPosition) { horizontalScrollBarBounds.Y += viewport.Height; } else { viewport.Y += horizontalScrollBarBounds.Height; } } else { if (!horizontalBarTopPosition) { horizontalScrollBarBounds.Y += viewport.Height - horizontalScrollBarBounds.Height; } } } } public override bool KeyboardStateChanged(KeyboardState state) { if (state.IsKeyDown(Keys.Right)) { XScrollPosition += 1; } return base.KeyboardStateChanged(state); } public override bool MouseStateChanged(MouseState state) { if (InputUtilities.MouseWithinBoundries(Boundaries)) { showingBars = true; } else { showingBars = false; } if (InputUtilities.MouseWithinBoundries(horizontalScrollBarBounds)) { if (state.LeftButton == ButtonState.Pressed) { mouseWasPressed = true; horizontalSelected = true; } if (!mouseWasPressed) { mouseRelativePosition.X = state.X - horizontalScrollBarBounds.X; } } if (InputUtilities.MouseWithinBoundries(verticalScrollBarBounds)) { if (state.LeftButton == ButtonState.Pressed) { mouseWasPressed = true; horizontalSelected = false; } if (!mouseWasPressed) { mouseRelativePosition.Y = state.Y - verticalScrollBarBounds.Y; } } if (mouseWasPressed) { if (horizontalSelected) { float latestPosition = state.X - mouseRelativePosition.X - X; XScrollPosition = latestPosition; } else { float latestPosition = state.Y - mouseRelativePosition.Y - Y; YScrollPosition = latestPosition; } if (state.LeftButton == ButtonState.Released) { mouseWasPressed = false; } } return base.MouseStateChanged(state); } } }