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 20:06:05
|
||||
2026-03-26 20:36:31
|
||||
@@ -1 +1 @@
|
||||
2c2f93c
|
||||
2c2ee0f
|
||||
@@ -164,6 +164,14 @@ namespace CMLeonOS.Gui.Apps
|
||||
SettingsManager.GUI_MouseSensitivity = value;
|
||||
}
|
||||
|
||||
private void ThemeChanged(int index, string themeName)
|
||||
{
|
||||
SettingsManager.GUI_Theme = themeName;
|
||||
UITheme.ApplyTheme(themeName);
|
||||
UITheme.RefreshOpenWindows(wm);
|
||||
ShowAppearanceCategory();
|
||||
}
|
||||
|
||||
private void ShowAppearanceCategory()
|
||||
{
|
||||
if (currentCategoryWindow != null)
|
||||
@@ -193,16 +201,36 @@ namespace CMLeonOS.Gui.Apps
|
||||
skipToGui.CheckBoxChanged = SkipToGuiChanged;
|
||||
wm.AddWindow(skipToGui);
|
||||
|
||||
appearance.DrawString("Wallpaper", Color.Gray, 12, 132);
|
||||
appearance.DrawString(GetWallpaperLabel(), Color.Black, 12, 152);
|
||||
appearance.DrawString("Use a BMP file or restore the default wallpaper.", Color.Gray, 12, 170);
|
||||
appearance.DrawString("Theme", Color.Gray, 12, 126);
|
||||
|
||||
Button chooseWallpaper = new Button(appearance, 12, 192, 132, 24);
|
||||
Dropdown themeDropdown = new Dropdown(appearance, 12, 146, 180, 24);
|
||||
string[] themes = UITheme.GetThemeNames();
|
||||
for (int i = 0; i < themes.Length; i++)
|
||||
{
|
||||
themeDropdown.Items.Add(themes[i]);
|
||||
}
|
||||
themeDropdown.RefreshItems();
|
||||
for (int i = 0; i < themes.Length; i++)
|
||||
{
|
||||
if (themes[i] == SettingsManager.GUI_Theme)
|
||||
{
|
||||
themeDropdown.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
themeDropdown.SelectionChanged = ThemeChanged;
|
||||
wm.AddWindow(themeDropdown);
|
||||
|
||||
appearance.DrawString("Wallpaper", Color.Gray, 12, 184);
|
||||
appearance.DrawString(GetWallpaperLabel(), Color.Black, 12, 204);
|
||||
appearance.DrawString("Use a BMP file or restore the default wallpaper.", Color.Gray, 12, 222);
|
||||
|
||||
Button chooseWallpaper = new Button(appearance, 12, 244, 132, 24);
|
||||
chooseWallpaper.Text = "Choose BMP";
|
||||
chooseWallpaper.OnClick = (_, _) => OpenWallpaperBrowser();
|
||||
wm.AddWindow(chooseWallpaper);
|
||||
|
||||
Button defaultWallpaper = new Button(appearance, 154, 192, 132, 24);
|
||||
Button defaultWallpaper = new Button(appearance, 154, 244, 132, 24);
|
||||
defaultWallpaper.Text = "Use Default";
|
||||
defaultWallpaper.OnClick = (_, _) => ApplyWallpaper(string.Empty);
|
||||
wm.AddWindow(defaultWallpaper);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Logger;
|
||||
using CMLeonOS.Settings;
|
||||
using System;
|
||||
|
||||
namespace CMLeonOS.Gui
|
||||
@@ -51,6 +52,9 @@ namespace CMLeonOS.Gui
|
||||
Console.WriteLine("Loading apps...");
|
||||
AppManager.LoadAllApps();
|
||||
|
||||
SettingsManager.LoadSettings();
|
||||
UILib.UITheme.ApplyTheme(SettingsManager.GUI_Theme);
|
||||
|
||||
ProcessManager.AddProcess(windowManager);
|
||||
|
||||
ProcessManager.AddProcess(windowManager, new SettingsService()).Start();
|
||||
|
||||
@@ -357,5 +357,11 @@ namespace CMLeonOS.Gui.UILib
|
||||
}
|
||||
wm.Update(decorationWindow);
|
||||
}
|
||||
|
||||
internal void RefreshTheme()
|
||||
{
|
||||
wm.Update(this);
|
||||
RenderDecoration();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ namespace CMLeonOS.Gui.UILib
|
||||
internal string Text { get; set; }
|
||||
internal object Tag { get; set; }
|
||||
internal bool Expanded { get; set; } = false;
|
||||
internal int AnimatedChildCount { get; set; } = 0;
|
||||
internal bool ExpandingAnimation { get; set; } = false;
|
||||
internal bool CollapsingAnimation { get; set; } = false;
|
||||
internal List<TreeNode> Children { get; } = new List<TreeNode>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,16 @@ namespace CMLeonOS.Gui.UILib
|
||||
visibleNodes.Add(node);
|
||||
visibleLevels.Add(level);
|
||||
|
||||
if (node.Expanded)
|
||||
if (node.Expanded || node.ExpandingAnimation || node.CollapsingAnimation)
|
||||
{
|
||||
for (int i = 0; i < node.Children.Count; i++)
|
||||
int visibleChildCount = node.Children.Count;
|
||||
|
||||
if (node.ExpandingAnimation || node.CollapsingAnimation)
|
||||
{
|
||||
visibleChildCount = Math.Min(node.Children.Count, Math.Max(0, node.AnimatedChildCount));
|
||||
}
|
||||
|
||||
for (int i = 0; i < visibleChildCount; i++)
|
||||
{
|
||||
AddVisibleNode(node.Children[i], level + 1);
|
||||
}
|
||||
@@ -90,7 +97,19 @@ namespace CMLeonOS.Gui.UILib
|
||||
|
||||
if (node.Children.Count > 0 && x >= indentX && x <= indentX + 10)
|
||||
{
|
||||
node.Expanded = !node.Expanded;
|
||||
if (node.Expanded || node.ExpandingAnimation)
|
||||
{
|
||||
node.ExpandingAnimation = false;
|
||||
node.CollapsingAnimation = true;
|
||||
node.AnimatedChildCount = node.Children.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Expanded = true;
|
||||
node.CollapsingAnimation = false;
|
||||
node.ExpandingAnimation = true;
|
||||
node.AnimatedChildCount = 0;
|
||||
}
|
||||
Render();
|
||||
return;
|
||||
}
|
||||
@@ -106,6 +125,7 @@ namespace CMLeonOS.Gui.UILib
|
||||
DrawRectangle(0, 0, Width, Height, Border);
|
||||
|
||||
BuildVisibleNodes();
|
||||
bool hasAnimation = false;
|
||||
|
||||
int maxRows = Math.Min(visibleNodes.Count, Math.Max(0, Height / RowHeight));
|
||||
for (int i = 0; i < maxRows; i++)
|
||||
@@ -124,7 +144,7 @@ namespace CMLeonOS.Gui.UILib
|
||||
{
|
||||
DrawRectangle(indentX, rowY + 6, 10, 10, Border);
|
||||
DrawHorizontalLine(6, indentX + 2, rowY + 11, Foreground);
|
||||
if (!node.Expanded)
|
||||
if (!node.Expanded || node.CollapsingAnimation)
|
||||
{
|
||||
DrawVerticalLine(6, indentX + 5, rowY + 8, Foreground);
|
||||
}
|
||||
@@ -134,7 +154,46 @@ namespace CMLeonOS.Gui.UILib
|
||||
DrawString(node.Text, Foreground, textX, rowY + 3);
|
||||
}
|
||||
|
||||
UpdateNodeAnimations(Nodes, ref hasAnimation);
|
||||
|
||||
if (hasAnimation)
|
||||
{
|
||||
WM.UpdateQueue.Enqueue(this);
|
||||
}
|
||||
|
||||
WM.Update(this);
|
||||
}
|
||||
|
||||
private void UpdateNodeAnimations(List<TreeNode> nodes, ref bool hasAnimation)
|
||||
{
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
TreeNode node = nodes[i];
|
||||
|
||||
if (node.ExpandingAnimation)
|
||||
{
|
||||
hasAnimation = true;
|
||||
node.AnimatedChildCount++;
|
||||
if (node.AnimatedChildCount >= node.Children.Count)
|
||||
{
|
||||
node.AnimatedChildCount = node.Children.Count;
|
||||
node.ExpandingAnimation = false;
|
||||
}
|
||||
}
|
||||
else if (node.CollapsingAnimation)
|
||||
{
|
||||
hasAnimation = true;
|
||||
node.AnimatedChildCount--;
|
||||
if (node.AnimatedChildCount <= 0)
|
||||
{
|
||||
node.AnimatedChildCount = 0;
|
||||
node.CollapsingAnimation = false;
|
||||
node.Expanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateNodeAnimations(node.Children, ref hasAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,23 +20,136 @@ namespace CMLeonOS.Gui.UILib
|
||||
{
|
||||
internal static class UITheme
|
||||
{
|
||||
internal static readonly Color WindowTitleBackground = Color.FromArgb(26, 34, 46);
|
||||
internal static readonly Color WindowTitleTopHighlight = Color.FromArgb(52, 67, 90);
|
||||
internal static readonly Color WindowTitleBottomBorder = Color.FromArgb(14, 18, 26);
|
||||
internal static readonly Color WindowTitleText = Color.FromArgb(239, 244, 252);
|
||||
internal static readonly Color WindowButtonBackground = Color.FromArgb(38, 49, 66);
|
||||
internal static Color WindowTitleBackground { get; private set; }
|
||||
internal static Color WindowTitleTopHighlight { get; private set; }
|
||||
internal static Color WindowTitleBottomBorder { get; private set; }
|
||||
internal static Color WindowTitleText { get; private set; }
|
||||
internal static Color WindowButtonBackground { get; private set; }
|
||||
|
||||
internal static readonly Color Surface = Color.FromArgb(245, 248, 252);
|
||||
internal static readonly Color SurfaceMuted = Color.FromArgb(228, 235, 245);
|
||||
internal static readonly Color SurfaceBorder = Color.FromArgb(149, 164, 183);
|
||||
internal static readonly Color TextPrimary = Color.FromArgb(33, 43, 56);
|
||||
internal static readonly Color TextSecondary = Color.FromArgb(96, 109, 128);
|
||||
internal static Color Surface { get; private set; }
|
||||
internal static Color SurfaceMuted { get; private set; }
|
||||
internal static Color SurfaceBorder { get; private set; }
|
||||
internal static Color TextPrimary { get; private set; }
|
||||
internal static Color TextSecondary { get; private set; }
|
||||
|
||||
internal static readonly Color Accent = Color.FromArgb(45, 117, 222);
|
||||
internal static readonly Color AccentDark = Color.FromArgb(28, 89, 184);
|
||||
internal static readonly Color AccentLight = Color.FromArgb(204, 225, 255);
|
||||
internal static Color Accent { get; private set; }
|
||||
internal static Color AccentDark { get; private set; }
|
||||
internal static Color AccentLight { get; private set; }
|
||||
|
||||
internal static readonly Color Success = Color.FromArgb(45, 152, 99);
|
||||
internal static readonly Color Warning = Color.FromArgb(210, 139, 54);
|
||||
internal static Color Success { get; private set; }
|
||||
internal static Color Warning { get; private set; }
|
||||
|
||||
internal static string CurrentThemeName { get; private set; } = "Default";
|
||||
|
||||
internal static string[] GetThemeNames()
|
||||
{
|
||||
return new string[] { "Default", "Graphite", "Forest" };
|
||||
}
|
||||
|
||||
internal static void ApplyTheme(string themeName)
|
||||
{
|
||||
string name = string.IsNullOrWhiteSpace(themeName) ? "Default" : themeName.Trim();
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "Graphite":
|
||||
WindowTitleBackground = Color.FromArgb(31, 34, 40);
|
||||
WindowTitleTopHighlight = Color.FromArgb(62, 69, 81);
|
||||
WindowTitleBottomBorder = Color.FromArgb(18, 20, 24);
|
||||
WindowTitleText = Color.FromArgb(239, 242, 247);
|
||||
WindowButtonBackground = Color.FromArgb(47, 53, 61);
|
||||
|
||||
Surface = Color.FromArgb(236, 239, 244);
|
||||
SurfaceMuted = Color.FromArgb(214, 220, 228);
|
||||
SurfaceBorder = Color.FromArgb(124, 134, 149);
|
||||
TextPrimary = Color.FromArgb(36, 42, 52);
|
||||
TextSecondary = Color.FromArgb(92, 101, 115);
|
||||
|
||||
Accent = Color.FromArgb(90, 131, 212);
|
||||
AccentDark = Color.FromArgb(64, 100, 176);
|
||||
AccentLight = Color.FromArgb(205, 220, 247);
|
||||
|
||||
Success = Color.FromArgb(61, 145, 108);
|
||||
Warning = Color.FromArgb(196, 138, 60);
|
||||
CurrentThemeName = "Graphite";
|
||||
break;
|
||||
|
||||
case "Forest":
|
||||
WindowTitleBackground = Color.FromArgb(24, 48, 36);
|
||||
WindowTitleTopHighlight = Color.FromArgb(60, 98, 77);
|
||||
WindowTitleBottomBorder = Color.FromArgb(13, 28, 20);
|
||||
WindowTitleText = Color.FromArgb(240, 248, 243);
|
||||
WindowButtonBackground = Color.FromArgb(38, 67, 52);
|
||||
|
||||
Surface = Color.FromArgb(242, 248, 244);
|
||||
SurfaceMuted = Color.FromArgb(220, 232, 224);
|
||||
SurfaceBorder = Color.FromArgb(134, 160, 145);
|
||||
TextPrimary = Color.FromArgb(33, 53, 41);
|
||||
TextSecondary = Color.FromArgb(95, 116, 104);
|
||||
|
||||
Accent = Color.FromArgb(53, 144, 98);
|
||||
AccentDark = Color.FromArgb(37, 112, 74);
|
||||
AccentLight = Color.FromArgb(202, 236, 217);
|
||||
|
||||
Success = Color.FromArgb(42, 153, 92);
|
||||
Warning = Color.FromArgb(191, 137, 55);
|
||||
CurrentThemeName = "Forest";
|
||||
break;
|
||||
|
||||
default:
|
||||
WindowTitleBackground = Color.FromArgb(26, 34, 46);
|
||||
WindowTitleTopHighlight = Color.FromArgb(52, 67, 90);
|
||||
WindowTitleBottomBorder = Color.FromArgb(14, 18, 26);
|
||||
WindowTitleText = Color.FromArgb(239, 244, 252);
|
||||
WindowButtonBackground = Color.FromArgb(38, 49, 66);
|
||||
|
||||
Surface = Color.FromArgb(245, 248, 252);
|
||||
SurfaceMuted = Color.FromArgb(228, 235, 245);
|
||||
SurfaceBorder = Color.FromArgb(149, 164, 183);
|
||||
TextPrimary = Color.FromArgb(33, 43, 56);
|
||||
TextSecondary = Color.FromArgb(96, 109, 128);
|
||||
|
||||
Accent = Color.FromArgb(45, 117, 222);
|
||||
AccentDark = Color.FromArgb(28, 89, 184);
|
||||
AccentLight = Color.FromArgb(204, 225, 255);
|
||||
|
||||
Success = Color.FromArgb(45, 152, 99);
|
||||
Warning = Color.FromArgb(210, 139, 54);
|
||||
CurrentThemeName = "Default";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RefreshOpenWindows(CMLeonOS.Gui.WindowManager wm)
|
||||
{
|
||||
if (wm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < wm.Windows.Count; i++)
|
||||
{
|
||||
CMLeonOS.Gui.Window window = wm.Windows[i];
|
||||
if (window is AppWindow appWindow)
|
||||
{
|
||||
appWindow.RefreshTheme();
|
||||
}
|
||||
else if (window is Control control)
|
||||
{
|
||||
control.Render();
|
||||
}
|
||||
else
|
||||
{
|
||||
wm.Update(window);
|
||||
}
|
||||
}
|
||||
|
||||
wm.RerenderAll();
|
||||
}
|
||||
|
||||
static UITheme()
|
||||
{
|
||||
ApplyTheme("Default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace CMLeonOS.Settings
|
||||
{ "GUI_ScreenWidth", "1280" },
|
||||
{ "GUI_ScreenHeight", "800" },
|
||||
{ "GUI_WallpaperPath", "" },
|
||||
{ "GUI_Theme", "Default" },
|
||||
{ "GUI_DarkNotepad", "false" },
|
||||
{ "SkipToGui", "false" }
|
||||
};
|
||||
@@ -208,6 +209,23 @@ namespace CMLeonOS.Settings
|
||||
}
|
||||
}
|
||||
|
||||
public static string GUI_Theme
|
||||
{
|
||||
get
|
||||
{
|
||||
if (settings.TryGetValue("GUI_Theme", out string value))
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(value) ? "Default" : value;
|
||||
}
|
||||
return "Default";
|
||||
}
|
||||
set
|
||||
{
|
||||
settings["GUI_Theme"] = string.IsNullOrWhiteSpace(value) ? "Default" : value;
|
||||
SaveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GUI_DarkNotepad
|
||||
{
|
||||
get
|
||||
|
||||
Reference in New Issue
Block a user