mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 10:53:59 +00:00
413 lines
14 KiB
C#
413 lines
14 KiB
C#
// The CMLeonOS Project (https://github.com/Leonmmcoset/CMLeonOS)
|
|
// Copyright (C) 2025-present LeonOS 2 Developer Team
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
using Cosmos.System;
|
|
using Cosmos.System.Graphics;
|
|
using CMLeonOS.Gui.SmoothMono;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
|
|
namespace CMLeonOS.Gui.UILib
|
|
{
|
|
internal class Table : Control
|
|
{
|
|
public Table(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
|
{
|
|
OnDown = TableDown;
|
|
}
|
|
|
|
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.ScrollbarUp.bmp")]
|
|
private static byte[] scrollbarUpBytes;
|
|
private static Bitmap scrollbarUpBitmap = new Bitmap(scrollbarUpBytes);
|
|
|
|
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.ScrollbarDown.bmp")]
|
|
private static byte[] scrollbarDownBytes;
|
|
private static Bitmap scrollbarDownBitmap = new Bitmap(scrollbarDownBytes);
|
|
|
|
internal List<TableCell> Cells { get; set; } = new List<TableCell>();
|
|
|
|
internal Action<int> TableCellSelected { get; set; }
|
|
|
|
internal bool AllowDeselection { get; set; } = true;
|
|
|
|
internal bool AllowSelection { get; set; } = true;
|
|
|
|
private double scrollY = 0;
|
|
|
|
private bool dragging = false;
|
|
private int lastDragY = 0;
|
|
|
|
private int _selectedCellIndex = -1;
|
|
internal int SelectedCellIndex
|
|
{
|
|
get
|
|
{
|
|
return _selectedCellIndex;
|
|
}
|
|
set
|
|
{
|
|
if (_selectedCellIndex != value)
|
|
{
|
|
_selectedCellIndex = value;
|
|
Render();
|
|
}
|
|
}
|
|
}
|
|
|
|
private int _scrollbarThickness = 20;
|
|
internal int ScrollbarThickness
|
|
{
|
|
get
|
|
{
|
|
return _scrollbarThickness;
|
|
}
|
|
set
|
|
{
|
|
_scrollbarThickness = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _background = UITheme.Surface;
|
|
internal Color Background
|
|
{
|
|
get
|
|
{
|
|
return _background;
|
|
}
|
|
set
|
|
{
|
|
_background = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _foreground = UITheme.TextPrimary;
|
|
internal Color Foreground
|
|
{
|
|
get
|
|
{
|
|
return _foreground;
|
|
}
|
|
set
|
|
{
|
|
_foreground = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _border = UITheme.SurfaceBorder;
|
|
internal Color Border
|
|
{
|
|
get
|
|
{
|
|
return _border;
|
|
}
|
|
set
|
|
{
|
|
_border = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _selectedBackground = UITheme.AccentLight;
|
|
internal Color SelectedBackground
|
|
{
|
|
get
|
|
{
|
|
return _selectedBackground;
|
|
}
|
|
set
|
|
{
|
|
_selectedBackground = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _selectedForeground = UITheme.TextPrimary;
|
|
internal Color SelectedForeground
|
|
{
|
|
get
|
|
{
|
|
return _selectedForeground;
|
|
}
|
|
set
|
|
{
|
|
_selectedForeground = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Color _selectedBorder = UITheme.Accent;
|
|
internal Color SelectedBorder
|
|
{
|
|
get
|
|
{
|
|
return _selectedBorder;
|
|
}
|
|
set
|
|
{
|
|
_selectedBorder = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private int _cellHeight = 20;
|
|
internal int CellHeight
|
|
{
|
|
get
|
|
{
|
|
return _cellHeight;
|
|
}
|
|
set
|
|
{
|
|
_cellHeight = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private Alignment _textAlignment = Alignment.Start;
|
|
internal Alignment TextAlignment
|
|
{
|
|
get
|
|
{
|
|
return _textAlignment;
|
|
}
|
|
set
|
|
{
|
|
_textAlignment = value;
|
|
Render();
|
|
}
|
|
}
|
|
|
|
private void TableDown(int x, int y)
|
|
{
|
|
if ((CanScrollUp || CanScrollDown) && x >= (Width - _scrollbarThickness))
|
|
{
|
|
int allCellsHeight = Cells.Count * CellHeight;
|
|
if (y < _scrollbarThickness && CanScrollUp)
|
|
{
|
|
scrollY = Math.Max(0, scrollY - CellHeight);
|
|
Render();
|
|
}
|
|
if (y >= Height - _scrollbarThickness && CanScrollDown)
|
|
{
|
|
scrollY = Math.Min(allCellsHeight - Height, scrollY + CellHeight);
|
|
Render();
|
|
}
|
|
if (y < Height - _scrollbarThickness && y >= _scrollbarThickness)
|
|
{
|
|
dragging = true;
|
|
lastDragY = (int)MouseManager.Y;
|
|
Render();
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
int scrollAdjustedY = (int)(y + scrollY);
|
|
if (scrollAdjustedY < 0 || scrollAdjustedY > _cellHeight * Cells.Count)
|
|
{
|
|
if (AllowDeselection)
|
|
{
|
|
SelectedCellIndex = -1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (AllowSelection)
|
|
{
|
|
SelectedCellIndex = scrollAdjustedY / _cellHeight;
|
|
TableCellSelected?.Invoke(_selectedCellIndex);
|
|
}
|
|
}
|
|
|
|
private bool CanScrollUp
|
|
{
|
|
get
|
|
{
|
|
return scrollY > 0;
|
|
}
|
|
}
|
|
|
|
private bool CanScrollDown
|
|
{
|
|
get
|
|
{
|
|
int allCellsHeight = Cells.Count * CellHeight;
|
|
return (scrollY < 0) || ((allCellsHeight > Height) && (scrollY < (allCellsHeight - Height)));
|
|
}
|
|
}
|
|
|
|
private void RenderScrollbar()
|
|
{
|
|
if (CanScrollUp || CanScrollDown)
|
|
{
|
|
/* Background */
|
|
DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, Height, UITheme.SurfaceMuted);
|
|
|
|
/* Track */
|
|
int trackAvailableHeight = Height - (ScrollbarThickness * 2);
|
|
double trackSize = (double)Height / (double)(Cells.Count * CellHeight);
|
|
double trackProgress = (double)scrollY / (double)((Cells.Count * CellHeight) - Height);
|
|
int trackY = (int)(_scrollbarThickness + (((double)trackAvailableHeight - ((double)trackAvailableHeight * trackSize)) * trackProgress));
|
|
// Border
|
|
DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, Height, UITheme.SurfaceBorder);
|
|
// Background
|
|
DrawFilledRectangle(Width - _scrollbarThickness + 1, trackY + 1, _scrollbarThickness - 2, (int)(trackSize * trackAvailableHeight) - 2, UITheme.AccentLight);
|
|
|
|
/* Up arrow */
|
|
// Border
|
|
DrawFilledRectangle(Width - _scrollbarThickness, 0, _scrollbarThickness, _scrollbarThickness, UITheme.SurfaceBorder);
|
|
// Background
|
|
DrawFilledRectangle(Width - _scrollbarThickness + 1, 1, _scrollbarThickness - 2, _scrollbarThickness - 2, CanScrollUp ? UITheme.Surface : UITheme.SurfaceMuted);
|
|
DrawImageAlpha(scrollbarUpBitmap, (int)((Width - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Width / 2))), (int)((_scrollbarThickness / 2) - (scrollbarUpBitmap.Height / 2)));
|
|
|
|
/* Down arrow */
|
|
// Border
|
|
DrawFilledRectangle(Width - _scrollbarThickness, Height - _scrollbarThickness, _scrollbarThickness, _scrollbarThickness, UITheme.SurfaceBorder);
|
|
// Background
|
|
DrawFilledRectangle(Width - _scrollbarThickness + 1, Height - _scrollbarThickness + 1, _scrollbarThickness - 2, _scrollbarThickness - 2, CanScrollDown ? UITheme.Surface : UITheme.SurfaceMuted);
|
|
DrawImageAlpha(scrollbarDownBitmap, (int)((Width - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Width / 2))), (int)((Height - _scrollbarThickness) + ((_scrollbarThickness / 2) - (scrollbarUpBitmap.Height / 2))));
|
|
}
|
|
}
|
|
|
|
internal void ScrollToTop()
|
|
{
|
|
scrollY = 0;
|
|
Render();
|
|
}
|
|
|
|
internal void ScrollToBottom()
|
|
{
|
|
int allCellsHeight = Cells.Count * CellHeight;
|
|
if (allCellsHeight > Height)
|
|
{
|
|
scrollY = allCellsHeight - Height;
|
|
}
|
|
else
|
|
{
|
|
scrollY = 0;
|
|
}
|
|
Render();
|
|
}
|
|
|
|
internal override void Render()
|
|
{
|
|
int scrollMax = (Cells.Count * CellHeight) - Height;
|
|
if (dragging)
|
|
{
|
|
scrollY += (int)(MouseManager.Y - lastDragY);
|
|
lastDragY = (int)MouseManager.Y;
|
|
if (MouseManager.MouseState != MouseState.Left)
|
|
{
|
|
dragging = false;
|
|
}
|
|
WM.UpdateQueue.Enqueue(this);
|
|
}
|
|
else if (scrollY < 0 || scrollY > scrollMax)
|
|
{
|
|
double oldScrollY = scrollY;
|
|
double move;
|
|
if (scrollY > 0)
|
|
{
|
|
move = (scrollMax - scrollY) / 8d;
|
|
}
|
|
else
|
|
{
|
|
move = (-scrollY) / 8d;
|
|
}
|
|
scrollY += move;
|
|
if (Math.Abs(scrollY - oldScrollY) > 0.05)
|
|
{
|
|
WM.UpdateQueue.Enqueue(this);
|
|
}
|
|
}
|
|
|
|
Clear(Background);
|
|
|
|
for (int i = 0; i < Cells.Count; i++)
|
|
{
|
|
TableCell cell = Cells[i];
|
|
bool selected = _selectedCellIndex == i;
|
|
int contentWidth = Width - ((CanScrollUp || CanScrollDown) ? _scrollbarThickness : 0);
|
|
Rectangle cellRect = new Rectangle(0, (int)((i * _cellHeight) - scrollY), contentWidth, _cellHeight);
|
|
|
|
if (cellRect.Y < -cellRect.Height || cellRect.Y > Height)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (cell.BackgroundColourOverride != null)
|
|
{
|
|
DrawFilledRectangle(cellRect.X, cellRect.Y, cellRect.Width, cellRect.Height, (Color)cell.BackgroundColourOverride);
|
|
}
|
|
else
|
|
{
|
|
// Border.
|
|
DrawFilledRectangle(cellRect.X, cellRect.Y, cellRect.Width, cellRect.Height, selected ? _selectedBorder : _border);
|
|
|
|
// Background.
|
|
DrawFilledRectangle(cellRect.X + 1, cellRect.Y + 1, cellRect.Width - 2, cellRect.Height - 2, selected ? _selectedBackground : _background);
|
|
}
|
|
|
|
int textX;
|
|
switch (_textAlignment)
|
|
{
|
|
case Alignment.Start:
|
|
textX = cellRect.X + 6 + (cell.Image != null ? (CellHeight - FontData.Height) / 2 : 0);
|
|
break;
|
|
case Alignment.Middle:
|
|
textX = cellRect.X + (cellRect.Width / 2) - (cell.Text.Length * FontData.Width / 2);
|
|
break;
|
|
case Alignment.End:
|
|
textX = cellRect.X + cellRect.Width - (cell.Text.Length * FontData.Width);
|
|
break;
|
|
default:
|
|
throw new Exception("Invalid Table alignment!");
|
|
}
|
|
|
|
|
|
int textY = cellRect.Y + (cellRect.Height / 2) - (16 / 2);
|
|
|
|
if (cell.Image != null)
|
|
{
|
|
textX += (int)cell.Image.Width + 6;
|
|
DrawImageAlpha(cell.Image, cellRect.X + 4, (int)(cellRect.Y + (cellRect.Height / 2) - (cell.Image.Height / 2)));
|
|
}
|
|
|
|
if (cell.ForegroundColourOverride != null)
|
|
{
|
|
DrawString(cell.Text, (Color)cell.ForegroundColourOverride, textX, textY);
|
|
}
|
|
else
|
|
{
|
|
DrawString(cell.Text, selected ? SelectedForeground : Foreground, textX, textY);
|
|
}
|
|
|
|
DrawHorizontalLine(cellRect.Width - 2, 1, cellRect.Y + cellRect.Height - 1, UITheme.SurfaceBorder);
|
|
}
|
|
|
|
//DrawString($"{scrollY.ToString()} {dragging.ToString()} {scrollMax.ToString()}", Color.Red, 0, 0);
|
|
|
|
RenderScrollbar();
|
|
|
|
WM.Update(this);
|
|
}
|
|
}
|
|
}
|