GUI for COFFEE script
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 14:04, xxxxxxxx wrote:
When you use a .res file. You use it with a full blown plugin structure. Not in the script manager.
The old v9.5SDK has some examples that you can learn from in it.However,
You can create what looks like a full blown plugin in the script manager. That will react to button clicks, slider changes, Text changes, etc.
This is generally how the new users gets their feet wet before jumping into the full blown plugin structure.
Note: When you use the script manager this way...You DO NOT use .res files.
It might be possible to call to the .res file from the script manager. But this is not encouraged.
If you need .res files. You are encouraged to use a full blown registered pluginHere is an example of an interactive script that looks and acts like a plugin.
Put this code in the script manager and then run it from there:enum { MYTEXT = 1002, MYVALUE = 2000, MYCOMBOBUTTON = 2003, APPLYBUTTON = 2004, _End_ } class MyDialog : GeModalDialog { public: MyDialog(); CreateLayout(); Init(); Command(id, msg); } MyDialog::MyDialog() { super(); } MyDialog::CreateLayout() { SetTitle("My Dialog"); AddGroupBeginV(1000, BFH_SCALE|BFV_SCALE, 1, "", 0); { AddGroupBorder(BORDER_GROUP_IN); AddGroupBorderSpace(4,4,4,4); AddGroupSpace(4,4); AddGroupBeginV(1001, BFH_SCALE|BFV_SCALE, 2, "", 0); { AddStaticText(MYTEXT, BFH_LEFT, 0,0, "My Value", 0); AddEditNumberArrows(MYVALUE, BFH_SCALE, 80, 0); } AddGroupEnd(); AddComboBox(MYCOMBOBUTTON, BFH_SCALE|BFH_FIT, 0, 0); AddItem(MYCOMBOBUTTON, 0, "First"); AddItem(MYCOMBOBUTTON, 1, "Second"); AddItem(MYCOMBOBUTTON, 2, "Third"); AddButton(APPLYBUTTON, BFH_SCALE|BFH_FIT, 0, 0, "Apply"); AddDlgGroup(DR_DLGGROUP_OK); // Enter button AddDlgGroup(DR_DLGGROUP_CANCEL); // Cancel button } AddGroupEnd(); return; } MyDialog::Init() { SetInt(MYCOMBOBUTTON, 0, 0, 3, 1); SetPercent(MYVALUE, 100.0, MINREAL, MAXREAL, 0.01); return; } MyDialog::Command(id, msg) { var child = GetInt(MYCOMBOBUTTON); //Gets the children of the combobutton switch (id == MYCOMBOBUTTON) { case 0: if(child == 0) { println("First Option Selected"); SetPercent(MYVALUE, 0.0, MINREAL, MAXREAL, 0.01); } break; case 1: if(child == 1) { println("Second Option Selected"); SetPercent(MYVALUE, 500.0, MINREAL, MAXREAL, 0.01); } case 2: if(child == 2) { println("Third Option Selected"); SetPercent(MYVALUE, 100.0, MINREAL, MAXREAL, 0.01); } } if(id == APPLYBUTTON) { println("You Cliked the Apply Button"); } return; } main(doc,op) { var dlg = new(MyDialog); var result = dlg->Open(-1, -1); }
-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 14:13, xxxxxxxx wrote:
Thanks a lot! This is really a great help!
I figured that .res files are out of place here. I only wanted to use them because ResEdit was a much better way to make the interface than doing all the stuff in code imo. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 14:47, xxxxxxxx wrote:
One more question. May be a bit noobish but how do I get variables that I set in MyDialog::Command in the main function? I announced them in public but I get an error when I call them in the main function.
I put my script into the main function which is right way to do it I guess?
It does work but I just don't get any variables that I have set with, f.e. a button. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 14:50, xxxxxxxx wrote:
One of the things that I found out the hard way is that even full blown, registered dialog based plugins, do not always support the .res file items. The support for .res files in these types of plugins is limited.
What makes this even more confusing is that the SDK recommends using .res files with dialog plugins. Which often don't work together.The members here have schooled me on this.
The basic rule of thumb is:
Dialog plugins : Rely heavily on the AddItem() functions..Not the .res files.
Tag & Object plugins: Rely mostly on the .res files.I personally use .res files in my dialog type plugins. But mostly out of habit.
The truth is I probably don't need it them in there 99% of the time.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 15:00, xxxxxxxx wrote:
Originally posted by xxxxxxxx
how do I get variables that I set in MyDialog::Command in the main function?
Hard to say without seeing your code.
But if you're doing something similar to my example. The main section is only used to execute the dialog. And you don't generally put any code in that section.In this case. Variables need to declared globally at the top. Or better yet within the dialog's class as class members.
Then you assign those variables to the various GUI gizmos in the CreateLayout() & Init() methods.
Then you call to them from the Command() method to get/set their values.Not to sound like a broken record. !
Wink
[URL-REMOVED]
But I think the 9.5SDK examples show examples of this kind of thing.-ScottA
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 15:34, xxxxxxxx wrote:
I figured
I don't get any errors anymore that I didn't announced the var but the string I added to it with clicking on the apply button don't get through to my test in the main function.
Problem is, if I not put the code into the main function. I get those odd errors again for some of my variables that "a variable or function is expected"Here is the code. It gets the position and rotation of the current object and gives them out into a text file (in the format of how AE is reading ascii keyframes). Plus your code of course, I actually just pasted my stuff into it, just to test if I can get the basics to work
And yes I downloaded the 9.5 SDK and I am looking through it but haven't found an answer to that yet
var test; enum { MYTEXT = 1002, MYVALUE = 2000, MYCOMBOBUTTON = 2003, APPLYBUTTON = 2004, _End_ } class MyDialog : GeModalDialog { public: MyDialog(); var stored_x, stored_y, stored_z; CreateLayout(); Init(); Command(id, msg); } MyDialog::MyDialog() { super(); } MyDialog::CreateLayout() { SetTitle("Scale Units"); AddGroupBeginV(1000, BFH_SCALE|BFV_SCALE, 1, "", 0); { AddGroupBorder(BORDER_GROUP_IN); AddGroupBorderSpace(4,4,4,4); AddGroupSpace(4,4); AddGroupBeginV(1001, BFH_SCALE|BFV_SCALE, 2, "", 0); { AddStaticText(MYTEXT, BFH_LEFT, 0,0, "X", 0); AddEditNumberArrows(MYVALUE, BFH_SCALE, 80, 0); } AddGroupEnd(); AddComboBox(MYCOMBOBUTTON, BFH_SCALE|BFH_FIT, 0, 0); AddItem(MYCOMBOBUTTON, 0, "First"); AddItem(MYCOMBOBUTTON, 1, "Second"); AddItem(MYCOMBOBUTTON, 2, "Third"); AddButton(APPLYBUTTON, BFH_SCALE|BFH_FIT, 0, 0, "Apply"); AddDlgGroup(DR_DLGGROUP_OK); // Enter button AddDlgGroup(DR_DLGGROUP_CANCEL); // Cancel button } AddGroupEnd(); return; } MyDialog::Init() { SetInt(MYCOMBOBUTTON, 0, 0, 3, 1); SetPercent(MYVALUE, 100.0, MINREAL, MAXREAL, 0.01); return; } MyDialog::Command(id, msg) { var child = GetInt(MYCOMBOBUTTON); //Gets the children of the combobutton switch (id == MYCOMBOBUTTON) { case 0: if(child == 0) { println("First Option Selected"); SetPercent(MYVALUE, 0.0, MINREAL, MAXREAL, 0.01); } break; case 1: if(child == 1) { println("Second Option Selected"); SetPercent(MYVALUE, 500.0, MINREAL, MAXREAL, 0.01); } case 2: if(child == 2) { println("Third Option Selected"); SetPercent(MYVALUE, 100.0, MINREAL, MAXREAL, 0.01); } } if(id == APPLYBUTTON) { println("You Clicked the Apply Button"); var test = "Test"; } return; } main(doc,op) { var dlg = new(MyDialog); var result = dlg->Open(-1, -1); var userEndTime = 90; //Change this value to record the number of frames to print var obj = doc->GetActiveObject(); if(!obj)return FALSE; //NOTE*: Use "False" for older C4d versions!!! var arr = new(array,userEndTime); //The array that holds the vector positions of the object var arr2 = new(array,userEndTime); var frames = new(array,userEndTime); //The array that holds the frame number the scrubber is on CallCommand(12501); // set the time slider to zero var i = 0; for(i=0; i<userEndTime; i++) { var frame = doc->GetTime()->GetFrame(doc->GetFps()); //Get the current frame frames[i] = int(frame); var pos = obj->GetPosition(); arr[i] = pos; var rot = obj->GetRelRot()*57.2957795; arr2[i] = rot; CallCommand(12414); // Goto Next Frame var redraw = DrawViews(DA_STATICBREAK); EventAdd(EVENT_ANIMATE); } CallCommand(12501); // set the time slider back to zero var text = doc->GetFilename(); text->SetFullString("C:/wsd"); are used if(!GeFileExist(text,TRUE))GeFileCreateDir(text); text->AddLast("Positions.rtf"); var file=new(BaseFile); var newline = "\n"; var AE_Header = "Adobe After Effects 8.0 Keyframe Data\n Units Per Second 23.889\n Source Width 640\n Source Height 360\n Source Pixel Aspect Ratio 1\n Comp Pixel Aspect Ratio 1\nTransform Position\n Frame X pixels Y pixels Z pixels \n"; var AE_Footer = "End of Keyframe Data"; var AE_Orient = "Transform Orientation\n Frame X degrees \n"; var tab = " "; var j; file->Open(text,GE_APPEND); file->WriteString(AE_Header); file->Close(); for(j=0; j<userEndTime; j++) { var myframes = stradd(tostring(frames[j])," "); var coord = stradd(tostring(arr[j].x,".1f")," ",tostring(arr[j].y,".1f")," ",tostring(arr[j].z,".1f"),tostring(newline)); if(!file->Open(text,GE_APPEND)) { file->WriteString(tab); file->WriteString(myframes); file->WriteString(coord); file->Close(); } file->WriteString(tab); file->WriteString(myframes); file->WriteString(coord); file->Close(); } file->Open(text,GE_APPEND); file->WriteString(AE_Orient); file->Close(); for(j=0; j<userEndTime; j++) { var myframes = stradd(tostring(frames[j])," "); var rotation = stradd(tostring(arr2[j].x,".1f")," ",tostring(arr2[j].y,".1f")," ",tostring(arr2[j].z,".1f"),tostring(newline)); if(!file->Open(text,GE_APPEND)) { file->WriteString(tab); file->WriteString(myframes); file->WriteString(rotation); file->Close(); } file->WriteString(tab); file->WriteString(myframes); file->WriteString(rotation); file->Close(); } file->Open(text,GE_APPEND); file->WriteString(AE_Footer); file->WriteString(test); file->Close(); }
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 18/07/2012 at 18:48, xxxxxxxx wrote:
I'm assuming that all you want to do is click a button and save the active object's data to a file?
So I'm going to remove the other GUI stuff in this example and just use a single button to make the code shorter.There's a bunch of different ways to do this:
-One way is to take your entire code and plop it under the button code. So when the button gets pressed. It runs the whole shebang.
-Another way is to put only the bare minimum code you need under the button. Then put everything else above it in the Command method(that's what I did).
-Another way is to create your own custom methods. Then call to them as needed in the button code.
This is the most OOP method and the cleanest way of working.
I don't like to preach about using a certain style. It's a matter of your own personal choice how you prefer to work.Here is your re-worked code:
var test; enum { APPLYBUTTON = 2004, _End_ } class MyDialog : GeModalDialog { public: MyDialog(); CreateLayout(); Init(); Command(id, msg); } MyDialog::MyDialog() { super(); } MyDialog::CreateLayout() { SetTitle("My Dialog"); AddButton(APPLYBUTTON, BFH_SCALE|BFH_FIT, 50, 50, "Apply"); return; } MyDialog::Init() { return; } MyDialog::Command(id, msg) { var userEndTime = 90; //Change this value to record the number of frames to print var doc = GetActiveDocument(); var obj = doc->GetActiveObject(); if(!obj)return FALSE; //NOTE*: Use "False" for older C4d versions!!! var arr = new(array,userEndTime); //The array that holds the vector positions of the object var arr2 = new(array,userEndTime); var frames = new(array,userEndTime); //The array that holds the frame number the scrubber is on CallCommand(12501); // set the time slider to zero var i = 0; for(i=0; i<userEndTime; i++) { var frame = doc->GetTime()->GetFrame(doc->GetFps()); //Get the current frame frames[i] = int(frame); var pos = obj->GetPosition(); arr[i] = pos; var rot = obj->GetRelRot()*57.2957795; arr2[i] = rot; CallCommand(12414); // Goto Next Frame var redraw = DrawViews(DA_STATICBREAK); EventAdd(EVENT_ANIMATE); } CallCommand(12501); // set the time slider back to zero var file=new(BaseFile); //Creates an instance of the new file class var text = doc->GetFilename(); //Assign the filename function to a variable text->SetFullString("C:/wsd"); //The folder name that holds the file *Note the way back slashes are used if(!GeFileExist(text,TRUE))GeFileCreateDir(text); //Creates the folder if it doesn't already exist text->AddLast("Positions.rtf"); //The file's name and file type extension var newline = "\n"; //Start a new text line var AE_Header = "Adobe After Effects 8.0 Keyframe Data\n Units Per Second 23.889\n Source Width 640\n Source Height 360\n Source Pixel Aspect Ratio 1\n Comp Pixel Aspect Ratio 1\nTransform Position\n Frame X pixels Y pixels Z pixels \n"; var AE_Footer = "End of Keyframe Data"; var AE_Orient = "Transform Orientation\n Frame X degrees \n"; var tab = " "; var j; if(id == APPLYBUTTON) { println("You Clicked the Apply Button"); file->Open(text,GE_APPEND); file->WriteString(AE_Header); for(j=0; j<userEndTime; j++) { var myframes = stradd(tostring(frames[j])," "); var coord = stradd(tostring(arr[j].x,".1f")," ",tostring(arr[j].y,".1f")," ",tostring(arr[j].z,".1f"),tostring(newline)); file->WriteString(tab); file->WriteString(myframes); file->WriteString(coord); } file->Close(); } return; } main(doc,op) { var dlg = new(MyDialog); var result = dlg->Open(-1, -1); };
You had a whole bunch of repeating stuff going on. And I don't know If I missed anything in my re-write. But hopefully you'll get the picture how it all flows. And what goes where.
When writing to text files. I recommend not opening and closing the file multiple times throughout the code if you can help it. Because it's time consuming and you might run into errors doing that.
Try to gather all of your data ahead of time so that when it comes time to writing it to the file. You only open & close the file once. Or at least as few times as possible.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 19/07/2012 at 04:02, xxxxxxxx wrote:
Ugh, that makes it clear now
And Method 2 is even the they way I wanted it to be in the end
I still don't now why I got thoses errors. I actually tried method one, I guess I should take a deeper look at it after work.
Oh and it wasn't repeated code, it was the rotation and the footer you removed
I will have some more input controls but I think I can do that now, I was just missing this damn connection between my code and the guiThanks a lot again. You were a great help!
E: Ah, you meant the double
} file->WriteString(tab); file->WriteString(myframes); file->WriteString(coord); file->Close(); }
For some reason it only worked at some point when I did that twice :S
I think I messed something up which I resolved without knowing at a later point, it's really unnecessary. -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 19/07/2012 at 08:29, xxxxxxxx wrote:
Ok I got most of my UI working. Only one problem persists. I'm sure its unrelated to the GUI but I don't want to open a new thread for that.
ForMyDialog::Command(id, msg) { var MaxTime = doc->GetMaxTime();
I get [FAIL] Script 'Keyframe Exporter' Line 62 Pos 20 : Variable or function expected
Doesn't matter what I use GetTime or GetFPS etc. I always get this error and I have no idea why
Those var's work just fine later in the script.
For example:var frame = doc->GetTime()->GetFrame(doc->GetFps());
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 19/07/2012 at 08:50, xxxxxxxx wrote:
Hard to say based on that short amount of code.
But my first guess is that the problem is coming because "doc" is not defined yet in the Command method's code block.I don't know how much you know about how the methods work in these plugins.
But put very simply. If a variable is not listed in the params. You have to define the variable yourself.
MyDialog::Command(id, msg) does not have "doc" in it. So you have to define it in the Command methods code block like this: var doc = GetActiveDocument();P.S.- I don't know if you know this. But Coffee is basically dead. And hasn't been updated much for a long time now.
Coffee is a great first step towards learning C++. But Python is the future of scripting in C4D. So I would switch to that language if possible. It will make your life much easier down the road.
I never use Coffee anymore myself. Just C++ & Python.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 19/07/2012 at 08:54, xxxxxxxx wrote:
Ugh, I'm just stupid.
I didn't put var doc = GetActiveDocument(); onto the top, so everything above got an error ofcourseI know that COFFEE isn't the way to go anymore but I don't know anything about python and my C++ knowledge isn't advanced enough imo. Also it seems like you basically have to use Visual Studio or Xcode for C++ plugins and I absolutley hate both IDEs