scrolling + proper anchoring

This commit is contained in:
GoaLitiuM
2021-03-13 23:05:45 +02:00
parent e2d7fbd40a
commit 7973daf799
7 changed files with 182 additions and 118 deletions

View File

@@ -40,8 +40,8 @@
"V": {
"Order": -999999999,
"Size": {
"X": 1439.0,
"Y": 818.0
"X": 1456.0,
"Y": 813.0
}
}
},
@@ -52,6 +52,7 @@
"V": {
"ConsoleHeight": 0.635,
"ConsoleFont": "43f32bec443158643f53699f07b2e09c",
"BackgroundTexture": "16a2d3f1465e834c8ac965bd072c1dca",
"BackgroundColor": {
"R": 0.0,
"G": 0.0,
@@ -69,7 +70,7 @@
"Transform": {
"Translation": {
"X": -82.89323425292969,
"Y": 108.37522888183594,
"Y": 111.32740783691406,
"Z": 114.5750503540039
}
},
@@ -99,7 +100,7 @@
"Transform": {
"Translation": {
"X": 0.0,
"Y": 22.328903198242189,
"Y": 28.7337646484375,
"Z": 0.0
}
},
@@ -137,8 +138,8 @@
},
"V": {
"Size": {
"X": 1439.0,
"Y": 818.0
"X": 1456.0,
"Y": 813.0
}
}
},
@@ -158,13 +159,13 @@
"Transform": {
"Translation": {
"X": 0.0,
"Y": 738.0,
"Y": 733.0,
"Z": 0.0
}
},
"Control": "FlaxEngine.GUI.Label",
"Data": {
"Text": "FPS: 690\nrFPS: 690\nCon: NaNms\nDirectX11\nGC memory: 6.903736MB",
"Text": "FPS: 15\nrFPS: 11\nCon: NaNms\nDirectX11\nGC memory: 13.52053MB",
"TextColor": {
"R": 1.0,
"G": 1.0,

View File

@@ -183,9 +183,9 @@ namespace Cabrito
OnClose -= instance.OnConsoleClose;
}
public static IReadOnlyCollection<string> GetLines()
public static IReadOnlyCollection<string> Lines
{
return consoleLines.AsReadOnly();
get => consoleLines.AsReadOnly();
}
// Echoes text to Console.

View File

@@ -22,6 +22,10 @@ namespace Cabrito
{
}
public ConsoleContainerControl(Rectangle bounds) : base(bounds)
{
}
public override void OnGotFocus()
{
base.OnGotFocus();

View File

@@ -11,6 +11,13 @@ namespace Cabrito
{
public class ConsoleContentTextBox : Control
{
struct LineInfo
{
public int lineIndex;
public int lineOffset;
public int lineLength;
}
[HideInEditor]
public ConsoleInputTextBox inputBox;
@@ -30,20 +37,32 @@ namespace Cabrito
public Color BorderColor;
public Color TextColor = Color.White;
public int DefaultMargin = 1;
public int ScrollOffset = 0;
public int ScrollMouseLines = 3;
private Vector2 scrollOffset = new Vector2(0);
private float heightMultiplier = 1.0f;
public float HeightMultiplier
{
get => heightMultiplier;
set
{
heightMultiplier = value;
Height = Screen.Size.Y * HeightMultiplier;
}
}
private int selectionStartLine = 0;
private int selectionStartChar = 0;
private int selectionEndLine = 0;
private int selectionEndChar = 0;
private bool selectionActive;
public bool HasSelection => !(selectionStartLine == selectionEndLine && selectionStartChar == selectionEndChar);
public ConsoleContentTextBox() : base()
{
}
public ConsoleContentTextBox(ConsoleInputTextBox inputBox, float x, float y, float width, float height) : base(x, y, width, height)
@@ -55,6 +74,7 @@ namespace Cabrito
_layout.VerticalAlignment = TextAlignment.Near;
_layout.TextWrapping = TextWrapping.WrapChars;
_layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2);
//IsMultiline = true;
//IsReadOnly = true;
@@ -62,6 +82,14 @@ namespace Cabrito
AutoFocus = false;
}
private int GetFontCharacterWidth()
{
var font = Font.GetFont();
if (!font)
return 0;
return (int)font.MeasureText("a").X; // hacky, but works for fixed-size fonts...
}
public int GetFontHeight()
{
var font = Font.GetFont();
@@ -71,13 +99,22 @@ namespace Cabrito
return (int)Mathf.Round(LineSpacing * (font.Height / Platform.DpiScale) * Scale.Y);
}
struct LineInfo
private int GetHeightInLines()
{
public int lineIndex;
public int lineOffset;
public int lineLength;
var font = Font.GetFont();
if (!font)
return 0;
return (int)(Height / (font.Height / Platform.DpiScale)); // number of fully visible lines
}
public override void OnParentResized()
{
Height = Screen.Size.Y * HeightMultiplier;
base.OnParentResized();
}
private void CalculateVisibleLines(IReadOnlyCollection<string> lines, out int firstVisibleLine, out int lastVisibleLine, out LineInfo[] wrappedLines)
{
wrappedLines = null;
@@ -88,14 +125,21 @@ namespace Cabrito
if (!font)
return;
float fontWidth = (int)font.MeasureText("a").X; // hacky, but works for fixed-size fonts...
float fontWidth = GetFontCharacterWidth();
int lineMaxChars = (int)(Width / fontWidth);
int lineMaxLines = (int)(Height / (font.Height / Platform.DpiScale)); // number of fully visible lines
int lineMaxLines = GetHeightInLines();
int numLines = 0;
int lineIndex = lines.Count - 1;
int lineIndex = lines.Count;
List<LineInfo> lineInfos = new List<LineInfo>(lineMaxLines+1);
int linesSkipped = 0;
foreach (string line in lines.Reverse())
{
lineIndex--;
if (linesSkipped < ScrollOffset)
{
linesSkipped++;
continue;
}
int numChars = 0;
int startIndex = lineInfos.Count;
while (numChars < line.Length)
@@ -111,7 +155,6 @@ namespace Cabrito
if (lineInfos.Count - startIndex > 1)
lineInfos.Reverse(startIndex, lineInfos.Count - startIndex);
numLines++;
lineIndex--;
if (lineInfos.Count > lineMaxLines)
break;
@@ -121,8 +164,8 @@ namespace Cabrito
wrappedLines = lineInfos.ToArray();
//return lines[lines.Count - numLines .. lines.Count]; // C# 8.0...
firstVisibleLine = lines.Count - numLines;
lastVisibleLine = lines.Count;
lastVisibleLine = lineIndex;
firstVisibleLine = lastVisibleLine - numLines;
}
public static double accumDrawTime = 0.0;
@@ -149,7 +192,7 @@ namespace Cabrito
if (borderColor.A > 0.0f)
Render2D.DrawRectangle(rect, borderColor);
var lines = Console.GetLines();
var lines = Console.Lines;
if (lines.Count > 0)
{
@@ -157,51 +200,10 @@ namespace Cabrito
// Apply view offset and clip mask
var textClipRectangle = new Rectangle(1, 1, Width - 2, Height - 2);
Render2D.PushClip(textClipRectangle);
/*bool useViewOffset = !_viewOffset.IsZero;
if (useViewOffset)
Render2D.PushTransform(Matrix3x3.Translation2D(-_viewOffset));*/
// Check if any text is selected to draw selection
//if (HasSelection)
{
/*Vector2 leftEdge = font.GetCharPosition(text, SelectionLeft + TextPrefix.Length, ref _layout);
Vector2 rightEdge = font.GetCharPosition(text, SelectionRight + TextPrefix.Length, ref _layout);
float fontHeight = GetFontHeight();
float spacing = GetRealLineSpacing();
// Draw selection background
float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
alpha = alpha * alpha;
Color selectionColor = SelectionColor * alpha;
int selectedLinesCount = 1 + Mathf.FloorToInt((rightEdge.Y - leftEdge.Y) / fontHeight);
if (selectedLinesCount == 1) // Selected is part of single line
{
Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, rightEdge.X - leftEdge.X, fontHeight);
Render2D.FillRectangle(r1, selectionColor);
}
else // Selected is more than one line
{
float leftMargin = _layout.Bounds.Location.X;
Rectangle r1 = new Rectangle(leftEdge.X, leftEdge.Y, 1000000000, fontHeight);
Render2D.FillRectangle(r1, selectionColor);
for (int i = 3; i <= selectedLinesCount; i++)
{
leftEdge.Y += fontHeight;
Rectangle r = new Rectangle(leftMargin, leftEdge.Y, 1000000000, fontHeight);
Render2D.FillRectangle(r, selectionColor);
}
Rectangle r2 = new Rectangle(leftMargin, rightEdge.Y, rightEdge.X - leftMargin, fontHeight);
Render2D.FillRectangle(r2, selectionColor);
}*/
}
// Make sure lengthy lines are split
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
float lineHeight = font.Height / Platform.DpiScale;
float accumHeight = wrappedLines.Length * lineHeight;
@@ -228,6 +230,7 @@ namespace Cabrito
Color selectionColor = SelectionColor;// * alpha;
TextLayoutOptions layout = _layout;
layout.Bounds = rect;
layout.Bounds.Y -= accumHeight - Height;
//for (int i = startLine; i < lastLine; i++)
foreach (LineInfo li in wrappedLines)
@@ -301,6 +304,7 @@ namespace Cabrito
// render lines
{
TextLayoutOptions layout = _layout;
layout.Bounds = rect;
layout.Bounds.Y -= accumHeight - Height;
foreach (LineInfo li in wrappedLines)
{
@@ -322,10 +326,6 @@ namespace Cabrito
Render2D.FillRectangle(caretBounds, CaretColor * alpha);
}*/
// Restore rendering state
//if (useViewOffset)
// Render2D.PopTransform();
Render2D.PopClip();
}
sw.Stop();
@@ -361,10 +361,11 @@ namespace Cabrito
if (font == null)
return false;
var lines = Console.GetLines();
var lines = Console.Lines;
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
TextLayoutOptions layout = _layout;
layout.Bounds = new Rectangle(0, 0, Size);
float lineHeightNormalized = font.Height;
float lineHeight = lineHeightNormalized / Platform.DpiScale;
float visibleHeight = wrappedLines.Length * lineHeight;
@@ -413,11 +414,43 @@ namespace Cabrito
Copy();
return true;
}
else if (key == KeyboardKeys.PageUp)
{
ScrollOffset += GetHeightInLines() / 2;
var maxOffset = Console.Lines.Count - GetHeightInLines();
if (ScrollOffset > maxOffset)
ScrollOffset = maxOffset;
}
else if (key == KeyboardKeys.PageDown)
{
ScrollOffset -= GetHeightInLines() / 2;
if (ScrollOffset < 0)
ScrollOffset = 0;
}
//else if (ctrlDown && key == KeyboardKeys.A)
// SelectAll();
return base.OnKeyDown(key);
}
public override bool OnMouseWheel(Vector2 location, float delta)
{
if (delta < 0)
{
ScrollOffset -= ScrollMouseLines;
if (ScrollOffset < 0)
ScrollOffset = 0;
}
else if (delta > 0)
{
ScrollOffset += ScrollMouseLines;
var maxOffset = Console.Lines.Count - GetHeightInLines();
if (ScrollOffset > maxOffset)
ScrollOffset = maxOffset;
}
return false;
}
public override bool OnMouseDown(Vector2 location, MouseButton button)
{
bool ret = false;
@@ -427,8 +460,7 @@ namespace Cabrito
ret = true;
}
var lines = Console.GetLines();
if (button == MouseButton.Left && lines.Count > 0)
if (button == MouseButton.Left && Console.Lines.Count > 0)
{
bool selectionStarted = !selectionActive;
Focus();
@@ -512,7 +544,7 @@ namespace Cabrito
selectionRightChar = selectionStartChar;
}
var lines = Console.GetLines();
var lines = Console.Lines;
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
StringBuilder selectedText = new StringBuilder();

View File

@@ -90,6 +90,7 @@ namespace Cabrito
{
Clear();
}
contentBox.ScrollOffset = 0;
return true;
}
else if (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown)

View File

@@ -50,7 +50,6 @@ namespace Cabrito
private UIControl rootControl;
private ConsoleContentTextBox consoleBox;
private ConsoleInputTextBox consoleInputBox;
private Image backgroundImage;
internal InputEvent consoleInputEvent;
@@ -71,49 +70,59 @@ namespace Cabrito
int fontHeight = fontRaw.Height;
// root actor which holds all the elements
var rootContainerControl = new ContainerControl(0, 0, screenSize.X, screenSize.Y);
//var rootContainerControl = new ContainerControl(new Rectangle(0, 0, screenSize.X, screenSize.Y));
var rootContainerControl = new ContainerControl(new Rectangle());
rootContainerControl.SetAnchorPreset(AnchorPresets.StretchAll, false);
rootControl = Actor.AddChild<UIControl>();
rootControl.Name = "ConsoleRoot";
rootControl.Control = rootContainerControl;
if (backgroundImage == null)
{
backgroundImage = new Image(0, 0, consoleSize.X, consoleSize.Y);
if (BackgroundTexture != null)
{
backgroundImage.Brush = new TextureBrush(BackgroundTexture);
}
else
{
backgroundImage.Brush = new SolidColorBrush(BackgroundColor);
backgroundImage.KeepAspectRatio = false;
}
var locationFix = backgroundImage.Location;
var parentControl = rootControl.AddChild<UIControl>();
parentControl.Name = "ConsoleBackground";
parentControl.Control = backgroundImage;
backgroundImage.Location = locationFix; // workaround to UIControl.Control overriding the old position
backgroundImage.Enabled = false;
}
// Create a container that keeps the focus in the input box when clicked outside the console window.
// The container must be created before the content box so interacting with the console lines wont get
// stolen by this container.
var containerControl = new ConsoleContainerControl(0, 0, screenSize.X, screenSize.Y);
var focusControl = rootControl.AddChild<UIControl>();
var containerControl = new ConsoleContainerControl(new Rectangle());
containerControl.SetAnchorPreset(AnchorPresets.StretchAll, false);
/*var focusControl = rootControl.AddChild<UIControl>();
focusControl.Name = "ConsoleInputContainer";
focusControl.Control = containerControl;
focusControl.Control = containerControl;*/
var focusControl = new UIControl()
{
Parent = rootControl,
Name = "ConsoleInputContainer",
Control = containerControl
};
var contentContainer = new VerticalPanel()
{
AutoSize = true,
Margin = Margin.Zero,
Spacing = 0,
Bounds = new Rectangle(),
BackgroundColor = BackgroundColor
};
contentContainer.SetAnchorPreset(AnchorPresets.StretchAll, true);
var contentContainerControl = rootControl.AddChild<UIControl>();
contentContainerControl.Name = "ContentContainer";
contentContainerControl.Control = contentContainer;
{
if (consoleBox == null)
{
consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight);
//consoleBox = new ConsoleContentTextBox(null, 0, 0, consoleSize.X, consoleSize.Y - fontHeight);
consoleBox = new ConsoleContentTextBox(null, 0, 0, 0, 0);
consoleBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false);
//consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight);
consoleBox.Height = consoleSize.Y - fontHeight;
consoleBox.Font = fontReference;
//consoleBox.HorizontalAlignment = TextAlignment.Near;
//consoleBox.VerticalAlignment = TextAlignment.Near;
consoleBox.HeightMultiplier = ConsoleHeight;
consoleBox.Wrapping = TextWrapping.WrapWords;
consoleBox.BackgroundColor = Color.Transparent;
consoleBox.BackgroundSelectedColor = Color.Transparent;
@@ -124,7 +133,7 @@ namespace Cabrito
}
var locationFix = consoleBox.Location;
var parentControl = rootControl.AddChild<UIControl>();
var parentControl = contentContainerControl.AddChild<UIControl>();
parentControl.Name = "ConsoleContent";
parentControl.Control = consoleBox;
consoleBox.Location = locationFix; // workaround to UIControl.Control overriding the old position
@@ -133,7 +142,12 @@ namespace Cabrito
{
if (consoleInputBox == null)
{
consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, consoleSize.Y - fontHeight, consoleSize.X, fontHeight);
//consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, consoleSize.Y - fontHeight, consoleSize.X, fontHeight);
consoleInputBox = new ConsoleInputTextBox(consoleBox, 0, 0, 0, 0);
consoleInputBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, false);
//consoleInputBox.Location = new Vector2(0, consoleSize.Y - fontHeight);
consoleInputBox.Height = fontHeight;
consoleInputBox.Font = fontReference;
consoleBox.inputBox = consoleInputBox;
@@ -147,7 +161,7 @@ namespace Cabrito
containerControl.inputBox = consoleInputBox;
var locationFix = consoleInputBox.Location;
var parentControl = rootControl.AddChild<UIControl>();
var parentControl = contentContainerControl.AddChild<UIControl>();
parentControl.Name = "ConsoleInput";
parentControl.Control = consoleInputBox;
consoleInputBox.Location = locationFix; // workaround to UIControl.Control overriding the old position
@@ -259,8 +273,6 @@ namespace Cabrito
//consoleInputEvent.Triggered -= OnConsoleInputEvent;
consoleInputEvent?.Dispose();
consoleBox?.Dispose();
backgroundImage?.DisposeChildren();
backgroundImage?.Dispose();
Debug.Logger.LogHandler.SendLog -= OnSendLog;
Debug.Logger.LogHandler.SendExceptionLog -= OnSendExceptionLog;
@@ -271,7 +283,21 @@ namespace Cabrito
if (consoleBox == null || consoleInputBox == null)
return;
float fontHeight = consoleBox.GetFontHeight();
//consoleBox.SetAnchorPreset(AnchorPresets.StretchAll, true);
//consoleBox.AnchorMax = new Vector2(1.0f, ConsoleHeight);
Vector2 screenSize = Screen.Size;
Vector2 consoleSize = new Vector2(screenSize.X, screenSize.Y * ConsoleHeight);
//consoleBox.Height = consoleSize.Y - consoleBox.GetFontHeight();
//consoleInputBox.SetAnchorPreset(AnchorPresets.HorizontalStretchTop, true);
//consoleInputBox.Location = new Vector2(0, consoleBox.Bottom);
//Font fontRaw = consoleBox.Font.GetFont();
//consoleBox.Height -= fontRaw.Height;
/*float fontHeight = consoleBox.GetFontHeight();
Vector2 screenSize = Screen.Size;
Vector2 consoleSize = new Vector2(screenSize.X, screenSize.Y * ConsoleHeight);
@@ -279,7 +305,7 @@ namespace Cabrito
consoleInputBox.Location = new Vector2(0, consoleBox.Height);
consoleInputBox.Height = fontHeight;
consoleInputBox.ScrollToCaret();
consoleInputBox.ScrollToCaret();*/
}
private void OnConsoleInputEvent()

View File

@@ -20,35 +20,35 @@ namespace Game
public override void OnAwake()
{
base.OnAwake();
/*
onExit.Triggered += () =>
{
if (Console.IsSafeToQuit)
Engine.RequestExit();
};
rootActor = Actor.GetChild(0);*/
rootActor = Actor.GetChild(0);
}
public override void OnDestroy()
{
/*base.OnDestroy();
base.OnDestroy();
onExit.Dispose();*/
onExit.Dispose();
}
public override void OnStart()
{
/*var initialEulerAngles = Actor.Orientation.EulerAngles;
var initialEulerAngles = Actor.Orientation.EulerAngles;
viewPitch = initialEulerAngles.X;
viewYaw = initialEulerAngles.Y;
viewRoll = initialEulerAngles.Z;*/
viewRoll = initialEulerAngles.Z;
}
Vector3 wishVelocity = new Vector3(0);
public override void OnFixedUpdate()
{
/*if (Console.IsOpen)
if (Console.IsOpen)
return;
var camera = rootActor.GetChild<Camera>();
@@ -87,12 +87,12 @@ namespace Game
rigidBody.LinearVelocity += accel;
//rigidBody.LinearVelocity = wishVelocity;
//rigidBody.LinearVelocity /= Time.DeltaTime;
*/
}
public override void OnUpdate()
{
/*float xAxis = InputManager.GetAxis("Mouse X");
float xAxis = InputManager.GetAxis("Mouse X");
float yAxis = InputManager.GetAxis("Mouse Y");
if (xAxis != 0.0f || yAxis != 0.0f)
{
@@ -110,7 +110,7 @@ namespace Game
camera.Transform = camTrans;
rootActor.Transform = rootTrans;
}*/
}
}
}
}