[Closed] help with buttons on rollouts
hi, im creating a custom floating toolbar for poly editing (trying to streamline my workflow and have a go a max script).
the trouble i am having is finding a way to deactivate a button (which for example does a ring select) when the opperation is not avalible.
here is the example i have:
rollout test "test" width:100 height:100
(
Button oiring_btn "ring" pos:[5,5] width:60 height:60
on oiring_btn pressed do
(
Try
(
if subobjectlevel == undefined then max modify mode
(Filters.GetModOrObj()).buttonOp #SelectEdgeRing
)
Catch (MessageBox "Failed" Title:"Poly Editing")
)
)
createDialog test 70 70 style:#(#style_toolwindow, #style_sysmenu)
it seems to be simple enough when its a button in a toolbar but thats quite different i suppose.
On IsEnabled Return Filters.Is_EPolySpecifyLevel #{3..4}
or another way a found
On isEnabled return
(
if (selection.count == 1 and classof selection[1].baseobject == Editable_Poly) and
((if (subobjectlevel == 2) == true then true else (if(subobjectlevel == 3) == true then true else false)) == true)
then true
else false
)
is there any way i can apply that to “button.enabled”?
and also is there not a more simple way of doing this
((if (subobjectlevel == 2) == true then true else (if(subobjectlevel == 3) == true then true else false)) == true)
is there an OR function? cant i just say: if subobjectlevel is equal to 3 OR 4?
any help would be great.
You could register a callback script that is executed each time the selection changes. It would call a function to update the enabled state of all your buttons.
Of course there is an OR logical operator. You could say
on isEnabled return subobjectLevel == 3 OR subobjectLevel == 4
or
on isEnabled return subobjectLevel > 2 AND subobjectLevel < 5
You don’t have to return true from an IF expression. You could just return the result of the comparison, as the handler wants TRUE or FALSE anyway.
In fact, this is the most convoluted boolean expression I have ever seen
((if (subobjectlevel == 2) == true then true else (if(subobjectlevel == 3) == true then true else false)) == true)
is the same as
(subobjectlevel == 2 OR subobjectlevel == 3)
Here is an example:
(
global SelAllVerts_Dialog
try(destroyDialog SelAllVerts_Dialog)catch()
rollout SelAllVerts_Dialog "Select All Vertices"
(
button selectAllVertices "Select All Vertices" enabled:false
on selectAllVertices pressed do
(
polyOp.setVertSelection $ #{1..(polyOp.getNumVerts $)}
redrawViews()
)
fn updateUI =
(
selectAllVertices.enabled = selection.count == 1 and classof $ == Editable_Poly
)
on SelAllVerts_Dialog open do
(
updateUI()
callbacks.removeScripts id:#selectAllVertices
callbacks.addScript #selectionSetChanged "SelAllVerts_Dialog.updateUI()" id:#selectAllVertices
)
on SelAllVerts_Dialog close do callbacks.removeScripts id:#selectAllVertices
)
createDialog SelAllVerts_Dialog
)
thank you for the help bobo.
In fact, this is the most convoluted boolean expression I have ever seen
i realised shorly after posting that there was better way of doing that. “you live and learn”
i had trouble because you cant do a serch for “or” in the help. i knew it had to exist i just could not find it.
could you shed some light on this:
in the EditablePolygon.mcr there is this
(
-- Active in Vertex, Edge levels:
On IsEnabled Return Filters.Is_EPolySpecifyLevel #{2..3}
On IsVisible Return Filters.Is_EPolySpecifyLevel #{2..3}
On Execute Do (
try (
if subobjectlevel == undefined then max modify mode
local A = Filters.GetModOrObj()
if ((subobjectLevel==1) or (subobjectLevel==2)) then (
if (Filters.Is_This_EditPolyMod A) then
(
if (subobjectLevel == 1) then A.ButtonOp #RemoveVertex
else A.ButtonOp #RemoveEdge
)
else A.buttonOp #Remove
) else (
-- Put us in a suitable SO level
subobjectLevel = 2
)
)
catch (MessageBox "Operation Failed" Title:"Poly Editing")
)
)
there is a few things in there that seem unnessasery.
what is the point of “if subobjectlevel == undefined then max modify mode”? because the button is only active in subobject level 1 and 2 so surely you cant get subobjectlevel == undefined.
Also “if ((subobjectLevel==1) or (subobjectLevel==2)) then” and “– Put us in a suitable SO level subobjectLevel = 2” are not needed for the same reason?
i did this:
(
On IsEnabled Return Filters.Is_EPolySpecifyLevel #{2..3}
On IsVisible Return Filters.Is_EPolySpecifyLevel #{2..3}
On Execute Do (
try (
local A = Filters.GetModOrObj()
if (Filters.Is_This_EditPolyMod A) then
(
if (subobjectLevel == 1) then A.ButtonOp #RemoveVertex
else A.ButtonOp #RemoveEdge
)
else A.buttonOp #Remove
)
catch (MessageBox "Failed" Title:"Poly Editing")
)
)
is there a problem with that? is there somthing i am overlooking?
thanks again
dan
Looks like somebody has been overly precautious
You are correct, since the event handlers have already checked for level 1 or 2, there is no point checking again inside the body. Your version should work and is of course shorter (you could remove even some more parentheses without a problem). But the shipping code also works and is not measureably slower, so it does not matter. It is just not the best example to learn from…
Looks like somebody has been overly precautious
i thought that might be the case:).
just have one problem now: i cant find an event callback that does what i need. what i need is a callback when the subobject level is changed or somthing like that.
this is the code i am testing.
(
global test
try(destroyDialog test)catch()
rollout test "test" width:100 height:100
(
Button oiring_btn "ring" pos:[5,5] width:60 height:60 enabled:false
on oiring_btn pressed do
(
Try
(
if subobjectlevel == undefined then max modify mode
(Filters.GetModOrObj()).buttonOp #SelectEdgeRing
)
Catch (MessageBox "Failed" Title:"Poly Editing")
)
fn updateUI =
(
oiring_btn.enabled = Filters.Is_EPolySpecifyLevel #{2..3}
)
on test open do
(
updateUI()
callbacks.removeScripts id:#polychangesub
callbacks.addScript #SelectionsetChanged "test.updateUI()" id:#polychangesub
)
on test close do callbacks.removeScripts id:#polychangesub
)
createDialog test 70 70 style:#(#style_toolwindow, #style_sysmenu)
)
and i though this was going to be simple:)
i should go to bed now, it 6:30 in the morning (oops)
Such a callback does not seem to exist.
There is a workaround, although not 100% perfect.
If you would place your dialog in a macroScript and include in the on IsEnabled returns() handler some code to update the UI of your dialog, as long as the button is visible on a toolbar, the code will be called when you change the SO level. (If you place the macro button on a floating toolbar and hide it though, the handler will never be called).
on isEnabled return (try(test.updateUI())catch(); true)
Of course, you should NOT use “test” as a global variable to hold a dialog name. Use something unique instead…
on isEnabled return (try(test.updateUI())catch(); true)
i can quite get that to work. from what i understand i put all the code i have for the dialog into a macro script (im assuming in the “On Execute Do”) and above that i put “on isEnabled return (try(rolloutname.updateUI())catch(); true)”. if i press the button the dialog pops up but nothing else seems to happen.
i cant believe that the callback does not exist surely im not the only one to want to do this.
back to the drawing board then or i could have the button activate when you have an editpoly selected but thats quite a compromise.
cheers
The handler can be in any macroScript. Infact, I implemented a dummy Macro button just to control your sample script and it worked well.
You must be doing something wrong – feel free to post more sample code for debugging…
i will get there in the end:) where there’s a will there’s way and all that.
ok, i have this macroScript:
MacroScript oiPoly_dummybtn
ButtonText:"none"
category:"oidan_polytools"
Tooltip:""
(
on isEnabled return (try(oipoly_dialog.updateUI())catch(); true)
)
and i have put that button on a toolbar.
then i have this script for the dialog:
(
global oipoly_dialog
try(destroyDialog oipoly_dialog)catch()
rollout oipoly_dialog "oipoly_dialog" width:100 height:100
(
Button oiring_btn "ring" pos:[5,5] width:60 height:60 enabled:false
on oiring_btn pressed do
(
Try
(
--if subobjectlevel == undefined then max modify mode
(Filters.GetModOrObj()).buttonOp #SelectEdgeRing
)
Catch (MessageBox "Failed" Title:"Poly Editing")
)
fn updateUI =
(
oiring_btn.enabled = Filters.Is_EPolySpecifyLevel #{2..3}
)
on oipoly_dialog open do
(
updateUI()
--callbacks.removeScripts id:#polychange
--callbacks.addScript #SelectionsetChanged "oipoly_dialog.updateUI()" id:#polychange
)
--on test close do callbacks.removeScripts id:#polychange
)
createDialog oipoly_dialog 70 70 style:#(#style_toolwindow, #style_sysmenu)
)
i am assuming that i dont need the callbacks parts of that ( i tried it with and without)
i am executing that from a maxscript window.
if i am alredy in vertex or edge mode when i execute the script the button is active but if i am no the button never becomes active.
im thinking it might be “Filters.Is_EPolySpecifyLevel #{2…3}” that is the problem.
i am really greatfull for the help Bobo:thumbsup:
Aha!
MacroScript oiPoly_dummybtn
ButtonText:"none"
category:"oidan_polytools"
Tooltip:""
(
on isEnabled return (try(oipoly_dialog.updateUI())catch(); true)
on execute do ()
)
You were missing the COMPULSORY on execute do() handler, so the dummy Macro was never updated. Adding that line made it work as expected. Sorry, forgot to mention that yesteday, it was late here, too…
i just cant get it to work:banghead:
this is exactly what i have
macroScript:
MacroScript oiPoly_dummybtn
ButtonText:"none"
category:"oidan_polytools"
Tooltip:""
(
on isEnabled return (try(oiPoly_dialog.updateUI())catch(); true)
On Execute Do ()
)
dialog code (run from a maxscript window):
(
global oiPoly_dialog
try(destroyDialog oiPoly_dialog)catch()
rollout oiPoly_dialog "oipoly_dialog" width:100 height:100
(
Button oiring_btn "ring" pos:[5,5] width:60 height:60 enabled:false
on oiring_btn pressed do
(
Try
(
(Filters.GetModOrObj()).buttonOp #SelectEdgeRing
)
Catch (MessageBox "Failed" Title:"Poly Editing")
)
fn updateUI =
(
--oiring_btn.enabled = Filters.Is_EPoly()
oiring_btn.enabled = Filters.Is_EPolySpecifyLevel #{2..3}
)
on oiPoly_dialog open do
(
updateUI()
)
)
createDialog oipoly_dialog 70 70 style:#(#style_toolwindow, #style_sysmenu)
)
it works with “Filters.Is_EPoly()” but if i try “Filters.Is_EPolySpecifyLevel #{2…3}” it does not. It cant seem to detect when i change the subobject level.
have i done somthing stupid? i just cant see whats wrong.
max 7 btw.
I copied your code 1:1 and it worked in Max 7.
No idea what you are doing wrong, but it should work.