In the last article we setup a simple document with one object of type OBJECT_COUNTER as the selected object containing one property of type PROPERTY_U32 and key count. Now, let's use this new state storage to initialise the interface.

We start by clearing out Populate().

void Populate() {
	for (uintptr_t i = 0; i < container->childCount; i++) {
		ElementDestroy(container->children[i]);
	}

	// TODO.

	ElementMessage(container, MSG_LAYOUT, 0, 0);
	ElementRepaint(container, NULL);
}

We'll switch on the type of the selected object. If we extended our application to use multiple different objects, then depending on which type of object is selected when the Populate() function is called, we'll get a different interface. For example, this is useful in a video editor where you have a timeline of clips and different clips should show different properties in some sort of inspector interface.

Object *object = SelectedObject();

if (object->type == OBJECT_COUNTER) {
	// TODO.
} else {
	// ...
}

Let's write the code to create the interface for the counter object. As before, we'll want a row panel.

Panel *row = PanelCreate(container, PANEL_HORIZONTAL | ELEMENT_H_FILL);

We create the decrement button. To decide whether it's disabled, we read the count from the selected object using our helper function ObjectReadU32.

Button *button = ButtonCreate(&row->e, 0, "-", -1);
bool disabled = ObjectReadU32(SelectedObject(), "count", 0 /* default value */) == 0;
if (disabled) button->e.messageUser = ButtonDisabledMessage;

Then we create the label, again reading the count from the selected object.

char buffer[64];
snprintf(buffer, sizeof(buffer), "Count: %d", ObjectReadU32(SelectedObject(), "count", 0));
LabelCreate(&row->e, ELEMENT_H_FILL | LABEL_CENTER, buffer, -1);

Finally, we create the increment button in a similar fashion to the decrement button.

Button *button = ButtonCreate(&row->e, 0, "+", -1);
bool disabled = ObjectReadU32(SelectedObject(), "count", 0) == 10;
if (disabled) button->e.messageUser = ButtonDisabledMessage;

And if you haven't already, we can now remove the old int count; global variable.

The end result of the application should be the same. Make sure that changing the initial value of propertyCount.u32 = 10; in the code gets the correct value in the label and disables the buttons correctly. It may seem like we're going slowly, but it's important to take this one step at a time.

part18.c

Part 17: The document-object model.

Part 19: Refactoring reactive elements.