2021-11-24 01:49 PM - last edited on 2021-11-26 08:47 PM by Laszlo Nagy
Hello there!
I am newbie in Add-on development, and did some progress but seems that i am stuck now.
I successfully invoked a 32400 type floating palette, where i placed a button, which should change a specified parameter of placed GDL object(s) written by me. (The GDL objects function well, i want to write an addon to speed up the planning process -> modify the parameter from the outside!).
the function call with the button click event (main.cpp):
void Palette::ButtonClicked(const DG::ButtonClickEvent& ev)
{
// --- Place ---
if (ev.GetSource() == &placeButton)
{
Do_PlaceSystem();
}
the function (main.cpp):
void Do_PlaceSystem()
{
API_Element element, mask;
API_ElementMemo memo;
API_ParamOwnerType paramOwner;
API_ChangeParamType chgParam;
API_GetParamsType getParams;
//GSErrCode err;
// selection
API_SelectionInfo selectionInfo;
GS::Array<API_Neig> selectionNeigs;
ACAPI_Selection_Get(&selectionInfo, &selectionNeigs, false, false);
BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
// get guids
GS::Array<API_Guid> selectedElements;
GSErrCode err = ACAPI_CallUndoableCommand("Place system",
[&]() -> GSErrCode
{
// if objects are selected
if (selectionInfo.typeID != API_SelEmpty)
{
// loop begins
for (const API_Neig& neig : selectionNeigs)
{
API_Elem_Head elemHead = {};
elemHead.guid = neig.guid;
ACAPI_Element_GetHeader(&elemHead);
BNZeroMemory(¶mOwner, sizeof(API_ParamOwnerType));
paramOwner.libInd = 0; // not library part
paramOwner.typeID = API_ObjectID; // object element
paramOwner.guid = neig.guid; // guid
// show guid / type of paramOwner: its working..
DG::InformationAlert(APIGuidToString(paramOwner.guid), "", "OK");
BNZeroMemory(&getParams, sizeof(API_GetParamsType));
err = ACAPI_Goodies(APIAny_OpenParametersID, ¶mOwner, nullptr);
if (err == NoError)
{
BNZeroMemory(&chgParam, sizeof(API_ChangeParamType));
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
if (err == NoError)
{
chgParam.index = 0; // parameter index
CHCopyC("bOrganizeAnchors", chgParam.name); // parameter name
chgParam.realValue = 1.0; // parameter new value
// show name and value: its working..
DG::InformationAlert((chgParam.name), "", "OK");
DG::InformationAlert(GS::ValueToUniString(chgParam.realValue), "", "OK");
err = ACAPI_Goodies(APIAny_ChangeAParameterID, &chgParam, nullptr);
if (err == NoError)
{
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
// TODO
// show if its successful: its NOT working...
DG::InformationAlert("APIAny_GetActParametersID is OK!", "", "OK");
// ERROR is here, its never reaches this part of the code
}
}
err = ACAPI_Goodies(APIAny_CloseParametersID, nullptr, nullptr);
// in the examples there's no " err = ... "
// if there's no " err = ..." crashes all the time...
}
if (err == NoError)
{
// show if its successful: its working
DG::InformationAlert("APIAny_CloseParametersID is OK!", "", "OK");
BNZeroMemory(&element, sizeof(API_Element));
BNZeroMemory(&memo, sizeof(API_ElementMemo));
element.header.typeID = API_ObjectID;
ACAPI_ELEMENT_MASK_CLEAR(mask);
ACAPI_ELEMENT_MASK_SETFULL(mask);
memo.params = getParams.params;
err = ACAPI_Element_Change(&element, &mask, &memo, APIMemoMask_AddPars, true);
if (err == NoError)
{
// show if its successful: its not working..
DG::InformationAlert("ACAPI_Element_Change is OK!", "", "OK");
}
}
} // loop ends
// clear memory
ACAPI_DisposeElemMemoHdls(&memo);
}
else
{
// if no object selected
DG::InformationAlert("No object is selected!", "", "OK");
}
return NoError;
}); // call undoable command end
if (err != NoError)
{
ACAPI_WriteReport("ACAPI_Element_Change failed.", false, err);
return;
}
// this is a must
//ACAPI_DisposeElemMemoHdls(&memo);
}
There are several questions:
-where to place the callundoablecommand? its better like it is now, its better in the event call? If i place it in the event call, how do i use ACAPI_DisposeElemMemoHdls(&memo);?
-the parameter of the GDL object is a boolean, however there are another parameters too (integers) i want to change later with another function. Which command is the best? I am trying to do that with ACAPI_Element_Change and tried ACAPI_Element_ChangeParameter too but none of these seems to work :S
-The GDL script runs til end if i change a parameter of a placed obejct? I am asking this, because this parameter ("bOrganizeAnchors") is triggering another bool parameter in the parameter script of the GDL too.. Do i have to change both or 1 is enough?
-the error is somewhere around the err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);... it never reaches that part of the code and i dont know why...
Thank you for your help!
Solved! Go to Solution.
2021-11-29 10:43 AM - last edited on 2021-12-02 03:42 AM by Laszlo Nagy
So, after several brain meltdowns and some barrels of coffee, i finally managed to make it work 😉
it's working!
// -----------------------------------------------------------------------------
// Change boolean parameter
// -----------------------------------------------------------------------------
void Do_ChangeBoolean(const char* param_name, bool param_new_value)
{
GSErrCode err = ACAPI_CallUndoableCommand("Place system",
[&]() -> GSErrCode
{
API_Element element, mask;
API_ElementMemo memo;
API_ParamOwnerType paramOwner;
API_ChangeParamType chgParam;
API_GetParamsType getParams;
GSErrCode err;
// selection
API_SelectionInfo selectionInfo;
GS::Array<API_Neig> selectionNeigs;
ACAPI_Selection_Get(&selectionInfo, &selectionNeigs, false, false);
BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
// if objects are selected
if (selectionInfo.typeID != API_SelEmpty)
{
// loop begins
for (const API_Neig& neig : selectionNeigs)
{
API_Elem_Head elemHead = {};
elemHead.guid = neig.guid;
ACAPI_Element_GetHeader(&elemHead);
BNZeroMemory(&element, sizeof(element));
element.header.guid = neig.guid;
//get the element
if (ACAPI_Element_Get(&element) == NoError)
{
if (element.header.hasMemo)
{
BNZeroMemory(&memo, sizeof(memo));
err = ACAPI_Element_GetMemo(element.header.guid, &memo, APIMemoMask_AddPars);
}
}
BNZeroMemory(¶mOwner, sizeof(API_ParamOwnerType));
paramOwner.libInd = 0; // not library part
paramOwner.typeID = API_ObjectID; // object element
paramOwner.guid = element.header.guid; // guid
BNZeroMemory(&getParams, sizeof(API_GetParamsType));
err = ACAPI_Goodies(APIAny_OpenParametersID, ¶mOwner, nullptr);
if (err == NoError)
{
BNZeroMemory(&chgParam, sizeof(API_ChangeParamType));
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
if (err == NoError)
{
chgParam.index = 0; // parameter index
CHCopyC(param_name, chgParam.name); // parameter name
chgParam.realValue = param_new_value; // parameter new value
err = ACAPI_Goodies(APIAny_ChangeAParameterID, &chgParam, nullptr);
if (err == NoError)
{
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
}
}
err = ACAPI_Goodies(APIAny_CloseParametersID, nullptr, nullptr);
if (err == NoError)
{
element.header.typeID = API_ObjectID;
ACAPI_ELEMENT_MASK_CLEAR(mask);
ACAPI_ELEMENT_MASK_SETFULL(mask);
memo.params = getParams.params;
err = ACAPI_Element_Change(&element, &mask, &memo, APIMemoMask_AddPars, true);
}
} // openParametersID end
} // loop ends
// clear memory
ACAPI_DisposeElemMemoHdls(&memo);
}
else
{
// if no object selected
DG::InformationAlert("No object is selected!", "", "OK");
}
return NoError;
}); // call undoable command end
if (err != NoError)
{
ACAPI_WriteReport("ACAPI_Element_Change failed.", false, err);
return;
}
}
2021-11-29 10:15 AM
Hi Bence,
If your program execution won't reach GetActParameters, it means that ChangeAParameter call returned with an error. These error values are designed to give you a vague sense of what the problem is. See here: https://archicadapi.graphisoft.com/documentation/error-codes.
Regarding the placement of UndoableCommand call: you should place it so that everything you want to make undoable is in its scope. There are no other strict rules, do whichever is more readable for you.
2021-11-29 10:43 AM - last edited on 2021-12-02 03:42 AM by Laszlo Nagy
So, after several brain meltdowns and some barrels of coffee, i finally managed to make it work 😉
it's working!
// -----------------------------------------------------------------------------
// Change boolean parameter
// -----------------------------------------------------------------------------
void Do_ChangeBoolean(const char* param_name, bool param_new_value)
{
GSErrCode err = ACAPI_CallUndoableCommand("Place system",
[&]() -> GSErrCode
{
API_Element element, mask;
API_ElementMemo memo;
API_ParamOwnerType paramOwner;
API_ChangeParamType chgParam;
API_GetParamsType getParams;
GSErrCode err;
// selection
API_SelectionInfo selectionInfo;
GS::Array<API_Neig> selectionNeigs;
ACAPI_Selection_Get(&selectionInfo, &selectionNeigs, false, false);
BMKillHandle((GSHandle*)&selectionInfo.marquee.coords);
// if objects are selected
if (selectionInfo.typeID != API_SelEmpty)
{
// loop begins
for (const API_Neig& neig : selectionNeigs)
{
API_Elem_Head elemHead = {};
elemHead.guid = neig.guid;
ACAPI_Element_GetHeader(&elemHead);
BNZeroMemory(&element, sizeof(element));
element.header.guid = neig.guid;
//get the element
if (ACAPI_Element_Get(&element) == NoError)
{
if (element.header.hasMemo)
{
BNZeroMemory(&memo, sizeof(memo));
err = ACAPI_Element_GetMemo(element.header.guid, &memo, APIMemoMask_AddPars);
}
}
BNZeroMemory(¶mOwner, sizeof(API_ParamOwnerType));
paramOwner.libInd = 0; // not library part
paramOwner.typeID = API_ObjectID; // object element
paramOwner.guid = element.header.guid; // guid
BNZeroMemory(&getParams, sizeof(API_GetParamsType));
err = ACAPI_Goodies(APIAny_OpenParametersID, ¶mOwner, nullptr);
if (err == NoError)
{
BNZeroMemory(&chgParam, sizeof(API_ChangeParamType));
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
if (err == NoError)
{
chgParam.index = 0; // parameter index
CHCopyC(param_name, chgParam.name); // parameter name
chgParam.realValue = param_new_value; // parameter new value
err = ACAPI_Goodies(APIAny_ChangeAParameterID, &chgParam, nullptr);
if (err == NoError)
{
err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
}
}
err = ACAPI_Goodies(APIAny_CloseParametersID, nullptr, nullptr);
if (err == NoError)
{
element.header.typeID = API_ObjectID;
ACAPI_ELEMENT_MASK_CLEAR(mask);
ACAPI_ELEMENT_MASK_SETFULL(mask);
memo.params = getParams.params;
err = ACAPI_Element_Change(&element, &mask, &memo, APIMemoMask_AddPars, true);
}
} // openParametersID end
} // loop ends
// clear memory
ACAPI_DisposeElemMemoHdls(&memo);
}
else
{
// if no object selected
DG::InformationAlert("No object is selected!", "", "OK");
}
return NoError;
}); // call undoable command end
if (err != NoError)
{
ACAPI_WriteReport("ACAPI_Element_Change failed.", false, err);
return;
}
}