-
-
Notifications
You must be signed in to change notification settings - Fork 2
Creating a new Control
BlockOut calls its controls, elements. However for simplicity sakes we will call them controls since most other Frameworks use that term.
To implement a control properly you require the following things:
- An actual control class that implements the
IUIElement
-Interface, for the practice of this page we will call this class:Foo
- A factory class that implements the
IUIElementFactory<Foo>
-Interface, again for our practice we will call this class:FooFactory
. These classes will be explained in a different tutorial.
BlockOut provides handy abstract classes that help you with the first point. We will be using those since they take a lot of work away from us.
BlockOut provides two abstract classes by default:
AbstractChildrenContainingUIElement
-
AbstractSimpleUIElement
Name is basically programm. If you are developing a control that contains other controls, then you useAbstractChildrenContainingUIElement
, if notAbstractSimpleUIElement
will in most cases suffice.
There is another third option available to you: AbstractFilteringChildrenContainingUIElement
, this option is for the controls that are parcticularly picky what they want to have as children. A good example is our Button
, it will not take any other control that accepts click events.
Now that we know what the basic building blocks of our controls are. In most cases you will need data to go into controls and get data out of controls. Let me introduce: DataBinding and Events.
To allow external systems to interact with the UI BlockOut provides you with a type called an IDependencyObject
. Any field in your control that you want to be accessed by the outside world needs to be an IDependecyObject<field_type>
.
The binding system then allows you to bind form the controls datacontext. Which in it self is an IDependencyObject<Object>
.
To help with accessing the value of your dependency object it is recommended to create a setter and a getter method which wrap and unwrap the value stored.
public class ScaleableControl extends AbstractSimpleUIElement
{
@NotNull
private IDependecyObject<Float> scale;
public ScaleableControl(...<abbreviated>..., final IDependencyObject<Float> scale)
{
<abbreviated>;
this.scale = scale;
}
@NotNull
public Float getScale()
{
final Float wrapped = scale.get(getDataContext());
if (wrapped == null) return 0F;
return wrapped;
}
public void setScale(@NotNull final Float scale)
{
this.scale = DependencyObjectHelper.CreateFromValue(scale);
}
}
Now that we know how to get data into controls. The thing that remains is: how do I get data out of the control and into any other control, or even some four own systems.
BlockOut uses an event framework for this. To use events create a field of type; Event<Control, EventArgs>
.
As you can see you need a class that represents the events arguments. This can be usefull for callbacks, but also to output data, in case of for example a TextBox you can have a TextChanged Event which outputs the new text for use.
public class ClickableControl extends AbstractSimpleUIElement implements IClickAcceptingUIElement
{
@NotNull
private Event<ClickableControl, ClickedEventArgs> onClicked = new Event<>(ClickableControl.class, ClickedEventArgs.class);
...<abbreviated>...;
public void onMouseClickBegin(final int localX, final int localY, final MouseButton button)
{
onClicked.raise(this, new ButtonClickedEventArgs(true, localX, localY, button));
}
public static class ClickedEventArgs
{
private final boolean start;
private final int localX;
private final int localY;
private final MouseButton button;
private final float timeDelta;
public ButtonClickedEventArgs(final boolean start, final int localX, final int localY, final MouseButton button)
{
this.start = start;
this.localX = localX;
this.localY = localY;
this.button = button;
this.timeDelta = 0f;
}
public ButtonClickedEventArgs(final boolean start, final int localX, final int localY, final MouseButton button, final float timeDelta)
{
this.start = start;
this.localX = localX;
this.localY = localY;
this.button = button;
this.timeDelta = timeDelta;
}
...<abbreviated>...;
}
}
Why are you talking to me about sidedness, we are still talking about UIs right?
Well yes, but UIs in BlockOut are controlled from the server side. They synchronise themselfs between client and server, and as such all controls exist on the server side as well.
This is the reason why the IUIElement
-Interface does not have any methods to draw controls. However if you have a control that needs to be drawn, simply implement the IDrawableUIElement
-Interface and ensure that its methods are marked with @SideOnly(Side.CLIENT)
and you are good to go.
But how do i get the data from the server to the client, you are asking? You do not need to worry about that, as long as you mark a control dirty during its update on the server side, it will automagically send the data to the client.