static void UI_MaterialEditorNewStage_f (void)
{
	material_t* m;
	int id;

	if (Cmd_Argc() < 2) {
		Com_Printf("Usage: %s <image index>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	m = &R_GetImageAtIndex(id)->material;
	materialStage_t* const s = Mem_PoolAllocType(materialStage_t, vid_imagePool);
	m->num_stages++;

	/* append the stage to the chain */
	if (!m->stages)
		m->stages = s;
	else {
		materialStage_t* ss = m->stages;
		while (ss->next)
			ss = ss->next;
		ss->next = s;
	}

	UI_MaterialEditorUpdate(R_GetImageAtIndex(id), s);
}
static void UI_MaterialEditorRemoveStage_f (void)
{
	image_t* image;
	int id, stageID;

	if (Cmd_Argc() < 3) {
		Com_Printf("Usage: %s <image index> <stage index>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	image = R_GetImageAtIndex(id);

	stageID = atoi(Cmd_Argv(2));
	if (stageID < 0 || stageID >= image->material.num_stages) {
		Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
		return;
	}

	materialStage_t** const anchor = stageID == 0 ? &image->material.stages : &UI_MaterialEditorGetStage(&image->material, stageID - 1)->next;
	materialStage_t*  const s      = *anchor;
	*anchor = s->next;
	Mem_Free(s);

	image->material.num_stages--;

	UI_MaterialEditorUpdate(image, nullptr);
}
static void UI_MaterialEditorSelectStage_f (void)
{
	image_t* image;
	int id, stageID;
	materialStage_t* materialStage;

	if (Cmd_Argc() < 3) {
		Com_Printf("Usage: %s <image index> <stage index>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	image = R_GetImageAtIndex(id);

	stageID = atoi(Cmd_Argv(2));
	if (stageID < 0 || stageID >= image->material.num_stages) {
		Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
		return;
	}

	materialStage = UI_MaterialEditorGetStage(&image->material, stageID);
	UI_MaterialEditorUpdate(image, materialStage);
}
void uiMaterialEditorNode::onMouseDown (uiNode_t* node, int x, int y, int button)
{
	int id;
	if (button != K_MOUSE1)
		return;

	id = UI_MaterialEditorNodeGetImageAtPosition(node, x, y);
	if (id == -1)
		return;

	/** @note here we use "num" to cache the selected image id. We can reuse it on the script with "<num>" */
	/* have we selected a new image? */
	if (node->num != id) {
		image_t* image = R_GetImageAtIndex(id);
		UI_MaterialEditorUpdate(image, nullptr);

		node->num = id;

		if (node->onChange)
			UI_ExecuteEventActions(node, node->onChange);
	}
}
static void UI_MaterialEditorRemoveStage_f (void)
{
	image_t *image;
	int id, stageID;

	if (Cmd_Argc() < 3) {
		Com_Printf("Usage: %s <image index> <stage index>\n", Cmd_Argv(0));
		return;
	}

	id = atoi(Cmd_Argv(1));
	if (id < 0 || id >= r_numImages) {
		Com_Printf("Given image index (%i) is out of bounds\n", id);
		return;
	}

	image = R_GetImageAtIndex(id);

	stageID = atoi(Cmd_Argv(2));
	if (stageID < 0 || stageID >= image->material.num_stages) {
		Com_Printf("Given stage index (%i) is out of bounds\n", stageID);
		return;
	}

	if (stageID == 0) {
		materialStage_t *s = image->material.stages;
		image->material.stages = s->next;
		Mem_Free(s);
	} else {
		materialStage_t *sParent = UI_MaterialEditorGetStage(&image->material, stageID - 1);
		materialStage_t *s = sParent->next;
		sParent->next = s->next;
		Mem_Free(s);
	}

	image->material.num_stages--;

	UI_MaterialEditorUpdate(image, NULL);
}