mirror of
https://git.alee14.me/shiftos-archive/ShiftOS_TheReturn.git
synced 2025-01-22 18:02:16 +00:00
HELP ME. I can't get autoscroll working in terminall.
This commit is contained in:
parent
23e622ffc3
commit
d23c5cc29d
9 changed files with 345 additions and 10 deletions
274
ShiftOS.Frontend/Apps/Terminal.cs
Normal file
274
ShiftOS.Frontend/Apps/Terminal.cs
Normal file
|
@ -0,0 +1,274 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
public string[] Lines
|
||||
{
|
||||
get
|
||||
{
|
||||
return Text.Split(new[] { "\n" }, StringSplitOptions.None);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Text = "";
|
||||
Index = 0;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public void SelectBottom()
|
||||
{
|
||||
Index = Text.Length - 1;
|
||||
RecalculateLayout();
|
||||
InvalidateTopLevel();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
Engine.Desktop.InvokeOnWorkerThread(() =>
|
||||
{
|
||||
SelectBottom();
|
||||
Text = Text.Insert(Index, text);
|
||||
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);
|
||||
float initial = ((caretSize.Height) - cursorpos.Y) - _vertOffset;
|
||||
if (initial < 0)
|
||||
{
|
||||
float difference = initial - Height;
|
||||
_vertOffset += initial + difference;
|
||||
}
|
||||
if (initial > Height)
|
||||
{
|
||||
float difference = initial - Height;
|
||||
_vertOffset -= initial - difference;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public PointF GetPointAtIndex(Graphics gfx)
|
||||
{
|
||||
float vertMeasure = 2.0f;
|
||||
float horizMeasure = 2.0f;
|
||||
int lineindexes = 0;
|
||||
for (int l = 0; l <= GetCurrentLine(); l++)
|
||||
{
|
||||
var measure = gfx.SmartMeasureString(Lines[l], LoadedSkin.TerminalFont, Width - 4);
|
||||
vertMeasure += measure.Width;
|
||||
if(l == GetCurrentLine())
|
||||
{
|
||||
string _linetext = Text.Substring(lineindexes, Index - lineindexes);
|
||||
var lMeasure = gfx.SmartMeasureString(_linetext, LoadedSkin.TerminalFont);
|
||||
horizMeasure = lMeasure.Width;
|
||||
if (horizMeasure > Width - 4)
|
||||
horizMeasure -= (Width-4);
|
||||
}
|
||||
else
|
||||
{
|
||||
lineindexes += Lines[l].Length;
|
||||
}
|
||||
}
|
||||
return new PointF(horizMeasure, vertMeasure);
|
||||
}
|
||||
|
||||
protected override void OnKeyEvent(KeyEvent e)
|
||||
{
|
||||
if (e.Key == Microsoft.Xna.Framework.Input.Keys.Enter)
|
||||
{
|
||||
Text = Text.Insert(Index, "\r\n");
|
||||
Index++;
|
||||
}
|
||||
base.OnKeyEvent(e);
|
||||
RecalculateLayout();
|
||||
InvalidateTopLevel();
|
||||
}
|
||||
|
||||
protected override void OnPaint(Graphics gfx)
|
||||
{
|
||||
RecalculateLayout();
|
||||
gfx.Clear(LoadedSkin.TerminalBackColorCC.ToColor());
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
//Draw the caret.
|
||||
var caretPos = GetPointAtIndex(gfx);
|
||||
var caretSize = gfx.SmartMeasureString(Text[Index - 1].ToString(), LoadedSkin.TerminalFont);
|
||||
if (IsFocusedControl)
|
||||
{
|
||||
gfx.FillRectangle(new SolidBrush(LoadedSkin.TerminalForeColorCC.ToColor()), new RectangleF(new PointF(caretPos.X, caretPos.Y - _vertOffset), new SizeF(2, caretSize.Height)));
|
||||
}//Draw the text
|
||||
var textMeasure = gfx.MeasureString(Text, LoadedSkin.TerminalFont, Width - 4);
|
||||
gfx.DrawString(Text, LoadedSkin.TerminalFont, new SolidBrush(LoadedSkin.TerminalForeColorCC.ToColor()), 2, 2 - _vertOffset);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
return gfx.MeasureString(s, font, width, textformat);
|
||||
}
|
||||
|
||||
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;
|
||||
return gfx.MeasureString(s, font, int.MaxValue, textformat);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ShiftOS.Engine;
|
||||
using ShiftOS.Frontend.GraphicsSubsystem;
|
||||
|
||||
namespace ShiftOS.Frontend.Desktop
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ namespace ShiftOS.Frontend.Desktop
|
|||
|
||||
public void InvokeOnWorkerThread(Action act)
|
||||
{
|
||||
act?.Invoke();
|
||||
UIManager.CrossThreadOperations.Enqueue(act);
|
||||
}
|
||||
|
||||
public void KillWindow(IWindowBorder border)
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ShiftOS.Frontend.Desktop
|
|||
|
||||
public override void InvokeAction(Action act)
|
||||
{
|
||||
act?.Invoke();
|
||||
UIManager.CrossThreadOperations.Enqueue(act);
|
||||
}
|
||||
|
||||
public override void Maximize(IWindowBorder border)
|
||||
|
|
|
@ -92,7 +92,6 @@ namespace ShiftOS.Frontend.GUI
|
|||
|
||||
}
|
||||
|
||||
base.OnPaint(gfx);
|
||||
gfx.DrawString(_text, _font, new SolidBrush(Engine.SkinEngine.LoadedSkin.ControlTextColor), new RectangleF(loc.X, loc.Y, sMeasure.Width, sMeasure.Height));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,48 @@ namespace ShiftOS.Frontend.GUI
|
|||
private int _index = 0;
|
||||
private Font _font = new 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 - 1);
|
||||
if (_text[_index] == '\n')
|
||||
_index++;
|
||||
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)
|
||||
|
|
|
@ -85,6 +85,8 @@ namespace ShiftOS.Frontend.GraphicsSubsystem
|
|||
|
||||
private static Texture2D DesktopBackground = null;
|
||||
|
||||
public static Queue<Action> CrossThreadOperations = new Queue<Action>();
|
||||
|
||||
public static void DrawBackgroundLayer(GraphicsDevice graphics, SpriteBatch batch, int width, int height)
|
||||
{
|
||||
if (SkinEngine.LoadedSkin == null)
|
||||
|
|
|
@ -79,10 +79,15 @@ namespace ShiftOS.Frontend
|
|||
|
||||
public void ShowText(Action<string> callback)
|
||||
{
|
||||
Title = "Not yet implemented.";
|
||||
lbmessage.Text = "This feature hasn't yet been implemented.";
|
||||
ShowPrompt(null);
|
||||
|
||||
AppearanceManager.SetupDialog(this);
|
||||
flyesno.Visible = false;
|
||||
btnok.Visible = true;
|
||||
txtinput.Visible = true;
|
||||
btnok.Click += () =>
|
||||
{
|
||||
callback?.Invoke(txtinput.Text);
|
||||
AppearanceManager.Close(this);
|
||||
};
|
||||
}
|
||||
|
||||
public void OnSkinLoad()
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Apps\Terminal.cs" />
|
||||
<Compile Include="Desktop\Desktop.cs" />
|
||||
<Compile Include="Desktop\WindowManager.cs" />
|
||||
<Compile Include="GraphicsSubsystem\UIManager.cs" />
|
||||
|
|
|
@ -113,10 +113,15 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type
|
|||
statslabel.Layout();
|
||||
};
|
||||
|
||||
//We'll use sandbox mode
|
||||
SaveSystem.IsSandbox = true;
|
||||
TerminalBackend.TerminalRequested += () =>
|
||||
{
|
||||
AppearanceManager.SetupWindow(new Apps.Terminal());
|
||||
};
|
||||
|
||||
SaveSystem.Begin();
|
||||
//We'll use sandbox mode
|
||||
SaveSystem.IsSandbox = false;
|
||||
|
||||
SaveSystem.Begin(true);
|
||||
|
||||
var textinput = new GUI.TextInput();
|
||||
textinput.Width = 250;
|
||||
|
@ -174,6 +179,12 @@ Reflection manager found {ReflectMan.Types.Count()} Common Language Runtime type
|
|||
/// <param name="gameTime">Provides a snapshot of timing values.</param>
|
||||
protected override void Update(GameTime gameTime)
|
||||
{
|
||||
if (UIManager.CrossThreadOperations.Count > 0)
|
||||
{
|
||||
var action = UIManager.CrossThreadOperations.Dequeue();
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
//Let's get the mouse state
|
||||
var mouseState = Mouse.GetState(this.Window);
|
||||
|
||||
|
|
Loading…
Reference in a new issue