Initial release of Node HUD
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) [year] [fullname]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+249
@@ -0,0 +1,249 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ComfyUI Node HUD 🛠️</title>
|
||||
<style>
|
||||
/* From extension vscode.github */
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.vscode-dark img[src$=\#gh-light-mode-only],
|
||||
.vscode-light img[src$=\#gh-dark-mode-only],
|
||||
.vscode-high-contrast:not(.vscode-high-contrast-light) img[src$=\#gh-light-mode-only],
|
||||
.vscode-high-contrast-light img[src$=\#gh-dark-mode-only] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/markdown.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Microsoft/vscode/extensions/markdown-language-features/media/highlight.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', system-ui, 'Ubuntu', 'Droid Sans', sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.task-list-item-checkbox {
|
||||
margin-left: -20px;
|
||||
vertical-align: middle;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
:root {
|
||||
--color-note: #0969da;
|
||||
--color-tip: #1a7f37;
|
||||
--color-warning: #9a6700;
|
||||
--color-severe: #bc4c00;
|
||||
--color-caution: #d1242f;
|
||||
--color-important: #8250df;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-note: #2f81f7;
|
||||
--color-tip: #3fb950;
|
||||
--color-warning: #d29922;
|
||||
--color-severe: #db6d28;
|
||||
--color-caution: #f85149;
|
||||
--color-important: #a371f7;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.markdown-alert {
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 16px;
|
||||
color: inherit;
|
||||
border-left: .25em solid #888;
|
||||
}
|
||||
|
||||
.markdown-alert>:first-child {
|
||||
margin-top: 0
|
||||
}
|
||||
|
||||
.markdown-alert>:last-child {
|
||||
margin-bottom: 0
|
||||
}
|
||||
|
||||
.markdown-alert .markdown-alert-title {
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
align-items: center;
|
||||
line-height: 1
|
||||
}
|
||||
|
||||
.markdown-alert .markdown-alert-title .octicon {
|
||||
margin-right: 0.5rem;
|
||||
display: inline-block;
|
||||
overflow: visible !important;
|
||||
vertical-align: text-bottom;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-note {
|
||||
border-left-color: var(--color-note);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-note .markdown-alert-title {
|
||||
color: var(--color-note);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-important {
|
||||
border-left-color: var(--color-important);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-important .markdown-alert-title {
|
||||
color: var(--color-important);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-warning {
|
||||
border-left-color: var(--color-warning);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-warning .markdown-alert-title {
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-tip {
|
||||
border-left-color: var(--color-tip);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-tip .markdown-alert-title {
|
||||
color: var(--color-tip);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-caution {
|
||||
border-left-color: var(--color-caution);
|
||||
}
|
||||
|
||||
.markdown-alert.markdown-alert-caution .markdown-alert-title {
|
||||
color: var(--color-caution);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body class="vscode-body vscode-light">
|
||||
<h1 id="comfyui-node-hud-️">ComfyUI Node HUD 🛠️</h1>
|
||||
<p><strong>Stop the spaghetti. Keep the data.</strong></p>
|
||||
<p>A lightweight UI extension for <a href="https://github.com/comfyanonymous/ComfyUI">ComfyUI</a> that adds a smart "Heads-Up Display" (HUD) to your nodes. It allows you to stack nodes behind one another to clean up your workspace, while still seeing exactly what is happening inside the stack via a sleek, tinted-glass dock.</p>
|
||||
<p><img src="file:///c:\Users\bthom\OneDrive\Desktop\ComfyUI_windows_portable\ComfyUI\custom_nodes\ComfyUI-Node-HUD\placeholder_for_your_screenshot.png" alt="Main Screenshot"></p>
|
||||
<h2 id="-features">✨ Features</h2>
|
||||
<h3 id="1-hiding-nodes">1. Hiding Nodes</h3>
|
||||
<p>Hide utility nodes (like String Primitives, Notes, or multiple LoRAs) behind a single "Parent" node. Clean Layout Dock detects these hidden nodes and generates a live status bar attached to the bottom of the parent.</p>
|
||||
<h3 id="2-smart-io-indicators-">2. Smart I/O Indicators 🚦</h3>
|
||||
<p>No more guessing if a hidden node is connected. The dock displays <strong>Smart Dots</strong> that visualize the data flow:</p>
|
||||
<ul>
|
||||
<li><strong>Left Dots (Inputs):</strong> Shows active incoming connections.</li>
|
||||
<li><strong>Right Dots (Outputs):</strong> Shows active outgoing data.</li>
|
||||
<li><strong>Color Coded:</strong> The dots match ComfyUI's standard wire colors:
|
||||
<ul>
|
||||
<li>🟣 <strong>Purple:</strong> Model</li>
|
||||
<li>🟡 <strong>Yellow:</strong> CLIP</li>
|
||||
<li>🔴 <strong>Red:</strong> VAE</li>
|
||||
<li>🌸 <strong>Pink:</strong> Latent</li>
|
||||
<li>🔵 <strong>Blue:</strong> Image</li>
|
||||
<li>🟢 <strong>Green:</strong> String / Text</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="3-live-status-feedback">3. Live Status Feedback</h3>
|
||||
<p>The dock updates in real-time to reflect the state of your nodes:</p>
|
||||
<ul>
|
||||
<li><strong>Active:</strong> Green text / Standard border.</li>
|
||||
<li><strong>Muted:</strong> Gray border & dimmed text.</li>
|
||||
<li><strong>Bypassed:</strong> Purple border.</li>
|
||||
<li><strong>Disconnected:</strong> If a node has no active inputs or outputs, a red error dot 🔴 appears.</li>
|
||||
</ul>
|
||||
<h3 id="4-tinted-glass-ui">4. "Tinted Glass" UI</h3>
|
||||
<p>The dock uses a semi-transparent dark background (85% opacity) to ensure readability without feeling "heavy" or blocking the grid entirely.</p>
|
||||
<hr>
|
||||
<h2 id="-installation">📥 Installation</h2>
|
||||
<h3 id="method-1-manager-coming-soon">Method 1: Manager (Coming Soon)</h3>
|
||||
<p><em>Once indexed, you can install this via the ComfyUI Manager.</em></p>
|
||||
<h3 id="method-2-manual-install">Method 2: Manual Install</h3>
|
||||
<ol>
|
||||
<li>Navigate to your ComfyUI <code>custom_nodes</code> directory:<pre><code class="language-bash"><span class="hljs-built_in">cd</span> ComfyUI/custom_nodes/
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>Clone this repository:<pre><code class="language-bash">git <span class="hljs-built_in">clone</span> [https://github.com/YOUR_USERNAME/ComfyUI-Clean-Dock.git](https://github.com/YOUR_USERNAME/ComfyUI-Clean-Dock.git)
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><strong>Restart ComfyUI</strong>.</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<h2 id="️-usage">🖱️ Usage</h2>
|
||||
<ol>
|
||||
<li><strong>Stack Your Nodes:</strong> Drag utility nodes (like <em>Primitive</em> or <em>Note</em>) physically behind a larger "Parent" node (like <em>Prompt Manager</em> or <em>KSampler</em>).</li>
|
||||
<li><strong>Activate the Dock:</strong>
|
||||
<ul>
|
||||
<li>Right-click the Parent Node.</li>
|
||||
<li>Select <strong>"Toggle Stack Info"</strong> from the menu.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>That's it!</strong> The dock will appear. If you move the nodes out from behind the parent, the dock updates instantly.</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<h2 id="-color-legend">🎨 Color Legend</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left">Color</th>
|
||||
<th style="text-align:left">Meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">🟣</td>
|
||||
<td style="text-align:left"><strong>Model</strong> (Checkpoint / LoRA)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🟡</td>
|
||||
<td style="text-align:left"><strong>CLIP</strong> (Conditioning)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🔴</td>
|
||||
<td style="text-align:left"><strong>VAE</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🌸</td>
|
||||
<td style="text-align:left"><strong>Latent</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🔵</td>
|
||||
<td style="text-align:left"><strong>Image</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🟢</td>
|
||||
<td style="text-align:left"><strong>String</strong> / Text</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">🔴 (Solid)</td>
|
||||
<td style="text-align:left"><strong>Error</strong> / Disconnected</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr>
|
||||
<h2 id="-contributing">🤝 Contributing</h2>
|
||||
<p>This extension is pure JavaScript. Feel free to submit PRs for new features or styling tweaks!</p>
|
||||
<h2 id="-license">📄 License</h2>
|
||||
<p>MIT License.</p>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
# ComfyUI Node HUD 🛠️
|
||||
|
||||
**Stop the spaghetti. Keep the data.**
|
||||
|
||||
A lightweight UI extension for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) that adds a smart "Heads-Up Display" (HUD) to your nodes. It allows you to stack nodes behind one another to clean up your workspace, while still seeing exactly what is happening inside the stack via a sleek, tinted-glass dock.
|
||||
|
||||

|
||||
|
||||
## ✨ Features
|
||||
|
||||
### 1. Hiding Nodes
|
||||
Hide utility nodes (like String Primitives, Notes, or multiple LoRAs) behind a single "Parent" node. Clean Layout Dock detects these hidden nodes and generates a live status bar attached to the bottom of the parent.
|
||||
|
||||
### 2. Smart I/O Indicators 🚦
|
||||
No more guessing if a hidden node is connected. The dock displays **Smart Dots** that visualize the data flow:
|
||||
* **Left Dots (Inputs):** Shows active incoming connections.
|
||||
* **Right Dots (Outputs):** Shows active outgoing data.
|
||||
* **Color Coded:** The dots match ComfyUI's standard wire colors:
|
||||
* 🟣 **Purple:** Model
|
||||
* 🟡 **Yellow:** CLIP
|
||||
* 🔴 **Red:** VAE
|
||||
* 🌸 **Pink:** Latent
|
||||
* 🔵 **Blue:** Image
|
||||
* 🟢 **Green:** String / Text
|
||||
|
||||
### 3. Live Status Feedback
|
||||
The dock updates in real-time to reflect the state of your nodes:
|
||||
* **Active:** Green text / Standard border.
|
||||
* **Muted:** Gray border & dimmed text.
|
||||
* **Bypassed:** Purple border.
|
||||
* **Disconnected:** If a node has no active inputs or outputs, a red error dot 🔴 appears.
|
||||
|
||||
### 4. "Tinted Glass" UI
|
||||
The dock uses a semi-transparent dark background (85% opacity) to ensure readability without feeling "heavy" or blocking the grid entirely.
|
||||
|
||||
---
|
||||
|
||||
## 📥 Installation
|
||||
|
||||
### Method 1: Manager (Coming Soon)
|
||||
*Once indexed, you can install this via the ComfyUI Manager.*
|
||||
|
||||
### Method 2: Manual Install
|
||||
1. Navigate to your ComfyUI `custom_nodes` directory:
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes/
|
||||
```
|
||||
2. Clone this repository:
|
||||
```bash
|
||||
git clone [https://github.com/YOUR_USERNAME/ComfyUI-Clean-Dock.git](https://github.com/YOUR_USERNAME/ComfyUI-Clean-Dock.git)
|
||||
```
|
||||
3. **Restart ComfyUI**.
|
||||
|
||||
---
|
||||
|
||||
## 🖱️ Usage
|
||||
|
||||
1. **Stack Your Nodes:** Drag utility nodes (like *Primitive* or *Note*) physically behind a larger "Parent" node (like *Prompt Manager* or *KSampler*).
|
||||
2. **Activate the Dock:**
|
||||
* Right-click the Parent Node.
|
||||
* Select **"Toggle Stack Info"** from the menu.
|
||||
3. **That's it!** The dock will appear. If you move the nodes out from behind the parent, the dock updates instantly.
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Color Legend
|
||||
|
||||
| Color | Meaning |
|
||||
| :--- | :--- |
|
||||
| 🟣 | **Model** (Checkpoint / LoRA) |
|
||||
| 🟡 | **CLIP** (Conditioning) |
|
||||
| 🔴 | **VAE** |
|
||||
| 🌸 | **Latent** |
|
||||
| 🔵 | **Image** |
|
||||
| 🟢 | **String** / Text |
|
||||
| 🔴 (Solid) | **Error** / Disconnected |
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
This extension is pure JavaScript. Feel free to submit PRs for new features or styling tweaks!
|
||||
|
||||
## 📄 License
|
||||
|
||||
MIT License.
|
||||
@@ -0,0 +1,2 @@
|
||||
WEB_DIRECTORY = "./web/js"
|
||||
__all__ = ["WEB_DIRECTORY"]
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 791 KiB |
@@ -0,0 +1,211 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
|
||||
app.registerExtension({
|
||||
name: "Comfy.CleanLayoutDock",
|
||||
|
||||
// 1. Toggle Menu
|
||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
||||
const getExtraMenuOptions = nodeType.prototype.getExtraMenuOptions;
|
||||
nodeType.prototype.getExtraMenuOptions = function(_, options) {
|
||||
if (getExtraMenuOptions) getExtraMenuOptions.apply(this, arguments);
|
||||
options.push({
|
||||
content: "Toggle Stack Info",
|
||||
callback: () => {
|
||||
this.show_stack_info = !this.show_stack_info;
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 2. Draw Foreground
|
||||
const onDrawForeground = nodeType.prototype.onDrawForeground;
|
||||
nodeType.prototype.onDrawForeground = function(ctx) {
|
||||
if (onDrawForeground) onDrawForeground.apply(this, arguments);
|
||||
|
||||
if (!this.show_stack_info) return;
|
||||
|
||||
const stackList = getHiddenNodes(this, app.graph);
|
||||
if (stackList.length === 0) return;
|
||||
|
||||
ctx.save();
|
||||
drawDock(this, ctx, stackList, app.graph);
|
||||
ctx.restore();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// --- HELPER: Find Hidden Nodes ---
|
||||
function getHiddenNodes(parent, graph) {
|
||||
const stackList = [];
|
||||
if (!graph || !graph._nodes) return stackList;
|
||||
|
||||
const pLeft = parent.pos[0];
|
||||
const pRight = parent.pos[0] + parent.size[0];
|
||||
const pTop = parent.pos[1];
|
||||
const pBottom = parent.pos[1] + parent.size[1];
|
||||
|
||||
for (const node of graph._nodes) {
|
||||
if (node.id === parent.id) continue;
|
||||
const nx = node.pos[0];
|
||||
const ny = node.pos[1];
|
||||
if (nx >= pLeft && nx < pRight && ny >= pTop && ny < pBottom) {
|
||||
stackList.push(node);
|
||||
}
|
||||
}
|
||||
return stackList;
|
||||
}
|
||||
|
||||
// --- HELPER: Get Link Color ---
|
||||
function getLinkColor(link) {
|
||||
const type = link.type;
|
||||
const colorMap = LGraphCanvas.link_type_colors;
|
||||
|
||||
// 1. Check Comfy Registry first
|
||||
if (colorMap[type]) return colorMap[type];
|
||||
|
||||
// 2. Common Fallbacks
|
||||
if (type === "STRING") return "#66ff66"; // <--- FIXED: Standard Green
|
||||
if (type === "INT") return "#22cc22"; // Integer Green
|
||||
if (type === "FLOAT") return "#22cc22"; // Float Green
|
||||
if (type === "LATENT") return "#ff99aa";
|
||||
if (type === "IMAGE") return "#66aaff";
|
||||
if (type === "MODEL") return "#6666aa";
|
||||
if (type === "VAE") return "#ff4444";
|
||||
if (type === "CLIP") return "#ffff66";
|
||||
if (type === "CONDITIONING") return "#aa6666";
|
||||
|
||||
return "#aaaaff"; // The "Lint Blue" Default
|
||||
}
|
||||
|
||||
// --- DRAWER ---
|
||||
function drawDock(node, ctx, stackList, graph) {
|
||||
if (!node.size) return;
|
||||
|
||||
const dockHeight = 26;
|
||||
const chipHeight = 16;
|
||||
const padding = 6;
|
||||
const dotRadius = 3;
|
||||
const dotSpacing = 8;
|
||||
|
||||
const x = 0;
|
||||
const y = node.size[1];
|
||||
|
||||
/*
|
||||
// Background
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.beginPath();
|
||||
if (ctx.roundRect) ctx.roundRect(x, y, node.size[0], dockHeight, [0, 0, 6, 6]);
|
||||
else ctx.rect(x, y, node.size[0], dockHeight);
|
||||
ctx.fill();
|
||||
*/
|
||||
|
||||
// Background (Tinted Glass Style)
|
||||
ctx.fillStyle = "rgba(20, 20, 20, 0.85)"; // 85% Opaque Dark Grey
|
||||
ctx.beginPath();
|
||||
if (ctx.roundRect) ctx.roundRect(x, y, node.size[0], dockHeight, [0, 0, 6, 6]);
|
||||
else ctx.rect(x, y, node.size[0], dockHeight);
|
||||
ctx.fill();
|
||||
|
||||
// Optional: Add a subtle glass border for definition
|
||||
ctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
|
||||
let currentX = x + padding;
|
||||
ctx.font = "10px Arial";
|
||||
ctx.textBaseline = "middle";
|
||||
|
||||
for (const item of stackList) {
|
||||
// 1. Gather Dots
|
||||
const leftDots = [];
|
||||
const rightDots = [];
|
||||
|
||||
// Check Inputs
|
||||
if (item.inputs) {
|
||||
for (const input of item.inputs) {
|
||||
if (input.link) {
|
||||
const link = graph.links[input.link];
|
||||
if (link) leftDots.push(getLinkColor(link));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check Outputs
|
||||
if (item.outputs) {
|
||||
for (const output of item.outputs) {
|
||||
if (output.links && output.links.length > 0) {
|
||||
// Use color of first link
|
||||
const link = graph.links[output.links[0]];
|
||||
if (link) rightDots.push(getLinkColor(link));
|
||||
else if (LGraphCanvas.link_type_colors[output.type]) {
|
||||
rightDots.push(LGraphCanvas.link_type_colors[output.type]);
|
||||
} else {
|
||||
// Manual check for disconnected outputs that usually have colors
|
||||
if (output.type === "STRING") rightDots.push("#66ff66");
|
||||
else rightDots.push("#cccccc");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: Disconnected
|
||||
if (leftDots.length === 0 && rightDots.length === 0) {
|
||||
leftDots.push("#ff4444"); // Red error dot
|
||||
}
|
||||
|
||||
// 2. Calculate Size
|
||||
let text = item.title || item.type;
|
||||
if (text.length > 20) text = text.substring(0, 18) + "..";
|
||||
const textWidth = ctx.measureText(text).width;
|
||||
|
||||
const leftSpace = 6 + (leftDots.length * dotSpacing);
|
||||
const rightSpace = 6 + (rightDots.length * dotSpacing);
|
||||
const chipWidth = leftSpace + textWidth + rightSpace;
|
||||
|
||||
if (currentX + chipWidth > node.size[0]) break;
|
||||
|
||||
// 3. Determine Border Color
|
||||
let borderColor = "#444";
|
||||
if (item.mode === 2) borderColor = "#888888"; // Mute
|
||||
else if (item.mode === 4) borderColor = "#cc66ff"; // Bypass
|
||||
|
||||
const centerY = y + (dockHeight/2);
|
||||
|
||||
// 4. Draw Chip
|
||||
ctx.fillStyle = "#222";
|
||||
ctx.strokeStyle = borderColor;
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
ctx.beginPath();
|
||||
if (ctx.roundRect) ctx.roundRect(currentX, y + (dockHeight - chipHeight)/2, chipWidth, chipHeight, 8);
|
||||
else ctx.rect(currentX, y + (dockHeight - chipHeight)/2, chipWidth, chipHeight);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// 5. Draw Left Dots
|
||||
let dotX = currentX + 6;
|
||||
for (const color of leftDots) {
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(dotX + dotRadius, centerY, dotRadius, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
dotX += dotSpacing;
|
||||
}
|
||||
|
||||
// 6. Draw Text
|
||||
ctx.fillStyle = "#ccc";
|
||||
ctx.fillText(text, currentX + leftSpace, centerY);
|
||||
|
||||
// 7. Draw Right Dots
|
||||
dotX = currentX + leftSpace + textWidth + 6;
|
||||
for (const color of rightDots) {
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(dotX + dotRadius, centerY, dotRadius, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
dotX += dotSpacing;
|
||||
}
|
||||
|
||||
currentX += chipWidth + padding;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user