Great script and great use of dotNet.
Haven’t delved into the code yet, but a bit of functionality that might be helpful is to have the option for then donNet control capture the hotkey that launched the script and when it gets a key up, turn itself off. This way it works like holding down the ctrl alt or shift key, only scrubbing while its key is down. It should be pretty straightforward, only I don’t know if it’s possible for the script to determine which key called it in the first place. I’ll look into it.
Added a sticky mode, but it’s still not perfect. If you activate it with a keyboard shortcut, when you release the key it will exit the mouse wheel capture. However, there are still some usage quirks to iron out. Here’s what I got so far (usable, but annoying in some cases):
--******************************************************************************
--*
--* MouseWheely v1.6
--* by Ofer Zelichover (c) 02/2008
--* www.oferz.com maxscript@oferz.com
--*
--******************************************************************************
--* You may use this script freely as you see fit. *
--* You may use parts or the script as a whole in your own scripts. *
--* (it would be nice if you give me a credit if you do so ;)) *
--******************************************************************************
--* This script comes with no waranty!
--* Although I tried this script and couldn't find any problems with it, I can,
--* in no way be held responsible for any kind of loss or damage, whether
--* direct or indirect, due to the use of this script.
--*
--* ********************************************************************
--* IF YOU DON'T LIKE THE ABOVE STATEMENT, DON'T USE THIS SCRIPT
--* ********************************************************************
--*
--* If you find any bugs in this script, please let me know.
--******************************************************************************
--* Description *
--* ------------- *
--* Allows the usage of the mouse wheel to scroll the time slider
--*
--******************************************************************************
--* Isntallation and Usage:
--* ------------------------
--* After you run this script, the script will appear in the
--* "Os tools" category in the customize ui menu.
--* Assign it to a keyboard shortcut/button/RC Menu
--* After pressing the button/keyboard key/ RC menu item, use the mouse wheel
--* to scroll the time slider. Click anywhere to stop the opration.
--*
--***************************************************************************
--*********************************************************
-- Start of macroScript
--************************************************************
macroScript Os_timeWheely
category:"Os Tools"
tooltip:"Use mouse wheel to scroll time slider"
buttontext:"TimeWheely"
(
--------- Struct definition
global s_MouseWheel
struct s_MouseWheel (
message = undefined, -- The message that will be displayed in the status bar.
-- You can pass the message as a msg: parameter to the start function
-- instead of setting it directly.
onChangeFunc = undefined, -- The onChange callback function. DO NOT set it directly. Use registerFn instead.
onActivateFunc = undefined, -- The onActivate callback function. DO NOT set it directly. Use registerFn instead.
onDeactivateFunc = undefined, -- The onDeactivate callback function. DO NOT set it directly. Use registerFn instead.
persistentWindow = false, -- If true, the window will always open (after the first start command).
-- If false, the window will be closed when the control loses focus. This mode is slightly less
-- effective (not noticable), but is safer.
stickyMode = false, -- When this is true, the key value will stored when a key is first pressed. When the key value
-- is changed the control will lose focus, thus ending the mouse wheel capture.
valueDivider = 120, -- The scroll wheel delta will be divided by this number before being passed to the callback.
fn createRollout =
(
rollout ro_MouseWheel "test"
(
-- Local Variable Definitions
--------------------------------------
local onChangeFn, onActivateFn, onDeActivateFn
local isActive = false
local msg = false
local divider = 120
local persistentWin = false
local alt = false, ctrl = false, shift = false
local keyValue = undefined
local invalidKeyValues = #{16..18}
local sticky = true
-- User Interface
--------------------------------------
label dummyCont pos:[0,0]
dotNetControl cont "System.Windows.Forms.Control" pos:[0,0]
-- Functions
--------------------------------------
fn stop =
(
if persistentWin then
setFocus dummyCont
else
try(destroyDialog ro_MouseWheel)catch()
)
fn init =
(
if isKindOf onActivateFn MAXScriptFunction then
onActivateFn()
isActive = true
enableAccelerators = false
cont.focus()
)
fn done =
(
keyValue = undefined
if msg then (
popPrompt()
msg = false
)
isActive = false
enableAccelerators = true
if isKindOf onDeActivateFn MAXScriptFunction then
onDeActivateFn()
)
-- Event Handlers
----------------------------------------
on cont MouseWheel sender event do (
if isKindOf onChangeFn MAXScriptFunction then (
onChangeFn (event.delta / divider) alt:alt ctrl:ctrl shift:shift
)
)
on cont lostFocus do (
if not persistentWin then
try (destroyDialog ro_MouseWheel)catch()
else
done()
)
on cont KeyDown sender event do (
if sticky then (
if keyValue == undefined and not invalidKeyValues[event.KeyValue] then
keyValue = event.KeyValue
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on cont KeyUp sender event do (
if sticky then (
if keyValue == event.KeyValue then
stop()
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on ro_MouseWheel open do init()
on ro_MouseWheel close do done()
) -- end of ro_MouseWheel rollout
-- Return the rollout
ro_MouseWheel
),
roll = createRollout(),
fn setRollParams =
(
roll.onChangeFn = onChangeFunc
roll.onActivateFn = onActivateFunc
roll.onDeActivateFn = onDeactivateFunc
if superclassOf valueDivider == Number then
roll.divider = valueDivider
else
roll.divider = 120
roll.msg = message != undefined
roll.persistentWin = persistentWindow
roll.sticky = stickyMode
),
fn registerFn onChange: onActivate: onDeactivate: =
(
local changed = false
if isKindOf onChange MAXScriptFunction then (
onChangeFunc = onChange
changed = true
)
if isKindOf onActivate MAXScriptFunction then (
onActivateFunc = onActivate
changed = true
)
if isKindOf onDeactivate MAXScriptFunction then (
onDeactivateFunc = onDeactivate
changed = true
)
changed
),
fn unregisterFn type =
(
type = (type as string) as name
case type of (
#onChange: onChangeFunc = undefined
#onActivate: onActivateFunc = undefined
#onDeactivate: onDeactivateFunc = undefined
#all: (onChangeFunc = undefined; onActivateFunc = undefined; onDeactivateFunc = undefined)
)
setRollParams()
true
),
fn start msg: =
(
if isKindOf onChangeFunc MAXScriptFunction then (
if msg != unsupplied then
message = msg
if not persistentWindow then
try(destroyDialog roll)catch()
if not persistentWindow or not roll.open then
createDialog roll pos:[-10000,-10000]
setRollParams()
if message != undefined then (
pushPrompt (message as string)
)
if persistentWindow then
roll.init()
true
) else (
roll.isActive = false
false
)
),
fn stop =
(
try(roll.stop())catch()
),
fn isActive =
(
isProperty roll #cont and isProperty roll.cont #Focused and roll.cont.Focused
)
) -- end of s_MouseWheel struct
------------------------------------------------------------------------------
-- Initialize the mouseWheel struct
local mouseWheel = s_MouseWheel()
fn onMouseWheelChanged val alt: ctrl: shift: =
(
if ctrl then
val *= 10
sliderTime += val
)
fn onDeAct = updateToolbarButtons()
mouseWheel.persistentWindow = true
mouseWheel.stickyMode = true
mouseWheel.registerFn onChange:onMouseWheelChanged onDeactivate:onDeAct
-- MacroScript Event Handlers
---------------------------------------
on isChecked do mouseWheel.isActive()
on execute do (
if mouseWheel.isActive() then (
mouseWheel.stop()
) else (
mouseWheel.start msg:"Scroll mouse wheel to slide the time slider"
)
updateToolbarButtons()
)
) -- end of Os_timeWheely macroscript
cheers,
o
Right, sticky mode, that’s the name. Nothing is ever perfect. Usable is all we can ask. And since you’re doing this out of the kindness of your heart, it’s asking a lot…
Thanks.
Hmm… this has me thinking. Anyone know if it’s possible to capture spaceNavigator or spacePilot (or explorer, I get all the names mixed up) data in a dot net? When I’m doing lip sync, I’d love to be able to scrub the timeline with my spaceThingie.
Great updates man! Although it seems to be stuck in +/- 10 frames mode now when assigned to a keyboard shortcut, is this normal?
EDIT: Actually, it’s working fine with my mouse wheel but not with my wacom’s scroll wheel… I guess this is becase the amount of ‘turning’ the wheel that’s required to trigger data is more sensitive.
How would I go about playing with a sensibility threshold value?
Cheers!
OK, I added support for settings in an ini file. The file should be placed in the 3dsmax_root\scripts folder, and in should be named mouseWheely.ini
For now there are only two options available:
StickyMode – setting this to false will turn off the sticky mode.
Divider – defines the number by which the raw value from the mouse wheel is divided. A lower value will cause a more “sensitive” scroll.
Here’s an example that will mimic the defaults (if no file is defined, or an option is not defined, the default for that option is used):
[Settings]
Divider=120
StickyMode=true
Here’s the new version:
--******************************************************************************
--*
--* MouseWheely v1.7
--* by Ofer Zelichover (c) 02/2008
--* www.oferz.com maxscript@oferz.com
--*
--******************************************************************************
--* You may use this script freely as you see fit. *
--* You may use parts or the script as a whole in your own scripts. *
--* (it would be nice if you give me a credit if you do so ;)) *
--******************************************************************************
--* This script comes with no waranty!
--* Although I tried this script and couldn't find any problems with it, I can,
--* in no way be held responsible for any kind of loss or damage, whether
--* direct or indirect, due to the use of this script.
--*
--* ********************************************************************
--* IF YOU DON'T LIKE THE ABOVE STATEMENT, DON'T USE THIS SCRIPT
--* ********************************************************************
--*
--* If you find any bugs in this script, please let me know.
--******************************************************************************
--* Description *
--* ------------- *
--* Allows the usage of the mouse wheel to scroll the time slider
--*
--******************************************************************************
--* Isntallation and Usage:
--* ------------------------
--* After you run this script, the script will appear in the
--* "Os tools" category in the customize ui menu.
--* Assign it to a keyboard shortcut/button/RC Menu
--* After pressing the button/keyboard key/ RC menu item, use the mouse wheel
--* to scroll the time slider. Click anywhere to stop the opration.
--*
--***************************************************************************
--*********************************************************
-- Start of macroScript
--************************************************************
macroScript Os_timeWheely
category:"Os Tools"
tooltip:"Use mouse wheel to scroll time slider"
buttontext:"TimeWheely"
(
--------- Struct definition
global s_MouseWheel
struct s_MouseWheel (
message = undefined, -- The message that will be displayed in the status bar.
-- You can pass the message as a msg: parameter to the start function
-- instead of setting it directly.
onChangeFunc = undefined, -- The onChange callback function. DO NOT set it directly. Use registerFn instead.
onActivateFunc = undefined, -- The onActivate callback function. DO NOT set it directly. Use registerFn instead.
onDeactivateFunc = undefined, -- The onDeactivate callback function. DO NOT set it directly. Use registerFn instead.
persistentWindow = false, -- If true, the window will always open (after the first start command).
-- If false, the window will be closed when the control loses focus. This mode is slightly less
-- effective (not noticable), but is safer.
stickyMode = false, -- When this is true, the key value will stored when a key is first pressed. When the key value
-- is changed the control will lose focus, thus ending the mouse wheel capture.
valueDivider = 120., -- The scroll wheel delta will be divided by this number before being passed to the callback.
fn createRollout =
(
rollout ro_MouseWheel "test"
(
-- Local Variable Definitions
--------------------------------------
local onChangeFn, onActivateFn, onDeActivateFn
local isActive = false
local msg = false
local divider = 120.
local persistentWin = false
local alt = false, ctrl = false, shift = false
local keyValue = undefined
local invalidKeyValues = #{16..18}
local sticky = true
-- User Interface
--------------------------------------
dotNetControl cont "System.Windows.Forms.Control" pos:[0,0]
-- Functions
--------------------------------------
fn stop =
(
if persistentWin then
cont.enabled = false
else
try(destroyDialog ro_MouseWheel)catch()
)
fn init =
(
if isKindOf onActivateFn MAXScriptFunction then
onActivateFn()
isActive = true
enableAccelerators = false
cont.enabled = true
cont.focus()
)
fn done =
(
keyValue = undefined
if msg then (
popPrompt()
msg = false
)
isActive = false
enableAccelerators = true
if isKindOf onDeActivateFn MAXScriptFunction then
onDeActivateFn()
)
-- Event Handlers
----------------------------------------
on cont MouseWheel sender event do (
if isKindOf onChangeFn MAXScriptFunction then (
onChangeFn (event.delta / divider) alt:alt ctrl:ctrl shift:shift
)
)
on cont lostFocus do (
if not persistentWin then
try (destroyDialog ro_MouseWheel)catch()
else
done()
)
on cont KeyDown sender event do (
if sticky then (
if keyValue == undefined and not invalidKeyValues[event.KeyValue] then
keyValue = event.KeyValue
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on cont KeyUp sender event do (
if sticky then (
if keyValue == event.KeyValue then
stop()
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on ro_MouseWheel open do init()
on ro_MouseWheel close do done()
) -- end of ro_MouseWheel rollout
-- Return the rollout
ro_MouseWheel
),
roll = createRollout(),
fn setRollParams =
(
roll.onChangeFn = onChangeFunc
roll.onActivateFn = onActivateFunc
roll.onDeActivateFn = onDeactivateFunc
if superclassOf valueDivider == Number then
roll.divider = valueDivider
else
roll.divider = 120
roll.msg = message != undefined
roll.persistentWin = persistentWindow
roll.sticky = stickyMode
),
fn registerFn onChange: onActivate: onDeactivate: =
(
local changed = false
if isKindOf onChange MAXScriptFunction then (
onChangeFunc = onChange
changed = true
)
if isKindOf onActivate MAXScriptFunction then (
onActivateFunc = onActivate
changed = true
)
if isKindOf onDeactivate MAXScriptFunction then (
onDeactivateFunc = onDeactivate
changed = true
)
changed
),
fn unregisterFn type =
(
type = (type as string) as name
case type of (
#onChange: onChangeFunc = undefined
#onActivate: onActivateFunc = undefined
#onDeactivate: onDeactivateFunc = undefined
#all: (onChangeFunc = undefined; onActivateFunc = undefined; onDeactivateFunc = undefined)
)
setRollParams()
true
),
fn start msg: =
(
if isKindOf onChangeFunc MAXScriptFunction then (
if msg != unsupplied then
message = msg
if not persistentWindow then
try(destroyDialog roll)catch()
if not persistentWindow or not roll.open then
createDialog roll pos:[-10000,-10000]
setRollParams()
if message != undefined then (
pushPrompt (message as string)
)
if persistentWindow then
roll.init()
true
) else (
roll.isActive = false
false
)
),
fn stop =
(
try(roll.stop())catch()
),
fn isActive =
(
isProperty roll #cont and isProperty roll.cont #Focused and roll.cont.Focused
)
) -- end of s_MouseWheel struct
------------------------------------------------------------------------------
-- Initialize the mouseWheel struct
local mouseWheel = s_MouseWheel()
local iniFile = getDir #Scripts + "\\mouseWheely.ini"
fn onMouseWheelChanged val alt: ctrl: shift: =
(
val = val as integer
if ctrl then
val *= 10
sliderTime += val
)
fn onDeAct = updateToolbarButtons()
mouseWheel.persistentWindow = true
mouseWheel.stickyMode = ((getINISetting iniFile "Settings" "StickyMode") as name) != #false
local val = getINISetting iniFile "Settings" "Divider"
if val != "" and val as float != undefined then
mouseWheel.valueDivider = val as float
mouseWheel.registerFn onChange:onMouseWheelChanged onDeactivate:onDeAct
-- MacroScript Event Handlers
---------------------------------------
on isChecked do mouseWheel.isActive()
on execute do (
if mouseWheel.isActive() then (
mouseWheel.stop()
) else (
mouseWheel.start msg:"Scroll mouse wheel to slide the time slider"
)
updateToolbarButtons()
)
) -- end of Os_timeWheely macroscript
enjOy,
o
Just a “practical” answer… I know that doing it in maxscript is much more of a challenge but if you just reaaaaaaaally want just the end result… I think that a mouse remapper would suffice, logitech’s drivers for example allow that for specific applications, so you can just turn it on in max…
hides at the incoming punches
punch!
I love working in Max with a tablet and I know that many people do, so getting the touch-wheel/touch-strip to move the time slider is pretty neat IMHO
Cheers
EDIT: Just one question; how to use the .ini file properly? Should the settings update each time the .ini is saved or are we required to restard MAX or run the script again…?
Added another option to the INI file:
useModifierKeys – when this setting is set to false, the ctrl key will not cause a 10f jump. Default: true.
--******************************************************************************
--*
--* MouseWheely v1.8
--* by Ofer Zelichover (c) 02/2008
--* www.oferz.com maxscript@oferz.com
--*
--******************************************************************************
--* You may use this script freely as you see fit. *
--* You may use parts or the script as a whole in your own scripts. *
--* (it would be nice if you give me a credit if you do so ;)) *
--******************************************************************************
--* This script comes with no waranty!
--* Although I tried this script and couldn't find any problems with it, I can,
--* in no way be held responsible for any kind of loss or damage, whether
--* direct or indirect, due to the use of this script.
--*
--* ********************************************************************
--* IF YOU DON'T LIKE THE ABOVE STATEMENT, DON'T USE THIS SCRIPT
--* ********************************************************************
--*
--* If you find any bugs in this script, please let me know.
--******************************************************************************
--* Description *
--* ------------- *
--* Allows the usage of the mouse wheel to scroll the time slider
--*
--******************************************************************************
--* Isntallation and Usage:
--* ------------------------
--* After you run this script, the script will appear in the
--* "Os tools" category in the customize ui menu.
--* Assign it to a keyboard shortcut/button/RC Menu
--* After pressing the button/keyboard key/ RC menu item, use the mouse wheel
--* to scroll the time slider. Click anywhere to stop the opration.
--*
--***************************************************************************
--*********************************************************
-- Start of macroScript
--************************************************************
macroScript Os_timeWheely
category:"Os Tools"
tooltip:"Use mouse wheel to scroll time slider"
buttontext:"TimeWheely"
(
--------- Struct definition
global s_MouseWheel
struct s_MouseWheel (
message = undefined, -- The message that will be displayed in the status bar.
-- You can pass the message as a msg: parameter to the start function
-- instead of setting it directly.
onChangeFunc = undefined, -- The onChange callback function. DO NOT set it directly. Use registerFn instead.
onActivateFunc = undefined, -- The onActivate callback function. DO NOT set it directly. Use registerFn instead.
onDeactivateFunc = undefined, -- The onDeactivate callback function. DO NOT set it directly. Use registerFn instead.
persistentWindow = false, -- If true, the window will always open (after the first start command).
-- If false, the window will be closed when the control loses focus. This mode is slightly less
-- effective (not noticable), but is safer.
stickyMode = false, -- When this is true, the key value will stored when a key is first pressed. When the key value
-- is changed the control will lose focus, thus ending the mouse wheel capture.
valueDivider = 120., -- The scroll wheel delta will be divided by this number before being passed to the callback.
fn createRollout =
(
rollout ro_MouseWheel "test"
(
-- Local Variable Definitions
--------------------------------------
local onChangeFn, onActivateFn, onDeActivateFn
local isActive = false
local msg = false
local divider = 120.
local persistentWin = false
local alt = false, ctrl = false, shift = false
local keyValue = undefined
local invalidKeyValues = #{16..18}
local sticky = true
-- User Interface
--------------------------------------
dotNetControl cont "System.Windows.Forms.Control" pos:[0,0]
-- Functions
--------------------------------------
fn stop =
(
if persistentWin then
cont.enabled = false
else
try(destroyDialog ro_MouseWheel)catch()
)
fn init =
(
if isKindOf onActivateFn MAXScriptFunction then
onActivateFn()
isActive = true
enableAccelerators = false
cont.enabled = true
cont.focus()
)
fn done =
(
keyValue = undefined
if msg then (
popPrompt()
msg = false
)
isActive = false
enableAccelerators = true
if isKindOf onDeActivateFn MAXScriptFunction then
onDeActivateFn()
)
-- Event Handlers
----------------------------------------
on cont MouseWheel sender event do (
if isKindOf onChangeFn MAXScriptFunction then (
onChangeFn (event.delta / divider) alt:alt ctrl:ctrl shift:shift
)
)
on cont lostFocus do (
if not persistentWin then
try (destroyDialog ro_MouseWheel)catch()
else
done()
)
on cont KeyDown sender event do (
if sticky then (
if keyValue == undefined and not invalidKeyValues[event.KeyValue] then
keyValue = event.KeyValue
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on cont KeyUp sender event do (
if sticky then (
if keyValue == event.KeyValue then
stop()
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on ro_MouseWheel open do init()
on ro_MouseWheel close do done()
) -- end of ro_MouseWheel rollout
-- Return the rollout
ro_MouseWheel
),
roll = createRollout(),
fn setRollParams =
(
roll.onChangeFn = onChangeFunc
roll.onActivateFn = onActivateFunc
roll.onDeActivateFn = onDeactivateFunc
if superclassOf valueDivider == Number then
roll.divider = valueDivider
else
roll.divider = 120
roll.msg = message != undefined
roll.persistentWin = persistentWindow
roll.sticky = stickyMode
),
fn registerFn onChange: onActivate: onDeactivate: =
(
local changed = false
if isKindOf onChange MAXScriptFunction then (
onChangeFunc = onChange
changed = true
)
if isKindOf onActivate MAXScriptFunction then (
onActivateFunc = onActivate
changed = true
)
if isKindOf onDeactivate MAXScriptFunction then (
onDeactivateFunc = onDeactivate
changed = true
)
changed
),
fn unregisterFn type =
(
type = (type as string) as name
case type of (
#onChange: onChangeFunc = undefined
#onActivate: onActivateFunc = undefined
#onDeactivate: onDeactivateFunc = undefined
#all: (onChangeFunc = undefined; onActivateFunc = undefined; onDeactivateFunc = undefined)
)
setRollParams()
true
),
fn start msg: =
(
if isKindOf onChangeFunc MAXScriptFunction then (
if msg != unsupplied then
message = msg
if not persistentWindow then
try(destroyDialog roll)catch()
if not persistentWindow or not roll.open then
createDialog roll pos:[-10000,-10000]
setRollParams()
if message != undefined then (
pushPrompt (message as string)
)
if persistentWindow then
roll.init()
true
) else (
roll.isActive = false
false
)
),
fn stop =
(
try(roll.stop())catch()
),
fn isActive =
(
isProperty roll #cont and isProperty roll.cont #Focused and roll.cont.Focused
)
) -- end of s_MouseWheel struct
------------------------------------------------------------------------------
-- Initialize the mouseWheel struct
local mouseWheel = s_MouseWheel()
local iniFile = getDir #Scripts + "\\mouseWheely.ini"
local useModifierKeys = ((getINISetting iniFile "Settings" "useModifierKeys") as name) != #false
fn onMouseWheelChanged val alt: ctrl: shift: =
(
val = val as integer
if useModifierKeys and ctrl then
val *= 10
sliderTime += val
)
fn onDeAct = updateToolbarButtons()
mouseWheel.persistentWindow = true
mouseWheel.stickyMode = ((getINISetting iniFile "Settings" "StickyMode") as name) != #false
local val = getINISetting iniFile "Settings" "Divider"
if val != "" and val as float != undefined then
mouseWheel.valueDivider = val as float
mouseWheel.registerFn onChange:onMouseWheelChanged onDeactivate:onDeAct
-- MacroScript Event Handlers
---------------------------------------
on isChecked do mouseWheel.isActive()
on execute do (
if mouseWheel.isActive() then (
mouseWheel.stop()
) else (
mouseWheel.start msg:"Scroll mouse wheel to slide the time slider"
)
updateToolbarButtons()
)
) -- end of Os_timeWheely macroscript
cheers,
o
Another small update, this one makes the changes in the INI file immediate, not requiring a max restart.
--******************************************************************************
--*
--* MouseWheely v1.81
--* by Ofer Zelichover (c) 02/2008
--* www.oferz.com maxscript@oferz.com
--*
--******************************************************************************
--* You may use this script freely as you see fit. *
--* You may use parts or the script as a whole in your own scripts. *
--* (it would be nice if you give me a credit if you do so ;)) *
--******************************************************************************
--* This script comes with no waranty!
--* Although I tried this script and couldn't find any problems with it, I can,
--* in no way be held responsible for any kind of loss or damage, whether
--* direct or indirect, due to the use of this script.
--*
--* ********************************************************************
--* IF YOU DON'T LIKE THE ABOVE STATEMENT, DON'T USE THIS SCRIPT
--* ********************************************************************
--*
--* If you find any bugs in this script, please let me know.
--******************************************************************************
--* Description *
--* ------------- *
--* Allows the usage of the mouse wheel to scroll the time slider
--*
--******************************************************************************
--* Isntallation and Usage:
--* ------------------------
--* After you run this script, the script will appear in the
--* "Os tools" category in the customize ui menu.
--* Assign it to a keyboard shortcut/button/RC Menu
--* After pressing the button/keyboard key/ RC menu item, use the mouse wheel
--* to scroll the time slider. Click anywhere to stop the opration.
--*
--***************************************************************************
--*********************************************************
-- Start of macroScript
--************************************************************
macroScript Os_timeWheely
category:"Os Tools"
tooltip:"Use mouse wheel to scroll time slider"
buttontext:"TimeWheely"
(
--------- Struct definition
global s_MouseWheel
struct s_MouseWheel (
message = undefined, -- The message that will be displayed in the status bar.
-- You can pass the message as a msg: parameter to the start function
-- instead of setting it directly.
onChangeFunc = undefined, -- The onChange callback function. DO NOT set it directly. Use registerFn instead.
onActivateFunc = undefined, -- The onActivate callback function. DO NOT set it directly. Use registerFn instead.
onDeactivateFunc = undefined, -- The onDeactivate callback function. DO NOT set it directly. Use registerFn instead.
persistentWindow = false, -- If true, the window will always open (after the first start command).
-- If false, the window will be closed when the control loses focus. This mode is slightly less
-- effective (not noticable), but is safer.
stickyMode = false, -- When this is true, the key value will stored when a key is first pressed. When the key value
-- is changed the control will lose focus, thus ending the mouse wheel capture.
valueDivider = 120., -- The scroll wheel delta will be divided by this number before being passed to the callback.
fn createRollout =
(
rollout ro_MouseWheel "test"
(
-- Local Variable Definitions
--------------------------------------
local onChangeFn, onActivateFn, onDeActivateFn
local isActive = false
local msg = false
local divider = 120.
local persistentWin = false
local alt = false, ctrl = false, shift = false
local keyValue = undefined
local invalidKeyValues = #{16..18}
local sticky = true
-- User Interface
--------------------------------------
dotNetControl cont "System.Windows.Forms.Control" pos:[0,0]
-- Functions
--------------------------------------
fn stop =
(
if persistentWin then
cont.enabled = false
else
try(destroyDialog ro_MouseWheel)catch()
)
fn init =
(
if isKindOf onActivateFn MAXScriptFunction then
onActivateFn()
isActive = true
enableAccelerators = false
cont.enabled = true
cont.focus()
)
fn done =
(
keyValue = undefined
if msg then (
popPrompt()
msg = false
)
isActive = false
enableAccelerators = true
if isKindOf onDeActivateFn MAXScriptFunction then
onDeActivateFn()
)
-- Event Handlers
----------------------------------------
on cont MouseWheel sender event do (
if isKindOf onChangeFn MAXScriptFunction then (
onChangeFn (event.delta / divider) alt:alt ctrl:ctrl shift:shift
)
)
on cont lostFocus do (
if not persistentWin then
try (destroyDialog ro_MouseWheel)catch()
else
done()
)
on cont KeyDown sender event do (
if sticky then (
if keyValue == undefined and not invalidKeyValues[event.KeyValue] then
keyValue = event.KeyValue
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on cont KeyUp sender event do (
if sticky then (
if keyValue == event.KeyValue then
stop()
)
alt = event.Alt
ctrl = event.Control
shift = event.Shift
event.SuppressKeyPress = true
event.Handled = false
)
on ro_MouseWheel open do init()
on ro_MouseWheel close do done()
) -- end of ro_MouseWheel rollout
-- Return the rollout
ro_MouseWheel
),
roll = createRollout(),
fn setRollParams =
(
roll.onChangeFn = onChangeFunc
roll.onActivateFn = onActivateFunc
roll.onDeActivateFn = onDeactivateFunc
if superclassOf valueDivider == Number then
roll.divider = valueDivider
else
roll.divider = 120
roll.msg = message != undefined
roll.persistentWin = persistentWindow
roll.sticky = stickyMode
),
fn registerFn onChange: onActivate: onDeactivate: =
(
local changed = false
if isKindOf onChange MAXScriptFunction then (
onChangeFunc = onChange
changed = true
)
if isKindOf onActivate MAXScriptFunction then (
onActivateFunc = onActivate
changed = true
)
if isKindOf onDeactivate MAXScriptFunction then (
onDeactivateFunc = onDeactivate
changed = true
)
changed
),
fn unregisterFn type =
(
type = (type as string) as name
case type of (
#onChange: onChangeFunc = undefined
#onActivate: onActivateFunc = undefined
#onDeactivate: onDeactivateFunc = undefined
#all: (onChangeFunc = undefined; onActivateFunc = undefined; onDeactivateFunc = undefined)
)
setRollParams()
true
),
fn start msg: =
(
if isKindOf onChangeFunc MAXScriptFunction then (
if msg != unsupplied then
message = msg
if not persistentWindow then
try(destroyDialog roll)catch()
if not persistentWindow or not roll.open then
createDialog roll pos:[-10000,-10000]
setRollParams()
if message != undefined then (
pushPrompt (message as string)
)
if persistentWindow then
roll.init()
true
) else (
roll.isActive = false
false
)
),
fn stop =
(
try(roll.stop())catch()
),
fn isActive =
(
isProperty roll #cont and isProperty roll.cont #Focused and roll.cont.Focused
)
) -- end of s_MouseWheel struct
------------------------------------------------------------------------------
-- Initialize the mouseWheel struct
local mouseWheel = s_MouseWheel()
local iniFile = getDir #Scripts + "\\mouseWheely.ini"
local useModifierKeys = ((getINISetting iniFile "Settings" "useModifierKeys") as name) != #false
fn onMouseWheelChanged val alt: ctrl: shift: =
(
val = val as integer
if useModifierKeys and ctrl then
val *= 10
sliderTime += val
)
fn onDeAct = updateToolbarButtons()
mouseWheel.persistentWindow = true
mouseWheel.stickyMode = ((getINISetting iniFile "Settings" "StickyMode") as name) != #false
local val = getINISetting iniFile "Settings" "Divider"
if val != "" and val as float != undefined then
mouseWheel.valueDivider = val as float
mouseWheel.registerFn onChange:onMouseWheelChanged onDeactivate:onDeAct
-- MacroScript Event Handlers
---------------------------------------
on isChecked do mouseWheel.isActive()
on execute do (
useModifierKeys = ((getINISetting iniFile "Settings" "useModifierKeys") as name) != #false
mouseWheel.stickyMode = ((getINISetting iniFile "Settings" "StickyMode") as name) != #false
local val = getINISetting iniFile "Settings" "Divider"
if val != "" and val as float != undefined then
mouseWheel.valueDivider = val as float
if mouseWheel.isActive() then (
mouseWheel.stop()
) else (
mouseWheel.start msg:"Scroll mouse wheel to slide the time slider"
)
updateToolbarButtons()
)
) -- end of Os_timeWheely macroscript
cheers,
o
Just adding onto the praise of how awesome this is. I have absolutely no use for a scrolly timeline but I’m already plotting how to hack it into a million other useful things.
It seems like the next logical step is to rewrite this as a function which can be called in any other script sort of like:
fn Zoomout =
(
ZoomOut()
)
fn ZoomIn =
(
ZoomIn()
)
fn Pan =
(
Pan
)
scrolliewheely Zoomin Zoomout Pan
Obviously the code is all fake. But just a way to activate it along with what function to do when that event is called.
Hi,
Actually it’s very easy to do already, that’s why I created the core functionality in a struct.
Here’s a small (and useless) demo of how to use the struct to control the radius of the selected objects with the mouse wheel. Just past in a new script window and press ctrl+e
(
global s_MouseWheel
local scroller = s_MouseWheel()
local paramsHolder = #()
fn onStart =
(
paramsHolder = #()
for o in selection do (
append paramsHolder o.wireColor
o.wireColor = red
)
)
fn onEnd =
(
for i = 1 to selection.count do
selection[i].wireColor = paramsHolder[i]
)
fn onChange val ctrl: alt: shift: =
(
for o in selection where isProperty o #Radius do
o.radius += val
)
scroller.persistentWindow = true
scroller.registerFn onChange:onChange onActivate:onStart onDeactivate:onEnd
scroller.start msg:"Use mouse wheel to change radius."
)
cheers,
o