Notifications
Clear all

[Closed] Moving a Dialog with a button?

Trying to find the best way to go about moving a dialog via, left click + drag (holding left mouse button) using a button within the rollout.

So far I got this. It works kind of, but it seems to crash max, and can’t uncheck the button.


try (destroydialog exdialog)
catch ()
global exdialog
rollout exdialog ""
(
	checkbutton moveexdialog "Click + Drag Me" pos:[5,5] width:95 height:20
	button closedialog "Close Me" pos:[105,5] width:55 height:20
	on moveexdialog changed state do
	(
		while state == true do
		(
			origmousepos = (mouse.screenpos - (moveexdialog.pos + [42,7]))
			SetDialogPos exdialog origmousepos
		)
	)
	on closedialog pressed do
	(
		try (destroydialog exdialog)
		catch ()
	)
)
createdialog exdialog width:170 height:30 style:#(#style_sysmenu, #style_minimizebox, #style_normalbox)

Looking for a cleaner way, and something that is hold left mouse button + drag, then on release it un-checks the button.

Please anyone with a solution via maxscript reply with the maxscript.

12 Replies

Found a solution, not sure if its the best, or cleanest but here it is.


try (destroydialog exdialog)
catch ()
global exdialog
rollout exdialog ""
(
	checkbutton moveexdialog "Click + Drag Me" pos:[5,5] width:95 height:20
	button closedialog "Close Me" pos:[105,5] width:55 height:20
	timer themoverollouttimer interval:10 active:false
	on themoverollouttimer tick do
	(
		origmousepos = (mouse.screenpos - (moveexdialog.pos + [42,7]))
		if (GetDialogPos exdialog) != origmousepos do
		(
			SetDialogPos exdialog origmousepos
		)
	)
	on moveexdialog changed state do
	(
		if state == true do
		(
			themoverollouttimer.active = true
		)
		if state == false do
		(
			themoverollouttimer.active = false
		)
	)
	on closedialog pressed do
	(
		try (destroydialog exdialog)
		catch ()
	)
)
createdialog exdialog width:170 height:30 style:#(#style_sysmenu, #style_minimizebox, #style_normalbox)

But I still need to find a way for it to work on left button held on the button, check the checkbutton, then when released needs to uncheck the checkbutton.

Anyone have any ideas?

 lo1

Here’s a better idea, use a dotnet button:

try (destroydialog exdialog)catch ()
global exdialog
rollout exdialog ""
(
	local mouseOffset = [0,0]
	local dragging = off
	
	dotNetControl moveexdialog "Button" pos:[5,5] width:95 height:20
	button closedialog "Close Me" pos:[105,5] width:55 height:20

	on exDialog open do
	(
		moveexdialog.text = "Move"
	)
	
	on moveexdialog mouseMove do
	(
		if (dragging) do
		(
			local newPos = mouse.screenpos - mouseOffset
			if (GetDialogPos exdialog) != newPos do
			(
				SetDialogPos exdialog newPos
			)
		)
	)
	
	on moveexdialog mousedown do
	(
		mouseOffset = mouse.screenPos - getDialogPos exDialog
		dragging = on
	)
	
	on moveexdialog mouseUp do
	(
		dragging = off
	)
	
	on closedialog pressed do
	(
		try (destroydialog exdialog)
		catch ()
	)
)
createdialog exdialog width:170 height:30 style:#(#style_sysmenu, #style_minimizebox, #style_normalbox)
1 Reply
(@cg3dopifex)
Joined: 11 months ago

Posts: 0

Ah thanks, exactly what I wanted, but one thing, is it possible to make it into a image button instead of text?

 lo1

Yes, use the .image property of the button, assign it a system.drawing.bitmap.

Isn’t is useless to check if (GetDialogPos exdialog) != newPos in the mouseMove function?

Got it! mouseMove is fired twice each time, don’t understand why!
Here the modified code for those who want to check.
By the way, love your snippet lo. So clean!

try (destroydialog exdialog)catch ()
global exdialog
rollout exdialog ""
(
	local mouseOffset = [0,0]
	local dragging = off
	
	dotNetControl moveexdialog "Button" pos:[5,5] width:95 height:20
	button closedialog "Close Me" pos:[105,5] width:55 height:20

	on exDialog open do
	(
		moveexdialog.text = "Move"
	)
	
	on moveexdialog mouseMove do
	(
		if (dragging) do
		(
			local diagPos = GetDialogPos exdialog
			local newPos = mouse.screenpos - mouseOffset
			format "% %
" diagPos newPos 
			if diagPos != newPos then
			(
				SetDialogPos exdialog newPos
				print "moved"
			)
			else
			(
				print "no move "
			)
		)
	)
	
	on moveexdialog mousedown do
	(
		mouseOffset = mouse.screenPos - getDialogPos exDialog
		dragging = on
	)
	
	on moveexdialog mouseUp do
	(
		dragging = off
	)
	
	on closedialog pressed do
	(
		try (destroydialog exdialog)
		catch ()
	)
)
createdialog exdialog width:170 height:30 style:#(#style_sysmenu, #style_minimizebox, #style_normalbox)
1 Reply
 lo1
(@lo1)
Joined: 11 months ago

Posts: 0

Calling SetDialogPos is what fires the second mouseMove event. It can be proved using this code:

on moveexdialog mouseMove do
	(
		if (dragging) do
		(
			local diagPos = GetDialogPos exdialog
			local newPos = mouse.screenpos - mouseOffset
			format "% %
" diagPos newPos 
			if diagPos != newPos then
			(
				dragging = off
				SetDialogPos exdialog newPos
				(dotnetClass "Application").doEvents() --process all queued messages
				dragging = on
				print "moved"
			)
			else
			(
				print "no move "
			)
		)
	)

OK thanks lo! I did dragable rollout before and didn’t notice the double event.
At least I will know next time

sometimes i don’t want to use any dotnet controls in my mxs dialog… so for many years this works for me:


 try(destroydialog dialog) catch()
 rollout dialog "" width:160 height:20
 (
 	groupbox border width:160 height:26 pos:[0,-6]
 	timer mover active:off interval:50
 	
 	local start
 	on mover tick do if mouse.pos != start do
 	(
 		setdialogpos dialog ((getdialogpos dialog) + mouse.pos - start)
 		start = mouse.pos
 	)
 	on dialog lbuttondown pos do
 	(
 		start = mouse.pos
 		mover.active = on
 	)
 	on dialog lbuttonup pos do mover.active = off
 	on dialog rbuttonup pos do destroydialog dialog
 )
 createDialog dialog style:#()
 

if i want to make some “visual” titlebar i use an imgTag and its events instead of the rollout’s.

Denis, did you used the timer for optimization? (kinda overkill?)
I usually did exactly the same without the timer and a local boolean as replace.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

how do you catch mouse moveevent without a timer?
yes… you can do it with rollout mousemove, but as i said i usually use imgTag

also… i did some experiments and found that with timer the motion is smoother and never being lost

Ok denis, I didn’t see the imgTag in your snippet. That’s why I didn’t pay attention to it.
Now I see how your rollouts must look like.
Here’s my version, with “lo’s double event avoidance trick”!

try(destroydialog UICAcomplete) catch()

rollout UICAcomplete "complete" width:200 height:200
(
	local screenSize = [0,0]
	local DragState = false
	local WinPos = [0,0]
	------------------------------------------------------------------------
	-- avoid out of screen rollout
	fn updatePos pos =
	(
		if (pos.x < 0) do (pos.x = 0); if (pos.y < 0) do (pos.y = 0)
		if (pos.x+UICAcomplete.width > screenSize.x) do (pos.x = screenSize.x-UICAcomplete.width)
		if (pos.y+UICAcomplete.height > screenSize.y) do (pos.y = screenSize.y-UICAcomplete.height)
		setDialogPos UICAcomplete pos
	)
	------------------------------------------------------------------------
	on UICAcomplete open do 
	(
		screenSize = [systemTools.GetScreenWidth(),systemTools.GetScreenHeight()]
		updatePos mouse.screenpos
	)
	------------------------------------------------------------------------
	-- drag
	on UICAcomplete lbuttonup mousepos do DragState = false
	on UICAcomplete lbuttondown mousepos do 
	(
		DragState = true
		WinPos = mousepos
	)
	on UICAcomplete mousemove mousepos do
	(
		if DragState == true do
		(
			localPos = mouse.screenpos-WinPos
			diagPos = GetDialogPos UICAcomplete
			if diagPos != localPos do
			(
				updatePos localPos
			)
		)
	)
	------------------------------------------------------------------------
	on UICAcomplete rbuttondown arg do (destroydialog UICAcomplete)
)

createdialog UICAcomplete style:#()