Notifications
Clear all

[Closed] Docking Dialogs

Hi

I wrote a tiny test script for docking dialogs and it works quite well, sometimes I get an infinite loop but this is no big deal.

How it works:
I create several dialogs and each time the user moved them, a function checks, if it is near another dialog, if so, it snaps the dragged dialog to them.
If the user snaps to the main dialog, he can drag all docked dialogs when moving it.

This all works quite promising, but the more dialogs you dock, the slower it gets

Is there a way to speed this up?

Here is the code:

try
 (
 	for i = 1 to rolloutList.count do
 		try destroyDialog rolloutList[i].RO catch()
 )
 catch()
 
 
 struct ROStruct
 (
 	parent,
 	docked = false,
 	offsetPos = [0,0],
 	RO
 )
 
 global ROMOVING = false
 
 
 function moveDockedRO =
 (
 	global ROMOVING = true
 	try
 	(
 		
 		for i = 1 to rolloutList.count do
 		(
 			local parentRO = getParentRO rolloutList[i].RO.name
 			if parentRO != undefined then
 			(
 				
 				setDialogPos rolloutList[i].RO ((getDialogPos rolloutList[rolloutList.count].RO) + rolloutList[i].offsetPos)
 				
 			)
 		)
 		
 	)catch()
 	global ROMOVING = false
 )
 
 
 
 
 
 
 
 function getParentRO dialogName =
 (
 	local thisRO = ""
 	for i = 1 to rolloutList.count do
 		if rolloutList[i].RO.name == dialogName then
 			thisRO = rolloutList[i]
 	
 	if thisRO.docked == false then
 		return undefined
 		
 	local tempParent = thisRO.parent
 	while tempParent.parent != undefined do
 	(
 		enableEscape = true
 		tempParent = tempParent.parent
 	)
 	
 	if tempParent.RO.name == "mainRO" then
 		return tempParent
 	
 	return undefined
 )
 
 
 
 function dockDialog dialogName =
 (
 	if ROMOVING == true then
 		return undefined
 	
 	local thisRO = ""
 	for i = 1 to rolloutList.count do
 		if rolloutList[i].RO.name == dialogName then
 			thisRO = rolloutList[i]
 	
 	thisRO.docked = false
 	thisRO.parent = undefined
 	
 	for i = 1 to rolloutList.count do
 	(
 		local thisPos = getDialogPos thisRO.RO
 		local ROPos = getDialogPos rolloutList[i].RO
 		local thisSize = getDialogSize thisRO.RO
 		local ROSize = getDialogSize rolloutList[i].RO
 		
 		
 		if rolloutList[i].RO.name != thisRO.RO.name then
 		(
 				--// dock left
 					--// left, right pos
 			if ((thisPos[1] + thisSize[1]) > ROPos[1] - 10) and ((thisPos[1] + thisSize[1]) < ROPos[1]) then
 			(
 					--// up, down pos
 				if ((thisPos[2] > ROPos[2] - 10) and (thisPos[2] < ROPos[2] + 10)) then
 				(
 					local newPos = ROPos
 					newPos[1] = ROPos[1] - thisSize[1] - 5
 					
 					if rolloutList[i].RO.name == "mainRO" then
 						newPos[2] = ROPos[2] + 3
 					
 					
 					setDialogPos thisRO.RO newPos
 					
 						
 					thisRO.parent = rolloutList[i]
 					thisRO.docked = true
 					
 					local parentRO = (getParentRO thisRO.RO.name)
 						
 					if parentRO != undefined then
 						thisRO.offsetPos = (getDialogPos thisRO.RO) - (getDialogPos parentRO.RO)
 					else
 						thisRO.offsetPos = [0,0]
 					
 					break
 				)
 			)
 			
 				--// dock right
 					--// left, right pos
 			if (thisPos[1] > (ROPos[1] + ROSize[1] )) and (thisPos[1] < (ROPos[1] + ROSize[1] + 10)) then
 			(
 					--// up, down pos
 				if ((thisPos[2] > ROPos[2] - 10) and (thisPos[2] < ROPos[2] + 10)) then
 				(
 					local newPos = ROPos
 					newPos[1] = ROPos[1] + ROSize[1] + 5
 					
 					if rolloutList[i].RO.name == "mainRO" then
 						newPos[2] = ROPos[2] + 3
 					
 					setDialogPos thisRO.RO newPos
 					
 					
 					thisRO.parent = rolloutList[i]
 					thisRO.docked = true
 					
 					local parentRO = (getParentRO thisRO.RO.name)
 						
 					if parentRO != undefined then
 						thisRO.offsetPos = (getDialogPos thisRO.RO) - (getDialogPos parentRO.RO)
 					else
 						thisRO.offsetPos = [0,0]
 					
 					break
 				)
 			)
 			
 				--// dock up
 					--// left, right pos
 			if (thisPos[1] > ROPos[1] - 10) and ((thisPos[1] + thisSize[1]) < (ROPos[1] + ROSize[1] + 10)) then
 			(
 					--// up, down pos
 				if ((thisPos[2] + thisSize[2] > ROPos[2] - 25) and (thisPos[2] + thisSize[2] < ROPos[2] - 15)) then
 				(
 					local newPos = ROPos
 					if rolloutList[i].RO.name == "mainRO" then
 						newPos[2] = ROPos[2] - thisSize[2] - 20
 					else
 						newPos[2] = ROPos[2] - thisSize[2] - 24
 					
 					
 					
 					if (thisPos[1] + thisSize[1]) < (ROPos[1] + ROSize[1] + 10)  and thisPos[1] + thisSize[1] > (ROPos[1] + ROSize[1] - 10) then
 						newPos[1] = ROPos[1] + ROSize[1] - thisSize[1]
 					
 					if (thisPos[1] >= ROPos[1] + 10) and ((thisPos[1] + thisSize[1]) <= (ROPos[1] + ROSize[1] - 10)) then
 						newPos[1] = thisPos[1]
 					
 					
 					setDialogPos thisRO.RO newPos
 					
 					
 					thisRO.parent = rolloutList[i]
 					thisRO.docked = true
 						
 					local parentRO = (getParentRO thisRO.RO.name)
 						
 					if parentRO != undefined then
 						thisRO.offsetPos = (getDialogPos thisRO.RO) - (getDialogPos parentRO.RO)
 					else
 						thisRO.offsetPos = [0,0]
 						
 					break
 				)
 			)
 			
 				--// dock down
 					--// left, right pos
 			if (thisPos[1] > ROPos[1] - 10) and ((thisPos[1] + thisSize[1]) < (ROPos[1] + ROSize[1] + 10)) then
 			(
 					--// up, down pos
 				if (thisPos[2] > (ROPos[2] + ROSize[2] + 20)) and (thisPos[2] < (ROPos[2] + ROSize[2] + 30)) then
 				(
 					local newPos = ROPos
 					if rolloutList[i].RO.name == "mainRO" then
 						newPos[2] = ROPos[2] + ROSize[2] + 26
 					else
 						newPos[2] = ROPos[2] + ROSize[2] + 24
 					
 					
 						
 					
 					if (thisPos[1] + thisSize[1]) < (ROPos[1] + ROSize[1] + 10)  and thisPos[1] + thisSize[1] > (ROPos[1] + ROSize[1] - 10) then
 						newPos[1] = ROPos[1] + ROSize[1] - thisSize[1]
 					
 					if (thisPos[1] >= ROPos[1] + 10) and ((thisPos[1] + thisSize[1]) <= (ROPos[1] + ROSize[1] - 10)) then
 						newPos[1] = thisPos[1]
 					
 					setDialogPos thisRO.RO newPos
 				
 					
 					thisRO.parent = rolloutList[i]
 					thisRO.docked = true
 						
 					local parentRO = (getParentRO thisRO.RO.name)
 						
 					if parentRO != undefined then
 						thisRO.offsetPos = (getDialogPos thisRO.RO) - (getDialogPos parentRO.RO)
 					else
 						thisRO.offsetPos = [0,0]
 						
 					break
 				)
 			)
 		)
 	)
 )
 
 
 
 
 
 
 global rolloutList = #()
 
 
 
 
 
 rollout test1RO "UpperLeft"
 (
 	label labDesc "UpperLeft"
 	
 	on test1RO moved value do
 	(
 		dockDialog "test1RO"
 	)
 )
 
 
 rollout test2RO "UpperMiddle"
 (
 	label labDesc "UpperMiddle"
 	
 	on test2RO moved value do
 	(
 		dockDialog "test2RO"
 	)
 )
 
 rollout test3RO "UpperRight"
 (
 	label labDesc "UpperRight"
 	
 	on test3RO moved value do
 	(
 		dockDialog "test3RO"
 	)
 )
 
 
 
 
 
 
 rollout mainRO "mainRO"
 (
 	on mainRO moved value do
 	(
 		moveDockedRO()
 	)
 )
 
 
 
 append rolloutList (ROStruct RO:test1RO)
 append rolloutList (ROStruct RO:test2RO)
 append rolloutList (ROStruct RO:test3RO)
 append rolloutList (ROStruct RO:mainRO)
 
 
 for i = 1 to (rolloutList.count - 1) do
 	createDialog rolloutList[i].RO 100 100 style:#(#style_toolwindow, #style_sysmenu )
 
 
 
 
 createDialog mainRO 310 0
3 Replies

cool

might have a scoping issue as it throws an error on first run:


-- Error occurred in dockDialog(); filename: ; position: 1393
--  Frame:
--   thisRO: ""
--   rolloutList: undefined
--   dialogName: "test3RO"
--   called in test3RO.moved(); filename: ; position: 6405
--  Frame:
--   value: [583,343]
>> MAXScript Rollout Handler Exception: -- Unknown property: "count" in undefined <<
-- Error occurred in dockDialog(); filename: ; position: 1393
--  Frame:
--   thisRO: ""
--   rolloutList: undefined
--   dialogName: "test3RO"
--   called in test3RO.moved(); filename: ; position: 6405
--  Frame:
--   value: [587,339]
>> MAXScript Rollout Handler Exception: -- Unknown property: "count" in undefined <<

Yeah, I think you need to evaluate it 2 times :S
Well, it is just for testings and there is absolutely no fine-tuning there ^^

The only problem I see is that it gets quite slow

well, one thing that should make it faster is to not have to loop over all of your dialogs when you don’t have to.

For example, when you move one dialog, you should only have to move its children. When you move those children, the ‘on <roll> moved’ event for them will trigger and they will take care of their own children (this could lead to an infinite loop if you dock things in a neat little circle). This does mean you have to assign a docked dialog to the parent dialog’s ‘children’ variable (you’ll have to make one), of course.

Also, I’m very confused by this little snippet of code (I admit I haven’t poked much further at your code, doing some timing tests today):


     local tempParent = thisRO.parent
     while tempParent.parent != undefined do
     (
         enableEscape = true
         tempParent = tempParent.parent
     )
[/cide]
That appears to be a potential infinite loop; is there any reason why tempParent.parent would suddenly -not- be undefined anymore?  I.e. is there a parallel script or so that sets this value?  That code above will easily peg the CPU (only 1 core, of course) so it seems iffy :)