aboutsummaryrefslogtreecommitdiff
path: root/ShiftOS.Frontend/GraphicsSubsystem
diff options
context:
space:
mode:
Diffstat (limited to 'ShiftOS.Frontend/GraphicsSubsystem')
-rw-r--r--ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs206
-rw-r--r--ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs483
2 files changed, 689 insertions, 0 deletions
diff --git a/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs b/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs
new file mode 100644
index 0000000..e2b93fe
--- /dev/null
+++ b/ShiftOS.Frontend/GraphicsSubsystem/GraphicsContext.cs
@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using ShiftOS.Frontend.Apps;
+
+namespace ShiftOS.Frontend.GraphicsSubsystem
+{
+ public class GraphicsContext
+ {
+ public GraphicsDevice Device
+ {
+ get
+ {
+ return _graphicsDevice;
+ }
+ }
+
+ private int _startx = 0;
+ private int _starty = 0;
+
+ private int _maxwidth = 1;
+ private int _maxheight = 1;
+
+ public int X
+ {
+ get
+ {
+ return _startx;
+ }
+ set
+ {
+ _startx = value;
+ }
+ }
+
+ public int Y
+ {
+ get
+ {
+ return _starty;
+ }
+ set
+ {
+ _starty = value;
+ }
+ }
+
+ public int Width
+ {
+ get
+ {
+ return _maxwidth;
+ }
+ set
+ {
+ _maxwidth = value;
+ }
+ }
+
+ public int Height
+ {
+ get
+ {
+ return _maxheight;
+ }
+ set
+ {
+ _maxheight = value;
+ }
+ }
+
+
+ private GraphicsDevice _graphicsDevice;
+ private SpriteBatch _spritebatch;
+
+ public GraphicsContext(GraphicsDevice device, SpriteBatch batch, int x, int y, int width, int height)
+ {
+ _graphicsDevice = device;
+ _spritebatch = batch;
+ _maxwidth = width;
+ _maxheight = height;
+ _startx = x;
+ _starty = y;
+ }
+
+ public void Clear(Color c)
+ {
+ DrawRectangle(0, 0, _maxwidth, _maxheight, c);
+ }
+
+ public void DrawLine(int x, int y, int x1, int y1, int thickness, Texture2D tex2)
+ {
+ x += _startx;
+ y += _starty;
+ int distance = (int)Vector2.Distance(new Vector2(x, y), new Vector2(x1, y1));
+ float rotation = getRotation(x, y, x1, y1);
+ _spritebatch.Draw(tex2, new Rectangle(x, y, distance, thickness), null, Color.White, rotation, Vector2.Zero, SpriteEffects.None, 0);
+ }
+
+ public void DrawLine(int x, int y, int x1, int y1, int thickness, Color color)
+ {
+ x += _startx;
+ y += _starty;
+ var tex2 = new Texture2D(_graphicsDevice, 1, 1, false, SurfaceFormat.Color);
+ byte[] colordata = new byte[] { color.B, color.G, color.R, color.A };
+ tex2.SetData<byte>(colordata);
+ int distance = (int)Vector2.Distance(new Vector2(x, y), new Vector2(x1, y1));
+ float rotation = getRotation(x, y, x1, y1);
+ _spritebatch.Draw(tex2, new Rectangle(x, y, distance, thickness), null, color, rotation, Vector2.Zero, SpriteEffects.None, 0);
+ }
+
+ public void DrawRectangle(int x, int y, int width, int height, Color color)
+ {
+ x += _startx;
+ y += _starty;
+ var tex2 = new Texture2D(_graphicsDevice, 1, 1, false, SurfaceFormat.Color);
+ byte[] colordata = new byte[] { color.B, color.G, color.R, color.A };
+ tex2.SetData<byte>(colordata);
+ _spritebatch.Draw(tex2, new Rectangle(x, y, width, height), color);
+ }
+
+ public void DrawRectangle(int x, int y, int width, int height, Texture2D tex2)
+ {
+ x += _startx;
+ y += _starty;
+ _spritebatch.Draw(tex2, new Rectangle(x, y, width, height), Color.White);
+ }
+
+ public Vector2 MeasureString(string text, System.Drawing.Font font, int wrapWidth = int.MaxValue)
+ {
+ using(var gfx = System.Drawing.Graphics.FromImage(new System.Drawing.Bitmap(1, 1)))
+ {
+ var s = gfx.SmartMeasureString(text, font, wrapWidth);
+ return new Vector2((float)Math.Ceiling(s.Width), (float)Math.Ceiling(s.Height));
+ }
+ }
+
+ public static List<TextCache> StringCaches = new List<TextCache>();
+
+ public void DrawString(string text, int x, int y, Color color, System.Drawing.Font font, int wrapWidth = 0)
+ {
+ x += _startx;
+ y += _starty;
+ var fontcache = StringCaches.FirstOrDefault(z => z.Text == text && z.FontFamily == font&&z.WrapWidth == wrapWidth);
+ if (fontcache == null)
+ {
+ Vector2 measure;
+ if (wrapWidth == 0)
+ measure = MeasureString(text, font);
+ else
+ measure = MeasureString(text, font, wrapWidth);
+ using(var bmp = new System.Drawing.Bitmap((int)measure.X, (int)measure.Y))
+ {
+ using(var gfx = System.Drawing.Graphics.FromImage(bmp))
+ {
+ var sFormat = System.Drawing.StringFormat.GenericTypographic;
+ sFormat.FormatFlags |= System.Drawing.StringFormatFlags.NoClip;
+
+ gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
+
+ gfx.DrawString(text, font, System.Drawing.Brushes.White, new System.Drawing.RectangleF(0, 0, bmp.Width, bmp.Height), sFormat);
+ }
+
+ var lck = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ var data = new byte[Math.Abs(lck.Stride) * lck.Height];
+ System.Runtime.InteropServices.Marshal.Copy(lck.Scan0, data, 0, data.Length);
+ var tex2 = new Texture2D(_graphicsDevice, bmp.Width, bmp.Height);
+ tex2.SetData<byte>(data);
+ fontcache = new TextCache();
+ fontcache.Text = text;
+ fontcache.FontFamily = font;
+ fontcache.WrapWidth = wrapWidth;
+ fontcache.Cache = tex2;
+ StringCaches.Add(fontcache);
+ }
+ }
+ _spritebatch.Draw(fontcache.Cache, new Rectangle(x, y, fontcache.Cache.Width, fontcache.Cache.Height), color);
+
+
+ }
+
+ private float getRotation(float x, float y, float x2, float y2)
+ {
+ float adj = x - x2;
+ float opp = y - y2;
+ float tan = opp / adj;
+ float res = MathHelper.ToDegrees((float)Math.Atan2(opp, adj));
+ res = (res - 180) % 360;
+ if (res < 0) { res += 360; }
+ res = MathHelper.ToRadians(res);
+ return res;
+ }
+ }
+
+ public class TextCache
+ {
+ public string Text { get; set; }
+ public System.Drawing.Font FontFamily { get; set; }
+ public Texture2D Cache { get; set; }
+ public int WrapWidth { get; set; }
+ }
+}
diff --git a/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs
new file mode 100644
index 0000000..942b8b6
--- /dev/null
+++ b/ShiftOS.Frontend/GraphicsSubsystem/UIManager.cs
@@ -0,0 +1,483 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using ShiftOS.Engine;
+using ShiftOS.Frontend.Desktop;
+using ShiftOS.Frontend.GUI;
+
+namespace ShiftOS.Frontend.GraphicsSubsystem
+{
+ public static class UIManager
+ {
+ private static List<GUI.Control> topLevels = new List<GUI.Control>();
+ public static System.Drawing.Size Viewport { get; set; }
+ public static GUI.Control FocusedControl = null;
+
+ public static void LayoutUpdate()
+ {
+ foreach (var toplevel in topLevels.ToArray())
+ toplevel.Layout();
+ }
+
+ public static void Animate(object owner, System.Reflection.PropertyInfo prop, double from, double to, int timeMs)
+ {
+ var t = new System.Threading.Thread(() =>
+ {
+ for(int i = 0; i < timeMs; i++)
+ {
+ double value = ProgressBar.linear(i, 0, timeMs, from, to);
+ prop.SetValue(owner, value);
+ System.Threading.Thread.Sleep(1);
+ }
+ });
+ t.IsBackground = true;
+ t.Start();
+ }
+
+ public static Dictionary<int, RenderTarget2D> TextureCaches = new Dictionary<int, RenderTarget2D>();
+
+ public static void DrawTArgets(SpriteBatch batch)
+ {
+ foreach(var ctrl in topLevels.ToArray())
+ {
+ if (ctrl.Visible == true)
+ {
+ int hc = ctrl.GetHashCode();
+ if (!TextureCaches.ContainsKey(hc))
+ {
+ ctrl.Invalidate();
+ continue;
+ }
+ var _target = TextureCaches[hc];
+ if (ExperimentalEffects)
+ {
+ for (int i = 5; i > 0; i--)
+ {
+ batch.Draw(_target, new Rectangle(ctrl.X - i, ctrl.Y - i, ctrl.Width+(i*2), ctrl.Height+(i*2)), new Color(Color.Black, 255 / (i * 2)));
+ }
+ }
+
+ batch.Draw(_target, new Rectangle(ctrl.X, ctrl.Y, ctrl.Width, ctrl.Height), Color.White);
+ }
+ }
+ }
+
+ public static void SendToBack(Control ctrl)
+ {
+ topLevels.Remove(ctrl);
+ topLevels.Insert(0, ctrl);
+ }
+
+ public static void DrawControlsToTargets(GraphicsDevice graphics, SpriteBatch batch, int width, int height)
+ {
+ foreach (var ctrl in topLevels.ToArray().Where(x=>x.Visible==true))
+ {
+ RenderTarget2D _target;
+ int hc = ctrl.GetHashCode();
+ if (!TextureCaches.ContainsKey(hc))
+ {
+ _target = new RenderTarget2D(
+ graphics,
+ ctrl.Width,
+ ctrl.Height,
+ false,
+ graphics.PresentationParameters.BackBufferFormat,
+ DepthFormat.Depth24);
+ TextureCaches.Add(hc, _target);
+ }
+ else
+ {
+ _target = TextureCaches[hc];
+ if(_target.Width != ctrl.Width || _target.Height != ctrl.Height)
+ {
+ _target = new RenderTarget2D(
+ graphics,
+ ctrl.Width,
+ ctrl.Height,
+ false,
+ graphics.PresentationParameters.BackBufferFormat,
+ DepthFormat.Depth24);
+ TextureCaches[hc] = _target;
+
+ }
+ }
+ if (ctrl.RequiresPaint)
+ {
+ graphics.SetRenderTarget(_target);
+ graphics.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
+ batch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied,
+ SamplerState.LinearClamp, DepthStencilState.Default,
+ RasterizerState.CullNone);
+ graphics.Clear(Color.Transparent);
+ var gfxContext = new GraphicsContext(graphics, batch, 0, 0, _target.Width, _target.Height);
+ ctrl.Paint(gfxContext);
+
+ graphics.SetRenderTarget(null);
+ TextureCaches[hc] = _target;
+ batch.End();
+ }
+ }
+ }
+
+ public static void AddTopLevel(GUI.Control ctrl)
+ {
+ if (!topLevels.Contains(ctrl))
+ topLevels.Add(ctrl);
+ ctrl.Layout();
+ }
+
+ public static void InvalidateAll()
+ {
+ foreach(var ctrl in topLevels)
+ {
+ ctrl.Invalidate();
+ }
+ }
+
+ public static void ProcessMouseState(MouseState state)
+ {
+ foreach(var ctrl in topLevels.ToArray())
+ {
+ ctrl.ProcessMouseState(state);
+ }
+ }
+
+ public static void ProcessKeyEvent(KeyEvent e)
+ {
+ if (e.ControlDown && e.Key == Keys.T)
+ {
+ AppearanceManager.SetupWindow(new Apps.Terminal());
+ return;
+ }
+ FocusedControl?.ProcessKeyEvent(e);
+ }
+
+ private static Texture2D DesktopBackground = null;
+
+ public static Dictionary<string, Texture2D> SkinTextures = new Dictionary<string, Texture2D>();
+
+ public static void ResetSkinTextures(GraphicsDevice graphics)
+ {
+ SkinTextures.Clear();
+ foreach(var byteArray in SkinEngine.LoadedSkin.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(x=>x.FieldType == typeof(byte[])))
+ {
+ var imgAttrib = byteArray.GetCustomAttributes(false).FirstOrDefault(x => x is ImageAttribute) as ImageAttribute;
+ if(imgAttrib != null)
+ {
+ var img = SkinEngine.GetImage(imgAttrib.Name);
+ if(img != null)
+ {
+ var bmp = (System.Drawing.Bitmap)img;
+ var lck = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ var data = new byte[Math.Abs(lck.Stride) * lck.Height];
+ Marshal.Copy(lck.Scan0, data, 0, data.Length);
+ bmp.UnlockBits(lck);
+ var tex2 = new Texture2D(graphics, bmp.Width, bmp.Height);
+ for(int i = 0; i < data.Length; i += 4)
+ {
+ byte r = data[i];
+ byte b = data[i + 2];
+ if (r == 1 && b == 1 && data[i + 1] == 1)
+ {
+ data[i + 3] = 0;
+ }
+ data[i] = b;
+ data[i + 2] = r;
+ }
+ tex2.SetData<byte>(data);
+ SkinTextures.Add(imgAttrib.Name, tex2);
+ }
+ }
+ }
+
+ foreach(var colorfield in SkinEngine.LoadedSkin.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).Where(x=>x.FieldType == typeof(System.Drawing.Color)))
+ {
+ var color = (System.Drawing.Color)colorfield.GetValue(SkinEngine.LoadedSkin);
+ var tex2 = new Texture2D(graphics, 1, 1);
+ tex2.SetData<byte>(new[] { color.R, color.G, color.B, color.A });
+ SkinTextures.Add(colorfield.Name, tex2);
+ }
+
+
+
+ }
+
+
+ public static bool ExperimentalEffects = true;
+
+ public static Queue<Action> CrossThreadOperations = new Queue<Action>();
+ internal static GraphicsDevice GraphicsDevice;
+
+ public static void DrawBackgroundLayer(GraphicsDevice graphics, SpriteBatch batch, int width, int height)
+ {
+ if (SkinEngine.LoadedSkin == null)
+ SkinEngine.Init();
+ graphics.Clear(SkinEngine.LoadedSkin.DesktopColor.ToMonoColor());
+ if (SkinTextures.ContainsKey("desktopbackground"))
+ {
+ batch.Draw(SkinTextures["desktopbackground"], new Rectangle(0, 0, Viewport.Width, Viewport.Height), Color.White);
+ }
+ }
+
+ public static Color ToMonoColor(this System.Drawing.Color color)
+ {
+ return new Color(color.R, color.G, color.B, color.A);
+ }
+
+ internal static void StopHandling(GUI.Control ctrl)
+ {
+ if (topLevels.Contains(ctrl))
+ topLevels.Remove(ctrl);
+
+ int hc = ctrl.GetHashCode();
+ if (TextureCaches.ContainsKey(hc))
+ {
+ TextureCaches[hc].Dispose();
+ TextureCaches.Remove(hc);
+ }
+
+ ctrl = null;
+ }
+ }
+
+ public class KeyEvent
+ {
+ public KeyEvent(bool control, bool alt, bool shift, Keys key)
+ {
+ ControlDown = control;
+ AltDown = alt;
+ ShiftDown = shift;
+ Key = key;
+ KeyChar = key.ToCharacter(shift);
+ }
+
+ public bool ControlDown { get; private set; }
+ public bool AltDown { get; private set; }
+ public bool ShiftDown { get; set; }
+ public Keys Key { get; private set; }
+
+ public char KeyChar { get; private set; }
+ }
+
+ public static class KeysExtensions
+ {
+ public static char ToCharacter(this Keys key, bool shift)
+ {
+ char c = '\0';
+ switch (key)
+ {
+ case Keys.Space:
+ c = ' ';
+ break;
+ case Keys.A:
+ c = 'a';
+ break;
+ case Keys.B:
+ c = 'b';
+ break;
+ case Keys.C:
+ c = 'c';
+ break;
+ case Keys.D:
+ c = 'd';
+ break;
+ case Keys.E:
+ c = 'e';
+ break;
+ case Keys.F:
+ c = 'f';
+ break;
+ case Keys.G:
+ c = 'g';
+ break;
+ case Keys.H:
+ c = 'h';
+ break;
+ case Keys.I:
+ c = 'i';
+ break;
+ case Keys.J:
+ c = 'j';
+ break;
+ case Keys.K:
+ c = 'k';
+ break;
+ case Keys.L:
+ c = 'l';
+ break;
+ case Keys.M:
+ c = 'm';
+ break;
+ case Keys.N:
+ c = 'n';
+ break;
+ case Keys.O:
+ c = 'o';
+ break;
+ case Keys.P:
+ c = 'p';
+ break;
+ case Keys.Q:
+ c = 'q';
+ break;
+ case Keys.R:
+ c = 'r';
+ break;
+ case Keys.S:
+ c = 's';
+ break;
+ case Keys.T:
+ c = 't';
+ break;
+ case Keys.U:
+ c = 'u';
+ break;
+ case Keys.V:
+ c = 'v';
+ break;
+ case Keys.W:
+ c = 'w';
+ break;
+ case Keys.X:
+ c = 'x';
+ break;
+ case Keys.Y:
+ c = 'y';
+ break;
+ case Keys.Z:
+ c = 'z';
+ break;
+ case Keys.D0:
+ if (shift)
+ c = ')';
+ else
+ c = '0';
+ break;
+ case Keys.D1:
+ if (shift)
+ c = '!';
+ else
+ c = '1';
+ break;
+ case Keys.D2:
+ if (shift)
+ c = '@';
+ else
+ c = '2';
+ break;
+ case Keys.D3:
+ if (shift)
+ c = '#';
+ else
+ c = '3';
+ break;
+ case Keys.D4:
+ if (shift)
+ c = '$';
+ else
+ c = '4';
+ break;
+ case Keys.D5:
+ if (shift)
+ c = '%';
+ else
+ c = '5';
+ break;
+ case Keys.D6:
+ if (shift)
+ c = '^';
+ else
+ c = '6';
+ break;
+ case Keys.D7:
+ if (shift)
+ c = '&';
+ else
+ c = '7';
+ break;
+ case Keys.D8:
+ if (shift)
+ c = '*';
+ else
+ c = '8';
+ break;
+ case Keys.D9:
+ if (shift)
+ c = '(';
+ else
+ c = '9';
+ break;
+ case Keys.OemBackslash:
+ if (shift)
+ c = '|';
+ else
+ c = '\\';
+ break;
+ case Keys.OemCloseBrackets:
+ if (shift)
+ c = '}';
+ else
+ c = ']';
+ break;
+ case Keys.OemComma:
+ if (shift)
+ c = '<';
+ else
+ c = ',';
+ break;
+ case Keys.OemPeriod:
+ if (shift)
+ c = '>';
+ else
+ c = '.';
+ break;
+ case Keys.OemQuestion:
+ if (shift)
+ c = '?';
+ else
+ c = '/';
+ break;
+ case Keys.OemSemicolon:
+ if (shift)
+ c = ':';
+ else
+ c = ';';
+ break;
+ case Keys.OemQuotes:
+ if (shift)
+ c = '"';
+ else
+ c = '\'';
+ break;
+ case Keys.OemTilde:
+ if (shift)
+ c = '~';
+ else
+ c = '`';
+ break;
+ case Keys.OemMinus:
+ if (shift)
+ c = '_';
+ else
+ c = '-';
+ break;
+ case Keys.OemPlus:
+ if (shift)
+ c = '+';
+ else
+ c = '=';
+ break;
+ }
+ if (char.IsLetter(c))
+ if (shift)
+ c = char.ToUpper(c);
+ return c;
+ }
+ }
+}