Notifications
Clear all

[Closed] Autoselecting viewport?

Hi, does anyone know if it`s possible to autoselect a viewport by hovering the mouse above it without the need to press the right mouse button? Thanks

17 Replies

hmm… only with an initialization phase, looks like… can’t get the viewports’ positions/dimensions arbitrarily… only for the active one. (As far as I can tell)

   So...

See further posts for updated code

   You can easily replace the rollout + timer to a .NYET timer if you really want to - I like the dialogs because it makes it easy to kill the timer (just kill the dialog), whereas .NYET timers tend to linger around especially if you lose the pointer variable to them and thus no longer have an easy way to kill the buggers.
  
  Edit: fix for < 4 viewports (d'oh)
 Edit: Switching layouts fixed
Edit: 'Fixed' viewport resizing breaking things

Edit: 2D viewports fixed

Have alook here.
http://scripts.breidt.net/#shortcuts

I’m using this for viewport maximize and some other toggles.

oh my god you`re a legend ZeBoxx2 !!! thanks so much works like a charm :bowdown:

scrimski: thanks for the link also mate but Zeboxx`s script is all I needed, thanks again guys

no prob

just checked the other script… looks like that’s more for being bound to a key, rather than automatically doing its trick… also has to loop through all viewports each time and I think doesn’t like 2D viewports… but most interestingly from that is that I guess they haven’t found a way to get the rect for a viewport automagically either… eyes Autodesk wishlist

1 Reply
(@scrimski)
Joined: 1 year ago

Posts: 0

The toggles are bound to keys, correct, but you just hover over the viewport and don’t need to rightclick it anymore.

Richard, nice solution, I’ll store that away for future reference.

I personally prefer ‘on mouse over’ focus and your script handles it nicely for any hotkey and it seems still fast enough, even though it checks ever 100ms. For non-3dsmax Windows work, I use a small utility called KatMouse ( http://ehiti.de/katmouse/ ) that has an option to set windows focus on scroll wheel. It does not always work for all applications but it has exceptions for those cases, too.

You probably could even speed up your script a tiny bit by checking the previously active viewportBox first and bailing out of that last ‘for i’ loop as soon as ‘contains’ is true for the first time?

Funny that the polling script still works even when 3ds Max is behind some other window or locked due to a modal dialog.

Cheers
– MartinB

yeah, 100ms poll isn’t too bad – a callback would be nicer, of course

And you’re right – I actually had an earlier version (that used entirely too much code) that would start from the currently active viewport and loop over the rest from there, which did trap that “if it’s still in the same window” bit, but that version ended up having some other problems so started afresh thinking there had to be a better way %)

I’ll adjust it to that loop in a moment – coffee now

figured I might as well spiffy it up further… see the code for changes… the big ones are macroscript definition and dotNetTimer. Note that the script should be in a startup or plugin (sub)folder, as the macroscript depends on the main body of code.


-- AutoVP - MouseOver Viewport Switcher
-- Richard Annema -- SplutterFish, LLC
--
-- v0.04
-- - trapping errors when called by the .NET Timer so that the thing can be halted right-quick.
--
-- v0.03
-- - fixed AutoVP not existing causing the macroscript to go boink.
-- - fixed layout change breaking the init routine
-- - made .NET Timer use a preference
--
-- v0.02
-- - structified
-- - slightly leaner in code run
-- - uses dotNetTimer in 3ds Max 9+
-- - added macroscript definition, typically to be used for a button to toggle AutoVP on/off (especially in 3ds Max 9+)
--
-- v0.01
-- - initial version

-- preference settings
global autoVP_interval = 100 -- milliseconds
global autoVP_useDotNetTimer = true -- if true, uses a .net timer in 3ds Max r9+

-- globals
global autoVP, autoVP_roll, autoVP_dotNyetInvoke

-- UI
if (classOf autoVP_roll == RolloutClass) then ( destroyDialog autoVP_roll )
rollout autoVP_roll "autoVP" width:64 height:32 (
	local ui_isOpen = false
	
	timer ticktock interval:100 active:true
	checkbutton ckb_active "active" checked:true pos:[4,4] width:56 height:24 highlightColor:(color 192 255 192) tooltip:"Toggle AutoVP"
	
	on ticktock tick do ( autoVP.setMouseActiveViewport() )
	
	on ckb_active changed state do (
		ticktock.active = state
		updateToolbarButtons()
	)
	
	on autoVP_roll open do (
		ui_isOpen = true
		updateToolbarButtons()
		ticktock.interval = autoVP_interval
		autoVP.init()
	)
	on autoVP_roll close do (
		ui_isOpen = false
		updateToolbarButtons()
	)
	on autoVP_roll moved pos do ( autoVP.uiPos = pos )
)

-- Main struct with variables and functions
Struct AutoVP_s (
	viewportBoxes,
	viewportLayout,
	viewportCount,
	uiPos,
	dotNetTimer = undefined,
	
	-- initialization function... get the positions/dimensions for each viewport
	fn init = (
		viewportBoxes = #()
		local currentVp = viewport.activeViewPort
		for i = 1 to viewport.numViews do (
			local index = (mod (i + currentVp) viewport.numViews) + 1
			viewport.activeViewPort = index
			local vpTopLeft = mouse.screenPos - mouse.pos
			local vpSize = getViewSize()
			viewportBoxes[index] = (Box2 vpTopLeft.x vpTopLeft.y vpSize.x vpSize.y)
		)
		if (currentVp != 0) then ( viewport.activeViewPort = currentVp )
		viewportLayout = viewport.getLayout()
		viewportCount = viewport.numViews
	),
	
	fn closeUI = (
		if (classOf autoVP_roll == RolloutClass) then ( destroyDialog autoVP_roll )
	),

	fn showUI = (
		-- destroy any existing autoVP dialog
		if (classOf autoVP_roll == RolloutClass) then ( destroyDialog autoVP_roll )

		-- begin the action, re-use last known position if available
		if (uiPos == undefined) then ( createDialog autoVP_roll style:#(#style_toolwindow,#style_sysmenu) )
		else ( createDialog autoVP_roll 64 32 uiPos.x uiPos.y style:#(#style_toolwindow,#style_sysmenu) )
	),
	
	fn getViewportUnderMouse = (
		local skip = false
		-- better make sure that layout changes don't ruin things here
		if (viewport.getLayout() != autoVP.viewportLayout) then (
			autoVP.init()
		)
		else if (viewport.numViews != autoVP.viewportCount) then (
			autoVP.init()
		)
		else (
			-- ditto for viewport resizings
			local currentVp = viewport.activeViewPort
			if (currentVp != 0) then (
				local currentVpAssumedBox = autoVP.viewportBoxes[currentVp]
				if (getViewSize() != [currentVpAssumedBox.w,currentVpAssumedBox.h]) then (
					autoVP.init()
				)
			)
		)

		local result = undefined
		for i = 1 to viewport.numViews do (
			viewportBox = autoVP.viewportBoxes[i]
			if (contains viewportBox mouse.screenPos) then (
				result = i
				exit
			)
		)
		result
	),
	
	fn setMouseActiveViewport = (
		local hoverView = getViewportUnderMouse()
		if ((hoverView != undefined) AND (hoverView != viewport.activeViewport)) then (
			viewport.activeViewPort = hoverView
		)
	)
)
autoVP = autoVP_s()

-- .NET events can't invoke functions that are within Structs properly ... so here's an intermediating function >_<
fn autoVP_dotNyetInvoke = (
	try (
		autoVP.setMouseActiveViewport()
	)
	catch (
		autoVP.dotNetTimer.stop()
		local err = getCurrentException()
		messageBox ("An error occurred and AutoVP has been halted.  The error was:
" + err)
	)
)

-- macroscript definition
macroscript AutoVP_mcr category:"SplutterFish" buttontext:"AutoVP" tooltip:"AutoVP - MouseOver Viewport Switcher (v0.04)" (
	on execute do (
		if (((maxVersion())[1] < 9000) OR (not autoVP_useDotNetTimer)) then (
			if (autoVP_roll.ui_isOpen) then (
				autoVP.closeUI()
			)
			else (
				autoVP.showUI()
			)
		)
		else (
			if (autoVP.dotNetTimer == undefined) then (
				autoVP.dotNetTimer = dotNetObject "System.Windows.Forms.Timer"
				dotnet.addEventHandler autoVP.dotNetTimer "tick" autoVP_dotNyetInvoke
			)
			if (autoVP.dotNetTimer.enabled) then ( autoVP.dotNetTimer.stop() )
			else (
				autoVP.dotNetTimer.interval = autoVP_interval
				autoVP.dotNetTimer.start()
			)
			updateToolbarButtons()
		)
	)
	on isChecked do (
		if (autoVP != undefined) then (
			if (((maxVersion())[1] < 9000) OR (not autoVP_useDotNetTimer)) then (
				autoVP_roll.ui_isOpen AND autoVP_roll.ticktock.active
			)
			else (
				if (autoVP.dotNetTimer != undefined) then ( autoVP.dotNetTimer.enabled )
				else ( false )
			)
		)
		else ( false )
	)
	on isEnabled do ( autoVP != undefined )
)
updateToolbarButtons()
  

wow ZeBoxx2 , this is really amazing

but the 2nd version is too Dangerous
if anything depending on a dotNetTimer fails , you have a complete disaster ! , at least that what i knew from experimenting with the dotNetTimer

as for the 2nd version , i’m having this habit of working like in maya , you know …maximize is a spacebar shortcut , when i do that with the 2nd version and hover over the front viewport and hit the spacebar i get …Zillion errors ! , i don’t know in general how to stop that dotNetTimer in such case and after Esc …i end up closing with Ctrl+Alt+Delete !

runtimeError: viewprot.activeviewport index out of range

stuff like that
i installed it in the startup folder , assigned a shortcut to the macro …
am i doing something wrong or what ?

yeah, that’s what I was afraid of with regard to the dotNetTimer, as I mentioned in my earlier posts… it’s hailed as some kind of holy grail of not having to have an UI in view… but at the same time, getting the darn thing to die DIE DIE is… well. And of course because it happily keeps running despite an error, you don’t just get 1 error popup… you get numerous

So… 1. I’ll check what happens with that spacebar thing and 2. I’ll make the timer method in 3ds Max 9+ a preference option

Page 1 / 2