Looking further into this, It seems that for .Net controls a new handle is attached to the window. I suppose everything is handled by this handle?
But for MXS rollouts it looks like RegisterDialogBar() creates its own window and make the rollout a children of it.
If you modify these two styles from a registered Rollout, the minimize and maximize buttons seems to work.
WS_EX_TOOLWINDOW >> CLEAR
WS_OVERLAPPEDWINDOW >> SET
You’ll also notice that now the rollout icon has changed to a system default icon instead of a Max icon.
i’m playing with the same right now
i made almost the same behavior for MXS Dialog except resize ability in docked state.
Definitely RegisterDialogBar() does create a window wrapper for the rollout. That’s why we lose some rollout features as stated in the Help file.
The two ways I see to overcome this limitation are:
- Create your own wrapper in C++
- Modify the wrapper style as mentioned earlier.
Alternatively you could use a .Net form (as you explained a long ago) and put the rollout in there, but I don’t like this one.
Here are the final bits for modifying the wrapper styles:
Only tested on Max 2016.
(
/* TOOLBAR ########################################################################################################### */
try
(
cui.UnregisterDialogBar ::RO_TOOLBAR
destroydialog ::RO_TOOLBAR
)catch()
rollout RO_TOOLBAR "Toolbar" width:300 height:150
(
on RO_TOOLBAR open do
(
)
)
createdialog RO_TOOLBAR
cui.RegisterDialogBar RO_TOOLBAR minSize:[-1,-1] maxSize:[-1,-1]
/* ROLLOUT ########################################################################################################### */
try destroydialog ::RO_ROLLOUT catch()
rollout RO_ROLLOUT "Rollout" width:300 height:150
(
)
createdialog RO_ROLLOUT style:#(#style_titlebar, #style_resizing, #style_sysmenu, #style_minimizebox, #style_maximizebox)
/* MODIFY CUI WINDOW WRAPPER STYLE AND EXTENDED STYLE ################################################################ */
fn CreateAssembly =
(
src = "using System;"
src += "using System.Runtime.InteropServices;"
src += "class User32"
src += "{"
src += " [DllImport(\"User32.DLL\", EntryPoint=\"SetWindowLong\")]"
src += " public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 index, Int32 newVal);"
src += "}"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(src)
User32Assembly = compilerResults.CompiledAssembly
User32Assembly.CreateInstance "User32"
)
user32 = CreateAssembly()
GWL_STYLE = -16
GWL_EXSTYLE = -20
style = -1798373308
extstyle = 65792
hwnd = dotnetobject "System.IntPtr" (UIAccessor.GetParentWindow RO_TOOLBAR.hwnd)
user32.SetWindowLong hwnd GWL_STYLE style
user32.SetWindowLong hwnd GWL_EXSTYLE extstyle
)
Ok, tested on Max 2014-2017 and it works.
On Max 2018+ things change significantly with QT and none of this works as is.
But here might be another way to get the same results.
nice job!
BTW. the registered dialog icon changes back to MAX one after you open Scene Explorer for example
WOW, black magic
The second time you run the script (after have opened the Scene Explorer once), the icon don’t even show up until you drag the window.
Well, the world isn’t perfect.
_hwnd = UIAccessor.GetParentWindow RO_TOOLBAR.hwnd
hwnd = dotnetobject "System.IntPtr" _hwnd
user32.SetWindowLong hwnd GWL_STYLE style
user32.SetWindowLong hwnd GWL_EXSTYLE extstyle
WM_GETICON = 0x007F
WM_SETICON = 0x0080
hicon_ptr = windows.sendmessage RO_TOOLBAR.hwnd WM_GETICON 0 0
windows.sendmessage _hwnd WM_SETICON 0 hicon_ptr
here is how to set HICON
Since this is the very first time I’m looking into this, I am very unfamiliar with the code and concepts.
I’ve tried to create a CUIFrame from the SDK and couldn’t not get it to be resizable when docked, so I think it might need to be handled in the CUIFrame callback and customize all the stuff there.
However, the .Net CUIFrame does already have all this implemented, so as a last option it might be good to try using what’s already done before creating your own solution.
How about something like this:
(
form = dotnetobject "System.Windows.Forms.Form"
CUIFrame = dotnetobject "ManagedServices.WinFormsCUIFrame" form
try destroydialog ::RO_ROLLOUT catch()
rollout RO_ROLLOUT "Rollout Dock Test" width:100 height:300
(
button bt1 "button"
on bt1 pressed do print "ME"
)
createdialog RO_ROLLOUT pos:[0,0]
fn CreateAssembly =
(
src = "using System;"
src += "using System.Runtime.InteropServices;"
src += "class User32"
src += "{"
src += "[DllImport(\"User32.DLL\", EntryPoint=\"SetWindowLong\")]"
src += "public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 index, Int32 newVal);"
src += "[DllImport(\"User32.dll\", SetLastError = true)]"
src += "public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);"
src += "[DllImport(\"User32.dll\", ExactSpelling=true, CharSet=CharSet.Auto)]"
src += "public static extern IntPtr GetParent(IntPtr hWnd);"
src += "[DllImport(\"User32.dll\", SetLastError = true, CharSet = CharSet.Auto)]"
src += "public static extern bool SetWindowText(IntPtr hwnd, String lpString);"
src += "}"
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.GenerateInMemory = true
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(src)
User32Assembly = compilerResults.CompiledAssembly
User32Assembly.CreateInstance "User32"
)
user32 = CreateAssembly()
toolHWND = dotnetobject "System.IntPtr" RO_ROLLOUT.hwnd
frameHWND = dotnetobject "System.IntPtr" form.Handle
user32.SetParent toolHWND frameHWND
GWL_STYLE = -16
GWL_EXSTYLE = -20
style = 0x56000000
extstyle = 0x00010200
user32.SetWindowLong toolHWND GWL_STYLE style
user32.SetWindowLong toolHWND GWL_EXSTYLE extstyle
fn Resized =
(
RO_ROLLOUT.width = form.Width
RO_ROLLOUT.height = form.height
)
dotnet.addeventhandler form "Resize" Resized
Resized()
parent = user32.GetParent form.Handle
user32.SetWindowText parent RO_ROLLOUT.title
)
Yes… that’s what I did in couple projects. But I want to make “true” version of dockable MXS dialog. I’m very close now. But still I can’t make it work “safe” and “simple”. But I’m pretty sure there is a solution
I got pretty much everything implemented using the .Net APIs, so it has a few more features than the default cui struct.
How did you finally add the rollout to the CUIFrame? I am just using the user32 parent as in my previous example.
i am still fighting with the scaling issue. but i want (and must) make everything done via c++ API. When you “parenting” the rollout the all you need is just “user32 parent”. All window and CUIFrame messages are automatically process right in your case. (not in c++ case).