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.
SOLVED!

Navigator Items especially Layouts

Anonymous
Not applicable
Hi there!

I tried to get navigator items in the navigator. I use AC20 so I'm using ACAPI_Environment calls.

The provided example of getting Views is working fine I can get the array of nav. items.
item.itemType = API_StoryNavItem;
item.mapId    = API_PublicViewMap;

err = ACAPI_Environment (APIEnv_SearchNavigatorItemID, &item, &items, NULL);
But i tried to change parameters to get layouts like below, and i'm getting this error:
APIERR_BADDATABASE	-2130313110	
.
item.itemType = API_LayoutNavItem;
item.mapId    = API_LayoutMap;

err = ACAPI_Environment (APIEnv_SearchNavigatorItemID, &item, &items, NULL);
From that error i tried to assign database info to the search query. with this.
API_DatabaseInfo db;
BNZeroMemory (&db, sizeof (API_DatabaseInfo));
db.typeID = APIWind_LayoutID;

item.itemType = API_LayoutNavItem;
item.mapId    = API_LayoutMap;
item.db		  =db;

err = ACAPI_Environment (APIEnv_SearchNavigatorItemID, &item, &items, NULL);
And this way i got the same result... database error.

So i tried to change the database before the query by:
err=ACAPI_Database (APIDb_ChangeCurrentDatabaseID,&db);
And this gave me the same database error. After that i don't have aní clue to solve my issue.

My main goal is that, to create an addon which publish every layout with different graphical overrides, so the background color of the active( printed) room is different then other rooms.

My plan was to do that is this: Loop through layouts, change graphical overrides, to meet the requirements, plot the layout, change back the original override, and then go to next.

So if you think that i'm on the wrong pat to solve this problem, then tell me. And of course if you have some idea what's wrong currently with this code, i'd be glad.
1 ACCEPTED SOLUTION

Accepted Solutions
Solution
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
APIEnv_SearchNavigatorItemID does not work for searching all layouts.
But you can iterate through the layout tree using APIEnv_GetNavigatorSetID and APIEnv_GetNavigatorChildrenItemsID methods:
GS::Array<API_NavigatorItem> GetNavItemChildren (const API_NavigatorItem& item)
{
    API_NavigatorItem** children = nullptr;
    err = ACAPI_Environment (APIEnv_GetNavigatorChildrenItemsID, &item, &children);
    if (err != NoError)
        return err;

    const Int32 childCount = BMhGetSize ((GSHandle)children) / Sizeof32 (API_NavigatorItem);
    GS::Array<API_NavigatorItem> childArray;
    for (Int32 ii = 0; ii < childCount; ++ii) {
        const API_NavigatorItem& childItem = (*children)[ii];
        childArray.Push (childItem);
        childArray.Append (GetNavItemChildren (childItem));
    }

    BMhKill ((GSHandle *)&children);

    return childArray;
}


GS::Array<API_NavigatorItem> GetAllLayoutNavItem ()
{
    API_NavigatorSet  set;
    BNZeroMemory (&set, sizeof (API_NavigatorSet));

    set.mapId = API_LayoutMap;
    GSErrCode err = ACAPI_Environment (APIEnv_GetNavigatorSetID, &set);
    if (err != NoError)
        return err;

    API_NavigatorItem rootItem;
    BNZeroMemory (&rootItem, sizeof (API_NavigatorItem));

    rootItem.guid = set.rootGuid;
    rootItem.mapId = set.mapId;

    return GetNavItemChildren (rootItem);
}

View solution in original post

10 REPLIES 10
Solution
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
APIEnv_SearchNavigatorItemID does not work for searching all layouts.
But you can iterate through the layout tree using APIEnv_GetNavigatorSetID and APIEnv_GetNavigatorChildrenItemsID methods:
GS::Array<API_NavigatorItem> GetNavItemChildren (const API_NavigatorItem& item)
{
    API_NavigatorItem** children = nullptr;
    err = ACAPI_Environment (APIEnv_GetNavigatorChildrenItemsID, &item, &children);
    if (err != NoError)
        return err;

    const Int32 childCount = BMhGetSize ((GSHandle)children) / Sizeof32 (API_NavigatorItem);
    GS::Array<API_NavigatorItem> childArray;
    for (Int32 ii = 0; ii < childCount; ++ii) {
        const API_NavigatorItem& childItem = (*children)[ii];
        childArray.Push (childItem);
        childArray.Append (GetNavItemChildren (childItem));
    }

    BMhKill ((GSHandle *)&children);

    return childArray;
}


GS::Array<API_NavigatorItem> GetAllLayoutNavItem ()
{
    API_NavigatorSet  set;
    BNZeroMemory (&set, sizeof (API_NavigatorSet));

    set.mapId = API_LayoutMap;
    GSErrCode err = ACAPI_Environment (APIEnv_GetNavigatorSetID, &set);
    if (err != NoError)
        return err;

    API_NavigatorItem rootItem;
    BNZeroMemory (&rootItem, sizeof (API_NavigatorItem));

    rootItem.guid = set.rootGuid;
    rootItem.mapId = set.mapId;

    return GetNavItemChildren (rootItem);
}
Anonymous
Not applicable
Tibor wrote:
But you can iterate through the layout tree using APIEnv_GetNavigatorSetID and APIEnv_GetNavigatorChildrenItemsID methods:
I'm playing around with Navigator. Since it was moved to separate class form Environment. I have updated code. However, it doesn't seem to work in any case. There is a slight success with Publisher Set. I can access set but I can't access any child. In the case of other types, I got nothing. Please help.
 GS::Array<API_NavigatorItem> GetNavItemChildren(const API_NavigatorItem* item)
{
	ACAPI_WriteReport("child", true);

	API_NavigatorItem** children = nullptr;
	//GS::ErrCode err = ACAPI_Environment(APIEnv_GetNavigatorChildrenItemsID, &item, &children);
	
	//API_NavigatorItem* = &item; 

	GS::ErrCode err = ACAPI_Navigator(APINavigator_GetNavigatorChildrenItemsID, &item, &children);
	err;
	ACAPI_WriteReport(GS::ValueToString(err), true);

	//if (err != NoError)
	//	return err;

	const Int32 childCount = BMhGetSize((GSHandle)children) / Sizeof32(API_NavigatorItem);
	GS::Array<API_NavigatorItem> childArray;
	ACAPI_WriteReport("cnt", true);

	ACAPI_WriteReport(GS::ValueToString(childCount), true);

	for (Int32 ii = 0; ii < childCount; ++ii) {
		const API_NavigatorItem& childItem = (*children)[ii];
		ACAPI_WriteReport(childItem.name, true);
		childArray.Push(childItem);
		childArray.Append(GetNavItemChildren(&childItem));
	}

	BMhKill((GSHandle *)&children);

	return childArray;
}


void GetAllLayoutNavItem()
{
	ACAPI_WriteReport("set", true);

	API_NavigatorSet  set;
	BNZeroMemory(&set, sizeof(API_NavigatorSet));

	//set.mapId = API_PublicViewMap;
	set.mapId = API_LayoutMap;

	//set.mapId = API_PublisherSets;
	int idx = 1; //for Publisher Set
	idx;
	GSErrCode err = ACAPI_Navigator(APINavigator_GetNavigatorSetID, &set);
	//if (err != NoError)
	//	return err;
	ACAPI_WriteReport(GS::ValueToString(err), true);
	const Int32 setCnr = BMhGetSize((GSHandle)&set) / Sizeof32(API_NavigatorSet);
	ACAPI_WriteReport(GS::ValueToString(setCnr), true);

	err;
	API_NavigatorItem rootItem;
	BNZeroMemory(&rootItem, sizeof(API_NavigatorItem));

	rootItem.guid = set.rootGuid;
	rootItem.mapId = set.mapId;
	ACAPI_WriteReport(set.name, true);
	ACAPI_WriteReport(GS::ValueToString(set.mapId), true);
	 GetNavItemChildren(&rootItem);

}
Anonymous
Not applicable
After a few hours of debugging, I found a solution. Code works. I passed GUID of Navi Set... Which seem quite logical. But as it turned out it should be rootGuid. Does anyone know the difference?
Anonymous
Not applicable
kzaremba wrote:
After a few hours of debugging, I found a solution. Code works. I passed GUID of Navi Set... Which seem quite logical. But as it turned out it should be rootGuid. Does anyone know the difference?
Can you post the final code which you have iterated layouts successfully with?
Anonymous
Not applicable
Tomer1 wrote:

Can you post the final code which you have iterated layouts successfully with?
Hi, as far as I remember this piece of code should work. Later on, I was just referring to GUID o set instead of rootGUID. Let me know if it's wroking.
Anonymous
Not applicable
I am able to implement your code but I want to use it to change the layout I’m currently on - change the active layout:
My target is to iterate (actually change on the project) through all layout and run the same code on every active layout at its turn.
Anonymous
Not applicable
I see. It's a bit different thing then. I don't have ready solution for it but I would start form Database_Control example. There are two interesting methods that can be a good starting point:
Do_OpenMyWindow and Do_ChangeAllDrawings

I suppose you can try to use Navigator GUIDs but probably more efficient will be to query Database itself.
Anonymous
Not applicable
Interesting.
From some reason Do_ChangeAllDrawings only change one drawing for every layout. So if there is more then one drawing in a specific layout only one will change.
Do you have any idea why it might happen?

Thanks in advance
Anonymous
Not applicable
I tried it myself. It seems to work ok. It changed all drawings Name and Number in Layout set. It's quite interesting since you don't have to even display layout to do it so it's very fast.