Find the next step in your career as a Graphisoft Certified BIM Manager!

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

How to change a parameter of a placed GDL object?

Csanyi Bence
Contributor

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(&paramOwner, 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, &paramOwner, 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!

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
Solution
Csanyi Bence
Contributor

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(&paramOwner, 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, &paramOwner, 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;
 }
}

 

View solution in original post

2 REPLIES 2
akomporday
Graphisoft
Graphisoft

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.

Solution
Csanyi Bence
Contributor

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(&paramOwner, 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, &paramOwner, 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;
 }
}

 

Didn't find the answer?

Check other topics in this Forum

Back to Forum

Read the latest accepted solutions!

Accepted Solutions

Start a new conversation!