From 15b3b356b0b7be41bd7d975528c46b30c3558988 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 3 Jul 2017 15:41:35 -0400 Subject: [PATCH] I fixed and broke stuff at the same time! --- ShiftOS.Frontend/GUI/Control.cs | 66 ++++++++++++++++- ShiftOS.Frontend/GUI/TextInput.cs | 66 +++++++++-------- .../GraphicsSubsystem/UIManager.cs | 32 ++++----- ShiftOS.Frontend/ShiftOS.cs | 72 ++++++++++++------- 4 files changed, 163 insertions(+), 73 deletions(-) diff --git a/ShiftOS.Frontend/GUI/Control.cs b/ShiftOS.Frontend/GUI/Control.cs index 90e7ba5..fcd5bf0 100644 --- a/ShiftOS.Frontend/GUI/Control.cs +++ b/ShiftOS.Frontend/GUI/Control.cs @@ -10,6 +10,7 @@ using ShiftOS.Frontend.GraphicsSubsystem; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using Microsoft.Xna.Framework; +using System.Runtime.InteropServices; namespace ShiftOS.Frontend.GUI { @@ -36,6 +37,48 @@ namespace ShiftOS.Frontend.GUI 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 { @@ -74,6 +117,9 @@ namespace ShiftOS.Frontend.GUI } set { + if (_anchor == value) + return; + _anchor = value; Invalidate(); } @@ -96,6 +142,8 @@ namespace ShiftOS.Frontend.GUI } set { + if (_opacity == value) + return; _opacity = value; Invalidate(); } @@ -164,6 +212,9 @@ namespace ShiftOS.Frontend.GUI } set { + if (_visible == value) + return; + _visible = value; Invalidate(); } @@ -213,6 +264,8 @@ namespace ShiftOS.Frontend.GUI } set { + if (_x == value) + return; _x = value; Invalidate(); } @@ -226,6 +279,8 @@ namespace ShiftOS.Frontend.GUI } set { + if (_y == value) + return; _y = value; Invalidate(); } @@ -239,6 +294,8 @@ namespace ShiftOS.Frontend.GUI } set { + if (_w == value) + return; _w = value; Invalidate(); } @@ -252,6 +309,8 @@ namespace ShiftOS.Frontend.GUI } set { + if (_h == value) + return; _h = value; Invalidate(); } @@ -329,7 +388,6 @@ namespace ShiftOS.Frontend.GUI } _invalidated = false; } - gfx.DrawImage(_texCache, 0, 0); foreach (var child in _children) { if (child.Visible) @@ -339,6 +397,10 @@ namespace ShiftOS.Frontend.GUI var cBmp = new Bitmap(child.Width, child.Height); child.Paint(System.Drawing.Graphics.FromImage(cBmp)); cBmp.SetOpacity((float)child.Opacity); + using(var cGfx = Graphics.FromImage(_texCache)) + { + cGfx.DrawImage(child.TextureCache, child.X, child.Y); + } child._invalidated = false; child._texCache = cBmp; gfx.DrawImage(cBmp, new System.Drawing.Point(child.X, child.Y)); @@ -352,7 +414,7 @@ namespace ShiftOS.Frontend.GUI } } } - + gfx.DrawImage(_texCache, 0, 0); } } diff --git a/ShiftOS.Frontend/GUI/TextInput.cs b/ShiftOS.Frontend/GUI/TextInput.cs index 7466cfd..e59e927 100644 --- a/ShiftOS.Frontend/GUI/TextInput.cs +++ b/ShiftOS.Frontend/GUI/TextInput.cs @@ -25,6 +25,21 @@ namespace ShiftOS.Frontend.GUI _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++; @@ -36,52 +51,47 @@ namespace ShiftOS.Frontend.GUI Invalidate(); base.OnKeyEvent(e); } - - private int textInputOffset = 0; - private int maxCanFit = 5; - string visibleText = ""; + float caretPos = 2f; protected void CalculateVisibleText() { - visibleText = ""; - caretPos = -1f; - using (var gfx = Graphics.FromImage(new Bitmap(1, 1))) + using(var gfx = Graphics.FromImage(new Bitmap(1, 1))) { - for (int i = textInputOffset; i < _text.Length; i++) + string toCaret = _text.Substring(0, _index); + var measure = gfx.MeasureString(toCaret, _font); + caretPos = 2 + measure.Width; + while(caretPos - _textDrawOffset < 0) { - visibleText += _text[i]; - var measure = gfx.MeasureString(visibleText, _font); - if (measure.Width > Width) - { - maxCanFit = visibleText.Length; - if(_index < textInputOffset) - { - textInputOffset = MathHelper.Clamp(_index - (maxCanFit / 2), 0, _text.Length - 1); - - } - if(_index > textInputOffset + maxCanFit) - { - textInputOffset = MathHelper.Clamp(_index + (maxCanFit / 2), 0, _text.Length - 1) - maxCanFit; - } - break; - } - Height = (int)measure.Height + 4; + _textDrawOffset -= 0.01f; } + while(caretPos - _textDrawOffset > Width) + { + _textDrawOffset += 0.01f; + } + } } + private float _textDrawOffset = 0; protected override void OnPaint(Graphics gfx) { gfx.Clear(LoadedSkin.ControlColor); - gfx.DrawString(visibleText, _font, new SolidBrush(LoadedSkin.ControlTextColor), 2, 2); + gfx.DrawString(_text, _font, new SolidBrush(LoadedSkin.ControlTextColor), 2 - _textDrawOffset, 2); if (IsFocusedControl) { //Draw caret. - gfx.FillRectangle(new SolidBrush(LoadedSkin.ControlTextColor), new RectangleF(caretPos, 2, 2, Height - 4)); + gfx.FillRectangle(new SolidBrush(LoadedSkin.ControlTextColor), new RectangleF(caretPos - _textDrawOffset, 2, 2, Height - 4)); } - gfx.DrawRectangle(new Pen(new SolidBrush(LoadedSkin.ControlTextColor), 1), new Rectangle(0, 0, Width - 1, Height - 1)); + else + { + if (string.IsNullOrEmpty(_text)) + { + gfx.DrawString(_label, _font, Brushes.Gray, 2, 2); + } + } + gfx.DrawRectangle(new Pen(new SolidBrush(LoadedSkin.ControlTextColor), 1), new System.Drawing.Rectangle(0, 0, Width - 1, Height - 1)); } diff --git a/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs index 372c5a6..97ad52d 100644 --- a/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs +++ b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs @@ -21,7 +21,7 @@ namespace ShiftOS.Frontend.GraphicsSubsystem public static void LayoutUpdate() { - foreach (var toplevel in topLevels) + foreach (var toplevel in topLevels.ToArray()) toplevel.Layout(); } @@ -40,32 +40,26 @@ namespace ShiftOS.Frontend.GraphicsSubsystem t.Start(); } + public static Dictionary TextureCaches = new Dictionary(); public static void DrawControls(GraphicsDevice graphics, SpriteBatch batch) { foreach (var ctrl in topLevels.ToArray()) { - using(var bmp = new System.Drawing.Bitmap(ctrl.Width, ctrl.Height)) + int hc = ctrl.GetHashCode(); + if (ctrl.RequiresPaint) { - var gfx = System.Drawing.Graphics.FromImage(bmp); - ctrl.Paint(gfx); - bmp.SetOpacity((float)ctrl.Opacity); - //get the bits of the bitmap - var data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - byte[] rgb = new byte[Math.Abs(data.Stride) * data.Height]; - Marshal.Copy(data.Scan0, rgb, 0, rgb.Length); - bmp.UnlockBits(data); - for(int i = 0; i < rgb.Length; i+=4) + var bmp = new System.Drawing.Bitmap(ctrl.Width, ctrl.Height); + ctrl.Paint(System.Drawing.Graphics.FromImage(bmp)); + if (TextureCaches.ContainsKey(hc)) { - byte r = rgb[i]; - byte b = rgb[i + 2]; - rgb[i] = b; - rgb[i + 2] = r; + TextureCaches[hc].Dispose(); + TextureCaches.Remove(hc); } - var tex2 = new Texture2D(graphics, bmp.Width, bmp.Height); - tex2.SetData(rgb); - batch.Draw(tex2, new Rectangle(ctrl.X, ctrl.Y, ctrl.Width, ctrl.Height), Color.White); + TextureCaches.Add(hc, new Texture2D(graphics, ctrl.Width, ctrl.Height)); + TextureCaches[hc].SetData(ctrl.PaintCache); } + batch.Draw(TextureCaches[hc], new Rectangle(ctrl.X, ctrl.Y, ctrl.Width, ctrl.Height), Color.White); } } @@ -139,7 +133,7 @@ namespace ShiftOS.Frontend.GraphicsSubsystem { public static char ToCharacter(this Keys key, bool shift) { - char c = ' '; + char c = '\0'; switch (key) { case Keys.Space: diff --git a/ShiftOS.Frontend/ShiftOS.cs b/ShiftOS.Frontend/ShiftOS.cs index 6bfa4dc..13e93ba 100644 --- a/ShiftOS.Frontend/ShiftOS.cs +++ b/ShiftOS.Frontend/ShiftOS.cs @@ -40,6 +40,8 @@ namespace ShiftOS.Frontend } private GUI.TextControl _titleLabel = null; + private Keys lastKey = Keys.None; + /// /// Allows the game to perform any initialization it needs to before starting to run. @@ -123,10 +125,16 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type textinput.Y = 0; UIManager.AddTopLevel(textinput); + framerate.Width = GraphicsDevice.PreferredBackBufferWidth; + framerate.Height = GraphicsDevice.PreferredBackBufferHeight; + framerate.TextAlign = GUI.TextAlign.BottomRight; + base.Initialize(); } + private Texture2D MouseTexture = null; + /// /// LoadContent will be called once per game and is the place to load /// all of your content. @@ -137,6 +145,14 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type this.spriteBatch = new SpriteBatch(base.GraphicsDevice); // TODO: use this.Content to load your game content here + var bmp = Properties.Resources.cursor_9x_pointer; + var _lock = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + byte[] rgb = new byte[Math.Abs(_lock.Stride) * _lock.Height]; + Marshal.Copy(_lock.Scan0, rgb, 0, rgb.Length); + bmp.UnlockBits(_lock); + MouseTexture = new Texture2D(GraphicsDevice.GraphicsDevice, bmp.Width, bmp.Height); + MouseTexture.SetData(rgb); + rgb = null; } /// @@ -145,9 +161,11 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type /// protected override void UnloadContent() { + MouseTexture = null; // TODO: Unload any non ContentManager content here } + /// /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. @@ -158,14 +176,14 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type //Let's get the mouse state var mouseState = Mouse.GetState(this.Window); - //Now let's process it. - UIManager.ProcessMouseState(mouseState); + //Now let's process it. + UIManager.ProcessMouseState(mouseState); //Cause layout update on all elements UIManager.LayoutUpdate(); //set framerate - framerate.Text = "ShiftOS 1.0 Beta 4\r\nCopyright (c) 2017 ShiftOS\r\nFPS: " + (1 / gameTime.ElapsedGameTime.TotalSeconds); + framerate.Text = "ShiftOS 1.0 Beta 4\r\nCopyright (c) 2017 ShiftOS\r\nFPS: " + (1000 / gameTime.ElapsedGameTime.TotalMilliseconds); //So we have mouse input, and the UI layout system working... @@ -180,22 +198,34 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type var keys = keystate.GetPressedKeys(); if (keys.Length > 0) { - //Of course, we need modifier keys... - //First for Control. - bool controlDown = keys.Contains(Keys.LeftControl) || keys.Contains(Keys.RightControl); - //Now SHIFT. - bool shiftDown = keys.Contains(Keys.LeftShift) || keys.Contains(Keys.RightShift); - //And ALT. - bool altDown = keys.Contains(Keys.LeftAlt) || keys.Contains(Keys.RightAlt); - - foreach(var key in keys) + var key = keys.FirstOrDefault(x => x != Keys.LeftControl && x != Keys.RightControl && x != Keys.LeftShift && x != Keys.RightShift && x != Keys.LeftAlt && x != Keys.RightAlt); + if (lastKey != key) { - //This'll make it so we skip the modifier keys. - if(key != Keys.LeftAlt && key != Keys.RightAlt && key != Keys.LeftControl && key != Keys.RightControl && key != Keys.LeftShift && key != Keys.RightShift) + lastKey = key; + //Of course, we need modifier keys... + //First for Control. + bool controlDown = keys.Contains(Keys.LeftControl) || keys.Contains(Keys.RightControl); + //Now SHIFT. + bool shiftDown = keys.Contains(Keys.LeftShift) || keys.Contains(Keys.RightShift); + //And ALT. + bool altDown = keys.Contains(Keys.LeftAlt) || keys.Contains(Keys.RightAlt); + + var keyevent = new KeyEvent(controlDown, altDown, shiftDown, key); + var t = new System.Threading.Thread(() => { - var keyevent = new KeyEvent(controlDown, altDown, shiftDown, key); UIManager.ProcessKeyEvent(keyevent); - } + lastKey = Keys.None; + System.Threading.Thread.Sleep(1000); + if(lastKey == keyevent.Key) + while (Keyboard.GetState().IsKeyDown(keyevent.Key)) + { + UIManager.ProcessKeyEvent(keyevent); + System.Threading.Thread.Sleep(75); + } + lastKey = Keys.None; + }); + t.Start(); + } } @@ -221,15 +251,9 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type //Draw a mouse cursor - var bmp = Properties.Resources.cursor_9x_pointer; - var data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - byte[] rgb = new byte[Math.Abs(data.Stride) * data.Height]; - Marshal.Copy(data.Scan0, rgb, 0, rgb.Length); - bmp.UnlockBits(data); + var mousepos = Mouse.GetState(this.Window).Position; - var tex2 = new Texture2D(graphics, bmp.Width, bmp.Height); - tex2.SetData(rgb); - spriteBatch.Draw(tex2, new Rectangle(mousepos.X, mousepos.Y, bmp.Width, bmp.Height), Color.White); + spriteBatch.Draw(MouseTexture, new Rectangle(mousepos.X, mousepos.Y, MouseTexture.Width, MouseTexture.Height), Color.White);