[Closed] Copy/Paste transform data?
I want to write a script that will let me do the following:
-
Select a bunch of objects, click a button, and thereby put the name of each object along with its transform data into some kind of text file.
-
Open up a new max file, load the info from that text file into buttons on a rollout, so that when I select an object and click the button with whatever name, it will paste the transform data from that named object into the object that is selected.
I’m sure I could figure out how to do something like this on my own, but it would me a long time and would probably be a big mess on top of it. What is the SIMPLEST way for me to do what I am trying to accomplish?
Your description of the process is pretty clear, which is the best first step in writing a good script.
The saving of the data is rather straight-forward. I would suggest using an INI file (setIniSetting(), getIniSetting()) since it performs most of the file management, reading and writing pretty much automatically.
You could alternatively store the info in memory in a global array if you are not going to use the data between Max sessions.
The tricky part is the UI portion. The simplest way would be to populate a ListBox with the names+transforms and use the doube-click handler of the ListBox to assign to whatever is selected. This will remove the need to build a UI procedurally with a button for each object etc. Not that you couldn’t do that, but it would be an easier Proof Of Concept.
Go on, try it out and ask questions if you hit a wall…
UI’s always take forever for this sort of thing. I am currently using XML to to store transforms and using this dynamic control to display the preset files. If you were to store each transform as a separate file, it would work well.
However, for your particular problem, it would probably be better to store in a single text file or XML file, and read the data as an array, like you stated. You could still use the FlowLayoutPanel to generate the ui, and store the Transform in the tag property of each button on the layoutpanel as it is generated.
try this as a start –
NodeArray = #()
-- create some stuff to store
for i = 1 to 20 do
(
sphere radius:2 position:[(random 0 100),(random 0 100),(random 0 100)] wirecolor:(color (random 0 255) (random 0 255) (random 0 255))
cone radius:2 position:[(random 0 100),(random 0 100),(random 0 100)] wirecolor:(color (random 0 255) (random 0 255) (random 0 255))
cylinder radius:2 position:[(random 0 100),(random 0 100),(random 0 100)] wirecolor:(color (random 0 255) (random 0 255) (random 0 255))
)
NodeArray = for o in objects collect o
try (destroydialog flctest ) catch()
rollout flctest "TM Storage" width:256 height:408
(
local maxBackColor = colorMan.getColor #background
local maxButtonColor = colorMan.getColor #pressedButton
local maxbackDNcol = (DotNetClass "System.Drawing.Color").FromArgb (maxBackColor[1] * 255.0f) (maxBackColor[2] * 255.0f) (maxBackColor[3] * 255.0f)
local maxbuttonDNcol=(DotNetClass "System.Drawing.Color").FromArgb (maxButtonColor[1] * 255.0f) (maxButtonColor[2] * 255.0f) (maxButtonColor[3] * 255.0f)
local ButtonSize = [75,30]
fn buttonhandler sender args =
(
for i = 0 to flctest.flc.controls.count-1 do
(
if (((flctest.flc.controls.item[i].gettype()).name) == "Button") do
(
flctest.flc.controls.item[i].backcolor = maxbackDNcol
)
)
sender.backcolor = (DotNetClass "System.Drawing.Color").Chartreuse
-- apply the transform from the selected button tag
if selection.count == 1 do (selection[1].transform = execute sender.tag)
)
fn AddFlowLayoutNodes control nodes buttonsizex buttonsizey=
(
for i = 1 to nodes.count do
(
flowbutton = dotnetobject "button"
flowbutton.font = dotNetObject "System.Drawing.Font" "Verdana" 7 ((dotNetClass "System.Drawing.FontStyle").regular)
flowbutton.backcolor = maxbackDNcol
flowbutton.Margin = dotnetobject "System.Windows.Forms.Padding" 1
flowbutton.flatstyle = (dotNetclass "System.Windows.Forms.FlatStyle").flat
flowbutton.size = dotnetobject "System.Drawing.Size" buttonsizex buttonsizey
flowbutton.FlatAppearance.MouseDownBackColor = maxbuttonDNcol
flowbutton.textalign = (dotnetclass "System.Drawing.ContentAlignment").MiddleCenter
flowbutton.text = Nodes[i].name
flowbutton.tag = Nodes[i].transform as string
dotnet.addeventhandler flowbutton "Click" buttonhandler
control.Controls.add flowbutton
if i == nodes.count do (return flowbutton)
)
dgc = dotnetclass "system.gc"
dgc.collect()
gc()
)
fn addseparator control title =
(
spacelabel = dotnetobject "label"
spacelabel.textalign = (dotnetclass "System.Drawing.ContentAlignment").bottomCenter
spacelabel.font = dotNetObject "System.Drawing.Font" "Verdana" 7 ((dotNetClass "System.Drawing.FontStyle").bold)
spacelabel.size = dotnetobject "System.Drawing.Size" (control.ClientRectangle.Right-19) 16
spacelabel.backcolor = (DotNetClass "System.Drawing.Color").gray
spacelabel.Margin = dotnetobject "System.Windows.Forms.Padding" 1
spacelabel.borderstyle = (dotNetClass "System.Windows.Forms.BorderStyle").fixedsingle
spacelabel.text = title
control.Controls.add spacelabel
return spacelabel
)
dotNetControl FLC "System.Windows.Forms.FlowLayoutPanel" pos:[2,4] width:250 height:400
on flctest open do
(
flc.borderstyle= (dotNetClass "System.Windows.Forms.BorderStyle").fixedsingle
flc.autoscroll = true
flc.backcolor = (DotNetClass "System.Drawing.Color").slategray
flc.SuspendLayout()
if NodeArray.count > 0 then
(
flc.setflowbreak (addseparator flc "Click To Set Transform") true
flc.setflowbreak (AddFlowLayoutNodes flc NodeArray buttonsize.x buttonsize.y) true
flc.resumelayout()
)
else flc.setflowbreak (addseparator flc "No TM Data") true
)
)
createdialog flctest style:#(#style_toolwindow, #style_sysmenu)
Only slightly ugly bit is the use of execute to retrieve the matrix3 value from the buttons tag property. I wanted to use DotNetMXSvalue to store the matrix3, but it appeared that in the loop to generate the buttons, it was updated the with the last stored TM value, so all tags read the same TM. strange one that, kind of useless unless i’ve done it wrong, which is probably likely.:shrug:
Pete, the question was about the SIMPLEST way to do it.
I wouldn’t call XML saving the simplest way possible
Elegant? Yes. But simplest?
macroScript CaptureTransforms category:"Forum Help"
(
local theIniFile = getDir #export + "\\_TransformData.ini"
deleteFile theIniFile
for o in selection do
setIniSetting theIniFile o.name "Transform" (o.transform as string)
)
macroScript ApplyCapturedTransforms category:"Forum Help"
(
global ApplyCapturedTransforms_Rollout
try(destroyDialog ApplyCapturedTransforms_Rollout) catch()
rollout ApplyCapturedTransforms_Rollout "Apply Transforms"
(
local theNames = #()
local theTransforms = #()
listbox lbx_transforms "Double-click to Apply To Selection" height:12
on lbx_transforms doubleClicked itm do
(
for o in selection do o.transform = execute theTransforms[itm]
)
on ApplyCapturedTransforms_Rollout open do
(
local theIniFile = getDir #export + "\\_TransformData.ini"
theNames = getIniSetting theIniFile
theTransforms = for i in theNames collect getIniSetting theIniFile i "Transform"
lbx_transforms.items = for i = 1 to theNames.count collect theNames[i] + " : " + theTransforms[i]
)
)
createDialog ApplyCapturedTransforms_Rollout 450 200
)
Hi Bobo,
isn’t XML the same as a text file but with those funny little wiggly lines all over it?
I take the point, but whether loading or saving through either method, I wanted to post the FlowlayoutPanel example just as an option for building the dynamic interface, ala RolloutCreator style.
I like what you posted.
I am just saying it might go over the head of most people including the OP.
Since he asked for the simplest approach, I felt yours was space age technology compared to simple INI file storage.
Hope I did not offend.
Hehe Bobo was faster!
Here’s my version, you can double click an item in the listbox like in Bobo’s version or you can select Apply all and it applies the trasnformations to objects with the same name, maybe this could be useful too, who knows! Cheers.
macroScript ObjCopyPaste
category:"K Scripts"
(
rollout objdataT "ObjT Copy/Paste" width:300
(
label lbl_objects "Objects:" align:#left
dotnetcontrol lst_obj "System.Windows.Forms.Listbox" align:#center height:200
label lbl_transform "Transform:" align:#left width: 275 height:42 style_sunkenedge:true
button btn_save "Save" align:#left across:2
button btn_load "Load" align:#right
button btn_apply "Apply all"
button btn_site "?" align:#center
local iniPath=getdir(#export)+"\\objT.ini"
on objdataT open do
(
lst_obj.HorizontalScrollbar=True
)
on btn_save pressed do
(
if selection.count!=0 then
(
iniPath=getdir(#export)+"\\objT.ini"
fileSave=getSaveFileName filename:iniPath types:"Ini File(*.ini)"
if fileSave!=undefined then
(
deleteFile fileSave
for i in selection do
(
setINISetting fileSave "Object Transforms" i.name (i.transform as string)
lst_obj.Items.Add i.name
)
)
)
)
on btn_load pressed do
(
fileOpen=getOPenFileName filename:iniPath types:"Ini File(*.ini)"
if fileOpen!=undefined then
(
iniSection=getIniSetting fileOpen
iniSection=iniSection[1]
iniKey=getIniSetting fileOpen iniSection
for i=1 to iniKey.count do
(
lst_obj.Items.Add iniKey[i]
)
iniPath=fileOpen
lst_obj.SelectedIndex=0
)
)
on lst_obj SelectedIndexChanged sender arg do
(
iniSection=getIniSetting iniPath
iniSection=iniSection[1]
iniKey=getIniSetting iniPath iniSection lst_obj.SelectedItem
lbl_transform.text=iniKey
)
on lst_obj DoubleClick sender arg do
(
for i in selection do
(
i.transform=execute lbl_transform.text
)
)
on btn_apply pressed do
(
if lst_obj.Items.Count!=0 then
(
iniSection=getIniSetting iniPath
iniSection=iniSection[1]
iniKey=getIniSetting iniPath iniSection
for i=1 to iniKey.count do
(
try
(
execute ("select $" + iniKey[i])
iniTransform=getiniSetting iniPath iniSection iniKey[i]
execute ("$"+iniKey[i] + ".transform="+iniTransform)
)
catch (print ("Object " + iniKey[i] + " not found"))
)
)
)
on btn_site pressed do
(
process=dotnetclass "System.Diagnostics.Process"
process.start "http://www.dimensao3.com/al"
)
)
clearListener()
createDialog objdataT
)
Wow! Thanks everyone, I will get right on trying each of these solutions out! I’ll even try the xml approach; maybe I will learn something.
I guess I’ve found some limitation in the getIniSetting, I can’t get past 1175 items Anyone knows something about this?
Edit: And using Bobo structure I can only get 1162 items