creating-mewui-controls
SKILL.md
Control Base Classes
| Base | Use Case |
|---|---|
Control |
Interactive elements (buttons, inputs) |
ContentControl |
Single-child containers |
Panel |
Multi-child layouts |
Basic Control Structure
public class MyButton : Control
{
private bool _isPressed;
// Property with invalidation
public string Text
{
get;
set
{
if (field != value)
{
field = value;
InvalidateMeasure();
}
}
} = "";
// Enable focus by overriding (not setting property)
public override bool Focusable => true;
// Measure: calculate desired size
protected override Size MeasureContent(Size availableSize)
{
var factory = GetGraphicsFactory();
using var ctx = factory.CreateMeasurementContext(GetDpi());
var textSize = ctx.MeasureText(Text, GetFont());
return new Size(textSize.Width + Padding.Horizontal, textSize.Height + Padding.Vertical);
}
// Render: draw the control
protected override void OnRender(IGraphicsContext context)
{
var bounds = new Rect(0, 0, Bounds.Width, Bounds.Height);
var bgColor = _isPressed ? Theme.Palette.ButtonPressedBackground
: IsMouseOver ? Theme.Palette.ButtonHoverBackground
: Theme.Palette.ButtonFace;
context.FillRoundedRectangle(bounds, 4, 4, bgColor);
context.DrawRoundedRectangle(bounds, 4, 4, Theme.Palette.BorderColor, 1);
context.DrawText(Text, bounds, GetFont(), Foreground,
TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap);
}
}
Input Handling
// Mouse - note: MouseEventArgs, not MouseButtonEventArgs
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.LeftButton)
{
_isPressed = true;
// Capture via Window
var root = FindVisualRoot();
if (root is Window window)
window.CaptureMouse(this);
InvalidateVisual();
e.Handled = true;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (_isPressed)
{
_isPressed = false;
var root = FindVisualRoot();
if (root is Window window)
window.ReleaseMouseCapture();
if (IsMouseOver) Click?.Invoke(this, EventArgs.Empty);
InvalidateVisual();
}
}
// Keyboard
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Space || e.Key == Key.Enter)
{
Click?.Invoke(this, EventArgs.Empty);
e.Handled = true;
}
}
Adding Binding Support
private ValueBinding<string>? _textBinding;
public void SetTextBinding(Func<string> get, Action<string>? set = null,
Action<Action>? subscribe = null, Action<Action>? unsubscribe = null)
{
_textBinding?.Dispose();
_textBinding = new ValueBinding<string>(get, set, subscribe, unsubscribe, () => Text = get());
// RegisterBinding is internal - use within MewUI assembly
Text = get();
}
Fluent Extensions
public static class MyButtonExtensions
{
public static MyButton Text(this MyButton btn, string text) { btn.Text = text; return btn; }
public static MyButton OnClick(this MyButton btn, Action handler) { btn.Click += (s,e) => handler(); return btn; }
public static MyButton BindText(this MyButton btn, ObservableValue<string> src)
{
btn.SetTextBinding(() => src.Value, v => src.Value = v,
h => src.Changed += h, h => src.Changed -= h);
return btn;
}
}
Input details: See input-handling.md ContentControl pattern: See content-control.md
Weekly Installs
3
Repository
christian289/do…audecodeGitHub Stars
16
First Seen
Feb 28, 2026
Security Audits
Installed on
opencode3
gemini-cli3
codebuddy3
github-copilot3
codex3
kimi-cli3