[Closed] Controller Callback
I will now try to explain in simple language how the system for sending messages in 3DS MAX is arranged using the example of a plugin.
The plugin creates an object that can send messages to all other objects that depend on it. It should be provided by the plugin developer.
One of these objects is ParamBlock.
ParamBlock already decides for itself how to pass this message and whom. Such objects including are elements UI (controls).
Thus, to receive messages from an object, you have to be either an object dependent on it, or to become the one to whom the ParamBlock sends messages.
Am I explaining clearly yet? …
I guess I got it, Are you taking about references that will create connections between objects? So we can get them by using “refs.dependents” or “refs.dependsOn” functions?
How about something like this. Far from perfection but with a little effort it could work for an in-house solution, and I guess it could all be wrapped inside a .Net derived control.
Note: Minimal implementation, so bugs are expected as well as unhandled behaviors.
EDIT: Removed all Change Handlers to handle all events within the Redrawing Callback.
(
try destroydialog ::RO_SPINNER catch()
rollout RO_SPINNER "" width:110 height:56
(
dotnetcontrol dn_spinner "System.Windows.Forms.NumericUpDown" pos:[16,16] width:80
local color_default = (dotnetclass "System.Drawing.Color").white
local color_animated = (dotnetclass "System.Drawing.Color").Red
local color_key = (dotnetclass "System.Drawing.Color").Green
local color_black = (dotnetclass "System.Drawing.Color").Black
local color_white = (dotnetclass "System.Drawing.Color").White
local ctrl = bezier_float()
local mouseDown = false
local valueChaged = false
fn Hold mAction mString: =
(
case mAction of
(
#start: if not thehold.holding() do thehold.begin()
#accept: if thehold.holding() do thehold.accept mString
#cancel: if thehold.holding() do thehold.cancel()
)
)
fn GetSpinnerValue =
(
val = getproperty dn_spinner #value asdotnetobject:true
return val.ToSingle val
)
fn UpdateControl =
(
dn_spinner.Value = ctrl.value
back = color_default
fore = color_black
if numkeys ctrl > 0 then
(
back = color_animated
fore = color_white
for j = 1 to numkeys ctrl do
(
if getkeytime ctrl j == currenttime do
(
back = color_key
fore = color_white
)
)
)
dn_spinner.BackColor = back
dn_spinner.ForeColor = fore
dn_spinner.Update()
)
fn AssignController mController =
(
if iskindof mController bezier_float then
(
ctrl = mController
)else(
ctrl = bezier_float()
$.height.controller = ctrl
)
dn_spinner.Value = ctrl.value
)
on RO_SPINNER open do
(
dn_spinner.Minimum = -1E9
dn_spinner.Maximum = 1E9
dn_spinner.DecimalPlaces = 4
dn_spinner.Increment = 0.1
dn_spinner.Value = ctrl.value
unregisterRedrawViewsCallback RO_SPINNER.UpdateControl
registerRedrawViewsCallback RO_SPINNER.UpdateControl
)
on RO_SPINNER close do
(
unregisterRedrawViewsCallback RO_SPINNER.UpdateControl
)
on dn_spinner MouseDown sender args do
(
Hold #start
mouseDown = true
valueChaged = false
)
on dn_spinner MouseUp sender args do
(
ctrl.value = GetSpinnerValue()
Hold #accept mString:"Parameter Changed"
if valueChaged == true do setfocus RO_SPINNER
mouseDown = false
)
on dn_spinner KeyUp sender args do
(
if args.KeyCode == args.KeyCode.Enter do
(
Hold #start
ctrl.value = GetSpinnerValue()
dn_spinner.Select 0 dn_spinner.Text.Count
Hold #accept mString:"Parameter Changed"
)
)
on dn_spinner ValueChanged sender args do
(
if mouseDown == true do
(
ctrl.value = GetSpinnerValue()
valueChaged = true
)
)
)
createdialog RO_SPINNER
/* TEST SCENE ------------------------------------ */
with undo off delete objects
node = box isselected:on
with animate on
(
at time 25 node.height = 75
at time 75 node.height = -50
at time 100 node.height = 25
)
RO_SPINNER.AssignController node.height.controller
/* ---------------------------------------------- */
)
Cool, My controls are WPF, But I don’t want to complicate everything with WPF stuffs and my focus is on update mechanism. So It seems your offered method “registerRedrawViewsCallback” works perfect.
I am not aware of a build-in WPF numericUpDown control or similar, but if you are using a third party control or creating your own, it should be pretty similar to the example. Probably Methods, Properties and Events will be different but it needs just the basic ones.
Other thing that would be nice is to add the Mouse drag behavior.
The only issue I find with the Redraw Callback is that it updates too many times in shaded views due to the progressive refinement of Nitrous driver. Maybe you can avoid it by checking the previous and current values and just update if they are different if you see the performance degrades too much.
If you are customizing your control, you could add an Update method to it and just call the method from the callback, or you could add the callback directly to the control in .Net so each control would have its own callback.
That’s is also another point, One register for all or register a callback for each control?
I would first try to have the Redraw Callback within the control, one Update() method and call it from the Callback. And create/destroy the Callback when controller is assigned/removed from the control.
That way you can update the controls individually, and the control would be ready to be added to any form without having to code a global Callback in each form.
If it doesn’t work as you would like you could still call the Update method from a Callback in the Form.