mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-03-03 15:30:27 +00:00
382 lines
11 KiB
C#
382 lines
11 KiB
C#
using Cosmos.System;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace CMLeonOS.Gui.UILib
|
|
{
|
|
internal class TextBox : Control
|
|
{
|
|
public TextBox(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
|
{
|
|
OnDown = TextBoxDown;
|
|
OnKeyPressed = TextBoxKeyPressed;
|
|
OnUnfocused = TextBoxUnfocused;
|
|
}
|
|
|
|
internal Action Submitted;
|
|
internal Action Changed;
|
|
|
|
internal virtual void RenderLine(int lineIndex, string lineText, int lineY, int xOffset)
|
|
{
|
|
DrawString(lineText, Foreground, xOffset, lineY);
|
|
}
|
|
|
|
internal string Text
|
|
{
|
|
get
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
for (int i = 0; i < lines.Count; i++)
|
|
{
|
|
builder.Append(lines[i]);
|
|
if (i != lines.Count - 1)
|
|
{
|
|
builder.AppendLine();
|
|
}
|
|
}
|
|
return builder.ToString();
|
|
}
|
|
set
|
|
{
|
|
lines = value.Split('\n').ToList();
|
|
|
|
caretLine = -1;
|
|
caretCol = 0;
|
|
|
|
MarkAllLines();
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private string _placeholderText = string.Empty;
|
|
internal string PlaceholderText
|
|
{
|
|
get
|
|
{
|
|
return _placeholderText;
|
|
}
|
|
set
|
|
{
|
|
_placeholderText = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
internal bool ReadOnly { get; set; } = false;
|
|
|
|
internal bool MultiLine { get; set; } = false;
|
|
|
|
internal bool Shield { get; set; } = false;
|
|
|
|
private Color _background = Color.White;
|
|
internal Color Background
|
|
{
|
|
get
|
|
{
|
|
return _background;
|
|
}
|
|
set
|
|
{
|
|
_background = value;
|
|
Clear(_background);
|
|
MarkAllLines();
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _foreground = Color.Black;
|
|
internal Color Foreground
|
|
{
|
|
get
|
|
{
|
|
return _foreground;
|
|
}
|
|
set
|
|
{
|
|
_foreground = value;
|
|
MarkAllLines();
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _placeholderForeground = Color.Gray;
|
|
internal Color PlaceholderForeground
|
|
{
|
|
get
|
|
{
|
|
return _placeholderForeground;
|
|
}
|
|
set
|
|
{
|
|
_placeholderForeground = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private void MoveCaret(int line, int col)
|
|
{
|
|
if (caretLine == line && caretCol == col) return;
|
|
MarkLine(caretLine);
|
|
caretLine = Math.Clamp(line, 0, lines.Count - 1);
|
|
caretCol = Math.Clamp(col, 0, lines[caretLine].Length);
|
|
MarkLine(caretLine);
|
|
Render();
|
|
}
|
|
|
|
private void TextBoxDown(int x, int y)
|
|
{
|
|
MoveCaret((y + scrollY) / fontHeight, ((x + scrollX) + (fontWidth / 2)) / fontWidth);
|
|
}
|
|
|
|
private void TextBoxUnfocused()
|
|
{
|
|
MarkLine(caretLine);
|
|
|
|
caretLine = -1;
|
|
caretCol = 0;
|
|
|
|
Render();
|
|
}
|
|
|
|
private void AutoScroll()
|
|
{
|
|
if (caretLine == -1) return;
|
|
|
|
if (scrollY + Height < (caretLine + 1) * fontHeight)
|
|
{
|
|
// Scroll up.
|
|
scrollY = ((caretLine + 1) * fontHeight) - Height;
|
|
MarkAllLines();
|
|
}
|
|
if (caretLine * fontHeight < scrollY)
|
|
{
|
|
// Scroll down.
|
|
scrollY = caretLine * fontHeight;
|
|
MarkAllLines();
|
|
}
|
|
|
|
if (scrollX + Width < (caretCol + 1) * fontWidth)
|
|
{
|
|
// Scroll right.
|
|
scrollX = ((caretCol + 1) * fontWidth) - Width;
|
|
MarkAllLines();
|
|
}
|
|
if (caretCol * fontWidth < scrollX)
|
|
{
|
|
// Scroll left.
|
|
scrollX = caretCol * fontWidth;
|
|
MarkAllLines();
|
|
}
|
|
}
|
|
|
|
private void TextBoxKeyPressed(KeyEvent key)
|
|
{
|
|
if (caretLine == -1 || ReadOnly) return;
|
|
switch (key.Key)
|
|
{
|
|
case ConsoleKeyEx.LeftArrow:
|
|
if (caretCol == 0)
|
|
{
|
|
if (caretLine == 0) return;
|
|
caretLine--;
|
|
caretCol = lines[caretLine].Length;
|
|
MarkLine(caretLine);
|
|
MarkLine(caretLine + 1);
|
|
}
|
|
else
|
|
{
|
|
caretCol--;
|
|
MarkLine(caretLine);
|
|
}
|
|
break;
|
|
case ConsoleKeyEx.RightArrow:
|
|
if (caretCol == lines[caretLine].Length)
|
|
{
|
|
if (caretLine == lines.Count - 1) return;
|
|
caretLine++;
|
|
|
|
caretCol = 0;
|
|
MarkLine(caretLine - 1);
|
|
MarkLine(caretLine);
|
|
}
|
|
else
|
|
{
|
|
caretCol++;
|
|
MarkLine(caretLine);
|
|
}
|
|
break;
|
|
case ConsoleKeyEx.UpArrow:
|
|
if (caretLine == 0) return;
|
|
|
|
caretLine--;
|
|
caretCol = Math.Min(lines[caretLine].Length, caretCol);
|
|
|
|
MarkLine(caretLine);
|
|
MarkLine(caretLine + 1);
|
|
break;
|
|
case ConsoleKeyEx.DownArrow:
|
|
if (caretLine == lines.Count - 1) return;
|
|
|
|
caretLine++;
|
|
caretCol = Math.Min(lines[caretLine].Length, caretCol);
|
|
|
|
MarkLine(caretLine - 1);
|
|
MarkLine(caretLine);
|
|
break;
|
|
case ConsoleKeyEx.Enter:
|
|
if (!MultiLine)
|
|
{
|
|
Submitted?.Invoke();
|
|
|
|
caretLine = -1;
|
|
caretCol = 0;
|
|
|
|
MarkAllLines();
|
|
break;
|
|
}
|
|
|
|
lines.Insert(caretLine + 1, lines[caretLine].Substring(caretCol));
|
|
lines[caretLine] = lines[caretLine].Substring(0, caretCol);
|
|
|
|
caretLine++;
|
|
caretCol = 0;
|
|
|
|
MarkLine(caretLine - 1);
|
|
MarkLine(caretLine);
|
|
|
|
Changed?.Invoke();
|
|
break;
|
|
case ConsoleKeyEx.Backspace:
|
|
if (caretCol == 0)
|
|
{
|
|
if (caretLine == 0) return;
|
|
|
|
caretLine--;
|
|
caretCol = lines[caretLine].Length;
|
|
|
|
lines[caretLine] += lines[caretLine + 1];
|
|
lines.RemoveAt(caretLine + 1);
|
|
|
|
MarkLine(caretLine);
|
|
MarkLine(caretLine + 1);
|
|
|
|
Changed?.Invoke();
|
|
}
|
|
else
|
|
{
|
|
lines[caretLine] = lines[caretLine].Remove(caretCol - 1, 1);
|
|
caretCol--;
|
|
MarkLine(caretLine);
|
|
|
|
Changed?.Invoke();
|
|
}
|
|
break;
|
|
default:
|
|
lines[caretLine] = lines[caretLine].Insert(caretCol, key.KeyChar.ToString());
|
|
caretCol++;
|
|
MarkLine(caretLine);
|
|
|
|
Changed?.Invoke();
|
|
break;
|
|
}
|
|
|
|
Render();
|
|
}
|
|
|
|
private void MarkLine(int lineNum)
|
|
{
|
|
if (markedLinesBegin == -1)
|
|
{
|
|
markedLinesBegin = lineNum;
|
|
}
|
|
else
|
|
{
|
|
markedLinesBegin = Math.Min(markedLinesBegin, lineNum);
|
|
}
|
|
if (markedLinesEnd == -1)
|
|
{
|
|
markedLinesEnd = lineNum;
|
|
}
|
|
else
|
|
{
|
|
markedLinesEnd = Math.Max(markedLinesEnd, lineNum);
|
|
}
|
|
}
|
|
|
|
internal void MarkAllLines()
|
|
{
|
|
markedLinesBegin = 0;
|
|
markedLinesEnd = lines.Count - 1;
|
|
}
|
|
|
|
private List<string> lines = new List<string>() { string.Empty };
|
|
|
|
private int markedLinesBegin = 0;
|
|
private int markedLinesEnd = 0;
|
|
|
|
private const int fontWidth = 8;
|
|
private const int fontHeight = 16;
|
|
|
|
private int caretLine = -1;
|
|
private int caretCol = 0;
|
|
|
|
private int scrollX = 0;
|
|
private int scrollY = 0;
|
|
|
|
internal override void Render()
|
|
{
|
|
if (Text == string.Empty)
|
|
{
|
|
Clear(_background);
|
|
|
|
DrawRectangle(0, 0, Width, Height, Color.Gray);
|
|
DrawString(PlaceholderText, PlaceholderForeground, 0, 0);
|
|
|
|
if (caretLine == 0)
|
|
{
|
|
DrawVerticalLine(fontHeight, 1, 0, Foreground);
|
|
}
|
|
|
|
WM.Update(this);
|
|
|
|
return;
|
|
}
|
|
|
|
if (markedLinesBegin == -1 || markedLinesEnd == -1) return;
|
|
|
|
AutoScroll();
|
|
|
|
for (int i = markedLinesBegin; i <= markedLinesEnd; i++)
|
|
{
|
|
int lineY = (i * fontHeight) - scrollY;
|
|
|
|
if (lineY < 0) continue;
|
|
if (lineY > Height) break;
|
|
|
|
DrawFilledRectangle(0, lineY, Width, fontHeight, Background);
|
|
|
|
if (i < lines.Count)
|
|
{
|
|
string lineText = Shield ? new string('*', lines[i].Length) : lines[i];
|
|
RenderLine(i, lineText, lineY, -scrollX);
|
|
|
|
if (caretLine == i)
|
|
{
|
|
DrawVerticalLine(fontHeight, ((caretCol * fontWidth) - scrollX) + 1, (caretLine * fontHeight) - scrollY, Foreground);
|
|
}
|
|
}
|
|
}
|
|
|
|
markedLinesBegin = -1;
|
|
markedLinesEnd = -1;
|
|
|
|
DrawRectangle(0, 0, Width, Height, Color.Gray);
|
|
|
|
WM.Update(this);
|
|
}
|
|
}
|
|
}
|