[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
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
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