Claude-skill-registry editor-ui-drawers
Comprehensive guide for using Editor UI Drawers (ButtonDrawer, ModalDrawer, TableDrawer, TreeDrawer, LayoutDrawer, TextDrawer, DragDropDrawer). Use when implementing any UI in editor panels to ensure consistency.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/editor-ui-drawers" ~/.claude/skills/majiayu000-claude-skill-registry-editor-ui-drawers && rm -rf "$T"
skills/data/editor-ui-drawers/SKILL.mdEditor UI Drawers
Table of Contents
- Overview
- When to Use This Skill
- ButtonDrawer
- ModalDrawer
- TableDrawer
- TreeDrawer
- LayoutDrawer
- TextDrawer
- DragDropDrawer
- EditorUIConstants Reference
- Summary
Overview
Drawers are static utility classes that provide common UI patterns with consistent styling. They wrap ImGui calls and automatically apply EditorUIConstants for sizing, spacing, and colors.
When to Use This Skill
- Adding buttons to any editor panel
- Creating modal dialogs or confirmations
- Rendering tables or trees
- Need spacing, separators, or tooltips
- Drawing colored text
- Implementing drag-drop visualization
Core Principle
Never use raw ImGui calls when a Drawer exists. Drawers ensure consistency and maintainability.
1. ButtonDrawer
Provides 11+ button variants with consistent sizing and behavior.
Available Methods
Standard Buttons
// Standard button (uses EditorUIConstants.StandardButtonWidth/Height) if (ButtonDrawer.DrawButton("Save")) Save(); // Custom size button if (ButtonDrawer.DrawButton("Export", width: 150, height: 30)) Export(); // With onClick callback ButtonDrawer.DrawButton("Load", onClick: Load); // With disabled state ButtonDrawer.DrawButton("Delete", disabled: !canDelete); // Full-width button (stretches to available width) if (ButtonDrawer.DrawFullWidthButton("Create New Scene")) CreateScene();
Specialized Buttons
// Compact button (minimal padding, toolbar use) if (ButtonDrawer.DrawCompactButton("×")) Close(); // Small utility button (uses EditorUIConstants.SmallButtonSize) if (ButtonDrawer.DrawSmallButton("+", tooltip: "Add Item")) AddItem(); // Colored semantic button if (ButtonDrawer.DrawColoredButton("Delete", MessageType.Error)) Delete(); if (ButtonDrawer.DrawColoredButton("Save", MessageType.Success)) Save(); if (ButtonDrawer.DrawColoredButton("Reload", MessageType.Warning)) Reload();
Modal Buttons
// Modal button with standard sizing ButtonDrawer.DrawModalButton("OK", onClick: () => Confirm()); // Modal button pair (OK/Cancel with proper spacing) ButtonDrawer.DrawModalButtonPair( okLabel: "Create", cancelLabel: "Cancel", onOk: () => CreateProject(), onCancel: () => CloseModal(), okDisabled: !isValid);
Toggle & Icon Buttons
// Toggle button (changes label based on state) ButtonDrawer.DrawToggleButton("Loop ON", "Loop OFF", ref isLooping); // Icon button with selection state if (ButtonDrawer.DrawIconButton("play_btn", playIconTexture, size, isSelected: isPlaying)) TogglePlay(); // Transparent icon button (for toolbars) if (ButtonDrawer.DrawTransparentIconButton("stop_btn", stopIconTexture, size, tooltip: "Stop")) Stop();
Button Groups
// Toolbar button group (automatic spacing) ButtonDrawer.DrawToolbarButtonGroup( ("Play", () => Play()), ("Pause", () => Pause()), ("Stop", () => Stop()) );
Usage Examples
// ✅ CORRECT - Use ButtonDrawer if (ButtonDrawer.DrawButton("Save")) { Save(); } // ✅ CORRECT - Use semantic colored button ButtonDrawer.DrawColoredButton("Delete", MessageType.Error); // ❌ WRONG - Don't use raw ImGui if (ImGui.Button("Save", new Vector2(120, 30))) // Don't do this! { Save(); }
2. ModalDrawer
Handles modal dialogs, popups, and confirmation prompts.
Available Methods
Centered Modal (Manual)
private bool _showModal; public void OnImGuiRender() { if (ButtonDrawer.DrawButton("Open")) _showModal = true; // Begin modal (centers automatically) if (ModalDrawer.BeginCenteredModal("My Modal", ref _showModal)) { ImGui.Text("Modal content here"); if (ButtonDrawer.DrawButton("Close")) _showModal = false; ModalDrawer.EndModal(); } }
Confirmation Modal (Complete)
private bool _showConfirm; public void OnImGuiRender() { // Trigger modal if (ButtonDrawer.DrawButton("Delete")) _showConfirm = true; // Render confirmation modal (call every frame) ModalDrawer.RenderConfirmationModal( title: "Confirm Delete", showModal: ref _showConfirm, message: "Are you sure you want to delete this item?", onOk: () => DeleteItem(), onCancel: () => Console.WriteLine("Cancelled"), okLabel: "Delete", cancelLabel: "Cancel"); }
Input Modal
private bool _showInput; private string _inputValue = ""; public void OnImGuiRender() { if (ButtonDrawer.DrawButton("Rename")) _showInput = true; ModalDrawer.RenderInputModal( title: "Rename Entity", showModal: ref _showInput, promptText: "Enter new name:", inputValue: ref _inputValue, maxLength: 100, validationMessage: string.IsNullOrEmpty(_inputValue) ? "Name cannot be empty" : null, errorMessage: null, isValid: !string.IsNullOrEmpty(_inputValue), onOk: () => Rename(_inputValue), onCancel: () => _inputValue = ""); }
Message Box
private bool _showMessage; ModalDrawer.RenderMessageBox( title: "Error", showModal: ref _showMessage, message: "Failed to load file!", messageType: MessageType.Error, onClose: () => Console.WriteLine("Message closed"));
List Selection Modal
private bool _showSelector; private string[] _items = { "Option 1", "Option 2", "Option 3" }; ModalDrawer.RenderListSelectionModal( title: "Select Item", showModal: ref _showSelector, items: _items, onItemSelected: item => Console.WriteLine($"Selected: {item}"), onCancel: () => Console.WriteLine("Cancelled"), emptyMessage: "No items available");
3. TableDrawer
Renders tables with consistent styling and behavior.
Available Methods
Basic Tables
// Two-column key-value table TableDrawer.DrawTwoColumnTable( id: "Shortcuts", leftHeader: "Key", rightHeader: "Action", leftWidth: 100, renderRows: () => { TableDrawer.DrawTableRow( () => ImGui.Text("Ctrl+S"), () => ImGui.Text("Save")); TableDrawer.DrawTableRow( () => ImGui.Text("Ctrl+O"), () => ImGui.Text("Open")); }); // Standard table (manual) if (TableDrawer.BeginStandardTable("MyTable", columnCount: 3)) { ImGui.TableSetupColumn("Name"); ImGui.TableSetupColumn("Type"); ImGui.TableSetupColumn("Size"); ImGui.TableHeadersRow(); TableDrawer.DrawTableRow( () => ImGui.Text("File1"), () => ImGui.Text("Image"), () => ImGui.Text("1.2 MB")); ImGui.EndTable(); }
Generic Data Table
var columns = new TableDrawer.ColumnDefinition[] { new() { Label = "Name", Flags = ImGuiTableColumnFlags.WidthStretch }, new() { Label = "Type", Flags = ImGuiTableColumnFlags.WidthFixed, InitWidth = 100 } }; TableDrawer.DrawDataTable( id: "Files", columns: columns, items: files, renderRow: file => { TableDrawer.DrawTableRow( () => ImGui.Text(file.Name), () => ImGui.Text(file.Type)); }, emptyMessage: "No files found");
Selectable Data Table
TableDrawer.DrawSelectableDataTable( id: "Entities", columns: columns, items: entities, selectedItem: _selectedEntity, getItemId: e => e.Id.ToString(), onItemSelected: e => _selectedEntity = e, renderRow: entity => { // Cell renderers for each column ImGui.TableSetColumnIndex(0); ImGui.Text(entity.Name); ImGui.TableSetColumnIndex(1); ImGui.Text(entity.Type); });
Sortable Table Headers
private string _sortColumn = "Name"; private bool _sortAscending = true; if (TableDrawer.BeginStandardTable("SortableTable", 2)) { ImGui.TableSetupColumn("Name"); ImGui.TableSetupColumn("Size"); ImGui.TableHeadersRow(); // Custom sortable headers ImGui.TableSetColumnIndex(0); TableDrawer.DrawSortableHeader("Name", "Name", _sortColumn, _sortAscending, (col, asc) => { _sortColumn = col; _sortAscending = asc; SortData(); }); // ... render rows ... ImGui.EndTable(); }
Helper Methods
// Selectable row with custom rendering TableDrawer.DrawSelectableRow( rowId: "row1", isSelected: true, onClicked: () => OnRowClick(), () => ImGui.Text("Cell 1"), () => ImGui.Text("Cell 2")); // Colored cell ImGui.TableSetColumnIndex(0); TableDrawer.DrawColoredCell("Error", EditorUIConstants.ErrorColor); // Empty table message TableDrawer.DrawEmptyTableMessage("No data available", MessageType.Info);
4. TreeDrawer
Renders tree structures with expand/collapse behavior.
Available Methods
Selectable Tree Nodes
// Tree node with selection if (TreeDrawer.DrawSelectableTreeNode("Entity", isSelected: _selected == entity, onClicked: () => SelectEntity(entity), onContextMenu: () => ShowContextMenu())) { // Render children TreeDrawer.DrawSelectableTreeNode("Child Entity", isSelected: false); ImGui.TreePop(); }
Selectable Items (Flat List)
// For flat lists with context menu and double-click TreeDrawer.DrawSelectableItem( label: "File.txt", isSelected: _selected == file, onClicked: () => SelectFile(file), onContextMenu: () => ShowFileContextMenu(), onDoubleClick: () => OpenFile(file));
Colored Tree Nodes
// Highlight search results or special states if (TreeDrawer.DrawColoredTreeNode("Important", EditorUIConstants.WarningColor, isSelected: false)) { // Render children... ImGui.TreePop(); }
Recursive Hierarchy
// Render entire hierarchy recursively TreeDrawer.DrawHierarchy( node: rootEntity, getChildren: e => e.Children, getLabel: e => e.Name, isSelected: e => e == _selectedEntity, onClicked: e => _selectedEntity = e, onContextMenu: e => ShowEntityContextMenu(e));
Usage Example
// ✅ CORRECT - Use TreeDrawer with context menu if (TreeDrawer.DrawSelectableTreeNode("Root", isSelected: _selected == root, onClicked: () => Select(root), onContextMenu: () => { if (ImGui.MenuItem("Delete")) Delete(root); })) { // Children... ImGui.TreePop(); }
5. LayoutDrawer
Layout utilities for spacing, inputs, checkboxes, and context menus.
Available Methods
Search & Filter Inputs
// Search input with clear button private string _searchQuery = ""; LayoutDrawer.DrawSearchInput( hint: "Search files...", searchQuery: ref _searchQuery, onQueryChanged: query => FilterFiles(query)); // Filter input private string _filter = ""; LayoutDrawer.DrawFilterInput("##filter", ref _filter, width: 200);
Separators & Spacing
// Separator with spacing before and after LayoutDrawer.DrawSeparatorWithSpacing(); // Only spacing before LayoutDrawer.DrawSeparatorWithSpacing(addSpacingBefore: true, addSpacingAfter: false);
Colored Checkbox
// Checkbox with custom color (for log filters, etc.) private bool _showErrors = true; LayoutDrawer.DrawColoredCheckbox("Errors", ref _showErrors, EditorUIConstants.ErrorColor);
Indented Sections
// Indent content block LayoutDrawer.DrawIndentedSection(() => { ImGui.Text("Indented text"); ImGui.Text("More indented text"); });
Combo Boxes
// Standard combo box private string _current = "Option1"; private string[] _options = { "Option1", "Option2", "Option3" }; LayoutDrawer.DrawComboBox( label: "Choose", currentItem: _current, items: _options, onSelected: item => _current = item, width: 200);
Context Menus
// Context menu for last item ImGui.Text("Right-click me"); LayoutDrawer.DrawContextMenu("item1", ("Delete", () => Delete()), ("Rename", () => Rename()), ("Duplicate", () => Duplicate()));
Tooltips
// Tooltip for last item ImGui.Button("Hover Me"); LayoutDrawer.DrawTooltip("This is a helpful tooltip");
6. TextDrawer
Text rendering with semantic color coding.
Available Methods
// Generic colored text TextDrawer.DrawColoredText("Custom Color", new Vector4(1, 0.5f, 0, 1)); // Semantic colored text TextDrawer.DrawErrorText("Error occurred!"); TextDrawer.DrawWarningText("Warning: Low memory"); TextDrawer.DrawSuccessText("Operation successful"); TextDrawer.DrawInfoText("Information message");
Usage Example
// ✅ CORRECT - Use TextDrawer for semantic colors TextDrawer.DrawErrorText("Failed to load file"); // ❌ WRONG - Don't manually push/pop colors ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 0, 0, 1)); // Don't do this! ImGui.Text("Error"); ImGui.PopStyleColor();
7. DragDropDrawer
Handles drag-and-drop visualization and logic.
Available Methods
Drag Source
// Create drag source for file ImGui.Button("Drag Me"); if (ImGui.IsItemActive()) { DragDropDrawer.CreateDragDropSource( dragDropId: DragDropDrawer.ContentBrowserItemPayload, payloadData: filePath, dragPreview: () => ImGui.Text($"Moving {Path.GetFileName(filePath)}")); }
Drop Target
// File drop target with validation ImGui.Button("Drop Here"); DragDropDrawer.HandleFileDropTarget( payloadType: DragDropDrawer.ContentBrowserItemPayload, validator: path => path.EndsWith(".png"), onDropped: path => LoadTexture(path)); // Drop target without validation ImGui.Button("Drop Anything"); DragDropDrawer.HandleFileDropTarget( payloadType: DragDropDrawer.ContentBrowserItemPayload, validator: null, onDropped: path => ProcessFile(path));
Extension Validators
// Create reusable validator var imageValidator = DragDropDrawer.CreateExtensionValidator( extensions: new[] { ".png", ".jpg", ".bmp" }, checkFileExists: true); // Use validator DragDropDrawer.HandleFileDropTarget( payloadType: DragDropDrawer.ContentBrowserItemPayload, validator: imageValidator, onDropped: path => LoadImage(path)); // Helper validation methods if (DragDropDrawer.HasValidExtension(path, ".png", ".jpg")) Console.WriteLine("Valid image"); if (DragDropDrawer.IsValidFile(path, ".cs", ".txt")) Console.WriteLine("File exists and has valid extension");
Constants
// Standard payload type for content browser items DragDropDrawer.ContentBrowserItemPayload // Value: "CONTENT_BROWSER_ITEM"
EditorUIConstants Reference
See constants-reference.md for complete documentation.
Quick Reference
Button Sizes:
= 120StandardButtonWidth
= 0 (auto-height)StandardButtonHeight
= 150WideButtonWidth
= 20SmallButtonSize
= 16IconSize
Spacing:
= 4StandardPadding
= 8LargePadding
= 2SmallPadding
Colors:
= Bright red (1.0, 0.3, 0.3)ErrorColor
= Yellow (1.0, 1.0, 0.0)WarningColor
= Bright green (0.3, 1.0, 0.3)SuccessColor
= Light gray (0.7, 0.7, 0.7)InfoColor
Axis Colors (for vectors):
= Red (0.8, 0.1, 0.15)AxisXColor
= Green (0.2, 0.7, 0.2)AxisYColor
= Blue (0.1, 0.25, 0.8)AxisZColor
Layout:
= 0.33 (1/3 width)PropertyLabelRatio
= 0.67 (2/3 width)PropertyInputRatio
= 60DefaultColumnWidth
= 120WideColumnWidth
= 200FilterInputWidth
Summary
7 Drawer Classes:
- ButtonDrawer - 11+ button variants (standard, colored, icon, toggle, modal)
- ModalDrawer - 5 modal types (centered, confirmation, input, message, list selection)
- TableDrawer - Data tables, sortable headers, selectable rows
- TreeDrawer - Hierarchical trees with selection and context menus
- LayoutDrawer - Search, filters, separators, combos, context menus, tooltips
- TextDrawer - Semantic colored text (error, warning, success, info)
- DragDropDrawer - File drag-drop with validation
Key Principles:
- Always use Drawers instead of raw ImGui
- All sizing uses EditorUIConstants
- Semantic colors via MessageType enum or dedicated methods
- Consistent patterns across the editor