Hi @C4DS,
First of all, as @Cairyn said, keep in mind this behavior/workflow is completely new for C4D user and it can be a bit weird for them. But is up to you to decide the overall design of your plugin.
With that's said and as you already figured it out, the main issue is you are changing data within a redraw.
To fix that, use a CoreMessage. See GeDialog Core Messages Manual.
#define GROUP_ID 9999
#define TAB_GROUP_ID 10000
#define REDRAW_MSG_ID 1000001 // Get a unique ID at https://plugincafe.maxon.net/c4dpluginid_cp
class TabDialog : public GeDialog
{
public:
maxon::BaseArray<Int32> tabIds;
Bool CreateLayout()
{
if (tabIds.IsEmpty())
{
tabIds.Append(10001);
tabIds.Append(10011);
tabIds.Append(10021);
}
DrawTab();
return true;
};
void DrawTab(Bool redraw=false)
{
// If we redraw, the group already exist so we flush it.
if (redraw)
LayoutFlushGroup(GROUP_ID);
// Otherwise we create it.
else
GroupBegin(GROUP_ID, BFH_SCALEFIT | BFV_TOP, 1, 1, ""_s, 0);
// Then we create our TabGroup
TabGroupBegin(TAB_GROUP_ID, BFH_SCALEFIT | BFV_SCALEFIT, TAB_TABS);
Int32* lastId = tabIds.GetLast();
for (Int32 x : tabIds)
{
String groupTitle;
if (x == *lastId)
groupTitle += "+"_s;
else
groupTitle += FormatString("Group @"_s, x);
GroupBegin(x, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, groupTitle, 0);
AddCheckbox(x + 1, BFH_LEFT, 0, 0, "Some Elements"_s);
GroupEnd();
}
GroupEnd();
GroupEnd();
if (redraw)
LayoutChanged(GROUP_ID);
};
Bool Command(Int32 id, const BaseContainer& msg)
{
// Check the command come from the Tab
if (id == TAB_GROUP_ID)
{
// Get the clicked tab ID
Int32 newTabId;
GetInt32(TAB_GROUP_ID, newTabId);
// Get the last value of our tabs
Int32* lastValue = tabIds.GetLast();
if (lastValue == nullptr)
return GeDialog::Command(id, msg);
// If it's the last value, we add a new tab, and call a Redraw
if (newTabId == *lastValue)
{
tabIds.Append(*lastValue + 10);
SpecialEventAdd(REDRAW_MSG_ID);
}
}
return GeDialog::Command(id, msg);
};
Bool CoreMessage(Int32 id, const BaseContainer& msg)
{
switch(id)
{
case REDRAW_MSG_ID:
{
// check if this core message is new
if (!CheckCoreMessage(msg))
break;
DrawTab(true);
// Set the active tab to the one which is just added
if (tabIds.GetCount() >= 2)
SetInt32(TAB_GROUP_ID, tabIds[tabIds.GetCount() - 2]);
break;
}
}
return GeDialog::CoreMessage(id, msg);
}
};
If you have any question, please let me know.
Cheers,
Maxime.