add:浮动栏自定义
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 工具栏按钮插件与宿主之间的桥梁。Phase 1 粗粒度暴露 MainWindow,后续收窄。
|
||||||
|
/// </summary>
|
||||||
|
public interface IToolbarHost
|
||||||
|
{
|
||||||
|
MainWindow Window { get; }
|
||||||
|
|
||||||
|
/// <summary>按 id 登记按钮的 view 实例(供 MainWindow 字段回填和互相查找)。</summary>
|
||||||
|
void RegisterView(string id, FrameworkElement view);
|
||||||
|
|
||||||
|
/// <summary>按 id 获取之前注册的 view。不存在返回 null。</summary>
|
||||||
|
FrameworkElement FindView(string id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 一个工具栏按钮(或任意浮动栏/白板栏条目)的插件化契约。
|
||||||
|
/// 实现类必须有无参构造函数,启动时会被 ToolbarRegistry 反射实例化。
|
||||||
|
/// </summary>
|
||||||
|
public interface IToolbarItem
|
||||||
|
{
|
||||||
|
/// <summary>稳定、唯一的 id,用于持久化用户配置。不要随便改。</summary>
|
||||||
|
string Id { get; }
|
||||||
|
|
||||||
|
ToolbarSlot DefaultSlot { get; }
|
||||||
|
|
||||||
|
/// <summary>同一 slot 内的默认顺序,小的在前。</summary>
|
||||||
|
int DefaultOrder { get; }
|
||||||
|
|
||||||
|
bool DefaultVisible { get; }
|
||||||
|
|
||||||
|
ToolbarInsertPosition DefaultPosition { get; }
|
||||||
|
|
||||||
|
/// <summary>仅当 Position 为 BeforeAnchor/AfterAnchor 时有意义,对应 XAML 里 x:Name。</summary>
|
||||||
|
string DefaultAnchorName { get; }
|
||||||
|
|
||||||
|
/// <summary>构造 UI 元素并接线所有行为。</summary>
|
||||||
|
FrameworkElement BuildView(IToolbarHost host);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 清空按钮。位置:夹在颜色面板与 StackPanelCanvasControls 之间,
|
||||||
|
/// 所以用 BeforeAnchor 锚到 StackPanelCanvasControls。
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class ClearToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.clear";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Clear";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarMain;
|
||||||
|
public override int DefaultOrder => 0;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.BeforeAnchor;
|
||||||
|
public override string DefaultAnchorName => "StackPanelCanvasControls";
|
||||||
|
|
||||||
|
protected override string IconBrushResourceKey => "RedBrush";
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.SymbolIconDelete_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachSymbolIconDelete(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class CursorToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.cursor";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Mouse";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarMain;
|
||||||
|
public override int DefaultOrder => 100;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.CursorIcon_Click(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachCursorIconView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class CursorWithDelToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.cursorWithDel";
|
||||||
|
public override string LocalizationKey => "FloatingBar_ClearAndMouse";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 320;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.Append;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.CursorWithDelIcon_Click(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachCursorWithDelBtn(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class EraserByStrokesToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.eraserByStrokes";
|
||||||
|
public override string LocalizationKey => "FloatingBar_StrokeEraser";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 110;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.EraserIconByStrokes_Click(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachEraserByStrokesIcon(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class EraserToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.eraser";
|
||||||
|
public override string LocalizationKey => "FloatingBar_AreaEraser";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 100;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.EraserIcon_Click(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachEraserIcon(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class FoldToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.fold";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Hide";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarEnd;
|
||||||
|
public override int DefaultOrder => 120;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.AfterAnchor;
|
||||||
|
public override string DefaultAnchorName => "FloatingBarEndSeparator";
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.FoldFloatingBar_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachFoldIcon(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class PenToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.pen";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Annotate";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarMain;
|
||||||
|
public override int DefaultOrder => 110;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.PenIcon_Click(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachPenIconView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class RedoToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.redo";
|
||||||
|
public override string LocalizationKey => "Board_Redo";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 310;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.Append;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.SymbolIconRedo_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
{
|
||||||
|
host.Window.AttachSymbolIconRedo(view);
|
||||||
|
view.SetBinding(System.Windows.UIElement.IsEnabledProperty,
|
||||||
|
new System.Windows.Data.Binding("IsEnabled") { ElementName = "BtnRedo" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class SelectToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.select";
|
||||||
|
public override string LocalizationKey => "FloatingBar_LassoSelect";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 120;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.SymbolIconSelect_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachSymbolIconSelect(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class ShapeDrawToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.shapeDraw";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Geometry";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 130;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.ImageDrawShape_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachShapeDrawBtn(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using Ink_Canvas.Properties;
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 通用 ToolbarImageButton 工具栏条目基类——大幅减少每个按钮的样板代码。
|
||||||
|
/// 派生类通常只需给 Id / 本地化键 / Slot / Order / 点击处理 / Attach 回填。
|
||||||
|
/// </summary>
|
||||||
|
internal abstract class ToolbarImageButtonItemBase : IToolbarItem
|
||||||
|
{
|
||||||
|
public abstract string Id { get; }
|
||||||
|
public abstract string LocalizationKey { get; }
|
||||||
|
public abstract ToolbarSlot DefaultSlot { get; }
|
||||||
|
public abstract int DefaultOrder { get; }
|
||||||
|
public virtual bool DefaultVisible => true;
|
||||||
|
public virtual ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.Prepend;
|
||||||
|
public virtual string DefaultAnchorName => null;
|
||||||
|
|
||||||
|
/// <summary>DynamicResource 名称,用于 IconBrush。默认为 null(使用控件自带前景色)。</summary>
|
||||||
|
protected virtual string IconBrushResourceKey => null;
|
||||||
|
|
||||||
|
protected abstract void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e);
|
||||||
|
|
||||||
|
/// <summary>构建后调用,用于回填 MainWindow 的原命名属性(partial 扩展里的 Attach*)。可选。</summary>
|
||||||
|
protected virtual void AfterBuild(IToolbarHost host, ToolbarImageButton view) { }
|
||||||
|
|
||||||
|
public FrameworkElement BuildView(IToolbarHost host)
|
||||||
|
{
|
||||||
|
var btn = new ToolbarImageButton
|
||||||
|
{
|
||||||
|
Label = Strings.GetString(LocalizationKey) ?? LocalizationKey
|
||||||
|
};
|
||||||
|
if (!string.IsNullOrEmpty(IconBrushResourceKey))
|
||||||
|
{
|
||||||
|
if (btn.TryFindResource(IconBrushResourceKey) is Brush brush) btn.IconBrush = brush;
|
||||||
|
else btn.SetResourceReference(ToolbarImageButton.IconBrushProperty, IconBrushResourceKey);
|
||||||
|
}
|
||||||
|
btn.ButtonMouseUp += (s, e) => OnClick(host, s, e);
|
||||||
|
AfterBuild(host, btn);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class ToolsToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.tools";
|
||||||
|
public override string LocalizationKey => "Board_Tools";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarEnd;
|
||||||
|
public override int DefaultOrder => 110;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.AfterAnchor;
|
||||||
|
public override string DefaultAnchorName => "FloatingBarEndSeparator";
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.SymbolIconTools_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachToolsBtn(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class UndoToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.undo";
|
||||||
|
public override string LocalizationKey => "Board_Undo";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarCanvasControls;
|
||||||
|
public override int DefaultOrder => 300;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.Append;
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.SymbolIconUndo_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
{
|
||||||
|
host.Window.AttachSymbolIconUndo(view);
|
||||||
|
view.SetBinding(System.Windows.UIElement.IsEnabledProperty,
|
||||||
|
new System.Windows.Data.Binding("IsEnabled") { ElementName = "BtnUndo" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar.Items
|
||||||
|
{
|
||||||
|
internal sealed class WhiteboardToolItem : ToolbarImageButtonItemBase
|
||||||
|
{
|
||||||
|
public override string Id => "builtin.whiteboard";
|
||||||
|
public override string LocalizationKey => "FloatingBar_Whiteboard";
|
||||||
|
public override ToolbarSlot DefaultSlot => ToolbarSlot.FloatingBarEnd;
|
||||||
|
public override int DefaultOrder => 100;
|
||||||
|
public override ToolbarInsertPosition DefaultPosition => ToolbarInsertPosition.AfterAnchor;
|
||||||
|
public override string DefaultAnchorName => "FloatingBarEndSeparator";
|
||||||
|
|
||||||
|
protected override void OnClick(IToolbarHost host, object sender, MouseButtonEventArgs e)
|
||||||
|
=> host.Window.ImageBlackboard_MouseUp(sender, e);
|
||||||
|
|
||||||
|
protected override void AfterBuild(IToolbarHost host, ToolbarImageButton view)
|
||||||
|
=> host.Window.AttachWhiteboardBtn(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// MainWindow 版的 IToolbarHost 实现。Phase 1 直接把 MainWindow 引用暴露给插件,
|
||||||
|
/// 插件可通过 host.Window 访问私有/内部成员(partial class 扩展或 internal 字段)。
|
||||||
|
/// 后续阶段逐步把具体行为抽成 Host 上的方法/事件,收窄这个接口。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ToolbarHost : IToolbarHost
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, FrameworkElement> _views = new Dictionary<string, FrameworkElement>();
|
||||||
|
|
||||||
|
public ToolbarHost(MainWindow window)
|
||||||
|
{
|
||||||
|
Window = window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainWindow Window { get; }
|
||||||
|
|
||||||
|
public void RegisterView(string id, FrameworkElement view)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id) || view == null) return;
|
||||||
|
_views[id] = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameworkElement FindView(string id)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id)) return null;
|
||||||
|
return _views.TryGetValue(id, out var v) ? v : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
public enum ToolbarInsertPosition
|
||||||
|
{
|
||||||
|
/// <summary>从容器头部依次插入;Order 小的在前。</summary>
|
||||||
|
Prepend,
|
||||||
|
/// <summary>追加到容器末尾。</summary>
|
||||||
|
Append,
|
||||||
|
/// <summary>插入到由 AnchorName 指定的已有元素之前。</summary>
|
||||||
|
BeforeAnchor,
|
||||||
|
/// <summary>插入到由 AnchorName 指定的已有元素之后(同一锚点多项按 Order 依次排列)。</summary>
|
||||||
|
AfterAnchor
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 单个工具栏按钮的用户配置(可见性、顺序、所属 slot、插入位置)。
|
||||||
|
/// 由 Settings.Toolbar 持久化。
|
||||||
|
/// </summary>
|
||||||
|
public class ToolbarItemConfig
|
||||||
|
{
|
||||||
|
[JsonProperty("visible")]
|
||||||
|
public bool Visible { get; set; } = true;
|
||||||
|
|
||||||
|
[JsonProperty("order")]
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("slot")]
|
||||||
|
public ToolbarSlot Slot { get; set; } = ToolbarSlot.FloatingBarMain;
|
||||||
|
|
||||||
|
[JsonProperty("position")]
|
||||||
|
public ToolbarInsertPosition Position { get; set; } = ToolbarInsertPosition.Prepend;
|
||||||
|
|
||||||
|
[JsonProperty("anchorName")]
|
||||||
|
public string AnchorName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ToolbarLayoutSettings
|
||||||
|
{
|
||||||
|
[JsonProperty("items")]
|
||||||
|
public Dictionary<string, ToolbarItemConfig> Items { get; set; } = new Dictionary<string, ToolbarItemConfig>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using Ink_Canvas.Helpers;
|
||||||
|
|
||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 扫描当前程序集里的 IToolbarItem 实现,按用户配置(Settings.Toolbar)排序/过滤后注入到目标容器。
|
||||||
|
/// </summary>
|
||||||
|
public static class ToolbarRegistry
|
||||||
|
{
|
||||||
|
private static List<IToolbarItem> _items;
|
||||||
|
|
||||||
|
public static IReadOnlyList<IToolbarItem> Discover()
|
||||||
|
{
|
||||||
|
if (_items != null) return _items;
|
||||||
|
|
||||||
|
var itemType = typeof(IToolbarItem);
|
||||||
|
_items = Assembly.GetExecutingAssembly()
|
||||||
|
.GetTypes()
|
||||||
|
.Where(t => !t.IsAbstract && !t.IsInterface && itemType.IsAssignableFrom(t))
|
||||||
|
.Select(t =>
|
||||||
|
{
|
||||||
|
try { return (IToolbarItem)Activator.CreateInstance(t); }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"ToolbarRegistry: 实例化 {t.FullName} 失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.Where(i => i != null)
|
||||||
|
.ToList();
|
||||||
|
return _items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>按 slot 分配工具栏条目到对应容器。调用者负责清空目标容器里要被接管的旧内容。</summary>
|
||||||
|
public static void Populate(IToolbarHost host, IDictionary<ToolbarSlot, Panel> slots, ToolbarLayoutSettings layout)
|
||||||
|
{
|
||||||
|
if (host == null || slots == null) return;
|
||||||
|
layout = layout ?? new ToolbarLayoutSettings();
|
||||||
|
|
||||||
|
var grouped = new Dictionary<ToolbarSlot, List<(IToolbarItem item, ToolbarItemConfig cfg)>>();
|
||||||
|
foreach (var item in Discover())
|
||||||
|
{
|
||||||
|
if (!layout.Items.TryGetValue(item.Id, out var cfg))
|
||||||
|
{
|
||||||
|
cfg = new ToolbarItemConfig
|
||||||
|
{
|
||||||
|
Visible = item.DefaultVisible,
|
||||||
|
Order = item.DefaultOrder,
|
||||||
|
Slot = item.DefaultSlot,
|
||||||
|
Position = item.DefaultPosition,
|
||||||
|
AnchorName = item.DefaultAnchorName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!cfg.Visible) continue;
|
||||||
|
if (!grouped.TryGetValue(cfg.Slot, out var list))
|
||||||
|
{
|
||||||
|
list = new List<(IToolbarItem, ToolbarItemConfig)>();
|
||||||
|
grouped[cfg.Slot] = list;
|
||||||
|
}
|
||||||
|
list.Add((item, cfg));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var kv in grouped)
|
||||||
|
{
|
||||||
|
if (!slots.TryGetValue(kv.Key, out var container) || container == null) continue;
|
||||||
|
InjectIntoContainer(host, container, kv.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InjectIntoContainer(IToolbarHost host, Panel container,
|
||||||
|
List<(IToolbarItem item, ToolbarItemConfig cfg)> entries)
|
||||||
|
{
|
||||||
|
// 按 Position 分桶,每桶内按 Order 升序。
|
||||||
|
var prepend = entries.Where(e => e.cfg.Position == ToolbarInsertPosition.Prepend).OrderBy(e => e.cfg.Order).ToList();
|
||||||
|
var append = entries.Where(e => e.cfg.Position == ToolbarInsertPosition.Append).OrderBy(e => e.cfg.Order).ToList();
|
||||||
|
var before = entries.Where(e => e.cfg.Position == ToolbarInsertPosition.BeforeAnchor).ToList();
|
||||||
|
var after = entries.Where(e => e.cfg.Position == ToolbarInsertPosition.AfterAnchor).ToList();
|
||||||
|
|
||||||
|
var prependIndex = 0;
|
||||||
|
foreach (var entry in prepend)
|
||||||
|
{
|
||||||
|
var view = BuildAndRegister(host, entry.item);
|
||||||
|
if (view == null) continue;
|
||||||
|
container.Children.Insert(prependIndex++, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var entry in append)
|
||||||
|
{
|
||||||
|
var view = BuildAndRegister(host, entry.item);
|
||||||
|
if (view == null) continue;
|
||||||
|
container.Children.Add(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var group in before.GroupBy(e => e.cfg.AnchorName))
|
||||||
|
{
|
||||||
|
var anchor = FindNamedChild(container, group.Key);
|
||||||
|
if (anchor == null)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"ToolbarRegistry: 未找到锚点 '{group.Key}' (BeforeAnchor)", LogHelper.LogType.Warning);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var idx = container.Children.IndexOf(anchor);
|
||||||
|
foreach (var entry in group.OrderBy(e => e.cfg.Order))
|
||||||
|
{
|
||||||
|
var view = BuildAndRegister(host, entry.item);
|
||||||
|
if (view == null) continue;
|
||||||
|
container.Children.Insert(idx++, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var group in after.GroupBy(e => e.cfg.AnchorName))
|
||||||
|
{
|
||||||
|
var anchor = FindNamedChild(container, group.Key);
|
||||||
|
if (anchor == null)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"ToolbarRegistry: 未找到锚点 '{group.Key}' (AfterAnchor)", LogHelper.LogType.Warning);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var idx = container.Children.IndexOf(anchor) + 1;
|
||||||
|
foreach (var entry in group.OrderBy(e => e.cfg.Order))
|
||||||
|
{
|
||||||
|
var view = BuildAndRegister(host, entry.item);
|
||||||
|
if (view == null) continue;
|
||||||
|
container.Children.Insert(idx++, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UIElement FindNamedChild(Panel container, string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(name)) return null;
|
||||||
|
foreach (UIElement child in container.Children)
|
||||||
|
{
|
||||||
|
if (child is FrameworkElement fe && fe.Name == name) return child;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrameworkElement BuildAndRegister(IToolbarHost host, IToolbarItem item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var view = item.BuildView(host);
|
||||||
|
if (view == null) return null;
|
||||||
|
host.RegisterView(item.Id, view);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogHelper.WriteLogToFile($"ToolbarRegistry: 构建 {item.Id} 失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Ink_Canvas.Controls.Toolbar
|
||||||
|
{
|
||||||
|
public enum ToolbarSlot
|
||||||
|
{
|
||||||
|
FloatingBarMain,
|
||||||
|
FloatingBarCanvasControls,
|
||||||
|
FloatingBarEnd,
|
||||||
|
BlackboardLeft,
|
||||||
|
BlackboardRight
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2467,9 +2467,7 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
<ikw:SimpleStackPanel Margin="2,0" Name="StackPanelFloatingBar" Orientation="Horizontal" Cursor="Arrow" HorizontalAlignment="Left">
|
<ikw:SimpleStackPanel Margin="2,0" Name="StackPanelFloatingBar" Orientation="Horizontal" Cursor="Arrow" HorizontalAlignment="Left">
|
||||||
<!--<ikw:SimpleStackPanel Name="Cursor_Icon" MouseDown="Border_MouseDown" MouseUp="CursorIcon_Click"-->
|
<!-- Cursor_Icon / Pen_Icon 由 ToolbarRegistry 动态注入(见 Controls/Toolbar/Items/*) -->
|
||||||
<controls:ToolbarImageButton x:Name="Cursor_Icon" ButtonMouseUp="CursorIcon_Click" Label="{i18n:I18n Key=FloatingBar_Mouse}" />
|
|
||||||
<controls:ToolbarImageButton x:Name="Pen_Icon" ButtonMouseUp="PenIcon_Click" Label="{i18n:I18n Key=FloatingBar_Annotate}" />
|
|
||||||
<ikw:SimpleStackPanel Width="0"
|
<ikw:SimpleStackPanel Width="0"
|
||||||
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
||||||
<Grid Margin="-14,5,14,5" Width="0" RenderTransformOrigin=" 1,0">
|
<Grid Margin="-14,5,14,5" Width="0" RenderTransformOrigin=" 1,0">
|
||||||
@@ -2849,15 +2847,12 @@
|
|||||||
ButtonMouseDown="FloatingBarToolBtnMouseDownFeedback_Panel" ButtonMouseLeave="FloatingBarToolBtnMouseLeaveFeedback_Panel" ButtonMouseUp="QuickColorGreen_Click" ToolTip="{i18n:I18n Key=Canvas_Color_Green}"/>
|
ButtonMouseDown="FloatingBarToolBtnMouseDownFeedback_Panel" ButtonMouseLeave="FloatingBarToolBtnMouseLeaveFeedback_Panel" ButtonMouseUp="QuickColorGreen_Click" ToolTip="{i18n:I18n Key=Canvas_Color_Green}"/>
|
||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
|
|
||||||
<controls:ToolbarImageButton x:Name="SymbolIconDelete" ButtonMouseUp="SymbolIconDelete_MouseUp" IconBrush="{DynamicResource RedBrush}" Label="{i18n:I18n Key=FloatingBar_Clear}" />
|
<!-- SymbolIconDelete 由 ClearToolItem 动态注入(BeforeAnchor=StackPanelCanvasControls) -->
|
||||||
<ikw:SimpleStackPanel Name="StackPanelCanvasControls" Visibility="Visible"
|
<ikw:SimpleStackPanel Name="StackPanelCanvasControls" Visibility="Visible"
|
||||||
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
||||||
|
|
||||||
|
|
||||||
<controls:ToolbarImageButton x:Name="Eraser_Icon" ButtonMouseUp="EraserIcon_Click" Label="{i18n:I18n Key=FloatingBar_AreaEraser}" />
|
<!-- Eraser_Icon / EraserByStrokes_Icon / SymbolIconSelect / ShapeDrawFloatingBarBtn 由 ToolbarRegistry 注入(Prepend) -->
|
||||||
<controls:ToolbarImageButton x:Name="EraserByStrokes_Icon" ButtonMouseUp="EraserIconByStrokes_Click" Label="{i18n:I18n Key=FloatingBar_StrokeEraser}" />
|
|
||||||
<controls:ToolbarImageButton x:Name="SymbolIconSelect" ButtonMouseUp="SymbolIconSelect_MouseUp" Label="{i18n:I18n Key=FloatingBar_LassoSelect}" />
|
|
||||||
<controls:ToolbarImageButton x:Name="ShapeDrawFloatingBarBtn" ButtonMouseUp="ImageDrawShape_MouseUp" Label="{i18n:I18n Key=FloatingBar_Geometry}" />
|
|
||||||
|
|
||||||
<Grid Width="0">
|
<Grid Width="0">
|
||||||
<Border x:Name="BorderDrawShape" Background="{DynamicResource FloatBarBackground}" Opacity="1"
|
<Border x:Name="BorderDrawShape" Background="{DynamicResource FloatBarBackground}" Opacity="1"
|
||||||
@@ -2911,9 +2906,7 @@
|
|||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<controls:ToolbarImageButton x:Name="SymbolIconUndo" ButtonMouseUp="SymbolIconUndo_MouseUp" Label="{i18n:I18n Key=Board_Undo}" IsEnabled="{Binding ElementName=BtnUndo, Path=IsEnabled}" />
|
<!-- SymbolIconUndo / SymbolIconRedo / CursorWithDelFloatingBarBtn 由 ToolbarRegistry 注入(Append) -->
|
||||||
<controls:ToolbarImageButton x:Name="SymbolIconRedo" ButtonMouseUp="SymbolIconRedo_MouseUp" Label="{i18n:I18n Key=Board_Redo}" IsEnabled="{Binding ElementName=BtnRedo, Path=IsEnabled}" />
|
|
||||||
<controls:ToolbarImageButton x:Name="CursorWithDelFloatingBarBtn" ButtonMouseUp="CursorWithDelIcon_Click" Label="{i18n:I18n Key=FloatingBar_ClearAndMouse}" />
|
|
||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
<Grid Width="0">
|
<Grid Width="0">
|
||||||
<Grid x:Name="BackgroundPaletteGrid" Margin="-203,-128,83,37">
|
<Grid x:Name="BackgroundPaletteGrid" Margin="-203,-128,83,37">
|
||||||
@@ -3051,12 +3044,10 @@
|
|||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<ikw:SimpleStackPanel
|
<ikw:SimpleStackPanel x:Name="StackPanelFloatingBarEnd"
|
||||||
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
Orientation="{Binding ElementName=StackPanelFloatingBar, Path=Orientation}">
|
||||||
<Border Margin="2,0,2,0" BorderBrush="#71717a" BorderThickness="1,0,0,0" />
|
<Border x:Name="FloatingBarEndSeparator" Margin="2,0,2,0" BorderBrush="#71717a" BorderThickness="1,0,0,0" />
|
||||||
<controls:ToolbarImageButton x:Name="WhiteboardFloatingBarBtn" ButtonMouseUp="ImageBlackboard_MouseUp" Label="{i18n:I18n Key=FloatingBar_Whiteboard}" />
|
<!-- WhiteboardFloatingBarBtn / ToolsFloatingBarBtn / Fold_Icon 由 ToolbarRegistry 注入(AfterAnchor=FloatingBarEndSeparator) -->
|
||||||
<controls:ToolbarImageButton x:Name="ToolsFloatingBarBtn" ButtonMouseUp="SymbolIconTools_MouseUp" Label="{i18n:I18n Key=Board_Tools}" />
|
|
||||||
<controls:ToolbarImageButton x:Name="Fold_Icon" ButtonMouseUp="FoldFloatingBar_MouseUp" Label="{i18n:I18n Key=FloatingBar_Hide}" />
|
|
||||||
<Grid Width="0">
|
<Grid Width="0">
|
||||||
<Border ClipToBounds="True" Name="BorderTools" Margin="-103,-156,-16,37"
|
<Border ClipToBounds="True" Name="BorderTools" Margin="-103,-156,-16,37"
|
||||||
CornerRadius="5" Background="{DynamicResource FloatBarBackground}" Opacity="1" BorderThickness="1"
|
CornerRadius="5" Background="{DynamicResource FloatBarBackground}" Opacity="1" BorderThickness="1"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
|
using Ink_Canvas.Controls.Toolbar;
|
||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using Ink_Canvas.Windows;
|
using Ink_Canvas.Windows;
|
||||||
using Ink_Canvas.Windows.SettingsViews.Helpers;
|
using Ink_Canvas.Windows.SettingsViews.Helpers;
|
||||||
@@ -74,6 +76,14 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
internal static DateTime? TrayTemporaryShowUntilUtc;
|
internal static DateTime? TrayTemporaryShowUntilUtc;
|
||||||
|
|
||||||
|
// Phase 1: Cursor_Icon / Pen_Icon 原为 XAML 自动生成字段,迁移到 ToolbarRegistry 动态注入后
|
||||||
|
// 由 ToolbarHost 在 Window_Loaded 中回填。外部代码 (MW_AutoTheme / MW_FloatingBarIcons 等)
|
||||||
|
// 以原字段名继续访问,无需修改。
|
||||||
|
internal ToolbarImageButton Cursor_Icon { get; private set; }
|
||||||
|
internal ToolbarImageButton Pen_Icon { get; private set; }
|
||||||
|
|
||||||
|
internal ToolbarHost ToolbarHost { get; private set; }
|
||||||
|
|
||||||
#region Window Initialization
|
#region Window Initialization
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1175,6 +1185,9 @@ namespace Ink_Canvas
|
|||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
loadPenCanvas();
|
loadPenCanvas();
|
||||||
|
// 工具栏插件化按钮先注入到容器,确保 LoadSettings 内部对 Cursor_Icon / Pen_Icon 等的访问非空。
|
||||||
|
// Settings.Toolbar 此时尚为默认值(全部可见),与旧 XAML 行为一致。
|
||||||
|
InitializeToolbarPlugins();
|
||||||
//加载设置
|
//加载设置
|
||||||
LoadSettings(true);
|
LoadSettings(true);
|
||||||
ApplyLanguageFromSettings();
|
ApplyLanguageFromSettings();
|
||||||
|
|||||||
@@ -1685,7 +1685,7 @@ namespace Ink_Canvas
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">发送者</param>
|
/// <param name="sender">发送者</param>
|
||||||
/// <param name="e">鼠标按钮事件参数</param>
|
/// <param name="e">鼠标按钮事件参数</param>
|
||||||
private void SymbolIconTools_MouseUp(object sender, MouseButtonEventArgs e)
|
internal void SymbolIconTools_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (BorderTools.Visibility == Visibility.Visible || BoardBorderTools.Visibility == Visibility.Visible)
|
if (BorderTools.Visibility == Visibility.Visible || BoardBorderTools.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
@@ -2793,7 +2793,7 @@ namespace Ink_Canvas
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">发送者</param>
|
/// <param name="sender">发送者</param>
|
||||||
/// <param name="e">路由事件参数</param>
|
/// <param name="e">路由事件参数</param>
|
||||||
private void EraserIconByStrokes_Click(object sender, MouseButtonEventArgs e)
|
internal void EraserIconByStrokes_Click(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
// 禁用高级橡皮擦系统
|
// 禁用高级橡皮擦系统
|
||||||
DisableEraserOverlay();
|
DisableEraserOverlay();
|
||||||
@@ -2825,7 +2825,7 @@ namespace Ink_Canvas
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">发送者</param>
|
/// <param name="sender">发送者</param>
|
||||||
/// <param name="e">路由事件参数</param>
|
/// <param name="e">路由事件参数</param>
|
||||||
private void CursorWithDelIcon_Click(object sender, MouseButtonEventArgs e)
|
internal void CursorWithDelIcon_Click(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
SymbolIconDelete_MouseUp(sender, null);
|
SymbolIconDelete_MouseUp(sender, null);
|
||||||
CursorIcon_Click(null, null);
|
CursorIcon_Click(null, null);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace Ink_Canvas
|
|||||||
/// 3. 如果形状绘制面板可见,则隐藏它
|
/// 3. 如果形状绘制面板可见,则隐藏它
|
||||||
/// 4. 如果形状绘制面板不可见,则显示它
|
/// 4. 如果形状绘制面板不可见,则显示它
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private void ImageDrawShape_MouseUp(object sender, MouseButtonEventArgs e)
|
internal void ImageDrawShape_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
if (BorderDrawShape.Visibility == Visibility.Visible)
|
if (BorderDrawShape.Visibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using Ink_Canvas.Controls;
|
||||||
|
using Ink_Canvas.Controls.Toolbar;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Ink_Canvas
|
||||||
|
{
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
// 这批属性替代了 XAML 中原有的 x:Name 自动生成字段;外部代码继续按原名访问。
|
||||||
|
// 由对应 Toolbar Item 的 AfterBuild 回填,Populate 发生在 Window_Loaded 早期。
|
||||||
|
internal ToolbarImageButton SymbolIconDelete { get; private set; }
|
||||||
|
internal ToolbarImageButton Eraser_Icon { get; private set; }
|
||||||
|
internal ToolbarImageButton EraserByStrokes_Icon { get; private set; }
|
||||||
|
internal ToolbarImageButton SymbolIconSelect { get; private set; }
|
||||||
|
internal ToolbarImageButton ShapeDrawFloatingBarBtn { get; private set; }
|
||||||
|
internal ToolbarImageButton SymbolIconUndo { get; private set; }
|
||||||
|
internal ToolbarImageButton SymbolIconRedo { get; private set; }
|
||||||
|
internal ToolbarImageButton CursorWithDelFloatingBarBtn { get; private set; }
|
||||||
|
internal ToolbarImageButton WhiteboardFloatingBarBtn { get; private set; }
|
||||||
|
internal ToolbarImageButton ToolsFloatingBarBtn { get; private set; }
|
||||||
|
internal ToolbarImageButton Fold_Icon { get; private set; }
|
||||||
|
|
||||||
|
internal void AttachCursorIconView(ToolbarImageButton btn) => Cursor_Icon = btn;
|
||||||
|
internal void AttachPenIconView(ToolbarImageButton btn) => Pen_Icon = btn;
|
||||||
|
internal void AttachSymbolIconDelete(ToolbarImageButton btn) => SymbolIconDelete = btn;
|
||||||
|
internal void AttachEraserIcon(ToolbarImageButton btn) => Eraser_Icon = btn;
|
||||||
|
internal void AttachEraserByStrokesIcon(ToolbarImageButton btn) => EraserByStrokes_Icon = btn;
|
||||||
|
internal void AttachSymbolIconSelect(ToolbarImageButton btn) => SymbolIconSelect = btn;
|
||||||
|
internal void AttachShapeDrawBtn(ToolbarImageButton btn) => ShapeDrawFloatingBarBtn = btn;
|
||||||
|
internal void AttachSymbolIconUndo(ToolbarImageButton btn) => SymbolIconUndo = btn;
|
||||||
|
internal void AttachSymbolIconRedo(ToolbarImageButton btn) => SymbolIconRedo = btn;
|
||||||
|
internal void AttachCursorWithDelBtn(ToolbarImageButton btn) => CursorWithDelFloatingBarBtn = btn;
|
||||||
|
internal void AttachWhiteboardBtn(ToolbarImageButton btn) => WhiteboardFloatingBarBtn = btn;
|
||||||
|
internal void AttachToolsBtn(ToolbarImageButton btn) => ToolsFloatingBarBtn = btn;
|
||||||
|
internal void AttachFoldIcon(ToolbarImageButton btn) => Fold_Icon = btn;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在 Window_Loaded 早期调用:按 Settings.Toolbar 配置把插件化按钮填充到对应容器。
|
||||||
|
/// 必须在 LoadSettings 之前,因为 LoadSettings 会访问 Cursor_Icon/Pen_Icon/Eraser_Icon 等。
|
||||||
|
/// </summary>
|
||||||
|
internal void InitializeToolbarPlugins()
|
||||||
|
{
|
||||||
|
ToolbarHost = new ToolbarHost(this);
|
||||||
|
var slots = new Dictionary<ToolbarSlot, Panel>
|
||||||
|
{
|
||||||
|
{ ToolbarSlot.FloatingBarMain, StackPanelFloatingBar },
|
||||||
|
{ ToolbarSlot.FloatingBarCanvasControls, StackPanelCanvasControls },
|
||||||
|
{ ToolbarSlot.FloatingBarEnd, StackPanelFloatingBarEnd },
|
||||||
|
{ ToolbarSlot.BlackboardLeft, BlackboardLeftSide },
|
||||||
|
{ ToolbarSlot.BlackboardRight, BlackboardRightSide }
|
||||||
|
};
|
||||||
|
ToolbarRegistry.Populate(ToolbarHost, slots, Settings?.Toolbar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ink_Canvas.Controls.Toolbar;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -37,6 +38,9 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
[JsonProperty("security")]
|
[JsonProperty("security")]
|
||||||
public Security Security { get; set; } = new Security();
|
public Security Security { get; set; } = new Security();
|
||||||
|
|
||||||
|
[JsonProperty("toolbar")]
|
||||||
|
public ToolbarLayoutSettings Toolbar { get; set; } = new ToolbarLayoutSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Security
|
public class Security
|
||||||
|
|||||||
Reference in New Issue
Block a user