// 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 . 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(); return dock; } } Window window; List Icons = new List(); WindowManager wm = ProcessManager.GetProcess(); SettingsService settingsService = ProcessManager.GetProcess(); internal static readonly int IconSize = 64; internal static readonly int IconImageMaxSize = 48; private static readonly Color DockBackground = Color.FromArgb(211, 211, 211); private static readonly Color ActiveIconBackground = Color.FromArgb(160, 190, 255); private static readonly Color ActiveIndicator = Color.FromArgb(36, 88, 196); 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(DockBackground); AppWindow focusedApp = wm.GetOwningAppWindow(wm.Focus); int x = 0; foreach (var icon in Icons) { int iconWidth = (int)icon.Size; bool isSelected = icon is AppDockIcon appDockIcon && appDockIcon.AppWindow == focusedApp; if (isSelected && iconWidth > 4 && window.Height > 4) { window.DrawFilledRectangle(x + 2, 2, iconWidth - 4, window.Height - 4, ActiveIconBackground); window.DrawFilledRectangle(x + 10, window.Height - 5, Math.Max(8, iconWidth - 20), 3, ActiveIndicator); } 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 += iconWidth; } 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(); } } } }