[Closed] CgTalk Maxscript Challenge 020: "Build a Better Tool"
Well, here’s my first challenge entry ever. So i’m likely to overdo it a bit. this one renames an object by doubleclicking on an item in a list. I’ve prefilled the list with dutch construction-elements. you also get a wirecolor (optionally).
A cool thing i learned is using a callback to trigger the script to pop up.
Use:
Execute the script
Select a single object
Enter a questionmark in the name of the object
Script pops up
Doubleclick on a name in the script
This is easily also implemented as macro. Well here it is
--the main body
(
--put an item in one of these arrays to associate a color with it
local redWire = #("gevel","straat")
local greenWire = #("gras","raam","boom")
local blueWire = #("kozijn","water","rand","dakrand")
local cyanWire = #("glas")
local magentaWire = #("vloer","dorpel")
local yellowWire = #("rollaag")
local blackWire = #("trasraam","plafond")
local whiteWire = #("Script by Klaas","stoeprand","lamp")
local defaultWire = #("wand","binnenwand","balkon","stoep",
"dak","boeibord","waterslag","hek","spijl","beschoeiing",
"deur")
--the list of names, will be sorted alphabetically later on
local nameListArray = #()
local wireAssignArrays = #(redWire,greenWire,blueWire,cyanWire,magentaWire,yellowWire,blackWire,whiteWire,defaultWire)
for arr in wireAssignArrays do join nameListArray arr --combine the different arrays with names to a single one
local defaultColor = color 180 180 158 --use this color if the name is put in the defaultWire array
--associate a name with a wirecolor
function fn_getWireColor myName =
(
theRightColor = undefined
for arr in wireAssignArrays do
(
found = findItem arr myName
if found != 0 do
(
case arr of
(
redWire:theRightColor = red
greenWire:theRightColor = green
blueWire:theRightColor = blue
cyanWire:theRightColor = color 0 255 255
magentaWire:theRightColor = color 255 0 255
yellowWire:theRightColor = yellow
blackWire:theRightColor = black
whiteWire:theRightColor = white
defaultWire:theRightColor = defaultColor
)
)
)
theRightColor
)
--initialize the listView
function fn_initListview lv =
(
lv.columns.add "" 16 --the color column
lv.columns.add "" 80 --the name column
lv.View = (dotNetClass "System.Windows.Forms.View").Details
lv.HeaderStyle = lv.Headerstyle.none --i don't want to see the columnheader
lv.fullRowSelect = true
lv.multiselect = false
)
--populate the listview
function fn_populateListview names lv doColor =
(
lv.items.clear()
--sort the names alphabetically
sort names
local theItemArray = #()
for o in names do
(
--the first item is the color
theItem = dotNetObject "listViewItem"
theItem.text = ""
theItem.UseItemStyleForSubItems = false--don't use colors of the main item in the subitem
theItem.subItems.add o --the subItem hold the actual name
--if the user wants to see the wires: change the color of the text of the items in the list
if doColor == true do
(
theColor = fn_getWireColor o
theItem.backColor = (dotNetClass "System.Drawing.Color").fromARGB theColor.r theColor.g theColor.b
)
append theItemArray theItem
)
lv.items.addrange theItemArray
)
--define the rollout
rollout theWhatsMyNameRollout "whatsmyname"
(
label theLabel "Doubleclick to apply" align:#center --pos:[2,2]
label theLabel1 "the objectname." align:#center --pos:[2,18]
checkBox chkDefaultWire "Use wirecolor" checked:true offset:[-11,0]
checkBox chkCloseOnRename "Close on rename" offset:[-11,0] checked:true
dotNetControl lvNameList "System.Windows.Forms.ListView" width:120 height:450 offset:[-11,0]--pos:[2,35]
--init and populate the list when the rollout opens
on theWhatsMyNameRollout open do
(
fn_initListview lvNameList
fn_populateListview nameListArray lvNameList (chkDefaultWire.checked)
)
--reflect the use of color in the UI
on chkDefaultWire changed state do
(
case state of
(
true:fn_populateListview nameListArray lvNameList true
false:fn_populateListview nameListArray lvNameList false
)
)
--apply name and wirecolor when an item is doubleclicked
on lvNameList doubleclick control eventArgs do
(
--get the name of the clicked item
theName = control.selectedItems.item[0].subItems.item[1].text
--get the right wirecolor for a name and paint it on an object
if chkDefaultWire.checked == true do
(
theColor = fn_getWireColor theName
for o in selection where isProperty o #Wirecolor do o.wirecolor = theColor
)
--apply the doubleclicked name to every selected item
for o = 1 to selection.count do
(
--create a three-digit number with leading zeros
theNumber = o as string
if theNumber.count < 3 do
(
leadingZero = ""
for n = 1 to 3 - theNumber.count do append leadingZero "0"
theNumber = leadingZero + theNumber
)
--apply the name
selection[o].name = (theName + "_" + theNumber)
)
if chkCloseOnRename.checked == true do destroyDialog theWhatsMyNameRollout
)
)--end rollout
)--end body
function fn_popItUp =
(
local theParam = callbacks.notificationParam()
local triggerCharacter = "?"
triggered = findString theParam[2] triggerCharacter
if triggered != undefined do
(
thePos = mouse.screenpos
thePos += [-200,0]
if thePos.x < 0 do thePos.x = 0
if thePos.y > 600 do thePos.y = 600
global theWhatsMyNameRollout
try(destroyDialog theWhatsMyNameRollout)catch()
createDialog theWhatsMyNameRollout 125 535 pos:thePos modal:false
)
)
--callback mechanism
callbacks.removeScripts id:#klaasRenamer --remove the callback
callbacks.addScript #nodeNameSet "fn_popItUp()" id:#klaasRenamer --add the callback
Klaas
Here is my small contribution for this challenge.
I call it the ‘Distance tool’ or ‘Position scale tool’.
(
tool disTool prompt:"Distance Tool started (Alt - Change center object, Ctrl - Average center)" numPoints:2
(
local objs, center, objsPos, mp, centerObj
local xRayBitArr = #{}
fn getCenter ctrlMode:true =
(
if not ctrlMode then (
center = centerObj.pos
) else (
center = [0,0,0]
for o in objs do (
center += o.pos
)
center *= 1.0 / objs.count
)
)
fn moveObj o p1 p2 ctrlMode:true =
(
v = center - objsPos[o]
objs[o].pos = objsPos[o] - v * (p1.y - p2.y) / 100
)
fn getCenterByRay lastObj =
(
local mRay = mapScreenToWorldRay mouse.pos
local lastDist = 9999999
for o in objs where o != lastObj do (
local newInt = intersectRay o mRay
if newInt != undefined do (
local newDist = distance mRay.pos newInt.pos
if newDist < lastDist do (
lastDist = newDist
lastObj = o
)
)
)
lastObj
)
fn init =
(
objs = selection as array
if objs.count > 1 then (
for g = 1 to geometry.count do (
xRayBitArr[g] = geometry[g].xRay
geometry[g].xRay = if not geometry[g].isSelected then true else false
)
deselect objects
centerObj = objs[1]
objsPos = #()
for o in objs do (
append objsPos o.pos
)
) else (
pushPrompt "Distance Tool stoped because less then two objects are selected."
#stop
)
)
fn done =
(
for g = 1 to geometry.count do (
geometry[g].xRay = xRayBitArr[g]
)
select objs
gc light:true
)
on start do init()
on freeMove do (
if not ctrlKey and altKey then (
if not mouse.buttonStates[1] and not mouse.buttonStates[1] and not mouse.buttonStates[1] then (
centerObj = getCenterByRay centerObj
flashNodes #(centerObj)
)
)
)
on mousePoint n do (
getCenter ctrlMode:ctrlKey
mp = viewPoint
)
on mouseMove n do (
if n == 2 then (
for o = 1 to objs.count do (
moveObj o mp viewPoint ctrlMode:ctrlKey
)
)
)
on mouseAbort aborted do (
for o = 1 to objs.count do (
objs[o].pos = objsPos[o]
)
)
on stop do done()
)
startTool disTool
)
select a couple of objects and evaluate the tool.
press left mouse button, hold and drag the mouse up and down to move
the selected object closer or further away from the first selected object.
use Alt to change the center object by ray hitting before you press the left mouse button.
use Ctrl while you press and hold left mouse button to move the selected objects relative to their average position.
rollout rollout1 "Selection Batch Renamer" width:243 height:44
(
editText edt1 "" pos:[7,8] width:140 height:27
button btn1 "Rename" pos:[158,9] width:74 height:25
on edt1 entered text do
(
)
on btn1 pressed do
(
for i = 1 to selection.count do
(
--objname = Execute (edt1 as String)
Selection[i].name=uniquename edt1.text
)
)
)
rollout about_ro "About..." (
label l0 "Written by Dave Wortley"
label l1 "Renames selected objects based on" align:#left
label l2 "selection order. Numbering will" align:#left
label l3 "automatically start from the first" align:#left
label l35 "free incrimental." align:#left
)
Renamer = newRolloutFloater "Renamer v 1.2" 250 95
addRollout rollout1 Renamer rolledUp:false
addRollout about_ro Renamer rolledUp:true
Simplicity and speed, key Functionality, the Renaming tool in max is slow, this is quick, doesn’t do anything fancy but works much better.
rollout QRender_rollout "Draft Renderer" width:150 height:20
(
--button btn_store "Store" pos: [5,5] width:40 height:17 enabled:false
button btn_Render "Render" pos:[5,5] width:70 height:17 enabled:true
editText edt1 "" pos:[75,4] width:60 height:17 text:"500"
--button btn_restore "Restore" pos:[155,4] width:56 height:17 enabled:false
fn store =
(
renderSceneDialog.close()
--renderers.current = RendererClass.classes[4]()
global i = renderers.current
global m = i.gi_on
global a = i.imagesampler_type
global b = i.filter_on
global c = i.gi_primary_type
global d = i.gi_irradmap_preset
global l = i.gi_irradmap_subdivs
global f = i.gi_irradmap_showCalcPhase
global g = i.gi_secondary_type
global h = i.lightcache_subdivs
global j = i.lightcache_sampleSize
global k = i.lightcache_showCalcPhase
global n = i.qmc_earlyTermination_threshold
global p = i.system_frameStamp_on
--btn_store.enabled = false
--btn_render.enabled = true
)
fn restore =
(
i = renderers.current
i.gi_on = m
i.imagesampler_type = a
i.filter_on = b
i.gi_primary_type = c
i.gi_irradmap_preset = d
i.gi_irradmap_subdivs = l
i.gi_irradmap_showCalcPhase = f
i.gi_secondary_type = g
i.lightcache_subdivs = h
i.lightcache_sampleSize = j
i.lightcache_showCalcPhase = k
i.qmc_earlyTermination_threshold = n
i.system_frameStamp_on = false
--btn_store.enabled = true
--btn_render.enabled = false
--btn_restore.enabled = false
--renderSceneDialog.open()
gc()
)
on btn_Render pressed do
(
store()
renderSceneDialog.cancel()
renderSceneDialog.close()
i = renderers.current
--set
i.gi_on = true
i.imagesampler_type = 0
i.filter_on = false
i.gi_primary_type = 0
i.gi_irradmap_preset = 3
i.gi_irradmap_subdivs = 30
i.gi_irradmap_showCalcPhase = true
i.gi_secondary_type = 3
i.lightcache_subdivs = 100
i.lightcache_sampleSize = 0.01
i.lightcache_showCalcPhase = 1
i.qmc_earlyTermination_threshold = 1.0
--to stop errors
i.options_defaultLights = false
i.system_frameStamp_on = true
i.system_frameStamp_string = "file: %filename | render time: %rendertime | %date"
RA = getRendImageAspect()
Rw = edt1.text as integer
Rh = Rw / RA
render outputwidth: Rw outputheight: Rh vfb: true progressbar: true --renderType: #region
--btn_restore.enabled = true
restore()
)
on edt1 entered text do
(
Rw = edt1.text
)
on btn_restore pressed do
(
)
)
Vray_Quick_render = newRolloutFloater "Vray Quick Render" 160 60
addRollout qrender_rollout Vray_quick_render rolledUp:false
Vray Quick Render
Quickly adjust Vray Render settings to low GI settings, antialiasing off, sampling low etc. Then restores settings after render. Ability to specify render size as well.
Great stuff guys, really good to see the brains ticking into new uses for max tools.
TzMtN: Nice catch on the offset fix. I think I was originally moving the objects after the cloning, then got lazy and pasted it into the offset. I like the tool interaction of your script, but I couldn’t get the alt and ctrl keys to work for the objects. Perhaps i was doing it wrong!
Dave: Nice and succinct! I can’t test it unfortunately (no Vray), but I love clean readable code! Good one on the renamer too… you’re right about the built in tool. You’d think with all the other speed improvements in max a simple object namer would be faster.
martroyx: Really clean interface! I like! I like the fact that you’ve made the randomness easy to understand and organise.
grabjacket: Very cool idea! I’d love to see it implemented with a double click on the object, but the concept of a predefined tagger is great!
I have a couple of tools i created at work so i know it’s not from scratch but i thought this would still be a good place to share them.
First one:
Spline Aligner
Draw a spline and create a bunch of objects.
Select the objects.
Run the script to create the dialog.
pick the Spline and the selected objects should be spaced evenly along the spline
play with the other options to re-position the objects along the spline
NOTE: if you check the ‘Follow’ checkbox, the objects will become oriented to the spline but they will not be reset to their original rotations if you uncheck it. Maybe something for the future…
(
global splineAligner
try(destroyDialog splineAligner)catch()
local dWidth = 250
local al = #Center
local os = [3,0]
local sel
fn splineFilter s =
(
if classof s == SplineShape OR s.category == #Splines then true else false
)
rollout splineAligner "Spline Aligner"
(
Group "Alignment"
(
pickButton pic_spline "Pick Spline Object" align:al across:2 width:(dWidth/2 - 8) \
offset:-os autoDisplay:true filter:splineFilter
button btn_align "Align" align:al width:(dWidth/2 - 10) offset:os enabled:false
radioButtons rdo_side "" labels:#("Left","Right","Center") align:#Right offset:[-10,3]
label lab_rdo "Align to:" align:#Left offset:[20,-20]
spinner spn_space "Spacing %: " fieldwidth:50 type:#float align:#Right across:2 range:[0,100,100] offset:[0,2]
spinner spn_offset "Offset: " fieldwidth:50 type:#float align:#Right offset:((os*2)+[0,2]) range:[-100,100,0]
checkbox chk_orient "Follow" across:2 checked:false
checkbox chk_flip "Reverse Order"
radioButtons rdo_orientAxis "" labels:#("X", "Y", "Z") align:#Left across:2
checkbox chk_flipAxis "Flip"
)
fn orientTo o tangent orientAxis flipAxis startDeg:0 endDeg:0 =
(
o.dir = tangent
case orientAxis of
(
1:
(
rotate o -90 o.transform[2]
rotate o -90 o.transform[1]
--in coordsys o rotate o -90 y_axis
if flipAxis then rotate o 180 o.transform[3]
)
2:
(
rotate o -90 o.transform[1]
if NOT flipAxis then rotate o 180 o.transform[3]
)
3:
(
if flipAxis then rotate o 180 o.transform[1]
)
)
)
fn fixFraction f =
(
if f > 1.0 then 1.0
else if f < 0.0 then 0
else f
)
fn alignToSpline arr s spc side flip ofs orient:false orientAxis:3 flipAxis:false startDeg:0 endDeg:0 =
(
spc /= 100.0
ofs /= 100.0
cnt = (arr.count - 1) as float
rotateOffset = eulerangles 0 0 0
if flip then
arr = for i = arr.count to 1 by -1 collect arr[i]
for a = 0 to cnt where isValidNode arr[a+1] do
(
case side of
(
1: -- #Left
(
frac = ((a / cnt) * spc)
arr[a+1].pos = interpCurve3D s 1 (fixFraction (frac + ofs))
if orient then
(
orientTo arr[a+1] (tangentCurve3D s 1 (fixFraction (frac + ofs))) orientAxis flipAxis
)
)
2: -- #Right
(
frac = ((a / cnt) * spc) + (1.0 - spc)
arr[a+1].pos = interpCurve3D s 1 (fixFraction (frac + ofs))
if orient then
(
orientTo arr[a+1] (tangentCurve3D s 1 (fixFraction (frac + ofs))) orientAxis flipAxis
)
)
3: -- #Center
(
frac = ((a / cnt) * spc) + ((1.0 - spc) / 2)
arr[a+1].pos = interpCurve3D s 1 (fixFraction (frac + ofs))
if orient then
(
orientTo arr[a+1] (tangentCurve3D s 1 (fixFraction (frac + ofs))) orientAxis flipAxis
)
)
)
)
)
on btn_align pressed do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on spn_space changed val do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object val rdo_side.state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on spn_offset changed val do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked val \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on rdo_side changed state do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on chk_orient changed state do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked spn_offset.value \
orient:state orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on chk_flip changed state do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state state spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
on chk_flipAxis changed state do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:state
)
on rdo_orientAxis changed state do
(
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 AND isValidNode pic_spline.object then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:state flipAxis:chk_flipAxis.checked
)
on pic_spline picked arg do
(
btn_align.enabled = true
sel = for s in selection where s != pic_spline.object collect s
if sel.count > 0 then
alignToSpline sel pic_spline.object spn_space.value rdo_side.state chk_flip.checked spn_offset.value \
orient:chk_orient.checked orientAxis:rdo_orientAxis.state flipAxis:chk_flipAxis.checked
)
)
createDialog splineAligner width:dWidth
)
EDIT: there seems to be some redundent arguments in the alignToSpline function. I guess i intended to add more functionality but never got around to it…
Second one:
Scale Objects Positions
Allows you to ‘scale’ the positions of selected objects about the selection center or average pivot position, in any combination of axes without affecting the actual scale of the objects.
TzMtN has already posted something similar but i think this one is still fairly different as you have a floating dialog to work with as needed.
Run the script select a bunch of objects and play with the spinners!
(
-- Globals
global scaleObjectPositions
try(destroyDialog scaleObjectPositions)catch()
-- Private Globals
local scriptName = "Scale Object Positions"
local version = 1.00
local dWidth = 175
local bw = (dWidth - 20) / 2.08
local fw = 45
local al = #center
local os = [-2,0]
local nowhere = [0,0,0]
local noMove = 100
local ext = 99999999
-- Private Global Functions
fn constructRolloutName =
(
ver = version as string
if ver.count < 4 then ver += "0"
" " + scriptName + " " + ver
)
-- Rollouts
rollout scaleObjectPositions (constructRolloutName())
(
local sel
local mid
local vecs
local starts
local goFlag = false
local count
local allSpinners
Group "Scale Group"
(
spinner spn_x "X:" range:[-ext,ext,100] type:#float fieldwidth:fw across:2 align:al offset:os
spinner spn_xy "XY:" range:[-ext,ext,100] type:#float fieldwidth:fw align:al
spinner spn_y "Y:" range:[-ext,ext,100] type:#float fieldwidth:fw across:2 align:al offset:os
spinner spn_yz "YZ:" range:[-ext,ext,100] type:#float fieldwidth:fw align:al
spinner spn_z "Z:" range:[-ext,ext,100] type:#float fieldwidth:fw across:2 align:al offset:os
spinner spn_zx "XZ:" range:[-ext,ext,100] type:#float fieldwidth:fw align:al
label lab_spacer "" across:2
spinner spn_xyz "XYZ:" range:[-ext,ext,100] type:#float fieldwidth:fw align:al offset:[-4,0]
radiobuttons rdo_mid "Middle Point:" labels:#("Selection Center","Average Pivot Position") align:#Left offset:[0,-20]
button btn_undo "Undo" width:bw align:al across:2
button btn_redo "Redo" width:bw align:al
)
-- Local Rollout Functions
fn resetMove =
(
for i = 1 to count do sel[i].pos = starts[i]
)-- end resetMove function
fn sortLinkedObjs arr = -- needed for when the spinners are zeroed out
(
--collect all unlinked objects
tempArr = for a in arr where a.children.count == 0 AND a.parent == undefined collect a
--collect all objects with parents but no children and join with the array 'tempArr'
join tempArr (for a in arr where a.children.count == 0 AND a.parent != undefined collect a)
--go through all items in tempArr and append their parents to tempArr. Should work recursively.
for t in tempArr where ((findItem arr t.parent) > 0) do append tempArr t.parent
--remove duplicate objects
for i = tempArr.count to 1 by -1 where (index = findItem tempArr tempArr[i]) > 0 AND
index != i do deleteItem tempArr index
--reverse the array order
sortedArray = for i = tempArr.count to 1 by -1 collect tempArr[i]
sortedArray
)-- end sortLinkedObjs function
fn getCenterPoint =
(
if rdo_mid.state == 1 then selection.center
else
(
mid = [0,0,0]
for s in selection do mid += s.pos
mid / selection.count
)
)-- end getCenterPoint function
fn initValues =
(
sel = sortLinkedObjs (selection as array)
mid = getCenterPoint()
vecs = for s in sel collect /*normalize*/ (s.pos - mid)
starts = for s in sel collect s.pos
goFlag = true
count = sel.count
flagForeground sel true
)-- end initValues function
fn scaleMoveObjects factor =
(
factor /= 100.0
for i = 1 to count do sel[i].pos = vecs[i] * factor + mid
)-- end scaleMoveObjects function
mapped fn resetSpinners s = s.value = 100 -- end scaleMoveObjects function
fn btn_up rcFlag =
(
if goFlag AND rcFlag then max undo
goFlag = false
resetSpinners allSpinners
)-- end btn_up function
fn btn_Down =
(
if selection.count > 1 then
(
-- Fake the undo buffer by 'moving' to the same positions
undo "Scale Object Positions" on move selection nowhere
initValues()
)
else goFlag = false
)-- end btn_Down function
-- Rollout Event Handlers
on spn_x changed val do if goFlag do scaleMoveObjects [val,noMove,noMove]
on spn_xy changed val do if goFlag do scaleMoveObjects [val,val,noMove]
on spn_y changed val do if goFlag do scaleMoveObjects [noMove,val,noMove]
on spn_yz changed val do if goFlag do scaleMoveObjects [noMove,val,val]
on spn_z changed val do if goFlag do scaleMoveObjects [noMove,noMove,val]
on spn_zx changed val do if goFlag do scaleMoveObjects [val,noMove,val]
on spn_xyz changed val do if goFlag do scaleMoveObjects [val,val,val]
on spn_x buttondown do btn_Down()
on spn_xy buttondown do btn_Down()
on spn_y buttondown do btn_Down()
on spn_yz buttondown do btn_Down()
on spn_z buttondown do btn_Down()
on spn_zx buttondown do btn_Down()
on spn_xyz buttondown do btn_Down()
on spn_x buttonup rightClickFlag do btn_up rightClickFlag
on spn_xy buttonup rightClickFlag do btn_up rightClickFlag
on spn_y buttonup rightClickFlag do btn_up rightClickFlag
on spn_yz buttonup rightClickFlag do btn_up rightClickFlag
on spn_z buttonup rightClickFlag do btn_up rightClickFlag
on spn_zx buttonup rightClickFlag do btn_up rightClickFlag
on spn_xyz buttonup rightClickFlag do btn_up rightClickFlag
on btn_undo pressed do
(
max undo
)
on btn_redo pressed do
(
max redo
)
on scaleObjectPositions open do
(
allSpinners = for c in scaleObjectPositions.controls where classof c == SpinnerControl collect c
)
)-- end scaleObjectPositions rollout definition
createDialog scaleObjectPositions width:dWidth style:#(#style_toolwindow, #style_border, #style_sysmenu)
)