Aka
Yet Another UI Plugin (name to be defined.. suggestions?).
So, after my almost-meltdown of last week, I decided to sit down at the drawing table again and start with Yet Another UI system.
This time though, I decided to leave out all the GameObject related stuff, no scaling, no rotation, just pure and simple overlay-based UI. It's so simple that it's fixed at using VisibilityGroup 30 and ScreenOverlay. You can't even change that

The interface is declared by code (pretend you are writing your
Form1.Designer.cs file by hand) and it currently supports full screen management and automatic resizing of the controls, depending on the layout component they are put inside and if set to behave so.
There are 4 kind of layout components:
- DockPanel - usual Top, Left, Right, Bottom, Center, with multiple controls in a peripheral section; only one can be in the Center
- StackPanel - Horizontal and Vertical
- GridPanel - percent-based; also supports Row and Column span
- CanvasPanel - freeform positioning, will not resize your controls
and at the moment the following Controls are complete:
- Button
- CheckButton
- Separator (well, it's just a placeholder so it was quite easy
) - TextBox
To avoid having to deal with events, which might break the flow of the engine, everything is collected and pushed back in the OnUpdate phase; you can react to mouse and keyboard via delegates (multicast supported!).
This is the result of my first 4 days of work.. how it looks in the editor:
don't mind the checkerboards around.. they are just unskinned controlsHow it works (in less than 15 seconds

):
notice that the UI is resized to fit the window, as it was stretched to fill the editor before, and some controls are resized as a consequence while others retain the same sizeAnd the code required to obtain that (don't get scared, there's a lot all around the place but it's quite simple and easy to read I believe)
Code:
public class TestUI : UI
{
[DontSerialize]
private DockPanel _root;
[DontSerialize]
private StackPanel _sp;
[DontSerialize]
private CheckButton _check;
[DontSerialize]
private Button _btn;
protected override ControlsContainer CreateUI()
{
ContentRef<Appearance> panelAppearance = ContentProvider.RequestContent<Appearance>(@"Data\UI\Panel\Appearance.Appearance.res");
ContentRef<Appearance> textBoxAppearance = ContentProvider.RequestContent<Appearance>(@"Data\UI\TextBox\Appearance.Appearance.res");
ContentRef<Appearance> buttonAppearance = ContentProvider.RequestContent<Appearance>(@"Data\UI\Button\Appearance.Appearance.res");
_root = new DockPanel() {
Size = new Size(500, 500),
Position = new Vector2(200, 100)
};
_sp = new StackPanel() {
Size = new Size(100, 100),
Docking = DockPanel.Dock.Center,
Stacking = StackPanel.Stack.Vertical,
Margin = new Border(5),
Appearance = panelAppearance
};
_sp.AddChild(new Button() {
Size = new Size(50, 50),
Docking = DockPanel.Dock.Top,
StretchToFill = false
});
_sp.AddChild(new Separator() {
Size = new Size(5)
});
_sp.AddChild(new Button() {
Size = new Size(60, 60),
Docking = DockPanel.Dock.Bottom,
Appearance = buttonAppearance
});
_sp.AddChild(new Button() {
Size = new Size(20, 20),
Docking = DockPanel.Dock.Bottom,
StretchToFill = false
});
_sp.AddChild(new Separator() {
Size = new Size(5)
});
_sp.AddChild(new Button() {
Size = new Size(50, 50),
Docking = DockPanel.Dock.Bottom,
Appearance = buttonAppearance,
Status = Control.ControlStatus.Disabled
});
DockPanel dp = new DockPanel() {
Size = new Size(200, 100),
Docking = DockPanel.Dock.Left
};
dp.AddChild(new Button() {
Size = new Size(20, 50),
Docking = DockPanel.Dock.Left
});
dp.AddChild(new Button() {
Size = new Size(50, 50),
Docking = DockPanel.Dock.Right
});
dp.AddChild(_sp);
GridPanel gp = new GridPanel() {
Docking = DockPanel.Dock.Center,
Margin = new Border(4),
Rows = new float[] { .5f, .5f },
Columns = new float[] { .2f, .6f, .2f }
};
gp.AddChild(new Button());
gp.AddChild(_check = new CheckButton() {
Size = new Size(100, 100),
Grid = new GridPanel.GridInfo() { Row = 1, ColSpan = 2 },
StretchToFill = false,
Appearance = buttonAppearance,
Glyph = ContentProvider.RequestContent<Material>(@"Data\UI\Panel\Base.Material.res"),
GlyphAlignment = Alignment.Bottom,
GlyphMargin = new Border(12),
Text = "ClickMe!",
TextAlignment = Alignment.Top,
TextMargin = new Border(5),
Font = ContentProvider.RequestContent<Font>(@"Data\OpenSans.Font.res"),
FontColor = ColorRgba.White
});
gp.AddChild(new Button() {
Grid = new GridPanel.GridInfo() { Row = 1, Column = 2 }
});
_root.AddChild(_btn = new Button() {
Size = new Size(200, 100),
Docking = DockPanel.Dock.Top,
StretchToFill = false,
Appearance = buttonAppearance,
MouseButtonEventHandler = (button, args) => //delegate here
{
if (args.Button == Duality.Input.MouseButton.Left && args.IsPressed)
{
Duality.Log.Game.Write("CLICK!");
}
}
});
_root.AddChild(dp);
_root.AddChild(new TextBox() {
Size = new Size(200, 50),
Docking = DockPanel.Dock.Bottom,
Font = ContentProvider.RequestContent<Font>(@"Data\OpenSans.Font.res"),
Appearance = textBoxAppearance,
FontColor = ColorRgba.Red,
TextAlignment = Alignment.BottomRight,
TextMargin = new Border(5)
});
_root.AddChild(new Button() {
Size = new Size(50, 100),
Docking = DockPanel.Dock.Right
});
_root.AddChild(new Button() {
Size = new Size(50, 100),
Docking = DockPanel.Dock.Right,
StretchToFill = false
});
_root.AddChild(gp);
return _root;
}
protected override void OnUpdate()
{
base.OnUpdate();
_sp.Visible = _check.Checked;
}
}
Well, that's it for now.
Next stop:
RadioButtons and
Scrollbars.
Comments? suggestions? requests?
