We value your input!
Please participate in Archicad 28 Home Screen and Tooltips/Quick Tutorials survey

Archicad C++ API
About Archicad add-on development using the C++ API.

How to group items in list view

Anonymous
Not applicable
Hello,

I would like to know how i can achieve grouping of list items in my list view. I attached an image to show what I want to achieve.

I need to use the code in c++. I know how to make a normal list view:
 // -----------------------------------------------------------------------------
// Set/adjust the dialog items
// -----------------------------------------------------------------------------

static void ListDataDlg_Set (short 	dialId, DGUserData userData)
{
	API_ListData	listdata;
	char			keyStr[NAME_LEN2];
	char			codeStr[NAME_LEN2];
	Int32			count;
	Int32			i;
	bool			filter;

	if (userData == 0L) {
		return;
	}

	 

	listdata = *((API_ListData *) (userData));

	listdata.header.setIndex = (short) DGPopUpGetItemUserData (dialId, DBSetPopupItem,
				(short) DGGetItemValLong (dialId, DBSetPopupItem));

	GS::UniString temp = DGGetItemText (dialId, KeyEditTextItem);
	CHTruncate (UniStringToConstCString (temp), keyStr, NAME_LEN2);
	temp = DGGetItemText (dialId, CodeEditTextItem);
	CHTruncate (UniStringToConstCString (temp), codeStr, NAME_LEN2);

	switch (DGGetItemValLong (dialId, TypeIDPopupItem)) {

		case 1:		listdata.header.typeID = API_ComponentID;
					CHCopyC (keyStr, listdata.component.keycode);
					CHCopyC (codeStr, listdata.component.code);
					DGEnableItem (dialId, KeyEditTextItem);
					break;

		case 2:		listdata.header.typeID = API_DescriptorID;
					CHCopyC (keyStr, listdata.descriptor.keycode);
					CHCopyC (codeStr, listdata.descriptor.code);
					DGEnableItem (dialId, KeyEditTextItem);
					break;

		case 3:		listdata.header.typeID = API_KeyID;
					CHCopyC (codeStr, listdata.key.code);
					DGDisableItem (dialId, KeyEditTextItem);
					break;

		case 4:		listdata.header.typeID = API_UnitID;
					CHCopyC (codeStr, listdata.unit.code);
					DGDisableItem (dialId, KeyEditTextItem);
					break;
	}

	DGListDeleteItem (dialId, SearchListItem, DG_ALL_ITEMS);

	filter = (DGGetCheckedRadio (dialId, 1) == FilterRadioItem);
	Search_ListData (&listdata, &count, filter);

	if (count < 1 || listHdl == NULL)
		return;

	for (i = 1; i <= count; i++)
		DGListInsertItem (dialId, SearchListItem, DG_LIST_BOTTOM);

	SetDGList (dialId, count);
	DGListSelectItem (dialId, SearchListItem, 1);

	return;
}		// ListDataDlg_Set

static void		Search_ListData (API_ListData *param, Int32 *count, bool filter)
{
	API_ListData	listdata;
	Int32			i;
	Int32			beginIndex, endIndex;
	GSErrCode		err;

	listdata	= *param;
	*count		= 0;
	err			= NoError;

	/* ACAPI_ListData_Search fails if keyCode is an empty string */

	/* ------- Search it ------- */
	if (filter && (param->header.typeID == API_UnitID || param->header.typeID == API_KeyID ||
		(param->header.typeID == API_ComponentID && strlen (param->component.code) != 0) ||
		(param->header.typeID == API_DescriptorID && strlen (param->descriptor.code) != 0))) {

		err = ACAPI_ListData_Search (&listdata);

		if (err == NoError)
			err = ACAPI_ListData_Get (&listdata);

		if (err == NoError) {
			err = AppendList (&listdata, count);
			if (listdata.header.typeID == API_DescriptorID)
				BMKillHandle (&listdata.descriptor.name);
		}
	} else {

	/* ------ Search list ------ */
		if (filter) {
			err = ACAPI_ListData_Search (&listdata);
			if (err != NoError)
				return;

			beginIndex = listdata.header.index;
		} else
			beginIndex = 1;

		err = ACAPI_ListData_GetNum (param->header.setIndex, param->header.typeID, &endIndex);
		if (err != NoError)
			return;

		BNZeroMemory (&listdata, sizeof (API_ListData));
		listdata.header.typeID	 = param->header.typeID;
		listdata.header.setIndex = param->header.setIndex;

		for (i = beginIndex; i <= endIndex; i++) {

			listdata.header.index		= i;
			err = ACAPI_ListData_Get (&listdata);
			if (err != NoError)
				break;

			if (filter) {
				if (listdata.header.typeID == API_ComponentID &&
					!CHEqualCStrings (listdata.component.keycode, param->component.keycode))
					break;

				if	(listdata.header.typeID == API_DescriptorID &&
					!CHEqualCStrings (listdata.descriptor.keycode, param->descriptor.keycode)) {

					BMKillHandle (&listdata.descriptor.name);
					break;
				}
			}

			if (err == NoError) {
				err = AppendList (&listdata, count);
				if (listdata.header.typeID == API_DescriptorID)
					BMKillHandle (&listdata.descriptor.name);
			}

			if (err != NoError)
				return;
		}
	}

	return;
}		// Search_ListData

But how can I group those items under a header like in the example.

Thanks

111.jpeg
4 REPLIES 4
Erenford
Booster
The one in the picture is from GDL though, not the API Dialog Manager. In GDL its merely setting an object's parameter as title type and setting the parameters below it as its children.

The closest imitation I could think of is using a ListBox and setting up a column for the "arrow down/right" toggle icon which when click, will populate that listitem's children. And then when clicked again will delete all those children.
Anonymous
Not applicable
Thank you for your answer...

I understand that the upper one is from GDL. I also know how to make these when creating my custom GDL objects. But the lower one (with the IFC properties etc.) seems to be some UI class/element.

So as an example, in the DevKit in C++ I can make a list view with: DG::SingleSelListView

Like this I would also expect some class to make this kind of list, or is such class not available in the DevKit?

Hope you can clear this up.
Thanks!
ReignBough
Enthusiast
You can create a class/structure that uses flags the same as the modifier flags of API_AddParType (or you can set your own modifier flags). Then modify it whenever you "toggle" an item in the list. Then re-populate the list. Something like (populate list with parameter of a LibPart):
bool isOpen = false;
//... clear list before loop
for (... i = 0; i < cnt; i++)
{
    if (flags & API_ParFlag_Hidden)
        continue;

    // check if parent or child
    if (flags & API_ParFlag_Child)
    {
        // skip if parent is "close"
        if (!isOpen)
            continue;
    }
    // set isOpen if item is not child
    else
    {
        isOpen = (flags & API_ParFlag_Open) > 0;
    }

    //... populate list here checking if it is disabled, bold, separator, etc.
}
~ReignBough~
ARCHICAD 26 INT (from AC18)
Windows 11 Pro, AMD Ryzen 7, 3.20GHz, 32.0GB RAM, 64-bit OS
Anonymous
Not applicable
I already did listview grouping by this way. Thanks