Hi guys! I'm new to the C++ sdk (worked exclusively with maxscript before this), and I'm wondering how do you create a floating dialog box? I'm using the plugin wizard and created a utility project, but have yet to figure out how to get it out of the command panel. Thanks for all the help!
P.S. Trying to create a floating dialog box that loads a material library and displays their pictures and allows
users to apply a material to selected objects in the scene.
a) you can also drag out the commandpanel
b) you have to write "some" extra code for connecting the ParamBlocks and Rollups to the Win Dialog
see
\maxsdk\samples\modifiers\uvwunwrap\ToolRenderUVs.cpp \maxsdk\samples\modifiers\uvwunwrap\uvwunwrap\ToolPelt.cpp
check also
GetIRollup() CreateRWParamMap2()
You can find a good sample in
\maxsdk\samples\modifiers\UVWunwrap\unwrap\UI
it is a bit confusing with this all menu and windows but that's a good source to look in especially:
UnwrapCustomToolBar.cpp
and
UnwrapCustomUI.cpp
the rest is in mods.rc file
in the easy term, first you need to create an interface in .rc format, then add a class for loading it as a float rollout
@omidt_gh wrote:in the easy term, first you need to create an interface in .rc format, then add a class for loading it as a float rollout
Today, I'd not start with .rc created dialogs but consider using QT instead. I'd also think about the requirement of using paramblks. QT delivers all features for nice scaleable and resizeable dialogs, including easier localization as well.
Although there are still some bugs in the integration of QT in Max, the advantages outweigh imho.
It shouldn't be a big issue, there are a tons of introduction of how to use QT instead of MFC that you can find on web.
Or you can just look in to the 3dsmax Documentation>
If you need a good start i recommended to looking in to ADN sample repository https://github.com/ADN-DevTech/3dsMax-SampleCode/tree/master/DCM_Operand
For a sample QT code
Also, do not forget to check this tutorial :
https://help.autodesk.com/view/MAXDEV/2021/ENU/?guid=__developer_writing_plug_ins_using_qt_with_3ds_...
the best example to start from as a tool is the ChannelInfo project (TreeViewUtil.cpp) shows how to throw up a floating tool dialog and tie into max via mxs so it's easy hook into the ui.
it can be reduced something like this
#define TEMPLATE_UTIL_OBJ_CLASS_ID Class_ID(0xe823fa8, 0x21c0384c)
#define TEMPLATE_UTIL_OBJ_FP_INTERFACE_ID Interface_ID(0x436202d5, 0x70000ea6)
//********************************************************************************************
// TemplateUtilObj Our Tools class definition
class TemplateUtilObj : public UtilityObj
{
public:
HWND hPanel; // utility rollout panel
IUtil *iu;
Interface *ip;
HWND floaterHWND; // our floating window
// Constructor/Destructor
TemplateUtilObj();
~TemplateUtilObj() {}
// stuff for the utility panel
void BeginEditParams(Interface *ip,IUtil *iu);
void EndEditParams(Interface *ip,IUtil *iu);
// util panel
void Init(HWND hWnd) {}
void Destroy(HWND hWnd) {}
void DeleteThis() {}
// tool window handling routines
void CreateNewWindow();
void InitWindow();
void DestroyWindow();
void UpdateUI();
LRESULT NotifyHandler( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
// our util global static
static TemplateUtilObj utilObj;
//********************************************************************************************
// the class descriptor
class TemplateUtilObjClassDesc : public ClassDesc2
{
public:
int IsPublic() { return TRUE; }
void * Create(BOOL loading=FALSE) { return &utilObj; }
const TCHAR * ClassName() { return GetString(IDS_TEMPLATE_CLASS_NAME); }
SClass_ID SuperClassID() { return UTILITY_CLASS_ID; }
Class_ID ClassID() { return TEMPLATE_UTIL_OBJ_CLASS_ID; }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
const TCHAR* InternalName() { return _T("TemplateUtilObj"); }
HINSTANCE HInstance() { return hInstance; } // returns owning module handle
};
static TemplateUtilObjClassDesc TemplateUtilObjDesc;
ClassDesc2* GetTemplateUtilObjDesc() { return &TemplateUtilObjDesc; }
//********************************************************************************************
// function publishing, make some basic functionality available to mxs mostly so we can call our
// utility from the ui via a macroscript without switching to the utility panel first !
class TemplateUtilObjFnP : public FPStaticInterface
{
public:
DECLARE_DESCRIPTOR(TemplateUtilObjFnP);
enum functionID { kOpenWindow, kCloseWindow, kIsOpen };
BEGIN_FUNCTION_MAP
VFN_0(kOpenWindow, OpenWindow)
VFN_0(kCloseWindow, CloseWindow)
FN_0(kIsOpen, TYPE_BOOL, IsOpen)
END_FUNCTION_MAP
void OpenWindow() { utilObj.CreateNewWindow(); }
void CloseWindow() { if(utilObj.floaterHWND) DestroyWindow(utilObj.floaterHWND); }
bool IsOpen() { return IsWindowOpen(); }
static bool IsWindowOpen() { return windowOpen; }
static void SetWindowOpen(bool val) { windowOpen = val; GetCUIFrameMgr()->SetMacroButtonStates(false); }
private:
static bool windowOpen;
};
//********************************************************************************************
// create the global static instance
static TemplateUtilObjFnP theTemplateUtilObjFnP(TEMPLATE_UTIL_OBJ_FP_INTERFACE_ID, _T("utilObj"),
IDS_TEMPLATE_CLASS_NAME, NULL, FP_CORE,
TemplateUtilObjFnP::kOpenWindow, _T("openWindow"), -1, TYPE_VOID, FP_NO_REDRAW, 0,
TemplateUtilObjFnP::kCloseWindow, _T("closeWindow"), -1, TYPE_VOID, FP_NO_REDRAW, 0,
TemplateUtilObjFnP::kIsOpen, _T("isOpen"), -1, TYPE_BOOL, FP_NO_REDRAW, 0, p_end);
//********************************************************************************************
// initialize the showing static
bool TemplateUtilObjFnP::windowOpen = false;
static INT_PTR CALLBACK TemplateUtilObjPanelProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
utilObj.Init(hWnd); // can we delete these ?
break;
case WM_DESTROY:
utilObj.Destroy(hWnd); // can we delete these ?
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_NEW_FLOATER_BTN:
utilObj.CreateNewWindow();
break;
case IDOK:
case IDCANCEL:
DestroyWindow(hWnd);
break;
}
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
utilObj.ip->RollupMouseMessage(hWnd,msg,wParam,lParam);
break;
default:
return FALSE;
}
return TRUE;
}
//********************************************************************************************
// the main handler callback for our floating tool window
static INT_PTR CALLBACK TemplateUtilObjWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
utilObj.floaterHWND = hWnd;
utilObj.InitWindow();
utilObj.ip->RegisterDlgWnd(hWnd);
utilObj.UpdateUI();
TemplateUtilObjFnP::SetWindowOpen(true);
break;
}
case WM_DESTROY:
{
utilObj.DestroyWindow();
utilObj.ip->UnRegisterDlgWnd(hWnd);
TemplateUtilObjFnP::SetWindowOpen(false);
break;
}
case WM_RBUTTONDOWN:
{
break;
}
case WM_NOTIFY:
return utilObj.NotifyHandler(hWnd, msg, wParam, lParam);
break;
// handle custom max controls handled here spinners etc here e.g.
// case CC_SPINNER_CHANGE:
// case CC_COLOR_SEL:
// case CC_COLOR_CHANGE:
// case CC_COLOR_CLOSE:
case WM_COMMAND:
switch (LOWORD(wParam))
{
// all other win32 dialog handled here
case IDOK:
case IDCANCEL:
DestroyWindow(hWnd);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//********************************************************************************************
// TemplateUtilObj, code for our utility starts here
TemplateUtilObj::TemplateUtilObj()
{
iu = NULL;
ip = NULL;
hPanel = NULL;
floaterHWND = NULL;
}
//********************************************************************************************
void TemplateUtilObj::BeginEditParams(Interface *ip,IUtil *iu)
{
this->iu = iu;
this->ip = ip;
hPanel = ip->AddRollupPage(hInstance, MAKEINTRESOURCE(IDD_TEMPLATE_WINDOW_PANEL),
TemplateUtilObjPanelProc, GetString(IDS_PARAMS), 0);
}
//********************************************************************************************
void TemplateUtilObj::EndEditParams(Interface *ip,IUtil *iu)
{
this->iu = NULL;
ip->DeleteRollupPage(hPanel);
hPanel = NULL;
}
//********************************************************************************************
void TemplateUtilObj::CreateNewWindow()
{
ip = GetCOREInterface(); // catches any script calls
if(floaterHWND == NULL)
CreateDialog(hInstance, MAKEINTRESOURCE(IDD_TEMPLATE_WINDOW), ip->GetMAXHWnd(), TemplateUtilObjWindowProc);
}
//********************************************************************************************
LRESULT TemplateUtilObj::NotifyHandler( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return 0L;
}
//********************************************************************************************
// Initialize the tool window
void TemplateUtilObj::InitWindow()
{
}
//********************************************************************************************
// destroy the tool window
void TemplateUtilObj::DestroyWindow()
{
floaterHWND = NULL;
}
//********************************************************************************************
void TemplateUtilObj::UpdateUI() {}
yes it's a floating window. you need a base plugin to hang it off
then the mcr would look like....
macroScript template_util
category: "My Utils"
buttontext: "util"
Icon: #("myicons",1)
tooltip: "template util"
(
on isChecked do utilObj.isOpen();
on execute do
(
if utilObj.isOpen() then
utilObj.closeWindow();
else
utilObj.openWindow();
)
)
you can use one of the typical win32 create window/dialog routines and register it with max using
RegisterDlgWnd(hWnd);
just about anytime. then when it's closed unregister it. What you do with it or what you display in it is upto you.
Channel info tree was a great suggestion, about the node base view I meant something like the image below.
Do you have any suggestions?
You did not get the question, i asked do you have any idea of how to create node base view in 3dsmax, like the image i send?
Can't find what you're looking for? Ask the community or share your knowledge.