| 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
if (ButtonDrawer.DrawButton("Save"))
Save();
if (ButtonDrawer.DrawButton("Export", width: 150, height: 30))
Export();
ButtonDrawer.DrawButton("Load", onClick: Load);
ButtonDrawer.DrawButton("Delete", disabled: !canDelete);
if (ButtonDrawer.DrawFullWidthButton("Create New Scene"))
CreateScene();
Specialized Buttons
if (ButtonDrawer.DrawCompactButton("×"))
Close();
if (ButtonDrawer.DrawSmallButton("+", tooltip: "Add Item"))
AddItem();
if (ButtonDrawer.DrawColoredButton("Delete", MessageType.Error))
Delete();
if (ButtonDrawer.DrawColoredButton("Save", MessageType.Success))
Save();
if (ButtonDrawer.DrawColoredButton("Reload", MessageType.Warning))
Reload();
Modal Buttons
ButtonDrawer.DrawModalButton("OK", onClick: () => Confirm());
ButtonDrawer.DrawModalButtonPair(
okLabel: "Create",
cancelLabel: "Cancel",
onOk: () => CreateProject(),
onCancel: () => CloseModal(),
okDisabled: !isValid);
Toggle & Icon Buttons
ButtonDrawer.DrawToggleButton("Loop ON", "Loop OFF", ref isLooping);
if (ButtonDrawer.DrawIconButton("play_btn", playIconTexture, size, isSelected: isPlaying))
TogglePlay();
if (ButtonDrawer.DrawTransparentIconButton("stop_btn", stopIconTexture, size, tooltip: "Stop"))
Stop();
Button Groups
ButtonDrawer.DrawToolbarButtonGroup(
("Play", () => Play()),
("Pause", () => Pause()),
("Stop", () => Stop())
);
Usage Examples
if (ButtonDrawer.DrawButton("Save"))
{
Save();
}
ButtonDrawer.DrawColoredButton("Delete", MessageType.Error);
if (ImGui.Button("Save", new Vector2(120, 30)))
{
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;
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()
{
if (ButtonDrawer.DrawButton("Delete"))
_showConfirm = true;
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
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"));
});
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 =>
{
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();
ImGui.TableSetColumnIndex(0);
TableDrawer.DrawSortableHeader("Name", "Name", _sortColumn, _sortAscending,
(col, asc) => { _sortColumn = col; _sortAscending = asc; SortData(); });
ImGui.EndTable();
}
Helper Methods
TableDrawer.DrawSelectableRow(
rowId: "row1",
isSelected: true,
onClicked: () => OnRowClick(),
() => ImGui.Text("Cell 1"),
() => ImGui.Text("Cell 2"));
ImGui.TableSetColumnIndex(0);
TableDrawer.DrawColoredCell("Error", EditorUIConstants.ErrorColor);
TableDrawer.DrawEmptyTableMessage("No data available", MessageType.Info);
4. TreeDrawer
Renders tree structures with expand/collapse behavior.
Available Methods
Selectable Tree Nodes
if (TreeDrawer.DrawSelectableTreeNode("Entity", isSelected: _selected == entity,
onClicked: () => SelectEntity(entity),
onContextMenu: () => ShowContextMenu()))
{
TreeDrawer.DrawSelectableTreeNode("Child Entity", isSelected: false);
ImGui.TreePop();
}
Selectable Items (Flat List)
TreeDrawer.DrawSelectableItem(
label: "File.txt",
isSelected: _selected == file,
onClicked: () => SelectFile(file),
onContextMenu: () => ShowFileContextMenu(),
onDoubleClick: () => OpenFile(file));
Colored Tree Nodes
if (TreeDrawer.DrawColoredTreeNode("Important", EditorUIConstants.WarningColor,
isSelected: false))
{
ImGui.TreePop();
}
Recursive Hierarchy
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
if (TreeDrawer.DrawSelectableTreeNode("Root", isSelected: _selected == root,
onClicked: () => Select(root),
onContextMenu: () =>
{
if (ImGui.MenuItem("Delete"))
Delete(root);
}))
{
ImGui.TreePop();
}
5. LayoutDrawer
Layout utilities for spacing, inputs, checkboxes, and context menus.
Available Methods
Search & Filter Inputs
private string _searchQuery = "";
LayoutDrawer.DrawSearchInput(
hint: "Search files...",
searchQuery: ref _searchQuery,
onQueryChanged: query => FilterFiles(query));
private string _filter = "";
LayoutDrawer.DrawFilterInput("##filter", ref _filter, width: 200);
Separators & Spacing
LayoutDrawer.DrawSeparatorWithSpacing();
LayoutDrawer.DrawSeparatorWithSpacing(addSpacingBefore: true, addSpacingAfter: false);
Colored Checkbox
private bool _showErrors = true;
LayoutDrawer.DrawColoredCheckbox("Errors", ref _showErrors, EditorUIConstants.ErrorColor);
Indented Sections
LayoutDrawer.DrawIndentedSection(() =>
{
ImGui.Text("Indented text");
ImGui.Text("More indented text");
});
Combo Boxes
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
ImGui.Text("Right-click me");
LayoutDrawer.DrawContextMenu("item1",
("Delete", () => Delete()),
("Rename", () => Rename()),
("Duplicate", () => Duplicate()));
Tooltips
ImGui.Button("Hover Me");
LayoutDrawer.DrawTooltip("This is a helpful tooltip");
6. TextDrawer
Text rendering with semantic color coding.
Available Methods
TextDrawer.DrawColoredText("Custom Color", new Vector4(1, 0.5f, 0, 1));
TextDrawer.DrawErrorText("Error occurred!");
TextDrawer.DrawWarningText("Warning: Low memory");
TextDrawer.DrawSuccessText("Operation successful");
TextDrawer.DrawInfoText("Information message");
Usage Example
TextDrawer.DrawErrorText("Failed to load file");
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 0, 0, 1));
ImGui.Text("Error");
ImGui.PopStyleColor();
7. DragDropDrawer
Handles drag-and-drop visualization and logic.
Available Methods
Drag Source
ImGui.Button("Drag Me");
if (ImGui.IsItemActive())
{
DragDropDrawer.CreateDragDropSource(
dragDropId: DragDropDrawer.ContentBrowserItemPayload,
payloadData: filePath,
dragPreview: () => ImGui.Text($"Moving {Path.GetFileName(filePath)}"));
}
Drop Target
ImGui.Button("Drop Here");
DragDropDrawer.HandleFileDropTarget(
payloadType: DragDropDrawer.ContentBrowserItemPayload,
validator: path => path.EndsWith(".png"),
onDropped: path => LoadTexture(path));
ImGui.Button("Drop Anything");
DragDropDrawer.HandleFileDropTarget(
payloadType: DragDropDrawer.ContentBrowserItemPayload,
validator: null,
onDropped: path => ProcessFile(path));
Extension Validators
var imageValidator = DragDropDrawer.CreateExtensionValidator(
extensions: new[] { ".png", ".jpg", ".bmp" },
checkFileExists: true);
DragDropDrawer.HandleFileDropTarget(
payloadType: DragDropDrawer.ContentBrowserItemPayload,
validator: imageValidator,
onDropped: path => LoadImage(path));
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
DragDropDrawer.ContentBrowserItemPayload
EditorUIConstants Reference
See constants-reference.md for complete documentation.
Quick Reference
Button Sizes:
StandardButtonWidth = 120
StandardButtonHeight = 0 (auto-height)
WideButtonWidth = 150
SmallButtonSize = 20
IconSize = 16
Spacing:
StandardPadding = 4
LargePadding = 8
SmallPadding = 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 = 60
WideColumnWidth = 120
FilterInputWidth = 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