Cookbook¶
This page collects short Tick UI recipes for patterns that come up across most projects. Each recipe is one task plus a code sample. For the model behind these patterns, refer to the topic pages they cross-link to.
A few recipes use Color.WithAlpha, an extension method on
UnityEngine.Color shipped with the package. It returns a copy of
the colour with the alpha channel replaced; RGB is untouched.
Layout¶
Title bar plus content¶
A fixed-height title strip on top, the rest for content.
ui.PushSizedVertical(new Size[] { 32, 1.0f });
{
ui.FillRounded(headerColor, 4);
ui.Text("Settings", "roboto_mono", 16, Color.white,
TextAlign.MiddleLeft);
ui.Next();
ui.PushColor(bodyColor);
ui.Fill();
ui.PopColor();
}
ui.Pop();
For the schema, refer to Layout schemas.
Header, body, footer¶
Three rows: fixed header, fill body, fixed footer.
ui.PushSizedVertical(new Size[] { 48, 1.0f, 32 });
{
DrawHeader(ui); ui.Next();
DrawBody(ui); ui.Next();
DrawFooter(ui);
}
ui.Pop();
Sidebar plus main¶
A fixed-width sidebar on the left, the rest for the main area.
ui.PushSizedHorizontal(new Size[] { 220, 1.0f });
{
DrawSidebar(ui); ui.Next();
DrawMainArea(ui);
}
ui.Pop();
Centered modal content¶
Content centered horizontally and vertically in the current rect, to a fixed maximum size.
using (ui.Auto().Center(480, 280))
{
ui.FillRounded(modalColor, 8);
using (ui.Auto().Pad(16))
{
DrawModalBody(ui);
}
}
Toolbar of equal buttons¶
A horizontal row of equal-sized buttons with a consistent gap.
using (ui.Auto().Top(36))
{
ui.PushSeriesHorizontal(80, 6);
{
DrawTool(ui, "select"); ui.Next();
DrawTool(ui, "move"); ui.Next();
DrawTool(ui, "rotate"); ui.Next();
DrawTool(ui, "scale");
}
ui.Pop();
}
Bottom-anchored status bar¶
A fixed-height strip pinned to the bottom; the rest is content.
ui.PushSizedVertical(new Size[] { 1.0f, 24 });
{
DrawContent(ui); ui.Next();
ui.Fill(statusColor);
ui.Text(statusText, "roboto_mono", 12, Color.white,
TextAlign.MiddleLeft);
}
ui.Pop();
Widgets¶
Labelled textbox¶
A field with a label on the left and the input on the right.
using (ui.Auto().Top(28))
{
ui.PushSizedHorizontal(new Size[] { 100, 1.0f });
{
ui.Text("Username", "roboto_mono", 14, textColor,
TextAlign.MiddleLeft);
ui.Next();
var config = TextboxConfig.Default;
config.Font = "roboto_mono";
config.FontSize = 14;
ui.Textbox("username", ref m_username, config,
out TextboxLayout layout);
ui.FillRounded(fieldColor, 4);
ui.PushRelativeRect(layout.TextRect);
ui.Text(layout.RenderText, config.Font, config.FontSize,
textColor, TextAlign.MiddleLeft);
ui.Pop();
}
ui.Pop();
}
For the full pattern, refer to Make a textbox.
Confirm and cancel row¶
A right-aligned button pair at the bottom of a form.
using (ui.Auto().Bottom(40).PadHorizontal(8))
{
using (ui.Auto().Right(80))
{
ui.FillRounded(primaryColor, 4);
ui.Text("Confirm", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("confirm")) Confirm();
}
using (ui.Auto().Right(160).Left(80))
{
ui.FillRounded(secondaryColor, 4);
ui.Text("Cancel", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("cancel")) Cancel();
}
}
Toggle button¶
A button that flips a bound bool and reflects its current
state in the visual.
ui.FillRounded(m_muted ? accentColor : neutralColor, 4);
ui.Text(m_muted ? "Muted" : "Mute", "roboto_mono", 14,
Color.white, TextAlign.MiddleCenter);
if (ui.Button("mute"))
m_muted = !m_muted;
Numeric stepper¶
A value with - and + buttons on either side.
ui.PushSizedHorizontal(new Size[] { 28, 1.0f, 28 });
{
if (ui.Button("dec")) m_count = Math.Max(0, m_count - 1);
ui.Text("-", "roboto_mono", 16, Color.white, TextAlign.MiddleCenter);
ui.Next();
ui.Text(m_count.ToString(), "roboto_mono", 14, textColor,
TextAlign.MiddleCenter);
ui.Next();
if (ui.Button("inc")) m_count++;
ui.Text("+", "roboto_mono", 16, Color.white, TextAlign.MiddleCenter);
}
ui.Pop();
Panels and overlays¶
Modal confirmation dialog¶
A blocking dialog with two actions; closes itself on either.
if (ui.BeginPanel("confirm-delete",
new Rect(0, 0, Screen.width, Screen.height),
new PanelConfig
{
Hidden = true,
BackdropColor = new Color(0, 0, 0, 0.6f),
}))
{
using (ui.Auto().Center(360, 160))
{
ui.FillRounded(modalColor, 8);
using (ui.Auto().Pad(16))
{
ui.PushSizedVertical(new Size[] { 1.0f, 32 });
{
ui.Text("Delete this item?", "roboto_mono", 16,
Color.white, TextAlign.TopLeft);
ui.Next();
if (ui.Button("ok")) { Delete(); ui.HidePanel("confirm-delete"); }
if (ui.Button("cancel")) ui.HidePanel("confirm-delete");
}
ui.Pop();
}
}
ui.EndPanel();
}
// Open with ShowModal — sets BlocksInput so input is blocked below.
if (m_userPressedDelete)
ui.ShowModal("confirm-delete");
For the full pattern, refer to Show a modal.
Right-click context menu¶
A popup that appears at the cursor on right-click and dismisses itself on click-outside.
if (ui.IsHovered() && Input.GetMouseButtonDown(1))
ui.ShowPopup("context-menu",
new Vector2(mouseX, mouseY));
if (ui.BeginPopup("context-menu", new Rect(0, 0, 200, 120), hidden: true))
{
using (ui.Auto().Pad(4))
{
DrawMenuItem(ui, "open", "Open");
DrawMenuItem(ui, "copy", "Copy");
DrawMenuItem(ui, "delete", "Delete");
}
ui.EndPopup();
}
BeginPopup wraps BeginPanel with AutoCloseOnOutsideClick = true,
so the panel hides itself automatically when input lands elsewhere.
Tabs in a panel¶
A row of tab buttons drives a switch over the body content.
ui.PushSizedVertical(new Size[] { 32, 1.0f });
{
ui.PushSplitHorizontal(3);
{
DrawTab(ui, Tab.General); ui.Next();
DrawTab(ui, Tab.Audio); ui.Next();
DrawTab(ui, Tab.Video);
}
ui.Pop();
ui.Next();
switch (m_activeTab)
{
case Tab.General: DrawGeneralPanel(ui); break;
case Tab.Audio: DrawAudioPanel(ui); break;
case Tab.Video: DrawVideoPanel(ui); break;
}
}
ui.Pop();
Scroll views¶
Scrollable log with auto-scroll-to-bottom¶
A vertical scroll view that snaps to the bottom whenever the underlying log gains a line.
if (m_logCountThisFrame > m_lastLogCount)
ui.ScrollToBottom("log");
m_lastLogCount = m_logCountThisFrame;
ScrollView.Begin(ui, "log",
new Vector2Int(contentW, totalHeight),
ScrollView.s_scrollConfigVertical);
{
ui.Text(m_logText, "roboto_mono", 12, textColor,
TextAlign.TopLeft, Wrap.Wrap);
}
ScrollView.End(ui);
For the helper, refer to Add a scroll view.
Repeated list items¶
A vertical list with one button per item; each iteration scoped to a unique ID.
int rowHeight = 28;
ScrollView.Begin(ui, "items",
new Vector2Int(contentW, items.Count * rowHeight),
ScrollView.s_scrollConfigVertical);
{
ui.PushSeriesVertical(rowHeight);
{
for (int i = 0; i < items.Count; i++)
{
ui.PushID(items[i].Id);
ui.FillRounded(ui.IsHovered() ? hoverColor : restColor, 4);
ui.Text(items[i].Name, "roboto_mono", 14, textColor,
TextAlign.MiddleLeft);
if (ui.Button("row"))
Open(items[i]);
ui.PopID();
if (i < items.Count - 1) ui.Next();
}
}
ui.Pop();
}
ScrollView.End(ui);
Animation¶
Hover colour transition¶
The button colour blends from rest to hover and back.
var ctx = ui.PushAnimate("save")
.Init().Color().Set(restColor).Done()
.Enter().Color().Blend(restColor, hoverColor, 0.2f).Done()
.Leave().Color().Blend(hoverColor, restColor, 0.2f).Done()
.BoolWhileTrue("hover", ui.IsHovered())
.Apply();
ui.FillRounded(ctx.GetColor(), 5);
ui.Text("Save", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("save")) Save();
ui.PopAnimate();
For the workflow, refer to Add an animation.
Press scale animation¶
The button shrinks while held, springs back on release.
var ctx = ui.PushAnimate("press")
.Init().Scale().Set(1.0f).Done()
.BoolBecomesTrue("down", ui.Button("press"))
.Scale().Blend(1.0f, 0.9f, 0.08f).Done()
.BoolBecomesFalse("down", ui.Button("press"))
.Scale().Blend(0.9f, 1.0f, 0.15f).Done()
.Apply();
ui.PushScale(ctx.GetFloat("scale"));
ui.FillRounded(buttonColor, 5);
ui.Text("Press me", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
ui.Pop();
ui.PopAnimate();
Slide-in reveal¶
A panel that slides into view the first frame it's visible.
if (ui.BeginPanel("drawer", drawerRect))
{
var ctx = ui.PushAnimate("drawer-slide")
.Init().Float().Set(0.0f).Done()
.Enter().Float().Blend(0.0f, 1.0f, 0.25f).Done()
.BoolWhileTrue("show", true)
.Apply();
float t = ctx.GetFloat("offset");
ui.Offset((1f - t) * drawerRect.width, 0);
ui.FillRounded(drawerColor, 8);
DrawDrawerBody(ui);
ui.PopAnimate();
ui.EndPanel();
}
Drawing¶
Card with drop shadow¶
A rounded card with a soft shadow under it.
using (ui.Auto().Center(320, 180))
{
ui.DropShadow(new Vector2(0, 4), 12, 8,
Color.black.WithAlpha(0.35f));
ui.FillRounded(cardColor, 8);
using (ui.Auto().Pad(16))
{
ui.Text("Card title", "roboto_mono", 18, textColor,
TextAlign.TopLeft);
}
}
For the primitive, refer to Drawing primitives.
Frosted-glass overlay¶
A translucent panel that blurs the content beneath it.
DrawBackgroundContent(ui);
using (ui.Auto().Center(400, 200))
{
ui.FillFrostedRounded(blur: 12, new CornerRadius(8),
Color.white.WithAlpha(0.05f));
using (ui.Auto().Pad(16))
{
ui.Text("Frosted panel", "roboto_mono", 16, Color.white,
TextAlign.TopLeft);
}
}
Progress bar¶
A horizontal bar filled to a 0-1 fraction of the rect.
using (ui.Auto().Top(8))
{
ui.FillRounded(trackColor, 4);
using (ui.Auto().PushRelativeRect(
new Rect(0, 0, ui.PeekWidth() * progress01, ui.PeekHeight())))
{
ui.FillRounded(fillColor, 4);
}
}
Image with rounded corners¶
A texture clipped to a rounded rect.
For the by-name lookup variant, refer to Drawing primitives.
Resources and theming¶
Push a theme overlay at runtime¶
A theme provider sits on top of the chain until you switch back.
m_baseGameUI.ResourceProviders.Push(m_darkThemeProvider);
// later, on theme change:
m_baseGameUI.ResourceProviders.Remove(m_darkThemeProvider);
m_baseGameUI.ResourceProviders.Push(m_lightThemeProvider);
For the model, refer to Resource providers.
Image by resource name¶
Look up a texture through the provider chain at draw time so theme swaps take effect without a code change.
Additional resources¶
- Layout cheatsheet: every single-rect layout helper in one table.
- Schemas: the multi-element schemas the recipes above use.
- Drawing primitives: the full
catalogue beyond
FillandText. - Animation guide: patterns for multi-widget animation.