diff --git a/Lattice.Core/Abstractions/INotificationService.cs b/Lattice.Core/Abstractions/INotificationService.cs new file mode 100644 index 0000000..43e779d --- /dev/null +++ b/Lattice.Core/Abstractions/INotificationService.cs @@ -0,0 +1,17 @@ +using Lattice.Core.Models; +using Lattice.Core.Models.Enums; + +namespace Lattice.Core.Abstractions; + +/// +/// Описывает сервис для рассылки уведомлений внутри системы Lattice. +/// +public interface INotificationService +{ + /// + /// Событие, возникающее при отправке нового сообщения. + /// + event EventHandler NotificationReceived; + + void Show(string message, NotificationSeverity severity = NotificationSeverity.Info, int durationSeconds = 5); +} \ No newline at end of file diff --git a/Lattice.Core/Lattice.Core.csproj b/Lattice.Core/Lattice.Core.csproj index e9f25d4..9fda911 100644 --- a/Lattice.Core/Lattice.Core.csproj +++ b/Lattice.Core/Lattice.Core.csproj @@ -1,28 +1,25 @@  - net8.0;net9.0;net10.0 enable enable Lattice.Core Lattice.Core - FrigaT FrigaT https://git.frigat.duckdns.org/FrigaT/Lattice https://git.frigat.duckdns.org/FrigaT/Lattice Core docking and layout engine for Lattice UI (WinUI 3 / Uno Platform). - true latest - - + + diff --git a/Lattice.Core/Models/Enums/DockDirection.cs b/Lattice.Core/Models/Enums/DockDirection.cs index 12d797a..76c725c 100644 --- a/Lattice.Core/Models/Enums/DockDirection.cs +++ b/Lattice.Core/Models/Enums/DockDirection.cs @@ -8,4 +8,4 @@ public enum DockDirection Top, Bottom, Floating, -} \ No newline at end of file +} diff --git a/Lattice.Core/Models/Enums/NotificationSeverity.cs b/Lattice.Core/Models/Enums/NotificationSeverity.cs new file mode 100644 index 0000000..4917f7b --- /dev/null +++ b/Lattice.Core/Models/Enums/NotificationSeverity.cs @@ -0,0 +1,8 @@ +namespace Lattice.Core.Models.Enums; + +public enum NotificationSeverity { + Info, + Success, + Warning, + Error, +} \ No newline at end of file diff --git a/Lattice.Core/Models/NotificationEventArgs.cs b/Lattice.Core/Models/NotificationEventArgs.cs new file mode 100644 index 0000000..45bbb64 --- /dev/null +++ b/Lattice.Core/Models/NotificationEventArgs.cs @@ -0,0 +1,5 @@ +using Lattice.Core.Models.Enums; + +namespace Lattice.Core.Models; + +public record NotificationEventArgs(string Message, NotificationSeverity Severity, int DurationSeconds); \ No newline at end of file diff --git a/Lattice.Core/Context/ContextManager.cs b/Lattice.Core/Services/ContextService.cs similarity index 93% rename from Lattice.Core/Context/ContextManager.cs rename to Lattice.Core/Services/ContextService.cs index 84bc996..4bc11f0 100644 --- a/Lattice.Core/Context/ContextManager.cs +++ b/Lattice.Core/Services/ContextService.cs @@ -1,11 +1,11 @@ using Lattice.Core.Abstractions; -namespace Lattice.Core.Context; +namespace Lattice.Core.Services; /// /// Реализация сервиса управления контекстом приложения. /// -public class ContextManager : IContextService +public class ContextService : IContextService { private string _currentContext = "Common"; diff --git a/Lattice.Core/Engine/LayoutManager.cs b/Lattice.Core/Services/LayoutService.cs similarity index 98% rename from Lattice.Core/Engine/LayoutManager.cs rename to Lattice.Core/Services/LayoutService.cs index 5c87cc0..3a833a5 100644 --- a/Lattice.Core/Engine/LayoutManager.cs +++ b/Lattice.Core/Services/LayoutService.cs @@ -6,12 +6,12 @@ using Microsoft.Extensions.Logging; using System.Text.Json; using System.Text.Json.Serialization; -namespace Lattice.Core.Engine; +namespace Lattice.Core.Services; /// /// Реализация сервиса управления макетом. /// -public class LayoutManager : ILayoutService +public class LayoutService : ILayoutService { private readonly ILogger? _logger; private LayoutNode? _root; @@ -22,7 +22,7 @@ public class LayoutManager : ILayoutService /// public event EventHandler? LayoutUpdated; - public LayoutManager(ILogger? logger = null) + public LayoutService(ILogger? logger = null) { _logger = logger; } diff --git a/Lattice.Core/Services/NotificationService.cs b/Lattice.Core/Services/NotificationService.cs new file mode 100644 index 0000000..85ba200 --- /dev/null +++ b/Lattice.Core/Services/NotificationService.cs @@ -0,0 +1,19 @@ +using Lattice.Core.Abstractions; +using Lattice.Core.Models; +using Lattice.Core.Models.Enums; + +namespace Lattice.Core.Services; + +/// +/// Простая реализация сервиса уведомлений. +/// Хранит только событие и вызывает его при Show(). +/// +public sealed class NotificationService : INotificationService +{ + public event EventHandler? NotificationReceived; + + public void Show(string message, NotificationSeverity severity = NotificationSeverity.Info, int durationSeconds = 5) + { + NotificationReceived?.Invoke(this, new NotificationEventArgs(message, severity, durationSeconds)); + } +} \ No newline at end of file diff --git a/Lattice.Studio/Controls/LatticeStudioShell.xaml b/Lattice.Studio/Controls/LatticeStudioShell.xaml new file mode 100644 index 0000000..9d8aa52 --- /dev/null +++ b/Lattice.Studio/Controls/LatticeStudioShell.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Lattice.Studio/Controls/LatticeStudioShell.xaml.cs b/Lattice.Studio/Controls/LatticeStudioShell.xaml.cs new file mode 100644 index 0000000..8b8464a --- /dev/null +++ b/Lattice.Studio/Controls/LatticeStudioShell.xaml.cs @@ -0,0 +1,144 @@ +using Lattice.Core.Abstractions; +using Lattice.Core.Models; +using Lattice.Core.Models.Enums; +using Microsoft.UI.Composition.SystemBackdrops; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; + +namespace Lattice.Studio.Controls; + +/// +/// Visual Studio 2026. +/// , . +/// +public sealed partial class LatticeStudioShell : UserControl +{ + private ILayoutService? _layoutManager; + private IContextService? _contextService; + private IEnumerable? _allActions; + + #region Dependency Properties ( ) + + public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register(nameof(Title), typeof(string), typeof(LatticeStudioShell), new PropertyMetadata("Lattice IDE")); + + public string Subtitle { get => (string)GetValue(SubtitleProperty); set => SetValue(SubtitleProperty, value); } + public static readonly DependencyProperty SubtitleProperty = + DependencyProperty.Register(nameof(Subtitle), typeof(string), typeof(LatticeStudioShell), new PropertyMetadata(string.Empty)); + + public IconSource TitleBarIcon { get => (IconSource)GetValue(TitleBarIconProperty); set => SetValue(TitleBarIconProperty, value); } + public static readonly DependencyProperty TitleBarIconProperty = + DependencyProperty.Register(nameof(TitleBarIcon), typeof(IconSource), typeof(LatticeStudioShell), new PropertyMetadata(null)); + + public object MenuContent { get => GetValue(MenuContentProperty); set => SetValue(MenuContentProperty, value); } + public static readonly DependencyProperty MenuContentProperty = + DependencyProperty.Register(nameof(MenuContent), typeof(object), typeof(LatticeStudioShell), new PropertyMetadata(null)); + + public object StatusContent { get => GetValue(StatusContentProperty); set => SetValue(StatusContentProperty, value); } + public static readonly DependencyProperty StatusContentProperty = + DependencyProperty.Register(nameof(StatusContent), typeof(object), typeof(LatticeStudioShell), new PropertyMetadata(null)); + + #endregion + + public LatticeStudioShell() + { + this.InitializeComponent(); + } + + /// + /// Studio Lattice.Core. + /// + /// ILayoutService . + /// IContextService . + /// (ActionDefinition). + public void Initialize(ILayoutService layoutManager, IContextService contextService, IEnumerable actions) + { + _layoutManager = layoutManager; + _contextService = contextService; + _allActions = actions; + + // + MainDockHost.Manager = _layoutManager; + + // ( Lattice.UI) + _contextService.ContextChanged += (s, newContext) => + { + // + this.DispatcherQueue.TryEnqueue(() => + { + StudioToolbar.UpdateItems(_allActions, newContext); + }); + }; + + // + StudioToolbar.UpdateItems(_allActions, _contextService.CurrentContext); + } + + /// + /// Windows 11 (TitleBar Backdrop). + /// MainWindow . + /// + /// WinUI 3. + public void SetupWindow(Window window) + { + // 1. (Windowing SDK 1.8) + window.ExtendsContentIntoTitleBar = true; + + // 2. TitleBar + if (AppTitleBar != null) + { + window.SetTitleBar(AppTitleBar); + } + + // 3. Mica Alt Visual Studio 2026 + window.SystemBackdrop = new MicaBackdrop() + { + Kind = MicaKind.BaseAlt + }; + } + + /// + /// . + /// + public void InitializeNotifications(INotificationService notificationService) + { + notificationService.NotificationReceived += (s, e) => + { + this.DispatcherQueue.TryEnqueue(() => + { + var infoBar = new InfoBar + { + Message = e.Message, + Severity = MapSeverity(e.Severity), + IsOpen = true, + Style = (Style)Application.Current.Resources["LatticeNotificationStyle"] + }; + + // + if (e.DurationSeconds > 0) + { + var timer = new DispatcherTimer + { + Interval = TimeSpan.FromSeconds(e.DurationSeconds) + }; + timer.Tick += (st, et) => { infoBar.IsOpen = false; timer.Stop(); }; + timer.Start(); + } + + // + infoBar.CloseButtonClick += (sender, args) => NotificationArea.Children.Remove(infoBar); + + NotificationArea.Children.Insert(0, infoBar); // + }); + }; + } + private InfoBarSeverity MapSeverity(NotificationSeverity severity) => severity switch + { + NotificationSeverity.Error => InfoBarSeverity.Error, + NotificationSeverity.Warning => InfoBarSeverity.Warning, + NotificationSeverity.Success => InfoBarSeverity.Success, + _ => InfoBarSeverity.Informational + }; +} diff --git a/Lattice.Studio/Controls/LatticeStudioWindow.xaml b/Lattice.Studio/Controls/LatticeStudioWindow.xaml new file mode 100644 index 0000000..a3468b2 --- /dev/null +++ b/Lattice.Studio/Controls/LatticeStudioWindow.xaml @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/Lattice.Studio/Controls/LatticeStudioWindow.xaml.cs b/Lattice.Studio/Controls/LatticeStudioWindow.xaml.cs new file mode 100644 index 0000000..0010025 --- /dev/null +++ b/Lattice.Studio/Controls/LatticeStudioWindow.xaml.cs @@ -0,0 +1,116 @@ +using Lattice.Core.Abstractions; +using Lattice.Core.Models; +using Lattice.Core.Services; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; + +namespace Lattice.Studio.Controls; + +/// +/// , LatticeStudioShell. +/// . +/// +public partial class LatticeStudioWindow : Window +{ + /// + /// Shell. + /// + public LatticeStudioShell Shell => ShellRoot; + + public LatticeStudioWindow() + { + InitializeComponent(); + + // + Title = "Lattice IDE"; + Shell.Title = Title; + } + + /// + /// Title, Shell. + /// + public new string Title + { + get => base.Title; + set + { + base.Title = value; + if (ShellRoot is not null) + { + ShellRoot.Title = value; + } + } + } + + // -------------------------------------------------------------------- + // Shell + // -------------------------------------------------------------------- + + public string Subtitle + { + get => Shell.Subtitle; + set => Shell.Subtitle = value; + } + + public IconSource TitleBarIcon + { + get => Shell.TitleBarIcon; + set => Shell.TitleBarIcon = value; + } + + public object MenuContent + { + get => Shell.MenuContent; + set => Shell.MenuContent = value; + } + + public object StatusContent + { + get => Shell.StatusContent; + set => Shell.StatusContent = value; + } + + // -------------------------------------------------------------------- + // Lattice.Core + // -------------------------------------------------------------------- + + /// + /// . + /// (MainWindow). + /// + public void Initialize( + ILayoutService layoutService, + IContextService contextService, + IEnumerable actions, + INotificationService notificationService) + { + Shell.Initialize(layoutService, contextService, actions); + Shell.InitializeNotifications(notificationService); + Shell.SetupWindow(this); + + OnShellInitialized(); + } + + /// + /// Lattice.Core. + /// . + /// + public void Initialize() + { + var layout = new LayoutService(); + var context = new ContextService(); + var notifications = new NotificationService(); + + // + var actions = Enumerable.Empty(); + + Initialize(layout, context, actions, notifications); + } + + /// + /// Shell. + /// + protected virtual void OnShellInitialized() + { + } +} \ No newline at end of file diff --git a/Lattice.Studio/Lattice.Studio.csproj b/Lattice.Studio/Lattice.Studio.csproj new file mode 100644 index 0000000..62839b4 --- /dev/null +++ b/Lattice.Studio/Lattice.Studio.csproj @@ -0,0 +1,45 @@ + + + net8.0-windows10.0.19041.0;net9.0-windows10.0.19041.0;net10.0-windows10.0.19041.0 + enable + enable + Lattice.Studio + Lattice.Studio + + FrigaT + FrigaT + https://git.frigat.duckdns.org/FrigaT/Lattice + https://git.frigat.duckdns.org/FrigaT/Lattice + + true + false + latest + + + + + + + + + + + + + + + + + + + MSBuild:Compile + + + + + + MSBuild:Compile + + + + \ No newline at end of file diff --git a/Lattice.Studio/README.md b/Lattice.Studio/README.md new file mode 100644 index 0000000..a6c59f5 --- /dev/null +++ b/Lattice.Studio/README.md @@ -0,0 +1,182 @@ +# **Lattice.Studio** + +`Lattice.Studio` — это модуль, предоставляющий готовую визуальную оболочку для приложений на WinUI 3, оформленную в стиле Visual Studio 2026. +Он включает: + +- нативный Windows 11 TitleBar, +- слот для меню, +- контекстный тулбар, +- область уведомлений, +- хост для докинга, +- статус‑бар, +- тему оформления (Dark/Light), +- и главное — **готовое окно верхнего уровня `LatticeStudioWindow`**. + +`LatticeStudioShell` служит визуальным контейнером, а `LatticeStudioWindow` — удобной точкой входа для реальных приложений. + +--- + +## 📦 Состав модуля + +### **1. LatticeStudioShell.xaml** +Определяет визуальную структуру IDE‑оболочки: + +- **TitleBar**: + - заголовок, + - иконка (`IconSource`), + - слот для меню (`MenuContent`), + - drag‑region. +- **LatticeContextualToolbar** — контекстный тулбар. +- **NotificationArea** — стек уведомлений. +- **LatticeDockHost** — хост для системы докинга. +- **StatusContent** — слот для статус‑бара. + +### **2. LatticeStudioShell.xaml.cs** +Реализует логику оболочки: + +- интеграция с сервисами: + - `ILayoutService`, + - `IContextService`, + - `INotificationService`; +- обновление тулбара при смене контекста; +- отображение уведомлений через `InfoBar`; +- настройка окна: + - `ExtendsContentIntoTitleBar`, + - кастомный TitleBar, + - Mica Alt backdrop. + +### **3. LatticeStudioWindow.xaml / .cs** +Готовое окно верхнего уровня: + +- содержит `LatticeStudioShell`, +- проксирует его свойства наружу: + - `Title`, + - `Subtitle`, + - `MenuContent`, + - `StatusContent`, + - `TitleBarIcon`, +- предоставляет удобный метод инициализации: + - `Initialize(...)` — с пользовательскими сервисами, + - `Initialize()` — со стандартными реализациями. + +Используется как базовый класс для `MainWindow`. + +### **4. Themes/StudioThemes.xaml** +Содержит тему оформления: + +- цвета панелей, +- цвета заголовков, +- акцентные цвета, +- поддержка Light/Dark. + +--- + +## ✨ Возможности + +- Готовая IDE‑оболочка для WinUI 3. +- Интеграция с Lattice.Core: + - докинг, + - контексты, + - команды. +- Нативный Windows 11 TitleBar. +- Встроенная система уведомлений. +- Слоты для меню и статус‑бара. +- Тема в стиле Visual Studio 2026. +- Готовое окно `LatticeStudioWindow` для быстрого старта. + +--- + +## 🚀 Быстрый старт + +## 🅰 Вариант 1 — минимальный XAML (всё в C#) + +### **MainWindow.xaml** + +```xml + + +``` + +### **MainWindow.xaml.cs** + +```csharp +public sealed partial class MainWindow : LatticeStudioWindow +{ + public MainWindow() + { + InitializeComponent(); + + Title = "My App"; + + MenuContent = BuildMenu(); + StatusContent = new TextBlock { Text = "Ready" }; + + Initialize(); // стандартные сервисы + } +} +``` + +--- + +## 🅱 Вариант 2 — декларативный XAML (меню/статус‑бар в XAML) + +### **MainWindow.xaml** + +```xml + + + + + + + + + + + + + + + + + + +``` + +### **MainWindow.xaml.cs** + +```csharp +public sealed partial class MainWindow : LatticeStudioWindow +{ + public MainWindow() + { + InitializeComponent(); + Title = "My App"; + Initialize(); // стандартные сервисы + } +} +``` + +--- + +## 🧩 Инициализация вручную + +Если нужны свои сервисы: + +```csharp +Initialize(layoutService, contextService, actions, notificationService); +``` + +Если нужен быстрый старт: + +```csharp +Initialize(); +``` \ No newline at end of file diff --git a/Lattice.Studio/Themes/StudioThemes.xaml b/Lattice.Studio/Themes/StudioThemes.xaml new file mode 100644 index 0000000..8ec0b03 --- /dev/null +++ b/Lattice.Studio/Themes/StudioThemes.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Lattice.UI/Lattice.UI.csproj b/Lattice.UI/Lattice.UI.csproj index 74d34ae..e090eb9 100644 --- a/Lattice.UI/Lattice.UI.csproj +++ b/Lattice.UI/Lattice.UI.csproj @@ -16,12 +16,7 @@ latest - - - - - - + @@ -34,40 +29,8 @@ - + MSBuild:Compile - - - - - MSBuild:Compile - - - - - - MSBuild:Compile - - - - - - MSBuild:Compile - - - - - - MSBuild:Compile - - - - - - MSBuild:Compile - - - - + \ No newline at end of file diff --git a/Lattice.UI/Themes/Generic.xaml b/Lattice.UI/Themes/Generic.xaml index 024198b..096522c 100644 --- a/Lattice.UI/Themes/Generic.xaml +++ b/Lattice.UI/Themes/Generic.xaml @@ -11,6 +11,7 @@ + diff --git a/Lattice.UI/Themes/Styles/LatticeNotification.xaml b/Lattice.UI/Themes/Styles/LatticeNotification.xaml new file mode 100644 index 0000000..4012332 --- /dev/null +++ b/Lattice.UI/Themes/Styles/LatticeNotification.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/Lattice.slnx b/Lattice.slnx index 311d94a..ba833f3 100644 --- a/Lattice.slnx +++ b/Lattice.slnx @@ -1,4 +1,5 @@ +