Notifications
Clear all

[Closed] Enable/disable controls at runtime in C++ material plugin

Hello,

I’m writing an open source material plugin for 3ds Max 2015-2017 in C++. Attached is a screenshot of the custom material being edited in the Material Editor.

I’d like to disable some of the controls based on the value of some other controls. I know this is done with Win32’s EnableWindow() function, but I’m not sure how to articulate things to implement this.

I’ve looked at the samples from the SDK but they seem rather old and badly written, and I find it hard to extract best practices from them.

Until now, in my material’s CreateParamDlg() method, I was simply doing:

ParamDlg* AppleseedDisneyMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams* imp)
{
    return g_appleseed_disneymtl_classdesc.CreateParamDlgs(hwMtlEdit, imp, this);
}


I’m now attempting this:

ParamDlg* AppleseedDisneyMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams* imp)
{
    ParamDlg* param_dialog = g_appleseed_disneymtl_classdesc.CreateParamDlgs(hwMtlEdit, imp, this);
    g_block_desc.SetUserDlgProc(new DisneyMtlUserDlgProc(this));
    return param_dialog;
}


where DisneyMtlUserDlgProc inherits from ParamMap2UserDlgProc. In the DlgProc method of DisneyMtlUserDlgProc, I do get WM_INITDIALOG messages etc. but it looks like HWND is the one of the material editor, not the one of the rollout containing the controls I’d like to enable/disable.

  1. Overall, is this the way to go?
  2. If yes, how can I retrieve the HWND of a given rollout?
  3. Any advice or example on how to organize this code?

Thanks for the help.

5 Replies
  1. Yes, I think this is the preferred way of doing this

The only other option I can think of is using a transient, read-only proxy parameter in your parameter block like “isBumpMethod” which has p_enable_ctrls and the control IDs that should be enabled/disabled. You could then add a PBAccessor to the method parameter which updates the “isXYZMethod” parameter whenever the method parameter changes.

  1. GetDlgItem(hWnd, IDC_XYZ) inside your DlgProc should give you the HWND of the control inside a rollout. This worked for sure the last time I used this. Do you use the P_AUTO_UI flag?

Hi hdmaster, thanks for the answer.

Yes, I’m using the P_AUTO_UI flag. I’ve tried retrieving the HWND of a control inside a rollout but GetDlgItem() returned 0.

Oh, I just realized that I’ve used the ParamMap2UserDlgProc only for object plugins and utilities. You should be able get the HWND of a rollout inside the material editor from the IParamMap2 passed to the DlgProc using IParamMap2::GetHWnd.

But instead of using EnableWindow directly better use IParamMap2::Enable, if the controls are linked to parameters.

I actually came to the same conclusion independently, thanks for confirming.

Unfortunately, it still doesn’t work. Here is the code:

namespace
{
    class DisneyMtlUserDlgProc
      : public ParamMap2UserDlgProc
    {
      public:
        explicit DisneyMtlUserDlgProc(AppleseedDisneyMtl* mtl) {}

        virtual void DeleteThis() override
        {
            delete this;
        }

        virtual INT_PTR DlgProc(
            TimeValue   t,
            IParamMap2* map,
            HWND        hwnd,
            UINT        umsg,
            WPARAM      wparam,
            LPARAM      lparam) override
        {
            switch (umsg)
            {
              case WM_INITDIALOG:
              {
                  HWND rollup_hwnd = map->GetHWnd();
                  HWND up_vector_combo_hwnd = GetDlgItem(rollup_hwnd, IDC_COMBO_BUMP_UP_VECTOR);
                  EnableWindow(up_vector_combo_hwnd, FALSE);
                  return TRUE;
              }
            }

            return FALSE;
        }
    };
}

ParamDlg* AppleseedDisneyMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams* imp)
{
    ParamDlg* param_dialog = g_appleseed_disneymtl_classdesc.CreateParamDlgs(hwMtlEdit, imp, this);
    g_block_desc.SetUserDlgProc(new DisneyMtlUserDlgProc(this));
    return param_dialog;
}

up_vector_combo_hwnd is always 0.

Note that I have multiple rollups for this plugin:
https://github.com/appleseedhq/appleseed-max/blob/master/src/appleseed-max-impl/disneymtl/appleseeddisneymtl.cpp#L163-L180

I figured it out. The problem was that user dialog procedure was bound to the first parameter map, while the controls I’m interested in are in the second parameter map.

Using the two-argument SetUserDlgProc() method that takes the ID of a ParamMap fixed the problem:

ParamDlg* AppleseedDisneyMtl::CreateParamDlg(HWND hwMtlEdit, IMtlParams* imp)
{
    ParamDlg* param_dialog = g_appleseed_disneymtl_classdesc.CreateParamDlgs(hwMtlEdit, imp, this);
    g_block_desc.SetUserDlgProc(ParamMapIdBump, new DisneyMtlUserDlgProc(this));
    return param_dialog;
}