Добавлен Studio

This commit is contained in:
2026-01-07 23:52:02 +03:00
parent ca5d912c9c
commit c3770c789b
19 changed files with 668 additions and 51 deletions

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="Lattice.Studio.Controls.LatticeStudioShell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Lattice.Studio.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:lui="using:Lattice.UI.Controls"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<!-- TitleBar с MenuBar -->
<RowDefinition Height="Auto" />
<!-- Тулбар -->
<RowDefinition Height="Auto" />
<!-- СЛОТ ДЛЯ УВЕДОМЛЕНИЙ -->
<RowDefinition Height="Auto" />
<!-- Докинг -->
<RowDefinition Height="*" />
<!-- Статус-бар -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Нативный TitleBar Windows 11 -->
<TitleBar x:Name="AppTitleBar"
Title="{x:Bind Title, Mode=OneWay}"
Subtitle="{x:Bind Subtitle, Mode=OneWay}"
IsBackButtonVisible="False"
IconSource="{x:Bind TitleBarIcon, Mode=OneWay}"
IsPaneToggleButtonVisible="False">
<!-- Вставляем меню прямо в заголовок -->
<TitleBar.Content>
<Grid x:Name="TitleBarContentGrid" Margin="8,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<!-- Меню -->
<ColumnDefinition Width="*" />
<!-- Зона перетаскивания -->
</Grid.ColumnDefinitions>
<!-- Слот для MenuBar -->
<ContentPresenter x:Name="MenuSlot"
Content="{x:Bind MenuContent, Mode=OneWay}"
VerticalAlignment="Center" />
<!-- Пустая область для захвата мышью (Drag Region) -->
<Canvas Grid.Column="1" Background="Transparent" />
</Grid>
</TitleBar.Content>
</TitleBar>
<!-- Тулбар -->
<lui:LatticeContextualToolbar Grid.Row="1" x:Name="StudioToolbar" />
<!-- Контейнер для уведомлений (StackPanel для нескольких сообщений) -->
<StackPanel Grid.Row="2" x:Name="NotificationArea" VerticalAlignment="Top" Canvas.ZIndex="100" />
<!-- Докинг -->
<lui:LatticeDockHost Grid.Row="3" x:Name="MainDockHost" />
<!-- Статус-бар -->
<ContentPresenter Grid.Row="4" Content="{x:Bind StatusContent, Mode=OneWay}" />
</Grid>
</UserControl>

View File

@@ -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;
/// <summary>
/// Îñíîâíàÿ îáîëî÷êà ïðèëîæåíèÿ â ñòèëå Visual Studio 2026.
/// Îáåñïå÷èâàåò èíòåãðàöèþ íàòèâíîãî çàãîëîâêà, ñèñòåìû äîêèíãà è êîíòåêñòíûõ êîìàíä.
/// </summary>
public sealed partial class LatticeStudioShell : UserControl
{
private ILayoutService? _layoutManager;
private IContextService? _contextService;
private IEnumerable<ActionDefinition>? _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();
}
/// <summary>
/// Èíèöèàëèçèðóåò îáîëî÷êó Studio è ñâÿçûâàåò å¸ ñ ñåðâèñàìè Lattice.Core.
/// </summary>
/// <param name="layoutManager">Ýêçåìïëÿð ILayoutService äëÿ óïðàâëåíèÿ îêíàìè.</param>
/// <param name="contextService">Ýêçåìïëÿð IContextService äëÿ óïðàâëåíèÿ êíîïêàìè òóëáàðà.</param>
/// <param name="actions">Ïîëíûé ñïèñîê îïðåäåëåíèé êîìàíä (ActionDefinition).</param>
public void Initialize(ILayoutService layoutManager, IContextService contextService, IEnumerable<ActionDefinition> 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);
}
/// <summary>
/// Íàñòðàèâàåò èíòåãðàöèþ ñ íàòèâíûì îêíîì Windows 11 (TitleBar è Backdrop).
/// Âûçûâàåòñÿ èç MainWindow ïðèëîæåíèÿ.
/// </summary>
/// <param name="window">Òåêóùåå îêíî WinUI 3.</param>
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
};
}
/// <summary>
/// Ïîäêëþ÷àåò ñåðâèñ óâåäîìëåíèé ê îáîëî÷êå.
/// </summary>
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
};
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="Lattice.Studio.Controls.LatticeStudioWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Lattice.Studio.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="LatticeStudioWindow">
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<local:LatticeStudioShell x:Name="ShellRoot" />
</Window>

View File

@@ -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;
/// <summary>
/// Îêíî âåðõíåãî óðîâíÿ, ñîäåðæàùåå LatticeStudioShell.
/// Îò íåãî íàñëåäóåòñÿ ðåàëüíîå ïðèëîæåíèå.
/// </summary>
public partial class LatticeStudioWindow : Window
{
/// <summary>
/// Âíóòðåííèé âèçóàëüíûé Shell.
/// </summary>
public LatticeStudioShell Shell => ShellRoot;
public LatticeStudioWindow()
{
InitializeComponent();
// Ñòàðòîâûé çàãîëîâîê
Title = "Lattice IDE";
Shell.Title = Title;
}
/// <summary>
/// Ïåðåîïðåäåëÿåì Title, ÷òîáû ñèíõðîíèçèðîâàòü åãî ñ Shell.
/// </summary>
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
// --------------------------------------------------------------------
/// <summary>
/// Åäèíàÿ òî÷êà èíèöèàëèçàöèè îêíà.
/// Âûçûâàåòñÿ èç êîíñòðóêòîðà íàñëåäíèêà (MainWindow).
/// </summary>
public void Initialize(
ILayoutService layoutService,
IContextService contextService,
IEnumerable<ActionDefinition> actions,
INotificationService notificationService)
{
Shell.Initialize(layoutService, contextService, actions);
Shell.InitializeNotifications(notificationService);
Shell.SetupWindow(this);
OnShellInitialized();
}
/// <summary>
/// Èíèöèàëèçèðóåò îêíî ñòàíäàðòíûìè ðåàëèçàöèÿìè ñåðâèñîâ Lattice.Core.
/// Ïîäõîäèò äëÿ áûñòðûõ ïðîòîòèïîâ è ïðîñòûõ ïðèëîæåíèé.
/// </summary>
public void Initialize()
{
var layout = new LayoutService();
var context = new ContextService();
var notifications = new NotificationService();
// Ïóñòîé íàáîð êîìàíä ïî óìîë÷àíèþ
var actions = Enumerable.Empty<ActionDefinition>();
Initialize(layout, context, actions, notifications);
}
/// <summary>
/// Õóê äëÿ íàñëåäíèêîâ — âûçûâàåòñÿ ïîñëå ïîëíîé èíèöèàëèçàöèè Shell.
/// </summary>
protected virtual void OnShellInitialized()
{
}
}

View File

@@ -0,0 +1,45 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0-windows10.0.19041.0;net9.0-windows10.0.19041.0;net10.0-windows10.0.19041.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>Lattice.Studio</AssemblyName>
<RootNamespace>Lattice.Studio</RootNamespace>
<Authors>FrigaT</Authors>
<Company>FrigaT</Company>
<RepositoryUrl>https://git.frigat.duckdns.org/FrigaT/Lattice</RepositoryUrl>
<PackageProjectUrl>https://git.frigat.duckdns.org/FrigaT/Lattice</PackageProjectUrl>
<UseWinUI>true</UseWinUI>
<IsTrimmable>false</IsTrimmable>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Controls\LatticeStudioWindow.xaml" />
<None Remove="Themes\StudioThemes.xaml" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Lattice.Core\Lattice.Core.csproj" />
<ProjectReference Include="..\Lattice.UI\Lattice.UI.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="Controls\LatticeStudioWindow.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Themes\StudioThemes.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

182
Lattice.Studio/README.md Normal file
View File

@@ -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`),
- dragregion.
- **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
<studio:LatticeStudioWindow
x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:studio="using:Lattice.Studio.Controls">
</studio:LatticeStudioWindow>
```
### **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
<studio:LatticeStudioWindow
x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:studio="using:Lattice.Studio.Controls">
<studio:LatticeStudioWindow.MenuContent>
<MenuBar>
<MenuBarItem Title="File">
<MenuFlyoutItem Text="New" />
<MenuFlyoutItem Text="Open" />
<MenuFlyoutSeparator />
<MenuFlyoutItem Text="Exit" />
</MenuBarItem>
</MenuBar>
</studio:LatticeStudioWindow.MenuContent>
<studio:LatticeStudioWindow.StatusContent>
<TextBlock Text="Ready" Margin="8,0"/>
</studio:LatticeStudioWindow.StatusContent>
</studio:LatticeStudioWindow>
```
### **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();
```

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<!-- Цвета Visual Studio 2026 (Dark) -->
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="LatticeStatusBarBackground" Color="#FF007ACC"/>
<SolidColorBrush x:Key="LatticePaneHeaderBackground" Color="#FF2D2D30"/>
<SolidColorBrush x:Key="LatticePaneBackground" Color="#FF1E1E1E"/>
<SolidColorBrush x:Key="LatticeActiveHeaderBrush" Color="#FF007ACC"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="LatticeStatusBarBackground" Color="#FF007ACC"/>
<SolidColorBrush x:Key="LatticePaneHeaderBackground" Color="#FFEEEEF2"/>
<SolidColorBrush x:Key="LatticePaneBackground" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="LatticeActiveHeaderBrush" Color="#FF007ACC"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>