mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 10:53:59 +00:00
加几个控件
This commit is contained in:
@@ -1 +1 @@
|
|||||||
2026-03-26 19:55:43
|
2026-03-26 20:06:05
|
||||||
@@ -1 +1 @@
|
|||||||
b607cee
|
2c2f93c
|
||||||
@@ -18,6 +18,7 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
private readonly List<Window> demoWindows = new List<Window>();
|
private readonly List<Window> demoWindows = new List<Window>();
|
||||||
|
|
||||||
private FileBrowser fileBrowser;
|
private FileBrowser fileBrowser;
|
||||||
|
private ToolTip toolTip;
|
||||||
private string headerTitle = "UILib Gallery";
|
private string headerTitle = "UILib Gallery";
|
||||||
private string headerDescription = "Browse and test the current UILib controls.";
|
private string headerDescription = "Browse and test the current UILib controls.";
|
||||||
|
|
||||||
@@ -186,6 +187,21 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
AddDemo(hint);
|
AddDemo(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowProgressDemo()
|
||||||
|
{
|
||||||
|
ClearPreview();
|
||||||
|
SetHeader("ProgressRing", "Animated busy indicator for indeterminate loading states.");
|
||||||
|
|
||||||
|
ProgressRing ring = new ProgressRing(previewHost, 24, 24, 56, 56);
|
||||||
|
ring.Active = true;
|
||||||
|
AddDemo(ring);
|
||||||
|
|
||||||
|
TextBlock hint = new TextBlock(previewHost, 100, 38, 320, 24);
|
||||||
|
hint.Text = "ProgressRing keeps animating while Active=true.";
|
||||||
|
hint.Foreground = UITheme.TextSecondary;
|
||||||
|
AddDemo(hint);
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowTableDemo()
|
private void ShowTableDemo()
|
||||||
{
|
{
|
||||||
ClearPreview();
|
ClearPreview();
|
||||||
@@ -239,6 +255,35 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
statusBar.Text = "Ready";
|
statusBar.Text = "Ready";
|
||||||
statusBar.DetailText = "UILib Demo";
|
statusBar.DetailText = "UILib Demo";
|
||||||
AddDemo(statusBar);
|
AddDemo(statusBar);
|
||||||
|
|
||||||
|
Separator separator = new Separator(previewHost, 20, 172, 360, 8);
|
||||||
|
separator.Background = Color.FromArgb(250, 252, 255);
|
||||||
|
separator.Foreground = UITheme.SurfaceBorder;
|
||||||
|
AddDemo(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowTreeDemo()
|
||||||
|
{
|
||||||
|
ClearPreview();
|
||||||
|
SetHeader("TreeView", "Hierarchical tree control for folders, settings and project structures.");
|
||||||
|
|
||||||
|
TreeView tree = new TreeView(previewHost, 20, 24, 300, 180);
|
||||||
|
|
||||||
|
TreeNode rootA = new TreeNode("System");
|
||||||
|
rootA.Expanded = true;
|
||||||
|
rootA.Children.Add(new TreeNode("Apps"));
|
||||||
|
rootA.Children.Add(new TreeNode("Config"));
|
||||||
|
|
||||||
|
TreeNode rootB = new TreeNode("User");
|
||||||
|
rootB.Children.Add(new TreeNode("Desktop"));
|
||||||
|
rootB.Children.Add(new TreeNode("Documents"));
|
||||||
|
rootB.Children.Add(new TreeNode("Pictures"));
|
||||||
|
|
||||||
|
tree.Nodes.Add(rootA);
|
||||||
|
tree.Nodes.Add(rootB);
|
||||||
|
tree.NodeSelected = (node) => SetHeader("TreeView", "Selected node: " + node.Text);
|
||||||
|
tree.Render();
|
||||||
|
AddDemo(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowDialogsDemo()
|
private void ShowDialogsDemo()
|
||||||
@@ -286,6 +331,20 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
notification.Show();
|
notification.Show();
|
||||||
};
|
};
|
||||||
AddDemo(notificationButton);
|
AddDemo(notificationButton);
|
||||||
|
|
||||||
|
Button toolTipButton = new Button(previewHost, 172, 68, 140, 28);
|
||||||
|
toolTipButton.Text = "ToolTip";
|
||||||
|
toolTipButton.OnClick = (_, _) =>
|
||||||
|
{
|
||||||
|
if (toolTip == null)
|
||||||
|
{
|
||||||
|
toolTip = new ToolTip(this, wm);
|
||||||
|
}
|
||||||
|
toolTip.Show(toolTipButton, "Manual ToolTip demo");
|
||||||
|
SetHeader("Dialogs", "ToolTip shown near the button.");
|
||||||
|
};
|
||||||
|
toolTipButton.OnUnfocused = () => toolTip?.Hide();
|
||||||
|
AddDemo(toolTipButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CategorySelected(int index)
|
private void CategorySelected(int index)
|
||||||
@@ -308,12 +367,18 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
ShowNumericDemo();
|
ShowNumericDemo();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
ShowTableDemo();
|
ShowProgressDemo();
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
ShowBarsDemo();
|
ShowTableDemo();
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
|
ShowTreeDemo();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
ShowBarsDemo();
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
ShowDialogsDemo();
|
ShowDialogsDemo();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -363,7 +428,9 @@ namespace CMLeonOS.Gui.Apps
|
|||||||
categoryTable.Cells.Add(new TableCell("Dropdown"));
|
categoryTable.Cells.Add(new TableCell("Dropdown"));
|
||||||
categoryTable.Cells.Add(new TableCell("Tabs"));
|
categoryTable.Cells.Add(new TableCell("Tabs"));
|
||||||
categoryTable.Cells.Add(new TableCell("Numeric"));
|
categoryTable.Cells.Add(new TableCell("Numeric"));
|
||||||
|
categoryTable.Cells.Add(new TableCell("Progress"));
|
||||||
categoryTable.Cells.Add(new TableCell("Table"));
|
categoryTable.Cells.Add(new TableCell("Table"));
|
||||||
|
categoryTable.Cells.Add(new TableCell("TreeView"));
|
||||||
categoryTable.Cells.Add(new TableCell("Bars && Blocks"));
|
categoryTable.Cells.Add(new TableCell("Bars && Blocks"));
|
||||||
categoryTable.Cells.Add(new TableCell("Dialogs"));
|
categoryTable.Cells.Add(new TableCell("Dialogs"));
|
||||||
wm.AddWindow(categoryTable);
|
wm.AddWindow(categoryTable);
|
||||||
|
|||||||
91
Gui/UILib/ProgressRing.cs
Normal file
91
Gui/UILib/ProgressRing.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace CMLeonOS.Gui.UILib
|
||||||
|
{
|
||||||
|
internal class ProgressRing : Control
|
||||||
|
{
|
||||||
|
public ProgressRing(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _background = UITheme.Surface;
|
||||||
|
internal Color Background
|
||||||
|
{
|
||||||
|
get { return _background; }
|
||||||
|
set { _background = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _ringColor = UITheme.Accent;
|
||||||
|
internal Color RingColor
|
||||||
|
{
|
||||||
|
get { return _ringColor; }
|
||||||
|
set { _ringColor = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _trackColor = UITheme.SurfaceBorder;
|
||||||
|
internal Color TrackColor
|
||||||
|
{
|
||||||
|
get { return _trackColor; }
|
||||||
|
set { _trackColor = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _active = true;
|
||||||
|
internal bool Active
|
||||||
|
{
|
||||||
|
get { return _active; }
|
||||||
|
set { _active = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int Thickness { get; set; } = 3;
|
||||||
|
|
||||||
|
private int frame = 0;
|
||||||
|
|
||||||
|
internal override void Render()
|
||||||
|
{
|
||||||
|
Clear(Background);
|
||||||
|
|
||||||
|
int radius = Math.Max(6, (Math.Min(Width, Height) / 2) - 4);
|
||||||
|
int centerX = Width / 2;
|
||||||
|
int centerY = Height / 2;
|
||||||
|
|
||||||
|
for (int angle = 0; angle < 360; angle += 12)
|
||||||
|
{
|
||||||
|
DrawArcPoint(centerX, centerY, radius, angle, TrackColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Active)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
int angle = (frame + (i * 18)) % 360;
|
||||||
|
Color color = Color.FromArgb(
|
||||||
|
Math.Max(60, RingColor.R - (i * 12)),
|
||||||
|
Math.Max(60, RingColor.G - (i * 12)),
|
||||||
|
Math.Max(60, RingColor.B - (i * 12)));
|
||||||
|
DrawArcPoint(centerX, centerY, radius, angle, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = (frame + 10) % 360;
|
||||||
|
WM.UpdateQueue.Enqueue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
WM.Update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawArcPoint(int centerX, int centerY, int radius, int angleDegrees, Color color)
|
||||||
|
{
|
||||||
|
double radians = angleDegrees * (Math.PI / 180d);
|
||||||
|
int pointX = centerX + (int)(Math.Cos(radians) * radius);
|
||||||
|
int pointY = centerY + (int)(Math.Sin(radians) * radius);
|
||||||
|
|
||||||
|
for (int y = -Thickness / 2; y <= Thickness / 2; y++)
|
||||||
|
{
|
||||||
|
for (int x = -Thickness / 2; x <= Thickness / 2; x++)
|
||||||
|
{
|
||||||
|
DrawPoint(pointX + x, pointY + y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
Gui/UILib/Separator.cs
Normal file
51
Gui/UILib/Separator.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace CMLeonOS.Gui.UILib
|
||||||
|
{
|
||||||
|
internal class Separator : Control
|
||||||
|
{
|
||||||
|
internal enum SeparatorOrientation
|
||||||
|
{
|
||||||
|
Horizontal,
|
||||||
|
Vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
public Separator(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _background = UITheme.Surface;
|
||||||
|
internal Color Background
|
||||||
|
{
|
||||||
|
get { return _background; }
|
||||||
|
set { _background = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color _foreground = UITheme.SurfaceBorder;
|
||||||
|
internal Color Foreground
|
||||||
|
{
|
||||||
|
get { return _foreground; }
|
||||||
|
set { _foreground = value; Render(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SeparatorOrientation Orientation { get; set; } = SeparatorOrientation.Horizontal;
|
||||||
|
|
||||||
|
internal override void Render()
|
||||||
|
{
|
||||||
|
Clear(Background);
|
||||||
|
|
||||||
|
if (Orientation == SeparatorOrientation.Horizontal)
|
||||||
|
{
|
||||||
|
int y = Height / 2;
|
||||||
|
DrawHorizontalLine(Width, 0, y, Foreground);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int x = Width / 2;
|
||||||
|
DrawVerticalLine(Height, x, 0, Foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
WM.Update(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Gui/UILib/ToolTip.cs
Normal file
56
Gui/UILib/ToolTip.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace CMLeonOS.Gui.UILib
|
||||||
|
{
|
||||||
|
internal class ToolTip
|
||||||
|
{
|
||||||
|
internal ToolTip(Process process, WindowManager wm)
|
||||||
|
{
|
||||||
|
this.process = process;
|
||||||
|
this.wm = wm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Process process;
|
||||||
|
private readonly WindowManager wm;
|
||||||
|
private Window window;
|
||||||
|
|
||||||
|
internal void Show(Window anchor, string text, int offsetX = 0, int offsetY = 0)
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
|
||||||
|
string message = text ?? string.Empty;
|
||||||
|
int width = Math.Max(80, (message.Length * 8) + 12);
|
||||||
|
int height = 24;
|
||||||
|
|
||||||
|
int x = anchor.ScreenX + offsetX;
|
||||||
|
int y = anchor.ScreenY + anchor.Height + 6 + offsetY;
|
||||||
|
|
||||||
|
if (x + width > wm.ScreenWidth)
|
||||||
|
{
|
||||||
|
x = (int)wm.ScreenWidth - width - 6;
|
||||||
|
}
|
||||||
|
if (y + height > wm.ScreenHeight)
|
||||||
|
{
|
||||||
|
y = anchor.ScreenY - height - 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
window = new Window(process, x, y, width, height);
|
||||||
|
window.Clear(Color.FromArgb(33, 39, 49));
|
||||||
|
window.DrawFilledRectangle(0, 0, width, height, Color.FromArgb(33, 39, 49));
|
||||||
|
window.DrawRectangle(0, 0, width, height, UITheme.SurfaceBorder);
|
||||||
|
window.DrawString(message, Color.White, 6, 4);
|
||||||
|
wm.AddWindow(window);
|
||||||
|
wm.Update(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Hide()
|
||||||
|
{
|
||||||
|
if (window != null)
|
||||||
|
{
|
||||||
|
wm.RemoveWindow(window);
|
||||||
|
window = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Gui/UILib/TreeNode.cs
Normal file
18
Gui/UILib/TreeNode.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace CMLeonOS.Gui.UILib
|
||||||
|
{
|
||||||
|
internal class TreeNode
|
||||||
|
{
|
||||||
|
internal TreeNode(string text, object tag = null)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string Text { get; set; }
|
||||||
|
internal object Tag { get; set; }
|
||||||
|
internal bool Expanded { get; set; } = false;
|
||||||
|
internal List<TreeNode> Children { get; } = new List<TreeNode>();
|
||||||
|
}
|
||||||
|
}
|
||||||
140
Gui/UILib/TreeView.cs
Normal file
140
Gui/UILib/TreeView.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace CMLeonOS.Gui.UILib
|
||||||
|
{
|
||||||
|
internal class TreeView : Control
|
||||||
|
{
|
||||||
|
public TreeView(Window parent, int x, int y, int width, int height) : base(parent, x, y, width, height)
|
||||||
|
{
|
||||||
|
OnClick = TreeViewClicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Action<TreeNode> NodeSelected;
|
||||||
|
|
||||||
|
internal List<TreeNode> Nodes { get; } = new List<TreeNode>();
|
||||||
|
|
||||||
|
private readonly List<TreeNode> visibleNodes = new List<TreeNode>();
|
||||||
|
private readonly List<int> visibleLevels = new List<int>();
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int RowHeight { get; set; } = 22;
|
||||||
|
|
||||||
|
internal TreeNode SelectedNode { get; private set; }
|
||||||
|
|
||||||
|
private void BuildVisibleNodes()
|
||||||
|
{
|
||||||
|
visibleNodes.Clear();
|
||||||
|
visibleLevels.Clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < Nodes.Count; i++)
|
||||||
|
{
|
||||||
|
AddVisibleNode(Nodes[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddVisibleNode(TreeNode node, int level)
|
||||||
|
{
|
||||||
|
visibleNodes.Add(node);
|
||||||
|
visibleLevels.Add(level);
|
||||||
|
|
||||||
|
if (node.Expanded)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < node.Children.Count; i++)
|
||||||
|
{
|
||||||
|
AddVisibleNode(node.Children[i], level + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TreeViewClicked(int x, int y)
|
||||||
|
{
|
||||||
|
BuildVisibleNodes();
|
||||||
|
int index = y / RowHeight;
|
||||||
|
if (index < 0 || index >= visibleNodes.Count)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode node = visibleNodes[index];
|
||||||
|
int level = visibleLevels[index];
|
||||||
|
int indentX = 8 + (level * 16);
|
||||||
|
|
||||||
|
if (node.Children.Count > 0 && x >= indentX && x <= indentX + 10)
|
||||||
|
{
|
||||||
|
node.Expanded = !node.Expanded;
|
||||||
|
Render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedNode = node;
|
||||||
|
NodeSelected?.Invoke(node);
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void Render()
|
||||||
|
{
|
||||||
|
Clear(Background);
|
||||||
|
DrawRectangle(0, 0, Width, Height, Border);
|
||||||
|
|
||||||
|
BuildVisibleNodes();
|
||||||
|
|
||||||
|
int maxRows = Math.Min(visibleNodes.Count, Math.Max(0, Height / RowHeight));
|
||||||
|
for (int i = 0; i < maxRows; i++)
|
||||||
|
{
|
||||||
|
TreeNode node = visibleNodes[i];
|
||||||
|
int level = visibleLevels[i];
|
||||||
|
int rowY = i * RowHeight;
|
||||||
|
|
||||||
|
if (node == SelectedNode)
|
||||||
|
{
|
||||||
|
DrawFilledRectangle(1, rowY + 1, Width - 2, RowHeight - 2, SelectedBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
int indentX = 8 + (level * 16);
|
||||||
|
if (node.Children.Count > 0)
|
||||||
|
{
|
||||||
|
DrawRectangle(indentX, rowY + 6, 10, 10, Border);
|
||||||
|
DrawHorizontalLine(6, indentX + 2, rowY + 11, Foreground);
|
||||||
|
if (!node.Expanded)
|
||||||
|
{
|
||||||
|
DrawVerticalLine(6, indentX + 5, rowY + 8, Foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int textX = indentX + (node.Children.Count > 0 ? 16 : 8);
|
||||||
|
DrawString(node.Text, Foreground, textX, rowY + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
WM.Update(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user