-
Notifications
You must be signed in to change notification settings - Fork 0
Closed
Labels
area:uiUI systemUI systempriority:p1High priorityHigh prioritytype:featureNew functionalityNew functionality
Milestone
Description
Summary
Create a new KeenEyes.UI.Abstractions project that defines UI component types, events, and layout contracts. This establishes the data model for the UI system without implementation details.
Parent: #416
Depends on: #412 (Graphics.Abstractions for FontHandle, TextureHandle)
Proposed Structure
src/KeenEyes.UI.Abstractions/
├── KeenEyes.UI.Abstractions.csproj
├── Components/
│ ├── UIElement.cs # Base marker + z-index + visibility
│ ├── UIRect.cs # Position, size, computed bounds
│ ├── UIStyle.cs # Background, border, corner radius, text color
│ ├── UIText.cs # Text content, font handle, alignment
│ ├── UIImage.cs # Texture handle, scale mode, tint
│ ├── UIInteractable.cs # IsHovered, IsPressed, IsFocused, JustClicked
│ ├── UIScrollable.cs # Scroll offset, content size
│ └── UILayout.cs # Flexbox: direction, gap, padding, alignment
├── Tags/
│ ├── UIRootTag.cs # Marks layout root elements
│ ├── UIDisabledTag.cs # Marks disabled elements
│ └── UIHiddenTag.cs # Marks hidden elements (skip render)
├── Events/
│ ├── UIClickEvent.cs # Entity that was clicked
│ ├── UIHoverEnterEvent.cs # Mouse entered element
│ ├── UIHoverExitEvent.cs # Mouse left element
│ ├── UIFocusEvent.cs # Element gained focus
│ ├── UIBlurEvent.cs # Element lost focus
│ ├── UIScrollEvent.cs # Scroll position changed
│ └── UITextInputEvent.cs # Character typed in focused text field
├── Layout/
│ ├── LayoutDirection.cs # Row, Column, RowReverse, ColumnReverse
│ ├── LayoutAlign.cs # Start, Center, End, Stretch, SpaceBetween
│ ├── LayoutJustify.cs # Start, Center, End, SpaceBetween, SpaceAround
│ └── LayoutConstraints.cs # MinWidth, MaxWidth, PreferredWidth, etc.
├── Styling/
│ ├── TextAlignment.cs # Left, Center, Right
│ ├── ImageScaleMode.cs # Stretch, Fit, Fill, NineSlice
│ └── Color.cs # RGBA color struct (if not in Common)
└── Extensions/
└── IUIContext.cs # Public UI API interface
Acceptance Criteria
Project Setup
- Create
KeenEyes.UI.Abstractions.csprojtargeting net10.0 - Reference
KeenEyes.Abstractions(for [Component], Entity, etc.) - Reference
KeenEyes.Graphics.Abstractions(for FontHandle, TextureHandle) - Enable nullable reference types
- Enable TreatWarningsAsErrors
- Mark as
<IsAotCompatible>true</IsAotCompatible> - Add to solution file
Core Components
UIElement
[Component]
public partial struct UIElement
{
public int ZIndex; // Render order (higher = on top)
public bool Visible; // Whether to render (default true)
}UIRect
[Component]
public partial struct UIRect
{
// Input (set by user or parent layout)
public float X, Y; // Position relative to parent
public float Width, Height; // Requested size
// Output (computed by UILayoutSystem)
public float ComputedX, ComputedY; // Absolute screen position
public float ComputedWidth, ComputedHeight; // Final size after layout
}UIStyle
[Component]
public partial struct UIStyle
{
public Color BackgroundColor;
public Color BorderColor;
public float BorderWidth;
public float CornerRadius;
public Color TextColor;
public float FontSize;
public float Opacity; // 0-1, affects entire element
}UIText
[Component]
public partial struct UIText
{
public string Content;
public FontHandle Font; // From Graphics.Abstractions
public TextAlignment Alignment;
public bool WordWrap;
}UIImage
[Component]
public partial struct UIImage
{
public TextureHandle Texture; // From Graphics.Abstractions
public ImageScaleMode ScaleMode;
public Color Tint;
public RectF? SourceRect; // For texture atlases
}UIInteractable
[Component]
public partial struct UIInteractable
{
// State flags (set by UIInputSystem)
public bool IsHovered; // Mouse is over element
public bool IsPressed; // Mouse button held on element
public bool IsFocused; // Has keyboard focus
// Frame flags (true for one frame only)
public bool JustClicked; // Click completed this frame
public bool JustPressed; // Press started this frame
public bool JustReleased; // Press ended this frame
public bool JustFocused; // Focus gained this frame
public bool JustBlurred; // Focus lost this frame
}UILayout
[Component]
public partial struct UILayout
{
public LayoutDirection Direction; // Row or Column
public float Gap; // Space between children
public float PaddingTop, PaddingRight, PaddingBottom, PaddingLeft;
public LayoutAlign AlignItems; // Cross-axis alignment
public LayoutJustify JustifyContent; // Main-axis distribution
}UIScrollable
[Component]
public partial struct UIScrollable
{
public float ScrollX, ScrollY; // Current scroll offset
public float ContentWidth, ContentHeight; // Total content size
public bool ScrollHorizontal; // Allow horizontal scroll
public bool ScrollVertical; // Allow vertical scroll
}Tag Components
-
UIRootTag- Marks elements that are layout roots -
UIDisabledTag- Marks disabled elements (no interaction) -
UIHiddenTag- Marks elements to skip during render
Event Types
All events are readonly record structs:
public readonly record struct UIClickEvent(Entity Entity, MouseButton Button);
public readonly record struct UIHoverEnterEvent(Entity Entity);
public readonly record struct UIHoverExitEvent(Entity Entity);
public readonly record struct UIFocusEvent(Entity Entity);
public readonly record struct UIBlurEvent(Entity Entity);
public readonly record struct UIScrollEvent(Entity Entity, float DeltaX, float DeltaY);
public readonly record struct UITextInputEvent(Entity Entity, char Character);Layout Enums
-
LayoutDirection- Row, Column, RowReverse, ColumnReverse -
LayoutAlign- Start, Center, End, Stretch -
LayoutJustify- Start, Center, End, SpaceBetween, SpaceAround, SpaceEvenly -
TextAlignment- Left, Center, Right -
ImageScaleMode- Stretch, Fit, Fill, NineSlice, None
IUIContext Interface
/// <summary>
/// Public API for UI operations exposed as a world extension.
/// </summary>
public interface IUIContext
{
// Focus management
Entity? FocusedElement { get; }
void SetFocus(Entity entity);
void ClearFocus();
void FocusNext(); // Tab navigation
void FocusPrevious(); // Shift+Tab navigation
// Hit testing
Entity? GetElementAt(float x, float y);
IEnumerable<Entity> GetElementsAt(float x, float y);
// Convenience event binding (optional, for app code)
void OnClick(Entity entity, Action callback);
void OnHover(Entity entity, Action<bool> callback);
}Documentation
- XML docs on all public types
- README.md explaining component purposes and usage patterns
- Examples of creating common UI patterns (button, panel, list)
Design Decisions
Why readonly record structs for events?
- Zero allocation
- Immutable
- Value semantics for ECS messaging
Why separate UIRect computed fields?
- User sets requested position/size
- Layout system computes actual position/size
- Clear separation of input vs output
Why flags in UIInteractable instead of just events?
- Systems can query current state without subscribing
- "JustClicked" pattern is common and efficient
- Both polling and events supported
Why FontHandle/TextureHandle from Graphics.Abstractions?
- UI renders text and images
- Handles are the abstraction for GPU resources
- No direct graphics API coupling
Technical Notes
- All components use
[Component]attribute for source generation - All tags use
[TagComponent]attribute - No behavior in components - pure data
- Events sent via
World.Send<T>()from UI systems - Layout algorithm based on simplified Flexbox model
Metadata
Metadata
Assignees
Labels
area:uiUI systemUI systempriority:p1High priorityHigh prioritytype:featureNew functionalityNew functionality