diff options
Diffstat (limited to 'ShiftOS.Frontend/GUI')
| -rw-r--r-- | ShiftOS.Frontend/GUI/Button.cs | 56 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/Control.cs | 707 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/ItemGroup.cs | 64 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/ListBox.cs | 162 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/PictureBox.cs | 128 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/ProgressBar.cs | 58 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/TextControl.cs | 112 | ||||
| -rw-r--r-- | ShiftOS.Frontend/GUI/TextInput.cs | 138 |
8 files changed, 1425 insertions, 0 deletions
diff --git a/ShiftOS.Frontend/GUI/Button.cs b/ShiftOS.Frontend/GUI/Button.cs new file mode 100644 index 0000000..c2e55b9 --- /dev/null +++ b/ShiftOS.Frontend/GUI/Button.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; +using ShiftOS.Engine; +using ShiftOS.Frontend.GraphicsSubsystem; + +namespace ShiftOS.Frontend.GUI +{ + public class Button : TextControl + { + public Button() + { + TextAlign = TextAlign.MiddleCenter; + Text = "Click me!"; + } + + protected override void OnLayout() + { + if(AutoSize == true) + { + int borderwidth = SkinEngine.LoadedSkin.ButtonBorderWidth * 2; + + using (var gfx = Graphics.FromImage(new Bitmap(1, 1))) + { + var measure = gfx.MeasureString(this.Text, this.Font); + Width = borderwidth + (int)measure.Width + 16; + Height = borderwidth + (int)measure.Height + 12; + } + } + } + + protected override void OnPaint(GraphicsContext gfx) + { + var bgCol = UIManager.SkinTextures["ButtonBackgroundColor"]; + var fgCol = SkinEngine.LoadedSkin.ControlTextColor.ToMonoColor(); + if (ContainsMouse) + bgCol = UIManager.SkinTextures["ButtonHoverColor"]; + if (MouseLeftDown) + bgCol = UIManager.SkinTextures["ButtonPressedColor"]; + + gfx.DrawRectangle(0, 0, Width, Height, UIManager.SkinTextures["ControlTextColor"]); + gfx.DrawRectangle(1, 1, Width - 2, Height - 2, bgCol); + + var measure = gfx.MeasureString(Text, Font); + + var loc = new Vector2((Width - measure.X) / 2, (Height - measure.Y) / 2); + + gfx.DrawString(Text, (int)loc.X, (int)loc.Y, fgCol, Font); + + } + } +} diff --git a/ShiftOS.Frontend/GUI/Control.cs b/ShiftOS.Frontend/GUI/Control.cs new file mode 100644 index 0000000..c16792b --- /dev/null +++ b/ShiftOS.Frontend/GUI/Control.cs @@ -0,0 +1,707 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System.Drawing; +using ShiftOS.Frontend.GraphicsSubsystem; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using Microsoft.Xna.Framework; +using System.Runtime.InteropServices; + +namespace ShiftOS.Frontend.GUI +{ + public abstract class Control + { + private int _x = 0; + private int _y = 0; + private int _w = 0; + private int _h = 0; + private Control _parent = null; + private List<Control> _children = new List<Control>(); + private bool _wasMouseInControl = false; + private bool _leftState = false; + private bool _rightState = false; + private bool _middleState = false; + private bool _visible = true; + private DockStyle _dock = DockStyle.None; + private bool _focused = false; + private bool _autoSize = false; + private double _opacity = 1.0; + private bool _invalidated = true; + private Bitmap _texCache = null; + private Anchor _anchor = null; + private int _mouseX = 0; + private int _mouseY = 0; + private bool _captureMouse = false; + + public bool RequiresPaint + { + get + { + bool requires_child_repaint = false; + foreach (var child in _children) + { + requires_child_repaint = child.RequiresPaint; + if (requires_child_repaint) + break; + } + return _invalidated || requires_child_repaint; + } + } + + public Image TextureCache + { + get + { + return _texCache; + } + } + + public byte[] PaintCache + { + get + { + var data = _texCache.LockBits(new System.Drawing.Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + var rgb = new byte[Math.Abs(data.Stride) * data.Height]; + Marshal.Copy(data.Scan0, rgb, 0, rgb.Length); + for(int i = 0; i < rgb.Length; i += 4) + { + byte r = rgb[i]; + byte b = rgb[i + 2]; + rgb[i] = b; + rgb[i + 2] = r; + } + _texCache.UnlockBits(data); + return rgb; + } + } + + public bool CaptureMouse + { + get + { + return _captureMouse; + } + set + { + _captureMouse = value; + } + } + + public int MouseX + { + get + { + return _mouseX; + } + } + + public int MouseY + { + get + { + return _mouseY; + } + } + + + public Anchor Anchor + { + get + { + return _anchor; + } + set + { + if (_anchor == value) + return; + + _anchor = value; + Invalidate(); + } + } + + public void Invalidate() + { + _invalidated = true; + foreach(var child in _children) + { + child.Invalidate(); + } + } + + public double Opacity + { + get + { + return _opacity; + } + set + { + if (_opacity == value) + return; + _opacity = value; + Invalidate(); + } + } + + public bool AutoSize + { + get + { + return _autoSize; + } + set + { + _autoSize = value; + } + } + + //Thank you, StackOverflow. + public static Bitmap ResizeImage(Image image, int width, int height) + { + var destRect = new System.Drawing.Rectangle(0, 0, width, height); + var destImage = new Bitmap(width, height); + + destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + + using (var graphics = Graphics.FromImage(destImage)) + { + graphics.CompositingMode = CompositingMode.SourceCopy; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + using (var wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); + } + } + + return destImage; + } + + public DockStyle Dock + { + get + { + return _dock; + } + set + { + _dock = value; + } + } + + public bool ContainsMouse + { + get { return _wasMouseInControl; } + } + + public bool Visible + { + get + { + return _visible; + } + set + { + if (_visible == value) + return; + + _visible = value; + Invalidate(); + } + } + + public void AddControl(Control ctrl) + { + if (!_children.Contains(ctrl)) + { + ctrl._parent = this; + _children.Add(ctrl); + Invalidate(); + } + } + + public bool MouseLeftDown + { + get + { + return _leftState; + } + } + + public bool MouseMiddleDown + { + get + { + return _middleState; + } + } + + public bool MouseRightDown + { + get + { + return _rightState; + } + } + + + + public int X + { + get + { + return _x; + } + set + { + if (_x == value) + return; + _x = value; + Invalidate(); + } + } + + public int Y + { + get + { + return _y; + } + set + { + if (_y == value) + return; + _y = value; + Invalidate(); + } + } + + public int Width + { + get + { + return _w; + } + set + { + if (_w == value) + return; + _w = value; + Invalidate(); + } + } + + public int Height + { + get + { + return _h; + } + set + { + if (_h == value) + return; + _h = value; + Invalidate(); + } + } + + public Control Parent + { + get + { + return _parent; + } + } + + public Control[] Children + { + get + { + return _children.ToArray(); + } + } + + public Point PointToParent(int x, int y) + { + return new Point(x + _x, y + _y); + } + + public Point PointToScreen(int x, int y) + { + var parentCoords = PointToParent(x, y); + Control parent = this._parent; + while(parent != null) + { + parentCoords = parent.PointToParent(parentCoords.X, parentCoords.Y); + parent = parent.Parent; + } + return parentCoords; + } + + public void ClearControls() + { + _children.Clear(); + Invalidate(); + } + + public Point PointToLocal(int x, int y) + { + return new GUI.Point(x - _x, y - _y); + } + + public virtual void MouseStateChanged() { } + + protected virtual void OnPaint(GraphicsContext gfx) + { + gfx.DrawRectangle(0, 0, Width, Height, UIManager.SkinTextures["ControlColor"]); + } + + public void SendToBack() + { + if(_parent != null) + { + _parent._children.Remove(this); + _parent._children.Insert(0, this); + } + else + { + UIManager.SendToBack(this); + } + } + + public void InvalidateTopLevel() + { + var parent = this; + while (parent.Parent != null) + parent = parent.Parent; + parent.Invalidate(); + } + + public void Paint(GraphicsContext gfx) + { + if (_visible == true) + { + OnPaint(gfx); + int draw_x = gfx.X; + int draw_y = gfx.Y; + int draw_width = gfx.Width; + int draw_height = gfx.Height; + foreach (var ctrl in _children) + { + if (ctrl.Visible == true) + { + gfx.X = draw_x + ctrl.X; + gfx.Y = draw_y + ctrl.Y; + gfx.Width = ctrl.Width; + gfx.Height = ctrl.Height; + ctrl.Paint(gfx); + gfx.X = draw_x; + gfx.Y = draw_y; + } + gfx.Width = draw_width; + gfx.Height = draw_height; + } + _invalidated = false; + } + } + + public void Layout() + { + //Dock style + if(_parent != null) + { + if(_anchor != null) + { + + } + + switch (_dock) + { + case DockStyle.Top: + X = 0; + Y = 0; + Width = _parent.Width; + break; + case DockStyle.Left: + X = 0; + Y = 0; + Height = _parent.Height; + break; + case DockStyle.Right: + Y = 0; + X = _parent.Width - Width; + Height = _parent.Height; + break; + case DockStyle.Bottom: + X = 0; + Y = _parent.Height - Height; + Width = _parent.Width; + break; + case DockStyle.Fill: + X = 0; + Y = 0; + Width = _parent.Width; + Height = _parent.Height; + break; + } + } + OnLayout(); + foreach (var child in _children) + child.Layout(); + } + + protected virtual void OnLayout() + { + //do nothing + } + + public bool IsFocusedControl + { + get + { + return UIManager.FocusedControl == this; + } + } + + public bool ContainsFocusedControl + { + get + { + if (UIManager.FocusedControl == null) + return false; + else + { + bool contains = false; + + var ctrl = UIManager.FocusedControl; + while(ctrl.Parent != null) + { + ctrl = ctrl.Parent; + if (ctrl == this) + contains = true; + } + return contains; + } + } + } + + public virtual bool ProcessMouseState(MouseState state) + { + //If we aren't rendering the control, we aren't accepting input. + if (_visible == false) + return false; + + + //Firstly, we get the mouse coordinates in the local space + var coords = PointToLocal(state.Position.X, state.Position.Y); + _mouseX = coords.X; + _mouseY = coords.Y; + //Now we check if the mouse is within the bounds of the control + if(coords.X >= 0 && coords.Y >= 0 && coords.X <= _w && coords.Y <= _h) + { + //We're in the local space. Let's fire the MouseMove event. + MouseMove?.Invoke(coords); + //Also, if the mouse hasn't been in the local space last time it moved, fire MouseEnter. + if(_wasMouseInControl == false) + { + _wasMouseInControl = true; + MouseEnter?.Invoke(); + Invalidate(); + } + + //Things are going to get a bit complicated. + //Firstly, we need to find out if we have any children. + bool _requiresMoreWork = true; + if(_children.Count > 0) + { + //We do. We're going to iterate through them all and process the mouse state. + foreach(var control in _children) + { + + //If the process method returns true, then we do not need to do anything else on our end. + + //We need to first create a new mousestate object with the new coordinates + + var nstate = new MouseState(coords.X, coords.Y, state.ScrollWheelValue, state.LeftButton, state.MiddleButton, state.RightButton, state.XButton1, state.XButton2); + //pass that state to the process method, and set the _requiresMoreWork value to the opposite of the return value + _requiresMoreWork = !control.ProcessMouseState(nstate); + //If it's false, break the loop. + if (_requiresMoreWork == false) + break; + } + } + + //If we need to do more work... + if(_requiresMoreWork == true) + { + bool fire = false; //so we know to fire a MouseStateChanged method + //Let's get the state values of each button + bool ld = state.LeftButton == ButtonState.Pressed; + bool md = state.MiddleButton == ButtonState.Pressed; + bool rd = state.RightButton == ButtonState.Pressed; + if(ld != _leftState || md != _middleState || rd != _rightState) + { + fire = true; + } + if (_leftState == true && ld == false) + { + Click?.Invoke(); + Invalidate(); + MouseUp?.Invoke(); + } + if (_leftState == false && ld == true) + { + var focused = UIManager.FocusedControl; + UIManager.FocusedControl = this; + focused?.InvalidateTopLevel(); + InvalidateTopLevel(); + MouseDown?.Invoke(); + + } + _leftState = ld; + _middleState = md; + _rightState = rd; + if (fire) + MouseStateChanged(); + } + return true; + } + else + { + _leftState = false; + _rightState = false; + _middleState = false; + MouseStateChanged(); + //If the mouse was in local space before, fire MouseLeave + if (_wasMouseInControl == true) + { + if (CaptureMouse == true) + { + _wasMouseInControl = true; + int newX = MathHelper.Clamp(state.X, X, X + Width); + int newY = MathHelper.Clamp(state.Y, Y, Y + Height); + Mouse.SetPosition(newX, newY); + + } + else + { + _wasMouseInControl = false; + MouseLeave?.Invoke(); + Invalidate(); + } + } + } + if (CaptureMouse == true) + { + _mouseX = coords.X; + _mouseY = coords.Y; + Layout(); + _wasMouseInControl = true; + int newX = MathHelper.Clamp(state.X, X, X + Width); + int newY = MathHelper.Clamp(state.Y, Y, Y + Height); + Mouse.SetPosition(newX, newY); + return true; + } + + //Mouse is not in the local space, don't do anything. + return false; + } + + protected virtual void OnKeyEvent(KeyEvent e) + { + + } + + public void ProcessKeyEvent(KeyEvent e) + { + OnKeyEvent(e); + KeyEvent?.Invoke(e); + } + + public event Action<Point> MouseMove; + public event Action MouseEnter; + public event Action MouseLeave; + public event Action Click; + public event Action<KeyEvent> KeyEvent; + public event Action MouseDown; + public event Action MouseUp; + } + + public struct Point + { + public Point(int x, int y) + { + X = x; + Y = y; + } + + public int X { get; set; } + public int Y { get; set; } + } + + public enum DockStyle + { + None, + Top, + Bottom, + Left, + Right, + Fill + } + + //Thanks, StackOverflow. + public static class BitmapExtensions + { + public static Image SetOpacity(this Image image, float opacity) + { + var colorMatrix = new ColorMatrix(); + colorMatrix.Matrix33 = opacity; + var imageAttributes = new ImageAttributes(); + imageAttributes.SetColorMatrix( + colorMatrix, + ColorMatrixFlag.Default, + ColorAdjustType.Bitmap); + var output = new Bitmap(image.Width, image.Height); + using (var gfx = Graphics.FromImage(output)) + { + gfx.SmoothingMode = SmoothingMode.AntiAlias; + gfx.DrawImage( + image, + new System.Drawing.Rectangle(0, 0, image.Width, image.Height), + 0, + 0, + image.Width, + image.Height, + GraphicsUnit.Pixel, + imageAttributes); + } + return output; + } + } + + [Flags] + public enum AnchorStyle + { + Top, + Left, + Bottom, + Right + } + + public class Anchor + { + public AnchorStyle Style { get; set; } + public int Distance { get; set; } + } +} diff --git a/ShiftOS.Frontend/GUI/ItemGroup.cs b/ShiftOS.Frontend/GUI/ItemGroup.cs new file mode 100644 index 0000000..e52a17f --- /dev/null +++ b/ShiftOS.Frontend/GUI/ItemGroup.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ShiftOS.Frontend.GUI +{ + public class ItemGroup : Control + { + private int _gap = 3; + private FlowDirection _flowDir = FlowDirection.LeftToRight; + private int _initialgap = 2; + + protected override void OnLayout() + { + if (AutoSize) + { + int _highesty = _initialgap; + int _xx = _initialgap; + foreach(var ctrl in Children) + { + _xx += ctrl.Width + _gap; + if (_highesty < ctrl.Height + _initialgap + _gap) + _highesty = ctrl.Height + _initialgap + _gap; + } + Width = _xx; + Height = _highesty; + } + + int _x = _initialgap; + int _y = _initialgap; + int _maxYForRow = 0; + foreach (var ctrl in Children) + { + if (_x + ctrl.Width + _gap > Width) + { + _x = _initialgap; + _y = _maxYForRow; + _maxYForRow = 0; + if (_maxYForRow < ctrl.Height + _gap) + _maxYForRow = ctrl.Height + _gap; + } + ctrl.X = _x; + ctrl.Y = _y; + ctrl.Dock = DockStyle.None; + ctrl.Layout(); + _x += ctrl.Width + _gap; + + if (_maxYForRow < ctrl.Height + _gap) + _maxYForRow = ctrl.Height + _gap; + + } + } + } + + public enum FlowDirection + { + LeftToRight, + TopDown, + RightToLeft, + BottomUp + } +} diff --git a/ShiftOS.Frontend/GUI/ListBox.cs b/ShiftOS.Frontend/GUI/ListBox.cs new file mode 100644 index 0000000..f9354e0 --- /dev/null +++ b/ShiftOS.Frontend/GUI/ListBox.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; +using ShiftOS.Frontend.GraphicsSubsystem; +using static ShiftOS.Engine.SkinEngine; + +namespace ShiftOS.Frontend.GUI +{ + public class ListBox : GUI.Control + { + private int fontheight = 0; + private List<object> items = new List<object>(); + private int selectedIndex = -1; + private int itemOffset = 0; + private int itemsPerPage = 1; + + public int SelectedIndex + { + get + { + return MathHelper.Clamp(selectedIndex, 0, items.Count - 1); + } + set + { + selectedIndex = MathHelper.Clamp(value, 0, items.Count - 1); + RecalculateItemsPerPage(); + SelectedIndexChanged?.Invoke(); + } + } + + public object SelectedItem + { + get + { + try + { + return items[SelectedIndex]; + } + catch + { + return ""; + } + } + } + + public void ClearItems() + { + selectedIndex = -1; + items.Clear(); + SelectedIndexChanged?.Invoke(); + Invalidate(); + } + + public void AddItem(object item) + { + items.Add(item); + RecalculateItemsPerPage(); + Invalidate(); + } + + public void RemoveItem(object item) + { + items.Remove(item); + selectedIndex = -1; + RecalculateItemsPerPage(); + SelectedIndexChanged?.Invoke(); + Invalidate(); + } + + public void RecalculateItemsPerPage() + { + itemsPerPage = 0; + while(itemsPerPage * fontheight < Height && itemsPerPage < items.Count - 1) + { + itemsPerPage++; + } + //We have the amount of items we can fit on screen. + //Now let's calculate the offset based on this, as well + //as the currently selected item. + //of course, if there IS one. + if(selectedIndex > -1) + { + if(selectedIndex >= items.Count) + { + selectedIndex = items.Count - 1; + } + while(this.itemOffset > selectedIndex) + { + itemOffset--; + } + while(this.itemOffset + itemsPerPage < selectedIndex) + { + itemOffset++; + } + } + } + + protected override void OnKeyEvent(KeyEvent e) + { + if(e.Key== Microsoft.Xna.Framework.Input.Keys.Down) + { + if(selectedIndex < items.Count - 2) + { + selectedIndex++; + RecalculateItemsPerPage(); + SelectedIndexChanged?.Invoke(); + Invalidate(); + } + } + else if(e.Key == Microsoft.Xna.Framework.Input.Keys.Up) + { + if(selectedIndex > 0) + { + selectedIndex--; + RecalculateItemsPerPage(); + SelectedIndexChanged?.Invoke(); + Invalidate(); + } + } + } + + protected override void OnPaint(GraphicsContext gfx) + { + gfx.Clear(LoadedSkin.ControlTextColor.ToMonoColor()); + gfx.DrawRectangle(1, 1, Width - 2, Height - 2, UIManager.SkinTextures["ControlColor"]); + for(int i = itemOffset; i < items.Count - 1 && i < itemsPerPage; i++) + { + int x = 1; + int y = fontheight * (i - itemOffset); + int width = Width - 2; + int height = fontheight; + if(i == selectedIndex) + { + //draw the string as selected + gfx.DrawRectangle(x, y, width, height, UIManager.SkinTextures["ControlTextColor"]); + gfx.DrawString(items[i].ToString(), x, y, LoadedSkin.ControlColor.ToMonoColor(), LoadedSkin.MainFont); + } + else + { + gfx.DrawRectangle(x, y, width, height, UIManager.SkinTextures["ControlColor"]); + gfx.DrawString(items[i].ToString(), x, y, LoadedSkin.ControlTextColor.ToMonoColor(), LoadedSkin.MainFont); + + } + } + } + + protected override void OnLayout() + { + if(fontheight != LoadedSkin.MainFont.Height) + { + fontheight = LoadedSkin.MainFont.Height; + Invalidate(); + } + base.OnLayout(); + } + + public event Action SelectedIndexChanged; + } +} diff --git a/ShiftOS.Frontend/GUI/PictureBox.cs b/ShiftOS.Frontend/GUI/PictureBox.cs new file mode 100644 index 0000000..6f60b29 --- /dev/null +++ b/ShiftOS.Frontend/GUI/PictureBox.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftOS.Engine; +using System.Drawing.Imaging; +using ShiftOS.Frontend.GraphicsSubsystem; +using Microsoft.Xna.Framework.Graphics; + +namespace ShiftOS.Frontend.GUI +{ + public class PictureBox : Control + { + private Texture2D img = null; + private ImageLayout _layout = ImageLayout.Fit; + + public ImageLayout ImageLayout + { + get + { + return _layout; + } + set + { + _layout = value; + } + } + + public Texture2D Image + { + get + { + return img; + } + set + { + if (img != null) + img.Dispose(); + img = value; + } + } + + protected override void OnLayout() + { + if (AutoSize) + { + Width = (img == null) ? 0 : img.Width; + Height = (img == null) ? 0 : img.Height; + } + } + + protected override void OnPaint(GraphicsContext gfx) + { + switch (_layout) + { + case ImageLayout.Stretch: + gfx.DrawRectangle(0, 0, Width, Height, Image); + break; + case ImageLayout.None: + gfx.DrawRectangle(0, 0, Image.Width, Image.Height, Image); + break; + } + + } + + //Again, thanks StackOverflow + static Image FixedSize(Image imgPhoto, int Width, int Height) + { + int sourceWidth = imgPhoto.Width; + int sourceHeight = imgPhoto.Height; + int sourceX = 0; + int sourceY = 0; + int destX = 0; + int destY = 0; + + float nPercent = 0; + float nPercentW = 0; + float nPercentH = 0; + + nPercentW = ((float)Width / (float)sourceWidth); + nPercentH = ((float)Height / (float)sourceHeight); + if (nPercentH < nPercentW) + { + nPercent = nPercentH; + destX = System.Convert.ToInt16((Width - + (sourceWidth * nPercent)) / 2); + } + else + { + nPercent = nPercentW; + destY = System.Convert.ToInt16((Height - + (sourceHeight * nPercent)) / 2); + } + + int destWidth = (int)(sourceWidth * nPercent); + int destHeight = (int)(sourceHeight * nPercent); + + Bitmap bmPhoto = new Bitmap(Width, Height, + PixelFormat.Format24bppRgb); + bmPhoto.SetResolution(imgPhoto.HorizontalResolution, + imgPhoto.VerticalResolution); + + Graphics grPhoto = Graphics.FromImage(bmPhoto); + grPhoto.Clear(SkinEngine.LoadedSkin.ControlColor); + grPhoto.InterpolationMode = + InterpolationMode.HighQualityBicubic; + + grPhoto.DrawImage(imgPhoto, + new Rectangle(destX, destY, destWidth, destHeight), + new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), + GraphicsUnit.Pixel); + + grPhoto.Dispose(); + return bmPhoto; + } + } + + public enum ImageLayout + { + None, + Stretch, + Tile, + Fit, + } +} diff --git a/ShiftOS.Frontend/GUI/ProgressBar.cs b/ShiftOS.Frontend/GUI/ProgressBar.cs new file mode 100644 index 0000000..a13bbf8 --- /dev/null +++ b/ShiftOS.Frontend/GUI/ProgressBar.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftOS.Frontend.GraphicsSubsystem; +using static ShiftOS.Engine.SkinEngine; + +namespace ShiftOS.Frontend.GUI +{ + public class ProgressBar : Control + { + private int _maximum = 100; + private int _value = 0; + + public int Maximum + { + get + { + return _maximum; + } + set + { + _maximum = value; + } + } + + public int Value + { + get + { + return _value; + } + set + { + _value = value; + } + } + + protected override void OnPaint(GraphicsContext gfx) + { + gfx.Clear(LoadedSkin.ProgressBarBackgroundColor.ToMonoColor()); + int w = (int)linear(_value, 0, _maximum, 0, Width); + gfx.DrawRectangle(0, 0, w, Height, LoadedSkin.ProgressColor.ToMonoColor()); + } + + static public double linear(double x, double x0, double x1, double y0, double y1) + { + if ((x1 - x0) == 0) + { + return (y0 + y1) / 2; + } + return y0 + (x - x0) * (y1 - y0) / (x1 - x0); + } + + } +} diff --git a/ShiftOS.Frontend/GUI/TextControl.cs b/ShiftOS.Frontend/GUI/TextControl.cs new file mode 100644 index 0000000..f1bbef1 --- /dev/null +++ b/ShiftOS.Frontend/GUI/TextControl.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftOS.Frontend.GraphicsSubsystem; + +namespace ShiftOS.Frontend.GUI +{ + public class TextControl : Control + { + private string _text = "Text Control"; + private TextAlign _textAlign = TextAlign.TopLeft; + private Font _font = new Font("Tahoma", 9f); + + protected override void OnLayout() + { + if (AutoSize) + { + using (var bmp = new Bitmap(1, 1)) + { + using(var gfx = Graphics.FromImage(bmp)) + { + var measure = gfx.MeasureString(_text, _font); + Width = (int)measure.Width; + Height = (int)measure.Height; + } + } + } + } + + public string Text + { + get { return _text; } + set { _text = value; } + } + + public Font Font + { + get + { + return _font; + } + set + { + _font = value; + } + } + + public TextAlign TextAlign + { + get { return _textAlign; } + set { _textAlign = value; } + } + + protected override void OnPaint(GraphicsContext gfx) + { + var sMeasure = gfx.MeasureString(_text, _font, Width); + PointF loc = new PointF(2, 2); + float centerH = (Width - sMeasure.X) / 2; + float centerV = (Height - sMeasure.Y) / 2; + switch (_textAlign) + { + case TextAlign.TopCenter: + loc.X = centerH; + break; + case TextAlign.TopRight: + loc.X = Width - sMeasure.X; + break; + case TextAlign.MiddleLeft: + loc.Y = centerV; + break; + case TextAlign.MiddleCenter: + loc.Y = centerV; + loc.X = centerH; + break; + case TextAlign.MiddleRight: + loc.Y = centerV; + loc.X = (Width - sMeasure.Y); + break; + case TextAlign.BottomLeft: + loc.Y = (Height - sMeasure.Y); + break; + case TextAlign.BottomCenter: + loc.Y = (Height - sMeasure.Y); + loc.X = centerH; + break; + case TextAlign.BottomRight: + loc.Y = (Height - sMeasure.Y); + loc.X = (Width - sMeasure.X); + break; + + } + + gfx.DrawString(_text, 0, 0, Engine.SkinEngine.LoadedSkin.ControlTextColor.ToMonoColor(), _font, this.Width); + } + } + + public enum TextAlign + { + TopLeft, + TopCenter, + TopRight, + MiddleLeft, + MiddleCenter, + MiddleRight, + BottomLeft, + BottomCenter, + BottomRight + } +} diff --git a/ShiftOS.Frontend/GUI/TextInput.cs b/ShiftOS.Frontend/GUI/TextInput.cs new file mode 100644 index 0000000..73954ef --- /dev/null +++ b/ShiftOS.Frontend/GUI/TextInput.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; + +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework; +using ShiftOS.Frontend.GraphicsSubsystem; +using static ShiftOS.Engine.SkinEngine; + +namespace ShiftOS.Frontend.GUI +{ + public class TextInput : Control + { + private string _label = "Type here!"; + private string _text = ""; + private int _index = 0; + private System.Drawing.Font _font = new System.Drawing.Font("Tahoma", 9f); + + public int Index + { + get + { + return _index; + } + set + { + if (_index == value) + return; + if(_text.Length == 0) + { + _index = 0; + return; + } + _index = MathHelper.Clamp(value, 0, _text.Length); + Invalidate(); + } + } + + public string Text + { + get + { + return _text; + } + set + { + if (_text == value) + return; + + _text = value; + if(_index >= _text.Length) + { + _index = _text.Length - 1; + } + Invalidate(); + } + } + + protected override void OnKeyEvent(KeyEvent e) + { + if(e.Key == Microsoft.Xna.Framework.Input.Keys.Left) + { + if (_index > 0) + _index--; + + } + if(e.Key == Microsoft.Xna.Framework.Input.Keys.Back) + { + if(_index > 0) + { + _text = _text.Remove(_index - 1, 1); + _index--; + } + } + if(e.Key == Microsoft.Xna.Framework.Input.Keys.Delete) + { + if(_index < _text.Length - 1) + { + _text = _text.Remove(_index, 1); + } + } + if (e.Key == Microsoft.Xna.Framework.Input.Keys.Right) + if (_index < _text.Length) + _index++; + if (e.KeyChar != '\0') { + _text = _text.Insert(_index, e.KeyChar.ToString()); + _index++; + } + CalculateVisibleText(); + Invalidate(); + base.OnKeyEvent(e); + } + + float caretPos = 2f; + + protected void CalculateVisibleText() + { + using(var gfx = System.Drawing.Graphics.FromImage(new System.Drawing.Bitmap(1, 1))) + { + string toCaret = _text.Substring(0, _index); + var measure = gfx.MeasureString(toCaret, _font); + caretPos = 2 + measure.Width; + while(caretPos - _textDrawOffset < 0) + { + _textDrawOffset -= 0.01f; + } + while(caretPos - _textDrawOffset > Width) + { + _textDrawOffset += 0.01f; + } + + } + } + + private float _textDrawOffset = 0; + + protected override void OnPaint(GraphicsContext gfx) + { + gfx.Clear(LoadedSkin.ControlColor.ToMonoColor()); + gfx.DrawString(_text, 2 - (int)Math.Floor(_textDrawOffset), 2, LoadedSkin.ControlTextColor.ToMonoColor(), _font); + if (IsFocusedControl) + { + //Draw caret. + + + gfx.DrawRectangle((int)(Math.Floor(caretPos) - Math.Floor(_textDrawOffset)), 2, 2, Height - 4, LoadedSkin.ControlTextColor.ToMonoColor()); + } + else + { + if (string.IsNullOrEmpty(_text)) + { + gfx.DrawString(_label, 2, 2, Color.Gray, _font); + } + } + } + } +} |
