mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-03-03 15:30:27 +00:00
GUI桌面环境
This commit is contained in:
22
Gui/ShellComponents/Dock/AppDockIcon.cs
Normal file
22
Gui/ShellComponents/Dock/AppDockIcon.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents.Dock
|
||||
{
|
||||
internal class AppDockIcon : BaseDockIcon
|
||||
{
|
||||
internal AppDockIcon(AppWindow appWindow) : base(
|
||||
image: appWindow.Icon,
|
||||
doAnimation: true)
|
||||
{
|
||||
AppWindow = appWindow;
|
||||
}
|
||||
|
||||
internal AppWindow AppWindow { get; init; }
|
||||
|
||||
internal override void Clicked()
|
||||
{
|
||||
ProcessManager.GetProcess<WindowManager>().Focus = AppWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Gui/ShellComponents/Dock/BaseDockIcon.cs
Normal file
82
Gui/ShellComponents/Dock/BaseDockIcon.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using Cosmos.System.Graphics;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents.Dock
|
||||
{
|
||||
internal abstract class BaseDockIcon
|
||||
{
|
||||
internal BaseDockIcon(Bitmap image, bool doAnimation = true)
|
||||
{
|
||||
if (doAnimation)
|
||||
{
|
||||
Size = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip to the end of the animation.
|
||||
Size = Dock.IconSize;
|
||||
}
|
||||
|
||||
Image = image;
|
||||
}
|
||||
|
||||
private double _size;
|
||||
internal double Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
set
|
||||
{
|
||||
_size = value;
|
||||
|
||||
if (_image != null)
|
||||
{
|
||||
SizedImage = _image.ResizeWidthKeepRatio((uint)Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap _image;
|
||||
internal Bitmap Image
|
||||
{
|
||||
get
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
set
|
||||
{
|
||||
_image = value;
|
||||
SizedImage = value.ResizeWidthKeepRatio((uint)Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal Bitmap SizedImage { get; private set; }
|
||||
|
||||
internal bool Closing { get; set; } = false;
|
||||
|
||||
internal bool CloseAnimationComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return Closing && (int)_size == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the dock icon's animation.
|
||||
/// </summary>
|
||||
/// <returns>If the dock needs to be rerendered.</returns>
|
||||
internal bool RunAnimation()
|
||||
{
|
||||
int oldSize = (int)Size;
|
||||
int goalSize = Closing ? 1 : Dock.IconSize;
|
||||
Size += (goalSize - Size) / 16;
|
||||
|
||||
return (int)Size != (int)oldSize;
|
||||
}
|
||||
|
||||
internal abstract void Clicked();
|
||||
}
|
||||
}
|
||||
190
Gui/ShellComponents/Dock/Dock.cs
Normal file
190
Gui/ShellComponents/Dock/Dock.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.UILib.Animations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents.Dock
|
||||
{
|
||||
internal class Dock : Process
|
||||
{
|
||||
internal Dock() : base("Dock", ProcessType.Application)
|
||||
{
|
||||
}
|
||||
|
||||
internal static Dock CurrentDock
|
||||
{
|
||||
get
|
||||
{
|
||||
Dock dock = ProcessManager.GetProcess<Dock>();
|
||||
return dock;
|
||||
}
|
||||
}
|
||||
|
||||
Window window;
|
||||
|
||||
List<BaseDockIcon> Icons = new List<BaseDockIcon>();
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
|
||||
internal static readonly int IconSize = 64;
|
||||
internal static readonly int IconImageMaxSize = 48;
|
||||
|
||||
private void Render()
|
||||
{
|
||||
int newDockWidth = 0;
|
||||
foreach (var icon in Icons)
|
||||
{
|
||||
newDockWidth += (int)icon.Size;
|
||||
}
|
||||
|
||||
if (newDockWidth != window.Width)
|
||||
{
|
||||
window.MoveAndResize((int)(wm.ScreenWidth / 2 - newDockWidth / 2), window.Y, newDockWidth, window.Height);
|
||||
}
|
||||
|
||||
window.Clear(Color.FromArgb(130, 202, 255));
|
||||
|
||||
int x = 0;
|
||||
foreach (var icon in Icons)
|
||||
{
|
||||
if (icon.Image != null)
|
||||
{
|
||||
Bitmap resizedImage = icon.Image.ResizeWidthKeepRatio((uint)Math.Min(IconImageMaxSize, icon.Size));
|
||||
|
||||
int imageX = (int)(x + ((icon.Size / 2) - (resizedImage.Width / 2)));
|
||||
window.DrawImageAlpha(resizedImage, imageX, (int)((window.Height / 2) - (resizedImage.Height / 2)));
|
||||
}
|
||||
|
||||
x += (int)icon.Size;
|
||||
}
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
internal int GetDockHeight()
|
||||
{
|
||||
return window.Height;
|
||||
}
|
||||
|
||||
internal void UpdateWindows()
|
||||
{
|
||||
// Add new windows and update icons.
|
||||
foreach (var window in wm.Windows)
|
||||
{
|
||||
if (window is not AppWindow appWindow)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
foreach (BaseDockIcon icon in Icons)
|
||||
{
|
||||
if (icon is AppDockIcon appDockIcon && appDockIcon.AppWindow == appWindow)
|
||||
{
|
||||
icon.Image = appWindow.Icon;
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
Icons.Add(new AppDockIcon(appWindow));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove deleted windows.
|
||||
foreach (BaseDockIcon icon in Icons)
|
||||
{
|
||||
if (icon is not AppDockIcon appDockIcon)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
foreach (Window window in wm.Windows)
|
||||
{
|
||||
if (window == appDockIcon.AppWindow)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
icon.Closing = true;
|
||||
}
|
||||
}
|
||||
|
||||
Render();
|
||||
}
|
||||
|
||||
private void DockClick(int x, int y)
|
||||
{
|
||||
int end = 0;
|
||||
foreach (var icon in Icons)
|
||||
{
|
||||
end += (int)icon.Size;
|
||||
|
||||
if (x < end)
|
||||
{
|
||||
icon.Clicked();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
window = new Window(this, (int)(wm.ScreenWidth / 2), (int)(wm.ScreenHeight + IconSize), IconSize, IconSize);
|
||||
window.OnClick = DockClick;
|
||||
wm.AddWindow(window);
|
||||
|
||||
Icons.Add(new StartMenuDockIcon());
|
||||
|
||||
Render();
|
||||
|
||||
MovementAnimation animation = new MovementAnimation(window)
|
||||
{
|
||||
From = new Rectangle(window.X, window.Y, window.Width, window.Height),
|
||||
To = new Rectangle(window.X, (int)(wm.ScreenHeight - IconSize), window.Width, window.Height),
|
||||
Duration = 10
|
||||
};
|
||||
animation.Start();
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
bool rerenderNeeded = false;
|
||||
|
||||
for (int i = Icons.Count - 1; i >= 0; i--)
|
||||
{
|
||||
BaseDockIcon icon = Icons[i];
|
||||
|
||||
if (icon.RunAnimation())
|
||||
{
|
||||
rerenderNeeded = true;
|
||||
}
|
||||
|
||||
if (icon.CloseAnimationComplete)
|
||||
{
|
||||
Icons.Remove(icon);
|
||||
}
|
||||
}
|
||||
|
||||
if (rerenderNeeded)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Gui/ShellComponents/Dock/StartMenuDockIcon.cs
Normal file
22
Gui/ShellComponents/Dock/StartMenuDockIcon.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Cosmos.System.Graphics;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents.Dock
|
||||
{
|
||||
internal class StartMenuDockIcon : BaseDockIcon
|
||||
{
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Dock.StartMenu.bmp")]
|
||||
private static byte[] _iconBytes_StartMenu;
|
||||
internal static Bitmap Icon_StartMenu = new Bitmap(_iconBytes_StartMenu);
|
||||
|
||||
internal StartMenuDockIcon() : base(
|
||||
image: Icon_StartMenu,
|
||||
doAnimation: false)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Clicked()
|
||||
{
|
||||
StartMenu.CurrentStartMenu.ToggleStartMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
204
Gui/ShellComponents/Lock.cs
Normal file
204
Gui/ShellComponents/Lock.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.Logger;
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents
|
||||
{
|
||||
internal class Lock : Process
|
||||
{
|
||||
internal Lock() : base("Lock", ProcessType.Application) { }
|
||||
|
||||
AppWindow window;
|
||||
|
||||
TextBox usernameBox;
|
||||
|
||||
TextBox passwordBox;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
Sound.SoundService soundService = ProcessManager.GetProcess<Sound.SoundService>();
|
||||
|
||||
private static class Images
|
||||
{
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Lock.Key.bmp")]
|
||||
private static byte[] _iconBytes_Key;
|
||||
internal static Bitmap Icon_Key = new Bitmap(_iconBytes_Key);
|
||||
}
|
||||
|
||||
private const int width = 352;
|
||||
private const int height = 128;
|
||||
private const int padding = 12;
|
||||
|
||||
private double shakiness = 0;
|
||||
|
||||
private void RenderBackground()
|
||||
{
|
||||
window.Clear(Color.LightGray);
|
||||
|
||||
window.DrawImageAlpha(Images.Icon_Key, padding, padding);
|
||||
|
||||
window.DrawString("Enter your username and password,\nthen press Enter to log on", Color.Black, (int)(padding + Images.Icon_Key.Width + padding), padding);
|
||||
}
|
||||
|
||||
private void ShowError(string text)
|
||||
{
|
||||
MessageBox messageBox = new MessageBox(this, "Logon Failed", text);
|
||||
messageBox.Show();
|
||||
}
|
||||
|
||||
private void Shake()
|
||||
{
|
||||
shakiness = 24;
|
||||
}
|
||||
|
||||
private void LogOn()
|
||||
{
|
||||
if (usernameBox.Text.Trim() == string.Empty || passwordBox.Text.Trim() == string.Empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string username = usernameBox.Text.Trim();
|
||||
string password = passwordBox.Text.Trim();
|
||||
|
||||
Logger.Logger.Instance.Info("Lock", $"Attempting login for user: {username}");
|
||||
|
||||
var users = UserSystem.GetUsers();
|
||||
Logger.Logger.Instance.Info("Lock", $"UserSystem.GetUsers() returned: {(users == null ? "null" : users.Count.ToString())}");
|
||||
|
||||
if (users == null || users.Count == 0)
|
||||
{
|
||||
Logger.Logger.Instance.Error("Lock", "User list is null or empty!");
|
||||
ShowError("User system error. Please restart.");
|
||||
Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
User foundUser = null;
|
||||
foreach (User user in users)
|
||||
{
|
||||
Logger.Logger.Instance.Info("Lock", $"Checking user: {user.Username} (lower: {user.Username.ToLower()})");
|
||||
if (user.Username.ToLower() == username.ToLower())
|
||||
{
|
||||
foundUser = user;
|
||||
Logger.Logger.Instance.Info("Lock", $"User matched: {foundUser.Username}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundUser == null)
|
||||
{
|
||||
Logger.Logger.Instance.Warning("Lock", $"User not found: {username}");
|
||||
Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Logger.Instance.Info("Lock", $"User found: {foundUser.Username}, Admin: {foundUser.Admin}");
|
||||
|
||||
string hashedInputPassword = UserSystem.HashPasswordSha256(password);
|
||||
Logger.Logger.Instance.Info("Lock", $"Password hash: {hashedInputPassword}");
|
||||
Logger.Logger.Instance.Info("Lock", $"Stored password hash: {foundUser.Password}");
|
||||
|
||||
if (foundUser.Password != hashedInputPassword)
|
||||
{
|
||||
Logger.Logger.Instance.Warning("Lock", $"Authentication failed for user: {foundUser.Username}");
|
||||
passwordBox.Text = string.Empty;
|
||||
|
||||
if (foundUser.LockedOut)
|
||||
{
|
||||
TimeSpan remaining = foundUser.LockoutEnd - DateTime.Now;
|
||||
if (remaining.Minutes > 0)
|
||||
{
|
||||
ShowError($"Try again in {remaining.Minutes}m, {remaining.Seconds}s.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError($"Try again in {remaining.Seconds}s.");
|
||||
}
|
||||
}
|
||||
|
||||
wm.Update(window);
|
||||
soundService.PlaySystemSound(Sound.SystemSound.Alert);
|
||||
Shake();
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Logger.Instance.Info("Lock", $"Authentication successful for user: {foundUser.Username}");
|
||||
|
||||
TryStop();
|
||||
UserSystem.SetCurrentLoggedInUser(foundUser);
|
||||
ProcessManager.AddProcess(wm, new ShellComponents.Taskbar()).Start();
|
||||
ProcessManager.AddProcess(wm, new ShellComponents.Dock.Dock()).Start();
|
||||
soundService.PlaySystemSound(Sound.SystemSound.Login);
|
||||
|
||||
Logger.Logger.Instance.Info("Lock", $"{foundUser.Username} logged on to the GUI.");
|
||||
}
|
||||
|
||||
private void LogOnClick(int x, int y)
|
||||
{
|
||||
LogOn();
|
||||
}
|
||||
|
||||
#region Process
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
var users = UserSystem.GetUsers();
|
||||
Logger.Logger.Instance.Info("Lock", $"Lock started. Total users: {users?.Count ?? 0}");
|
||||
if (users != null)
|
||||
{
|
||||
foreach (var user in users)
|
||||
{
|
||||
Logger.Logger.Instance.Info("Lock", $" - User: {user.Username}, Admin: {user.Admin}");
|
||||
}
|
||||
}
|
||||
|
||||
window = new AppWindow(this, (int)(wm.ScreenWidth / 2 - width / 2), (int)(wm.ScreenHeight / 2 - height / 2), width, height);
|
||||
window.Title = "CMLeonOS Logon";
|
||||
window.Icon = Images.Icon_Key;
|
||||
window.CanMove = false;
|
||||
window.CanClose = false;
|
||||
wm.AddWindow(window);
|
||||
|
||||
RenderBackground();
|
||||
|
||||
int boxesStartY = (int)(padding + Images.Icon_Key.Height + padding);
|
||||
|
||||
usernameBox = new TextBox(window, padding, boxesStartY, 160, 20);
|
||||
usernameBox.PlaceholderText = "Username";
|
||||
usernameBox.Submitted = LogOn;
|
||||
wm.AddWindow(usernameBox);
|
||||
|
||||
passwordBox = new TextBox(window, padding, boxesStartY + padding + 20, 160, 20);
|
||||
passwordBox.Shield = true;
|
||||
passwordBox.PlaceholderText = "Password";
|
||||
passwordBox.Submitted = LogOn;
|
||||
wm.AddWindow(passwordBox);
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
int oldX = window.X;
|
||||
int newX = (int)((wm.ScreenWidth / 2) - (width / 2) + (Math.Sin(shakiness) * 8));
|
||||
if (oldX != newX)
|
||||
{
|
||||
window.Move(newX, window.Y);
|
||||
}
|
||||
shakiness /= 1.1;
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
base.Stop();
|
||||
wm.RemoveWindow(window);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
280
Gui/ShellComponents/StartMenu.cs
Normal file
280
Gui/ShellComponents/StartMenu.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.UILib.Animations;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents
|
||||
{
|
||||
internal class StartMenu : Process
|
||||
{
|
||||
internal StartMenu() : base("StartMenu", ProcessType.Application)
|
||||
{
|
||||
}
|
||||
|
||||
internal static StartMenu CurrentStartMenu
|
||||
{
|
||||
get
|
||||
{
|
||||
StartMenu startMenu = ProcessManager.GetProcess<StartMenu>();
|
||||
if (startMenu == null && ProcessManager.GetProcess<Taskbar>() != null)
|
||||
{
|
||||
startMenu = (StartMenu)ProcessManager.AddProcess(ProcessManager.GetProcess<WindowManager>(), new StartMenu());
|
||||
startMenu.Start();
|
||||
}
|
||||
return startMenu;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Icons
|
||||
{
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.StartMenu.User.bmp")]
|
||||
private static byte[] _iconBytes_User;
|
||||
internal static Bitmap Icon_User = new Bitmap(_iconBytes_User);
|
||||
}
|
||||
|
||||
Window window;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
SettingsService settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
|
||||
private Button shutdownButton;
|
||||
private Button rebootButton;
|
||||
private Button allAppsButton;
|
||||
|
||||
private const int buttonsPadding = 12;
|
||||
private const int buttonsWidth = 96;
|
||||
private const int buttonsHeight = 20;
|
||||
private const int userHeight = 56;
|
||||
private const int userPadding = 12;
|
||||
private const int searchWidth = 128;
|
||||
|
||||
private bool isOpen = false;
|
||||
|
||||
internal void ShowStartMenu(bool focusSearch = false)
|
||||
{
|
||||
isOpen = true;
|
||||
|
||||
bool leftHandStartButton = settingsService.LeftHandStartButton;
|
||||
|
||||
window = new Window(this, leftHandStartButton ? 0 : (int)(wm.ScreenWidth / 2 - 408 / 2), 24, 408, 222);
|
||||
|
||||
window.Clear(Color.FromArgb(56, 56, 71));
|
||||
|
||||
window.DrawString($"Start", Color.White, 12, 12);
|
||||
|
||||
Rectangle userRect = new Rectangle(userPadding, window.Height - userHeight + userPadding, window.Width - (userPadding * 2), userHeight - (userPadding * 2));
|
||||
window.DrawImageAlpha(Icons.Icon_User, userRect.X, (int)(userRect.Y + (userRect.Height / 2) - (Icons.Icon_User.Height / 2)));
|
||||
window.DrawString(UserSystem.CurrentLoggedInUser.Username, Color.White, (int)(userRect.X + Icons.Icon_User.Width + userPadding), (int)(userRect.Y + (userRect.Height / 2) - (16 / 2)));
|
||||
|
||||
wm.AddWindow(window);
|
||||
|
||||
int x = 12;
|
||||
int y = 44;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
AppMetadata app = AppManager.AppMetadatas[i];
|
||||
|
||||
Button appButton = new Button(window, x, y, 90, 90);
|
||||
|
||||
appButton.Background = app.ThemeColor;
|
||||
appButton.Foreground = app.ThemeColor.GetForegroundColour();
|
||||
|
||||
appButton.Text = app.Name;
|
||||
appButton.Image = app.Icon;
|
||||
|
||||
appButton.OnClick = (x, y) =>
|
||||
{
|
||||
app.Start(this);
|
||||
HideStartMenu();
|
||||
};
|
||||
|
||||
wm.AddWindow(appButton);
|
||||
|
||||
x += appButton.Width + 8;
|
||||
if (x > window.Width - 90)
|
||||
{
|
||||
x = 12;
|
||||
y += 90 + 8;
|
||||
}
|
||||
}
|
||||
|
||||
shutdownButton = new Button(window, window.Width - buttonsWidth - buttonsPadding, window.Height - buttonsHeight - ((userHeight / 2) - (buttonsHeight / 2)), buttonsWidth, buttonsHeight);
|
||||
shutdownButton.Text = "Shut down";
|
||||
shutdownButton.OnClick = ShutdownClicked;
|
||||
wm.AddWindow(shutdownButton);
|
||||
|
||||
rebootButton = new Button(window, window.Width - (buttonsPadding * 2 + buttonsWidth * 2), window.Height - buttonsHeight - ((userHeight / 2) - (buttonsHeight / 2)), buttonsWidth, buttonsHeight);
|
||||
rebootButton.Text = "Restart";
|
||||
rebootButton.OnClick = RebootClicked;
|
||||
wm.AddWindow(rebootButton);
|
||||
|
||||
allAppsButton = new Button(window, window.Width - buttonsWidth - buttonsPadding, window.Height - buttonsHeight - userHeight, buttonsWidth, buttonsHeight);
|
||||
allAppsButton.Text = "All apps >";
|
||||
allAppsButton.OnClick = AllAppsClicked;
|
||||
wm.AddWindow(allAppsButton);
|
||||
|
||||
Table searchResults = null;
|
||||
TextBox searchBox = new TextBox(window, (window.Width / 2) - (searchWidth / 2), 12, searchWidth, 20);
|
||||
if (focusSearch)
|
||||
{
|
||||
wm.Focus = searchBox;
|
||||
}
|
||||
searchBox.PlaceholderText = "Search";
|
||||
searchBox.Changed = () =>
|
||||
{
|
||||
if (searchResults == null)
|
||||
{
|
||||
searchResults = new Table(searchBox, 0, searchBox.Height, searchBox.Width, 0);
|
||||
|
||||
searchResults.CellHeight = 24;
|
||||
|
||||
searchResults.TableCellSelected = (int index) =>
|
||||
{
|
||||
if (index != -1)
|
||||
{
|
||||
((AppMetadata)searchResults.Cells[index].Tag).Start(this);
|
||||
HideStartMenu();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
searchResults.Cells.Clear();
|
||||
|
||||
if (searchBox.Text.Trim().Length > 0)
|
||||
{
|
||||
foreach (AppMetadata app in AppManager.AppMetadatas)
|
||||
{
|
||||
if (app.Name.ToLower().StartsWith(searchBox.Text.ToLower()))
|
||||
{
|
||||
string name = app.Name;
|
||||
if (name.Length > 8)
|
||||
{
|
||||
name = name.Substring(0, 8).Trim() + "...";
|
||||
}
|
||||
searchResults.Cells.Add(new TableCell(app.Icon.Resize(20, 20), name, tag: app));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (searchResults.Cells.Count > 0)
|
||||
{
|
||||
searchResults.Resize(searchResults.Width, searchResults.Cells.Count * searchResults.CellHeight);
|
||||
searchResults.Render();
|
||||
|
||||
wm.AddWindow(searchResults);
|
||||
|
||||
wm.Update(searchResults);
|
||||
}
|
||||
else
|
||||
{
|
||||
wm.RemoveWindow(searchResults);
|
||||
}
|
||||
};
|
||||
searchBox.Submitted = () =>
|
||||
{
|
||||
searchBox.Text = string.Empty;
|
||||
wm.Update(searchBox);
|
||||
|
||||
if (searchResults != null && searchResults.Cells.Count > 0)
|
||||
{
|
||||
((AppMetadata)searchResults.Cells[0].Tag).Start(this);
|
||||
HideStartMenu();
|
||||
}
|
||||
};
|
||||
searchBox.OnUnfocused = () =>
|
||||
{
|
||||
if (searchResults != null)
|
||||
{
|
||||
wm.RemoveWindow(searchResults);
|
||||
searchResults = null;
|
||||
|
||||
searchBox.Text = string.Empty;
|
||||
wm.Update(searchBox);
|
||||
}
|
||||
};
|
||||
wm.AddWindow(searchBox);
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
private void ShutdownClicked(int x, int y)
|
||||
{
|
||||
Power.Shutdown(reboot: false);
|
||||
}
|
||||
|
||||
private void RebootClicked(int x, int y)
|
||||
{
|
||||
Power.Shutdown(reboot: true);
|
||||
}
|
||||
|
||||
private void AllAppsClicked(int x, int y)
|
||||
{
|
||||
Table allAppsTable = new Table(window, 0, 0, window.Width, window.Height);
|
||||
|
||||
allAppsTable.CellHeight = 32;
|
||||
|
||||
allAppsTable.Background = Color.FromArgb(56, 56, 71);
|
||||
allAppsTable.Foreground = Color.White;
|
||||
allAppsTable.Border = Color.FromArgb(36, 36, 51);
|
||||
|
||||
foreach (AppMetadata app in AppManager.AppMetadatas)
|
||||
{
|
||||
TableCell cell = new TableCell(app.Icon.Resize(20, 20), app.Name);
|
||||
/*cell.BackgroundColourOverride = app.ThemeColor;
|
||||
cell.ForegroundColourOverride = app.ThemeColor.GetForegroundColour();*/
|
||||
allAppsTable.Cells.Add(cell);
|
||||
}
|
||||
allAppsTable.Render();
|
||||
|
||||
allAppsTable.TableCellSelected = (int index) =>
|
||||
{
|
||||
if (index != -1)
|
||||
{
|
||||
AppManager.AppMetadatas[index].Start(this);
|
||||
HideStartMenu();
|
||||
}
|
||||
};
|
||||
|
||||
wm.AddWindow(allAppsTable);
|
||||
|
||||
MovementAnimation animation = new MovementAnimation(allAppsTable)
|
||||
{
|
||||
From = new Rectangle(allAppsTable.X, allAppsTable.Y, allAppsTable.Width, allAppsTable.Height),
|
||||
To = new Rectangle(allAppsTable.X, allAppsTable.Y, allAppsTable.Width, allAppsTable.Height + 64),
|
||||
Duration = 5
|
||||
};
|
||||
animation.Start();
|
||||
|
||||
wm.Update(allAppsTable);
|
||||
}
|
||||
|
||||
internal void HideStartMenu()
|
||||
{
|
||||
isOpen = false;
|
||||
wm.RemoveWindow(window);
|
||||
}
|
||||
|
||||
internal void ToggleStartMenu(bool focusSearch = false)
|
||||
{
|
||||
if (isOpen)
|
||||
{
|
||||
HideStartMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowStartMenu(focusSearch);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Gui/ShellComponents/Taskbar.cs
Normal file
146
Gui/ShellComponents/Taskbar.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
using Cosmos.System.Graphics;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using CMLeonOS.UILib.Animations;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.ShellComponents
|
||||
{
|
||||
internal class Taskbar : Process
|
||||
{
|
||||
internal Taskbar() : base("Taskbar", ProcessType.Application)
|
||||
{
|
||||
Critical = true;
|
||||
}
|
||||
|
||||
[IL2CPU.API.Attribs.ManifestResourceStream(ResourceName = "CMLeonOS.Gui.Resources.Start.bmp")]
|
||||
private static byte[] startBytes;
|
||||
private static Bitmap startBitmap = new Bitmap(startBytes);
|
||||
|
||||
Window window;
|
||||
|
||||
WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
|
||||
DateTime lastDate = DateTime.Now;
|
||||
|
||||
TextBlock time;
|
||||
|
||||
ImageBlock start;
|
||||
|
||||
SettingsService settingsService;
|
||||
|
||||
private bool miniCalendarOpen = false;
|
||||
private Calendar miniCalendar;
|
||||
|
||||
private int timeUpdateTicks = 0;
|
||||
|
||||
internal void SetLeftHandStartButton(bool left)
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
start.X = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
start.X = (int)((window.Width / 2) - (startBitmap.Width / 2));
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetTaskbarHeight()
|
||||
{
|
||||
return window.Height;
|
||||
}
|
||||
|
||||
internal void UpdateTime()
|
||||
{
|
||||
if (settingsService == null)
|
||||
{
|
||||
settingsService = ProcessManager.GetProcess<SettingsService>();
|
||||
}
|
||||
|
||||
string timeText;
|
||||
if (settingsService.TwelveHourClock)
|
||||
{
|
||||
timeText = DateTime.Now.ToString("ddd h:mm tt");
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText = DateTime.Now.ToString("ddd HH:mm");
|
||||
}
|
||||
if (time.Text != timeText)
|
||||
{
|
||||
time.Text = timeText;
|
||||
}
|
||||
}
|
||||
|
||||
private void StartClicked(int x, int y)
|
||||
{
|
||||
StartMenu.CurrentStartMenu.ToggleStartMenu();
|
||||
}
|
||||
|
||||
private void TimeClicked(int x, int y)
|
||||
{
|
||||
miniCalendarOpen = !miniCalendarOpen;
|
||||
if (miniCalendarOpen)
|
||||
{
|
||||
miniCalendar = new Calendar(window, window.Width - 256, window.Height, 256, 256);
|
||||
miniCalendar.Background = Color.FromArgb(56, 56, 71);
|
||||
miniCalendar.TodayBackground = Color.FromArgb(77, 77, 91);
|
||||
miniCalendar.Foreground = Color.White;
|
||||
miniCalendar.WeekendForeground = Color.LightPink;
|
||||
wm.AddWindow(miniCalendar);
|
||||
wm.Update(miniCalendar);
|
||||
}
|
||||
else
|
||||
{
|
||||
wm.RemoveWindow(miniCalendar);
|
||||
}
|
||||
}
|
||||
|
||||
#region Process
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
window = new Window(this, 0, -24, (int)wm.ScreenWidth, 24);
|
||||
window.Clear(Color.Black);
|
||||
wm.AddWindow(window);
|
||||
|
||||
time = new TextBlock(window, window.Width - 136, 0, 128, window.Height);
|
||||
time.Background = Color.Black;
|
||||
time.Foreground = Color.White;
|
||||
time.HorizontalAlignment = Alignment.End;
|
||||
time.VerticalAlignment = Alignment.Middle;
|
||||
time.OnClick = TimeClicked;
|
||||
wm.AddWindow(time);
|
||||
|
||||
start = new ImageBlock(window, (int)((window.Width / 2) - startBitmap.Width / 2), 0, 24, 24);
|
||||
start.Image = startBitmap;
|
||||
start.OnClick = StartClicked;
|
||||
wm.AddWindow(start);
|
||||
|
||||
UpdateTime();
|
||||
|
||||
MovementAnimation animation = new MovementAnimation(window)
|
||||
{
|
||||
From = new Rectangle(window.X, window.Y, window.Width, window.Height),
|
||||
To = new Rectangle(window.X, 0, window.Width, window.Height),
|
||||
Duration = 10
|
||||
};
|
||||
animation.Start();
|
||||
|
||||
wm.Update(window);
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
timeUpdateTicks++;
|
||||
if (timeUpdateTicks % 100 == 0)
|
||||
{
|
||||
UpdateTime();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user