| name | editor-ui-drawers |
| description | 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. |
Editor 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:
StandardButtonWidth= 120StandardButtonHeight= 0 (auto-height)WideButtonWidth= 150SmallButtonSize= 20IconSize= 16
Spacing:
StandardPadding= 4LargePadding= 8SmallPadding= 2
Colors:
ErrorColor= Bright red (1.0, 0.3, 0.3)WarningColor= Yellow (1.0, 1.0, 0.0)SuccessColor= Bright green (0.3, 1.0, 0.3)InfoColor= Light gray (0.7, 0.7, 0.7)
Axis Colors (for vectors):
AxisXColor= Red (0.8, 0.1, 0.15)AxisYColor= Green (0.2, 0.7, 0.2)AxisZColor= Blue (0.1, 0.25, 0.8)
Layout:
PropertyLabelRatio= 0.33 (1/3 width)PropertyInputRatio= 0.67 (2/3 width)DefaultColumnWidth= 60WideColumnWidth= 120FilterInputWidth= 200
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