This repository has been archived on 2025-01-01. You can view files and clone it, but cannot push or open issues or pull requests.
ShiftOS_TheReturn/ShiftOS.Frontend/Apps/Terminal.cs

402 lines
13 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
2017-07-04 09:52:49 -04:00
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
2017-07-04 09:52:49 -04:00
using System.Text.RegularExpressions;
using System.Threading.Tasks;
2017-07-04 09:52:49 -04:00
using Microsoft.Xna.Framework.Input;
using ShiftOS.Engine;
using ShiftOS.Frontend.GraphicsSubsystem;
using static ShiftOS.Engine.SkinEngine;
namespace ShiftOS.Frontend.Apps
{
[FileHandler("Shell script", ".trm", "fileicontrm")]
[Launcher("{TITLE_TERMINAL}", false, null, "{AL_UTILITIES}")]
[WinOpen("{WO_TERMINAL}")]
[DefaultTitle("{TITLE_TERMINAL}")]
[DefaultIcon("iconTerminal")]
public class Terminal : GUI.Control, IShiftOSWindow
{
private TerminalControl _terminal = null;
public Terminal()
{
Width = 493;
Height = 295;
}
public void OnLoad()
{
_terminal = new Apps.TerminalControl();
_terminal.Dock = GUI.DockStyle.Fill;
AddControl(_terminal);
_terminal.Layout();
AppearanceManager.ConsoleOut = _terminal;
AppearanceManager.StartConsoleOut();
TerminalBackend.PrintPrompt();
SaveSystem.GameReady += () =>
{
if (Shiftorium.UpgradeInstalled("desktop"))
{
AppearanceManager.Close(this);
}
else
TerminalBackend.PrintPrompt();
};
}
protected override void OnLayout()
{
if (ContainsFocusedControl || IsFocusedControl)
AppearanceManager.ConsoleOut = _terminal;
}
public void OnSkinLoad()
{
}
public bool OnUnload()
{
return true;
}
public void OnUpgrade()
{
}
}
public class TerminalControl : GUI.TextInput, ITerminalWidget
{
2017-07-04 09:52:49 -04:00
public TerminalControl()
{
Dock = GUI.DockStyle.Fill;
}
public string[] Lines
{
get
{
2017-07-04 09:52:49 -04:00
return Text.Split(new[] { "\r\n" }, StringSplitOptions.None);
}
}
public void Clear()
{
Text = "";
Index = 0;
_vertOffset = 0;
Invalidate();
}
public void SelectBottom()
{
Index = Text.Length - 1;
RecalculateLayout();
InvalidateTopLevel();
}
public void Write(string text)
{
Engine.Desktop.InvokeOnWorkerThread(() =>
{
Text += Localization.Parse(text);
SelectBottom();
Index += text.Length;
RecalculateLayout();
InvalidateTopLevel();
});
}
public void WriteLine(string text)
{
Write(text + Environment.NewLine);
}
public int GetCurrentLine()
{
int line = 0;
for(int i = 0; i < Text.Length; i++)
{
if(Text[i]=='\n')
{
line++;
continue;
}
if (i == Index)
return line;
}
return 0;
}
float _vertOffset = 0.0f;
protected void RecalculateLayout()
{
if(!string.IsNullOrEmpty(Text))
using (var gfx = Graphics.FromImage(new Bitmap(1, 1)))
{
var cursorpos = GetPointAtIndex(gfx);
var caretSize = gfx.SmartMeasureString(Text.ToString(), LoadedSkin.TerminalFont, Width - 4);
2017-07-04 09:52:49 -04:00
float initial = (((float)Math.Floor(caretSize.Height)) + cursorpos.Y) - _vertOffset;
if (initial < 0)
{
float difference = initial - Height;
2017-07-04 09:52:49 -04:00
_vertOffset = initial + difference;
}
if (initial > Height)
{
float difference = initial - Height;
2017-07-04 09:52:49 -04:00
_vertOffset = initial - difference;
}
}
}
2017-07-04 09:52:49 -04:00
protected override void OnLayout()
{
}
/// <summary>
/// Gets the X and Y coordinates (in pixels) of the caret.
/// </summary>
/// <param name="gfx">A <see cref="System.Drawing.Graphics"/> object used for font measurements</param>
/// <returns>An absolute fucking mess. Seriously, can someone fix this method so it uhh WORKS PROPERLY?</returns>
2017-07-04 09:52:49 -04:00
public Point GetPointAtIndex(Graphics gfx)
{
2017-07-04 09:52:49 -04:00
int vertMeasure = 2;
int horizMeasure = 2;
var textSize = gfx.SmartMeasureString(Text, LoadedSkin.TerminalFont, Width - 4);
int lineindex = 0;
int line = GetCurrentLine();
for (int l = 0; l < line; l++)
2017-07-04 09:52:49 -04:00
{
lineindex += Lines[l].Length;
var stringMeasure = gfx.SmartMeasureString(Lines[l], LoadedSkin.TerminalFont, Width - 4);
vertMeasure += (int)stringMeasure.Height;
2017-07-04 09:52:49 -04:00
}
var lnMeasure = gfx.SmartMeasureString(Text.Substring(lineindex, Index - lineindex), LoadedSkin.TerminalFont);
int w = (int)Math.Floor(lnMeasure.Width);
if (w > Width - 4)
w = w - (Width - 4);
horizMeasure = w;
2017-07-04 09:52:49 -04:00
return new Point(horizMeasure, vertMeasure);
}
private PointF CaretPosition = new PointF(2, 2);
private Size CaretSize = new Size(2, 15);
2017-07-04 09:52:49 -04:00
protected override void OnKeyEvent(KeyEvent a)
{
2017-07-04 09:52:49 -04:00
if (a.Key == Keys.Enter)
{
2017-07-04 09:52:49 -04:00
try
{
if (!TerminalBackend.PrefixEnabled)
{
string textraw = Lines[Lines.Length - 1];
TerminalBackend.SendText(textraw);
return;
}
var text = Lines;
var text2 = text[text.Length - 1];
var text3 = "";
var text4 = Regex.Replace(text2, @"\t|\n|\r", "");
WriteLine("");
2017-07-04 09:52:49 -04:00
{
if (TerminalBackend.PrefixEnabled)
{
text3 = text4.Remove(0, $"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ".Length);
}
TerminalBackend.LastCommand = text3;
TerminalBackend.SendText(text4);
if (TerminalBackend.InStory == false)
{
{
var result = SkinEngine.LoadedSkin.CurrentParser.ParseCommand(text3);
if (result.Equals(default(KeyValuePair<string, Dictionary<string, string>>)))
{
Console.WriteLine("{ERR_SYNTAXERROR}");
}
else
{
TerminalBackend.InvokeCommand(result.Key, result.Value);
}
}
}
if (TerminalBackend.PrefixEnabled)
{
TerminalBackend.PrintPrompt();
}
}
}
catch
{
}
}
else if (a.Key == Keys.Back)
{
try
{
var tostring3 = Lines[Lines.Length - 1];
var tostringlen = tostring3.Length + 1;
var workaround = $"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ";
var derp = workaround.Length + 1;
if (tostringlen != derp)
{
AppearanceManager.CurrentPosition--;
base.OnKeyEvent(a);
RecalculateLayout();
InvalidateTopLevel();
}
}
catch
{
Debug.WriteLine("Drunky alert in terminal.");
}
}
else if (a.Key == Keys.Left)
{
if (SaveSystem.CurrentSave != null)
{
var getstring = Lines[Lines.Length - 1];
var stringlen = getstring.Length + 1;
var header = $"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ";
var headerlen = header.Length + 1;
var selstart = Index;
var remstrlen = Text.Length - stringlen;
var finalnum = selstart - remstrlen;
if (finalnum != headerlen)
{
AppearanceManager.CurrentPosition--;
base.OnKeyEvent(a);
}
}
}
else if (a.Key == Keys.Up)
{
var tostring3 = Lines[Lines.Length - 1];
if (tostring3 == $"{SaveSystem.CurrentUser.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ")
Console.Write(TerminalBackend.LastCommand);
ConsoleEx.OnFlush?.Invoke();
return;
}
else
{
if (TerminalBackend.InStory)
{
return;
}
if (a.KeyChar != '\0')
{
Text = Text.Insert(Index, a.KeyChar.ToString());
Index++;
2017-07-04 09:52:49 -04:00
AppearanceManager.CurrentPosition++;
// RecalculateLayout();
2017-07-04 09:52:49 -04:00
InvalidateTopLevel();
}
}
}
protected override void OnPaint(GraphicsContext gfx)
2017-07-04 09:52:49 -04:00
{
gfx.Clear(LoadedSkin.TerminalBackColorCC.ToColor().ToMonoColor());
if (!string.IsNullOrEmpty(Text))
{
//Draw the caret.
if (IsFocusedControl)
{
// gfx.FillRectangle(new SolidBrush(LoadedSkin.TerminalForeColorCC.ToColor()), new RectangleF(new PointF(CaretPosition.X, CaretPosition.Y - _vertOffset), new SizeF(2, CaretSize.Height)));
}//Draw the text
gfx.DrawString(Text, 2, 2 - (int)Math.Floor(_vertOffset), LoadedSkin.TerminalForeColorCC.ToColor().ToMonoColor(), LoadedSkin.TerminalFont, Width - 4);
}
}
}
public static class ConsoleColorExtensions
{
public static Color ToColor(this ConsoleColor cc)
{
switch (cc)
{
case ConsoleColor.Black:
return Color.Black;
case ConsoleColor.Blue:
return Color.Blue;
case ConsoleColor.Cyan:
return Color.Cyan;
case ConsoleColor.DarkBlue:
return Color.DarkBlue;
case ConsoleColor.DarkCyan:
return Color.DarkCyan;
case ConsoleColor.DarkGray:
return Color.DarkGray;
case ConsoleColor.DarkGreen:
return Color.DarkGreen;
case ConsoleColor.DarkMagenta:
return Color.DarkMagenta;
case ConsoleColor.DarkRed:
return Color.DarkRed;
case ConsoleColor.DarkYellow:
return Color.Orange;
case ConsoleColor.Gray:
return Color.Gray;
case ConsoleColor.Green:
return Color.Green;
case ConsoleColor.Magenta:
return Color.Magenta;
case ConsoleColor.Red:
return Color.Red;
case ConsoleColor.White:
return Color.White;
case ConsoleColor.Yellow:
return Color.Yellow;
}
return Color.Empty;
}
}
public static class GraphicsExtensions
{
public static SizeF SmartMeasureString(this Graphics gfx, string s, Font font, int width)
{
if (string.IsNullOrEmpty(s))
s = " ";
var textformat = new StringFormat(StringFormat.GenericTypographic);
textformat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
textformat.Trimming = StringTrimming.None;
2017-07-04 09:52:49 -04:00
var measure = gfx.MeasureString(s, font, width, textformat);
return new SizeF((float)Math.Ceiling(measure.Width), (float)Math.Ceiling(measure.Height));
}
public static SizeF SmartMeasureString(this Graphics gfx, string s, Font font)
{
if (string.IsNullOrEmpty(s))
s = " ";
var textformat = new StringFormat(StringFormat.GenericTypographic);
textformat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
textformat.Trimming = StringTrimming.None;
2017-07-04 09:52:49 -04:00
var measure = gfx.MeasureString(s, font, int.MaxValue, textformat);
return new SizeF((float)Math.Ceiling(measure.Width), (float)Math.Floor(measure.Height));
}
}
}