• 0 Votes
    9 Posts
    2k Views
    B
    @Dunhou Thanks for the reference but yea I'm unfortunately using the xpresso here instead of the new node editor. Which in all regards, an unfortunate scenario is xpresso is not integrated to the new node editor. @m_adam Gotcha. Thanks. Looking forward to the update.
  • BaseDraw scale

    Cinema 4D SDK r19 r20 r21 c++
    3
    0 Votes
    3 Posts
    541 Views
    rsodreR
    @r_gigante Thanks, I used an inverse scale matrix wen calculating my gizmo points.
  • 0 Votes
    3 Posts
    1k Views
    L
    Manuel, thanks for taking the time and posting some links. Last night I was reading up on the Matrix and trying wrapping my head around it. I think I was stuck in the wrong area, I was trying to convert a baseObject to a pointObject to do the transformations.I would perfer not to have to open the axis window, but instead handle all this in a Python Function. I will look over the docs and samples to get a better idea of what I need to do. Thanks again for taking the time to respond to my post!
  • Merge Tags

    Cinema 4D SDK r19 r20 r21 c++
    9
    0 Votes
    9 Posts
    1k Views
    r_giganteR
    Hi @C4DS, thanks for following up. One note that it's worthy to share: the outcomes of this thread are valid as long as you need to stick to Classic API. In Maxon API (R20 and higher) you can make very good use of the CustomDataTag (see also GitHub example) whose data merging is managed directly by the modeling kernel. Last but not least, as usual, if the discussion has come to an end, please don't forget to mark the question as SOLVED. Cheers, R
  • HashMap operator = cannot access private member

    Cinema 4D SDK r19 c++
    5
    0 Votes
    5 Posts
    669 Views
    C4DSC
    @r_gigante Maybe a little late, but thanks for the info anyway. Always useful, and much appreciated! I went with a custom implementation using a BaseArray to store the information, and from there used the specific index in the array as the value in an HashMap Instead of the wanted: maxon::HashMap<Int32, DataStruct> mymap; I went with: class MyHashMap { ... maxon::BaseArray<DataStruct> mArray; maxon::HashMap<Int32, Int32> mArrayIndexMap; }; This is more or less what you have described. The only drawback here is that I still haven't found out how to implement range-based loop support ... but I went with using the old-fashioned indexed loop usage. Good enough for its purpose.
  • Bend Deformer Using C++

    Cinema 4D SDK c++ r19 sdk
    18
    2
    0 Votes
    18 Posts
    3k Views
    M
    Yes because I've done it
  • String compare

    Cinema 4D SDK
    7
    0 Votes
    7 Posts
    874 Views
    C4DSC
    @m_magalhaes Thanks for bringing this up, as it seems I had overlooked it on multiple occasions. Which also points me to the fact that the R19 SDK did have a String::operator == () Also overlooked that all those years. I need better glasses.
  • Communication between DescriptionTool and GeUserArea

    General Talk
    4
    0 Votes
    4 Posts
    813 Views
    C4DSC
    @s_bach said in Communication between DescriptionTool and GeUserArea: The typical modern approaches are patterns like Model-View-Controller or Model-View-Presenter. In such models, you don't "send data around". Thanks for mentioning this. As stated in my opening post, this is what I have been using, where the "model" is a singleton class, available as a global variable to all plugins to synchronize and share data. Maybe not quite the exact wording. I was just wondering if there is another means of providing this "model" instead of using an instanced (singleton) class via a global variable? So in your example, the interaction with the DescriptionToolData would write data into the model. And the GeUserArea would read that data from the model. The example I provided isn't making use of a "model" as it already represented too much code just to point out the bug that slipped into R21. There I indeed used a very simplified solution by "sending data around". But an overall "thank you" for bringing up the model-view discussion, as this made me realize I could use an observer pattern in another project of mine which would fix its current poorly chosen design. Daniel
  • Attach XPresso Graph to GUI via Python

    Cinema 4D SDK
    9
    1
    0 Votes
    9 Posts
    2k Views
    DunhouD
    @ashton_fcs_plugindev That is so cool , Is it finish yet? I am new to GeUserArea too , That's a dreamly example to learn GeUserArea.
  • How to add Layers Shader - C++

    Cinema 4D SDK c++ r19 sdk
    6
    0 Votes
    6 Posts
    752 Views
    mfersaouiM
    @s_bach Thank you.
  • 0 Votes
    9 Posts
    1k Views
    S
    @m_magalhaes Hello, thank you very much for your inspiration. You've been very helpful. There is no need to overwrite TranslateDescID(), only two macros HandleDescGetVector and HandleDescSetVector can realize my idea. Thanks again! Cheers, Sean
  • Disable default Right-Click Menu

    Cinema 4D SDK python r19 r20 r21
    9
    0 Votes
    9 Posts
    2k Views
    U
    @m_adam Thanks! Thats a perfect explanation that solves many of my issues - even in some of my other Plugins. I am sorry, I did in fact refer to c4d freezing when I said crashing. Sorry for the confusion.
  • Catch other object's delete/undo

    Cinema 4D SDK c++ r19 r20 r21
    5
    0 Votes
    5 Posts
    912 Views
    rsodreR
    @m_adam , AddEventNotification was exactly what I needed. I created a notification to NOTIFY_EVENT_UNDO, and then add my object to it. Now if I delete anything from my object after a polygon is deleted, it will be restored with Undo. Thanks! case MSG_NOTIFY_EVENT: { CHECK_BREAK( data != nullptr ); const auto eventData = static_cast<NotifyEventData*>( data ); if( eventData->eventid == NOTIFY_EVENT_UNDO ) { NotifyEventMsg* notifyMessage = static_cast<NotifyEventMsg*>( eventData->event_data ); CHECK_BREAK( notifyMessage != nullptr ); if( notifyMessage->msg_id == Int32( UNDOTYPE_DELETE ) ) { eventData->doc->AddUndo( UNDOTYPE_CHANGE, Get() ); } } break; }
  • Visual Studio - Debugging Plugin Error

    Cinema 4D SDK
    9
    1
    0 Votes
    9 Posts
    1k Views
    S
    Hello, you find information how to run a plugin from within Visual Studio in the documentation: Development for Microsoft Windows - Running Plugins. best wishes, Sebastian
  • DoUndo() issue when using loop selection, ring, ...

    Cinema 4D SDK r19 r20 r21
    6
    0 Votes
    6 Posts
    769 Views
    C4DSC
    @r_gigante Hi Riccardo, Thanks for the explanation. I wasn't sure that a "Solved" thread would still get revisited by SDK team members. As Manuel mentioned "I'll come back when I got more information", but the thread was set to solved, I wasn't sure the thread would get an update. Also, others visiting the forum (now or in future) might be misleaded by the state of the thread, thinking that the bug has been fixed, while it actually isn't. But now I understand a "bug fixed" tag is being added. Seems I need to pay more attention to the tags, as I assumed these tags were added by the creator of the thread. As such, I never really paid any attention later on, as I assumed the tags I added were the only ones to be available for that thread, and only the unsolved/solved state would change as a result of a resolution. Thanks for clarifying.
  • Howto add a Field input to a python plugin

    Cinema 4D SDK python r19 r20 r21
    3
    0 Votes
    3 Posts
    587 Views
    P
    @s_bach said in Howto add a Field input to a python plugin: FIELDLIST works fine - i think i got an strange error before and trying CUSTOMFIELDLIST etc. solved
  • Keyframing a property using python.

    Moved Cinema 4D SDK
    3
    0 Votes
    3 Posts
    822 Views
    M
    Hi Manual, Thanks for your help! Next time I will use the 'ask question' when posting a question. You code does exactly what I need, much appreciated! Cheers, Martijn
  • CustomGUI gadget triggered by other gadget

    Cinema 4D SDK c++ r19 r20 r21
    10
    1
    0 Votes
    10 Posts
    1k Views
    C4DSC
    @m_magalhaes Thanks for your message-example. I hadn't quite understood it the first time, and needed a re-trigger. Inspired by your reply I came up with this solution instead. While it still is based on messaging, I preferred to use the SpecialEventAdd. This way, I could pass the type value via a "custom message". Obviously the customgui needs to be set up to react accordingly to this SpecialEventAdd, but this is what I sort of expected to already have been built in into the customgui, in order to be able to react to a trigger to update its additional attributes. Now we only can react to the attribute at constructor time. Maybe a request for a future update/addition? Note for others reading this topic: The code below is just a quick solution, having collected code from different sources and examples. It might obviously be optimized and commented in a better way. Also, make sure to register appropriate pluginIDs, as all ones used here are for demonstration purposes only. For the example below I followed a different route for testing purposes. Obviously it would lead me too far to provide a fully working plugin with NodeData etc ... As such, I wen for a simple CommandData with a GeDialog containing a set of radio buttons and a customgui gadget. The radio buttons allow to switch between black/white and r/g/b and c/m/y/k. With each selection the customgui displays a different set of options, showing a colored rectangle per option. The code is R20, but easily adjustable for R21. Main.cpp // ======================== // Cinema 4D C++ plugin // // PluginName: Test // Dummy "empty" plugin // ======================== // Main.cpp #include "c4d.h" // === Registered pluginIDs === #define MYCOMMAND_PLUGIN_ID 1000000 // DUMMY VALUE for demonstration purposes only !!! #define CUSTOMGUI_GADGET_ID 1000002 // DUMMY VALUE for demonstration purposes only !!! // a specific message ID to trigger the gadget to set its type #define CUSTOMGUI_GADGET_SETTYPEMSG_ID 100 // the gadget IDs #define RADIO_BUTTONS 10000 #define CUSTOMGUI_GADGET 10010 extern Bool RegisterGadget(); // ==================================== // GeDialog // ==================================== class MyDialog : public GeDialog { public: MyDialog(void) {} virtual ~MyDialog(void) {} virtual Bool CreateLayout(void); virtual Bool InitValues(void); virtual void DestroyWindow(void); virtual Bool Command(Int32 id, const BaseContainer& msg); virtual Int32 Message(const BaseContainer& msg, BaseContainer& result); }; Bool MyDialog::CreateLayout(void) { Bool res = GeDialog::CreateLayout(); // when using a GeLoadString(<string-id>) // strings need to be defined in the main string resources, not in the dialogs subfolder SetTitle("Test Dialog"_s); GroupBegin(0, BFH_SCALEFIT | BFV_SCALEFIT, 1, 0, ""_s, 0); { GroupBorderSpace(4, 4, 4, 4); GroupBegin(0, BFH_LEFT, 2, 0, maxon::String(), 0); { // 3 radio buttons vertically AddRadioGroup(RADIO_BUTTONS, BFV_SCALEFIT, 0, 3); AddChild(RADIO_BUTTONS, 2, "BW"_s); AddChild(RADIO_BUTTONS, 3, "RGB"_s); AddChild(RADIO_BUTTONS, 4, "CMYK"_s); // the custom gadget BaseContainer bc; AddCustomGui(CUSTOMGUI_GADGET, CUSTOMGUI_GADGET_ID, String(), 0, 0, 0, bc); } GroupEnd(); } GroupEnd(); return res; } Bool MyDialog::InitValues(void) { // first call the parent instance if (!GeDialog::InitValues()) return false; // do our thing ... Int32 typevalue = 2; SetInt32(RADIO_BUTTONS, typevalue); // set default to black and white // and inform the gadget about it SpecialEventAdd(CUSTOMGUI_GADGET_ID, CUSTOMGUI_GADGET_SETTYPEMSG_ID, typevalue); return true; } void MyDialog::DestroyWindow(void) {} Bool MyDialog::Command(Int32 id, const BaseContainer& msg) { if (id == RADIO_BUTTONS) { Int32 typevalue; GetInt32(RADIO_BUTTONS, typevalue); // send this to the customgui gadget to update its representation, // using an EventAdd will trigger a "regular" EVMSG_CHANGE // but we prefer to provide a SpecialEventAdd, as such we: // 1. avoid that the gadget is triggered by every EVMSG_CHANGE // 2. allow to specify a specific value to change the type to //EventAdd(); SpecialEventAdd(CUSTOMGUI_GADGET_ID, CUSTOMGUI_GADGET_SETTYPEMSG_ID, typevalue); } return true; } Int32 MyDialog::Message(const BaseContainer& msg, BaseContainer& result) { return GeDialog::Message(msg, result); } // ==================================== // CommandData // ==================================== class MyCommand : public CommandData { INSTANCEOF(MyCommand, CommandData) public: MyDialog dlg; public: virtual Bool Execute(BaseDocument* doc); }; Bool MyCommand::Execute(BaseDocument* doc) { if (dlg.IsOpen() == false) dlg.Open(DLG_TYPE::ASYNC, MYCOMMAND_PLUGIN_ID, -1, -1, 300, 200, 0); return true; } Bool RegisterMyCommand(void) { return RegisterCommandPlugin(MYCOMMAND_PLUGIN_ID, "Test"_s, 0, AutoBitmap("icon.png"_s), "Test"_s, NewObjClear(MyCommand)); } // ==================================== // Plugin Main // ==================================== Bool PluginStart(void) { ApplicationOutput("Test"_s); RegisterMyCommand(); RegisterGadget(); return true; } void PluginEnd(void) { } Bool PluginMessage(Int32 id, void * data) { switch (id) { case C4DPL_INIT_SYS: if (!g_resource.Init()) return false; return true; case C4DMSG_PRIORITY: return true; case C4DPL_BUILDMENU: break; case C4DPL_ENDACTIVITY: return true; } return false; } CustomGUI_Gadget.cpp // CustomGUI_Gadget.cpp // The custom gadget is a sort of horizontal graphical radio button group // the number of buttons is dependent the gadget type // type = 0 -> not initialized, no buttons // type = 2 has 2 buttons (black and white) // type = 3 has 3 buttons (red, green, blue) // type = 4 has 4 buttons (cyan, magenta, yellow, black) #include "c4d.h" #include "lib_clipmap.h" const Int32 kItemSize = 30; // the size of each "button" // === Registered pluginIDs === #define CUSTOMGUI_GADGET_ID 1000002 // DUMMY VALUE for demonstration purposes only !!! #define CUSTOMGUI_GADGET_ATTRIBUTE_ID 1000003 // DUMMY VALUE for demonstration purposes only !!! #define USERAREA_ID 10001 // The ID of the UserArea GUI element. // a specific message ID to trigger the gadget to set its type #define CUSTOMGUI_GADGET_SETTYPEMSG_ID 100 //--------------------------- // The user area used to display the custom datatype //--------------------------- class GadgetUserArea : public GeUserArea { public: GadgetUserArea(); virtual ~GadgetUserArea(); virtual Bool Init(); virtual Bool InitValues(); virtual Bool GetMinSize(Int32& w, Int32& h); virtual void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg); virtual Bool InputEvent(const BaseContainer& msg); Int32 mSelection; Int32 mType; Vector bw[2]; Vector rgb[3]; Vector cmyk[4]; // use a GeClipMap for drawing AutoAlloc<GeClipMap> mClipmap; }; GadgetUserArea::GadgetUserArea() { mSelection = 0; mType = 0; } GadgetUserArea::~GadgetUserArea() { } Bool GadgetUserArea::Init() { bw[0] = Vector(0); bw[1] = Vector(255); rgb[0] = Vector(255, 0, 0); rgb[1] = Vector(0, 255, 0); rgb[2] = Vector(0, 0, 255); cmyk[0] = Vector(0, 255, 255); cmyk[1] = Vector(255, 0, 255); cmyk[2] = Vector(255, 255, 0); cmyk[3] = Vector(0); return true; } Bool GadgetUserArea::InitValues() { return true; } Bool GadgetUserArea::GetMinSize(Int32& w, Int32& h) { w = kItemSize * 4; h = kItemSize; return true; } void GadgetUserArea::DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg) { OffScreenOn(); if (!mClipmap) return; const Int32 w = GetWidth(); const Int32 h = GetHeight(); mClipmap->Init(w, h, 32); mClipmap->BeginDraw(); // background Int32 r, g, b; GetColorRGB(COLOR_BG, r, g, b); mClipmap->SetColor(r, g, b, 255); mClipmap->FillRect(x1, y1, x2, y2); Vector color; if (mType != 0) { // draw the possible options as background, // then draw the current selected option on top switch (mType) { case 2: // black and white { for (Int32 col = 0; col < 2; ++col) { color = bw[col]; mClipmap->SetColor(SAFEINT32(color.x), SAFEINT32(color.y), SAFEINT32(color.z), 255); Int32 x = col * kItemSize; mClipmap->FillRect(x + 2, 2, x + kItemSize - 2, kItemSize - 2); } break; } case 3: // RGB { for (Int32 col = 0; col < 3; ++col) { color = rgb[col]; mClipmap->SetColor(SAFEINT32(color.x), SAFEINT32(color.y), SAFEINT32(color.z), 255); Int32 x = col * kItemSize; mClipmap->FillRect(x + 2, 2, x + kItemSize - 2, kItemSize - 2); } break; } case 4: // CMYK { for (Int32 col = 0; col < 4; ++col) { color = cmyk[col]; mClipmap->SetColor(SAFEINT32(color.x), SAFEINT32(color.y), SAFEINT32(color.z), 255); Int32 x = col * kItemSize; mClipmap->FillRect(x + 2, 2, x + kItemSize - 2, kItemSize - 2); } break; } } if (mSelection >= 0) { // orange "selection" color GetColorRGB(COLOR_TEXTFOCUS, r, g, b); mClipmap->SetColor(r, g, b, 255); Int32 x = mSelection * kItemSize; mClipmap->Rect(x, 0, x + kItemSize, kItemSize); mClipmap->Rect(x + 1, 1, x + kItemSize - 1, kItemSize - 1); } } mClipmap->EndDraw(); DrawBitmap(mClipmap->GetBitmap(), 0, 0, w, h, 0, 0, w, h, BMP_ALLOWALPHA); } Bool GadgetUserArea::InputEvent(const BaseContainer& msg) { // check the input device switch (msg.GetInt32(BFM_INPUT_DEVICE)) { // some mouse interaction case BFM_INPUT_MOUSE: { // get the cursor position Int32 mx = msg.GetInt32(BFM_INPUT_X); Int32 my = msg.GetInt32(BFM_INPUT_Y); Global2Local(&mx, &my); // Note that the origin of a GeUserArea is upperleft // (which is equal to the 4th quadrant of cartesian coordinate system) mSelection = mx / kItemSize; // inform the parent that the data has changed BaseContainer m(BFM_ACTION); m.SetInt32(BFM_ACTION_ID, GetId()); m.SetData(BFM_ACTION_VALUE, mSelection); SendParentMessage(m); //Redraw(); return true; } } return false; } //---------------------------------------------------------------------------------------- // A custom GUI to display the ReferencePoint //---------------------------------------------------------------------------------------- class iGadget : public iCustomGui { INSTANCEOF(iGadget, iCustomGui) private: // The current tristate. Bool mTristate; // instance of the userarea to display the ReferencePointer GadgetUserArea mUA; public: iGadget(const BaseContainer &settings, CUSTOMGUIPLUGIN *plugin); virtual Bool CreateLayout(); virtual Bool InitValues(); virtual Bool Command(Int32 id, const BaseContainer &msg); virtual Int32 Message(const BaseContainer &msg, BaseContainer &result); virtual Bool SetData(const TriState<GeData> &tristate); virtual TriState<GeData> GetData(); virtual void CustomGuiRedraw(); }; iGadget::iGadget(const BaseContainer &settings, CUSTOMGUIPLUGIN *plugin) : iCustomGui(settings, plugin) { mUA.mType = settings.GetInt32(CUSTOMGUI_GADGET_ATTRIBUTE_ID); //mUA.mType = mType; // pass along the type to the userarea // Defining default values mTristate = false; }; Bool iGadget::CreateLayout() { GroupBegin(1000, BFH_SCALEFIT | BFV_FIT, 1, 1, String(), 0); { GroupSpace(0, 0); // Attach the User Area to the custom GUI AddUserArea(USERAREA_ID, BFH_SCALEFIT, 0, 0); AttachUserArea(mUA, USERAREA_ID); } GroupEnd(); return SUPER::CreateLayout(); }; Bool iGadget::InitValues() { // The data and it's tristate are handled automatically. this->SetInt32(USERAREA_ID, mUA.mSelection, mTristate); return true; }; Bool iGadget::Command(Int32 id, const BaseContainer &msg) { switch (id) { case USERAREA_ID: { // The Gadget was changed. // Update GUI this->InitValues(); // Send message to parent object to update the parameter value. BaseContainer m(BFM_ACTION); m.SetInt32(BFM_ACTION_ID, GetId()); m.SetData(BFM_ACTION_VALUE, msg.GetInt32(BFM_ACTION_VALUE)); SendParentMessage(m); return true; break; } } return SUPER::Command(id, msg); } Int32 iGadget::Message(const BaseContainer &msg, BaseContainer &result) { switch (msg.GetId()) { case BFM_CORE_MESSAGE: { if (!CheckCoreMessage(msg)) { break; } else { if (msg.GetInt32(BFM_CORE_ID) == EVMSG_CHANGE) { // get the parameter and update the userarea if needed //ApplicationOutput("iGadget::Message() detected EVMSG_CHANGE"); } if (msg.GetInt32(BFM_CORE_ID) == CUSTOMGUI_GADGET_ID) { UInt par1 = (UInt)msg.GetVoid(BFM_CORE_PAR1); UInt par2 = (UInt)msg.GetVoid(BFM_CORE_PAR2); //ApplicationOutput("iGadget::Message() detected a SpecialEventAdd @ @", par1, par2); if (par1 == CUSTOMGUI_GADGET_SETTYPEMSG_ID) { // The SpecialEventAdd which is responsable for this message // uses the CUSTOMGUI_GADGET_ID as message ID, // a specific value CUSTOMGUI_GADGET_SETTYPEMSG_ID as first parameter to indicate we want to set the gadget's type, // and finally the type value as the second parameter // -> SpecialEventAdd(CUSTOMGUI_GADGET_ID, CUSTOMGUI_GADGET_SETTYPEMSG_ID, typevalue); // accept the type change for the gadget and trigger an update // (see iGadget::Command, where user interaction in the userarea triggers an update) mUA.mType = (Int32)par2; // reset the selection to avoid "out of range" depending the type mUA.mSelection = 0; CustomGuiRedraw(); } } } break; } } return SUPER::Message(msg, result); } Bool iGadget::SetData(const TriState<GeData> &tristate) { // The data is changed from the outside. mUA.mSelection = tristate.GetValue().GetInt32(); mTristate = tristate.GetTri(); this->InitValues(); // need to update the userarea this->mUA.Redraw(); return true; }; TriState<GeData> iGadget::GetData() { // The data is requested from the outside. TriState<GeData> tri; tri.Add(mUA.mSelection); return tri; }; void iGadget::CustomGuiRedraw() { this->mUA.Redraw(); } //---------------------------------------------------------------------------------------- // This CustomGuiData class registers a new custom GUI for the ReferencePoint datatype. //---------------------------------------------------------------------------------------- class Gadget : public CustomGuiData { public: virtual Int32 GetId(); virtual CDialog* Alloc(const BaseContainer& settings); virtual void Free(CDialog* dlg, void* userdata); virtual const Char* GetResourceSym(); virtual CustomProperty* GetProperties(); virtual Int32 GetResourceDataType(Int32*& table); }; static Int32 g_stringtable[] = { DTYPE_LONG }; //< This array defines the applicable datatypes. static CustomProperty g_GadgetType[] = { { CUSTOMTYPE::LONG, CUSTOMGUI_GADGET_ATTRIBUTE_ID, "TYPE" }, { CUSTOMTYPE::END, 0, "" } }; Int32 Gadget::GetId() { return CUSTOMGUI_GADGET_ID; }; CDialog* Gadget::Alloc(const BaseContainer& settings) { // Creates and returns a new sub-dialog. iGadget* dlg = NewObjClear(iGadget, settings, GetPlugin()); if (!dlg) return nullptr; CDialog *cdlg = dlg->Get(); if (!cdlg) return nullptr; return cdlg; }; void Gadget::Free(CDialog* dlg, void* userdata) { // Destroys the given subdialog. if (!dlg || !userdata) return; iGadget* sub = static_cast<iGadget*>(userdata); DeleteObj(sub); }; const Char* Gadget::GetResourceSym() { // Returns the resource symbol. This symbol can be used in resource files in combination with "CUSTOMGUI". return "TYPE"; }; CustomProperty* Gadget::GetProperties() { // This method can return a pointer to a data structure holding various additional properties. return g_GadgetType; }; Int32 Gadget::GetResourceDataType(Int32*& table) { // Returns the applicable datatypes defined in the stringtable array. table = g_stringtable; return sizeof(g_stringtable) / sizeof(Int32); }; Bool RegisterGadget() { // only register the custom GUI when not already registered by another plugin if (IsLibraryInstalled(CUSTOMGUI_GADGET_ID)) return true; static BaseCustomGuiLib myGadgetLib; ClearMem(&myGadgetLib, sizeof(myGadgetLib)); FillBaseCustomGui(myGadgetLib); if (!InstallLibrary(CUSTOMGUI_GADGET_ID, &myGadgetLib, 1000, sizeof(myGadgetLib))) return false; if (!RegisterCustomGuiPlugin(/*GeLoadString(IDS_CUSTOMGUISTRING)*/"Gadget"_s, 0, NewObjClear(Gadget))) return false; return true; } With this I guess the topic can be closed. But feel free to provide further comments if I overlooked something.
  • Changing CUSTOMGUI_RANGE

    General Talk
    5
    0 Votes
    5 Posts
    1k Views
    r_giganteR
    Hi gsmetzer, with regard the use of the range slide in a resource file please have a look at <Cinema 4D folder>/resource/modules/olod.res: the LOD_BAR parameter is a range slider With regard to using the NodeData::GetDDescription() please check: py-dynamic_parameters_object_r18.pyp py-preference_r19.pyp py-spherify_modifier_r13.pyp Best, Riccardo