# 浮动工具栏（FloatingToolbar）

> 文档：`vjcad/doc/ui/index.md`（floating-toolbar 段）
> 示例：`vjcad/example/ui/15floatingtoolbar.js`

## 1. 用途

`FloatingToolbar` 是悬浮在画布上的可拖动小工具栏。适合：

- 不希望占用 Ribbon / 菜单的"自定义快捷键面板"
- 测量 / 标注等"工作模式临时面板"
- 移动端 / 触屏简化操作面板

由全局工厂 `createFloatingToolbar(id, options)` 创建，**单例**：相同 `id` 第二次调用会返回已有实例（并顺手 `show()` 它，新传的 options 被忽略）。**新建的工具栏默认是隐藏的**，必须调 `show()`。

## 2. 最小示例

```js
const { createFloatingToolbar, IconRegistry, IconCategory, Engine } = vjcad;

const tb = createFloatingToolbar('draw-tools', {
    title: '绘图工具',
    columns: 4,
    iconSize: 30,
    position: { top: '80px', right: '20px' },
    items: [
        { id: 'line',   icon: IconRegistry.getIcon('line',   IconCategory.Commands),
          tooltip: '直线 (LINE)',   command: 'LINE' },
        { id: 'circle', icon: IconRegistry.getIcon('circle', IconCategory.Commands),
          tooltip: '圆 (CIRCLE)',   command: 'CIRCLE' },
        { id: 'arc',    icon: IconRegistry.getIcon('arc',    IconCategory.Commands),
          tooltip: '圆弧 (ARC)',    command: 'ARC' },
        { id: 'zoomext',
          icon: '<svg viewBox="0 0 24 24" stroke="#58a6ff"><polyline points="15 3 21 3 21 9"/></svg>',
          tooltip: '缩放全图',
          onClick: () => Engine.zoomExtents() }
    ]
});
tb.show();
```

要点：

- `command` 字段直接走 `Engine.editor.executerWithOp(command)`
- 没注册过命令的项用 `onClick` 回调
- `IconRegistry.getIcon(name, IconCategory.Commands)` 返回内置 SVG 字符串，找不到时返回 `undefined`，自己 fallback

## 3. 配置项

```ts
interface FloatingToolbarOptions {
    title?: string;                     // 标题，留空 → 不显示标题栏
    showHeader?: boolean;               // 强制显示 / 隐藏标题栏
    position?: PanelPosition;           // { top?/right?/bottom?/left? } CSS 定位
    columns?: number;                   // 横向布局：每行多少列
    rows?: number;                      // 纵向布局：每列多少行
    iconSize?: number;                  // 图标按钮像素尺寸
    items?: FloatingToolbarItem[];
}

interface FloatingToolbarItem {
    id: string;                         // 唯一
    icon: string;                       // 只能是内联 SVG 字符串（以 '<svg' 开头）或图片 URL；不查 IconRegistry，
                                        // 写注册名会被当成 <img src="line"> 而裂图——要内置图标就 IconRegistry.getIcon(...) 取 SVG 串
    tooltip: string;                    // ⚠️ 必填（不是可选）
    command?: string;                   // 直接执行的 vjcad 命令
    onClick?: () => void;               // 自定义回调
    disabled?: boolean;
}
```

> `FloatingToolbarOptions` 只有上面 7 个键——**没有** `draggable` / `closeOnEsc`。

`columns` 与 `rows` 互斥：填了 `columns` 是横式（行数自适应），填了 `rows` 是竖式（列数自适应）。

## 4. 实例管理 API

```js
const tb = createFloatingToolbar('my-tools', { /* ... */ });

tb.show();         // 显示（新建后默认隐藏，必须调）
tb.hide();
tb.close();        // 与 hide() 完全相同，不触发任何事件
tb.destroy();      // 彻底销毁、从 DOM 移除、删 cache

tb.addItem({ id: 'spline', icon: '...', tooltip: '样条', command: 'SPLINE' });
tb.addItems([{ id: 'a', icon: '...', tooltip: 'A' }, { id: 'b', icon: '...', tooltip: 'B' }]);
tb.removeItem('spline');
tb.updateItem('line', { tooltip: '改了一下', disabled: true });
tb.resetPosition();   // 清掉持久化位置并复位到 options.position（没有 setPosition/toggle 方法）
tb.isVisible;
```

## 5. 单例特性

```js
const t1 = createFloatingToolbar('draw-tools', { title: 'A', columns: 4 });
const t2 = createFloatingToolbar('draw-tools', { title: 'B' });   // 不会重建
console.log(t1 === t2);   // true，title 仍是 'A'
```

需要"重新构建"时先 `destroy` 再 `create`：

```js
tb.destroy();
const fresh = createFloatingToolbar('draw-tools', { title: '新建' });
```

## 6. 实战：根据当前命令切换工具栏

```js
const drawTb = createFloatingToolbar('draw-tools', { /* 绘图项 */ });
const editTb = createFloatingToolbar('edit-tools', { /* 编辑项 */ });

const events = CadEventManager.getInstance();
events.on(CadEvents.SelectionChanged, () => {
    const sel = ssGetFirst() ?? [];
    if (sel.length > 0) { drawTb.hide(); editTb.show(); }
    else                { drawTb.show(); editTb.hide(); }
});
```

## 7. 可访问性 / 键盘

- 拖拽标题栏（或顶部 16px 拖动条）即可移动；拖动结束后位置**持久化到 localStorage**（键 `vjcad-ftb-pos-<id>`），下次同 id 创建时优先用缓存位置、忽略 `options.position`
- `resetPosition()` 删除该缓存并复位到 `options.position`
- 支持 tooltip 鼠标悬停出现

## 红旗

- `id` 全局唯一；与别的插件同 id 时**后创建者直接拿到先创建者的实例**（自己的 options/items 被忽略），不是互相覆盖——id 加插件前缀
- 一次性创建过多浮动工具栏（>4 个）会让画布变挤；通常配合命令上下文动态显示
- `command` 字段必须是已注册的命令名；命令未注册时点击没反应
- `tooltip` 是 `FloatingToolbarItem` 的**必填**字段
- `position` 在窗口缩放后不会自动重排，**自适应** 要自己监听 `window.resize` 后用 `resetPosition()` 或重建；改了 `options.position` 却不生效，多半是 localStorage 里有旧的拖动位置，先 `resetPosition()`
- `destroy()` 会移除 DOM 但不会注销点击监听里的引用，自定义 `onClick` 中如有外部资源记得释放

## 参考（官方文档 MCP）

- 文档：`vjcad/doc/ui/index.md`（floating-toolbar 段）
- 示例：`vjcad/example/ui/15floatingtoolbar.js`
