Peter Z Posted October 30, 2023 Share Posted October 30, 2023 Hi everybody, I want to create some sort of "old file transformer script", because I have several files with an old class structure, that I changed now. So what I want to archive is a script, that deletes specific classes and puts all the objects on that class into another specific class. Basically the same way the inbuilt class delete function is set up, but I want to do multiple classes in one go. I'm asking, because the function VS:DelClass will automatically put all objects of the deleted class into the none class. Or is there a different way? Quote Link to comment
MullinRJ Posted October 30, 2023 Share Posted October 30, 2023 Hello @Peter Z, Yes, you can use RenameClass(oldname, newname). The real work in your question is the interface. Probably the simplest way would be to create a text file with a list of old and new names then write a script to read and process it. Not sexy but not too hard to code. A fancy dialog based UI will be 99% dialog programming, and 1% code execution. Unless this is a chore that you expect to repeat a lot, KISS. Raymond Quote Link to comment
Peter Z Posted October 30, 2023 Author Share Posted October 30, 2023 Hi @MullinRJ, that approach makes sense, but if i want to rename the class into a name that already exists, dosn't it create a class with that name and adds a 2? Because I would also use it, if I add an object or symbol from an old file into a new one, which already uses my new class structure. Yes the interface will be another topic, but I'll think about that when I get there 😄 Quote Link to comment
JBenghiat Posted October 30, 2023 Share Posted October 30, 2023 Assuming you have a list of old classes that map to new classes, and you have a means to traverse them (if you switch to python, you can use a dict). Classes have handles, so for each old name, see if GetObject returns a handle. If the handle exists but does not refer to a class, you need to either generate a warning or handle the name conflict in some way. Otherwise continue: Try to get a handle for the new class name. If it does not exist, simply rename the old class to the new class. If the new class name exists but does not refer to a class, handle the conflict by either alerting the user or modifying the new class name until it is valid Once you have a valid name for the new class, do a ForEachObject with deep traversal and change any objects that use the old class to use the new class. 2 Quote Link to comment
MullinRJ Posted October 30, 2023 Share Posted October 30, 2023 Hello @Peter Z, If you want to use an existing name, you would need to go through the document and change all objects existing in the old class to the new (existing) class. This can be achieved with: ForEachObject() and ForEachObject(). Here is a quickly crafted script to change one class to another. USE WITH CAUTION AND ALWAYS USE ON A COPY FIRST. PROCEDURE ChangeClassNames; { Change the name of a class to a new name. If objects exist in the OLD class, then } { change the Class Name of all objects in the document, and in the symbol library, } { that have an existing class name of kOldClass to the new class name kNewClass. } { THIS SCRIPT IS VERY LIGHTLY TESTED! } { TRY ON A COPY OF YOUR FILE AND CHECK RESULTS CARFEFULLY BEFORE PROCEEDING! } { 30 OCT 2023 — RAYMOND MULLIN } CONST kOldClass = 'oldClassName'; kNewClass = 'newClassName'; CR = c_h_r(13); { *** remove "_" characters before use *** } VAR LCnt, SCnt :Longint; procedure ChangeClass(H :Handle); { Change the class name to class kNewClass. } Begin SetClass(H, kNewClass); LCnt := LCnt + 1; End; { ChangeClass } function ChangeClass1(H :Handle) :Boolean; { Change the class name of any object that has a class of kOldClass to class kNewClass. } Begin if (GetClass(H) = kOldClass) then begin SetClass(H, kNewClass); SCnt := SCnt + 1; end; { if } End; { ChangeClass1 } BEGIN LCnt := 0; { count of changed objects on layers } SCnt := 0; { count of changed objects in symbols } if (GetObject(kNewClass) = nil) then { if New Class Name does not exist } RenameClass(kOldClass, kNewClass) else begin { if New Class Name exists } ForEachObject(ChangeClass, (C=kOldClass)); { change class name of all objects placed in document } ForEachObjectInList(ChangeClass1, 0, 2, FSymDef); { change class name of all objects in SymDef list } AlrtDialog(concat('# of objects on layers changed: ', LCnt, CR, '# of objects in symbols changed: ', SCnt, CR, 'Total objects changed: ', LCnt + SCnt)); end; { if / else } {DelClass(kOldClass);} { delete Old Class Name when done – OPTIONAL } SysBeep; { make noise when done } END; Run(ChangeClassNames); HTH, Raymond Quote Link to comment
MullinRJ Posted October 30, 2023 Share Posted October 30, 2023 @JBenghiat brings up a good point. You also have to test if a name conflict is with a Class Name or a name to another resource or object. The code I posted does not resolve that, and assumes the name in conflict is another Class Name. If you need help modifying the code, please write back, or have at it. You may modify the code above to your liking. Raymond Quote Link to comment
Peter Z Posted November 5, 2023 Author Share Posted November 5, 2023 Hi guys, first of all thanks for your replies, you are absolutely mad. @MullinRJ Thanks for the script. I tested it and it worked flawlessly. I am also trying to figure out what you did in the script. Thanks for the detailed comments. Now as I said, I want to do it for multiple classes at once. Would you put the whole script in a loop and iterate through all the classes in a list, or is there a more elegant approach? Side note: I definitely know which classes are coming in and where they should go, I don't have to account for any uncertainties. Quote Link to comment
MullinRJ Posted November 5, 2023 Share Posted November 5, 2023 2 hours ago, Peter Z said: Would you put the whole script in a loop and iterate through all the classes in a list, or is there a more elegant approach? Yes, I would build a list of class names and their replacements, then iterate through the list. There may be a more elegant approach, but none comes to mind. There are many ways to build the list, and that may be where you achieve elegance. You'll want to restructure the example program to make the main loop into a procedure that you call for each item in your list, passing it the new and old class names. ForEachObjectInList() will do most of the heavy lifting. If you have any questions about the existing example, please write back. All the best, Raymond Quote Link to comment
Jesse Cogswell Posted November 5, 2023 Share Posted November 5, 2023 There's not a great way to go about being able to handle multiple classes at a time without writing a dialog box. So I did. It basically builds an array of classes (sorted alphabetically) and populates a List Browser on the left and a List Box on the right. When you select a class on the left, it will jump to the List Box to select the new class. When a class is selected in the List Box, it adds it to the selected row in the List Browser and makes the choice ineligible to be selected in the List Browser. Likewise, it will remove the original class from the List Box, so you can't convert in circles. There's also an option to delete the original class by clicking on the Delete column of the List Browser (with code to prevent the None and Dimension class from being deleted). Code is pasted below. List Browsers are fairly complicated and are tedious to code, but there's a terrific primer here: https://developer.vectorworks.net/index.php/User:CBM-c-/VS-List_Browsers_part_1 PROCEDURE ClassTransformer; {* Converts objects in one class to a different class with options to delete original class Developed by: Jesse Cogswell VW Version: 24 (VW2019) Date: 11/5/2023 Revisions: *} VAR dialog,layoutDialog:LONGINT; classArray:DYNARRAY[] OF STRING; PROCEDURE BuildClassArray; {Builds array of class names and sorts alphabetically} VAR i:INTEGER; BEGIN ALLOCATE classArray[1..ClassNum]; FOR i:=1 TO ClassNum DO classArray[i]:=ClassList(i); SortArray(classArray,ClassNum,0); END; PROCEDURE TransformClass(origClass,targetClass:STRING; deleteClass:BOOLEAN); {Converts objects in origClass to given targetClass, deletes origClass if deleteClass is TRUE} CONST kSymbolDef = 16; kNone = 'None'; kDim = 'Dimension'; VAR resList,numItems:LONGINT; i,insertMode,breakMode:INTEGER; currentClass:STRING; PROCEDURE TransformObjectClass(h:HANDLE); {Converts class of given object to targetClass} BEGIN SetClass(h,targetClass); END; BEGIN ForEachObject(TransformObjectClass,(INSYMBOL & INOBJECT & INVIEWPORT & (C = origClass))); resList:=BuildResourceList(kSymbolDef,0,'',numItems); FOR i:=1 TO numItems DO BEGIN GetSymbolOptionsN(GetNameFromResourceList(resList,i),insertMode,breakMode,currentClass); IF(currentClass = origClass) THEN SetSymbolOptionsN(GetNameFromResourceList(resList,i),insertMode,breakMode,targetClass); END; IF((deleteClass) & (origClass <> kNone) & (origClass <> kDim)) THEN DelClass(origClass); END; FUNCTION DrawDialog(DName:STRING) : LONGINT; {Creates dialog box} CONST kLBWidth = 100; kLBHeight = 50; kListBoxWidth = 50; VAR dia:LONGINT; BEGIN dia:=CreateLayout(DName,FALSE,'OK','Cancel'); CreateLB(dia,11,kLBWidth,kLBHeight); CreateListBoxN(dia,21,kListBoxWidth,kLBHeight,FALSE); CreateGroupBox(dia,101,'Transform From',TRUE); CreateGroupBox(dia,102,'Transform To',TRUE); SetFirstGroupItem(dia,101,11); SetFirstGroupItem(dia,102,21); SetFirstLayoutItem(dia,101); SetRightItem(dia,101,102,0,0); DrawDialog:=dia; END; PROCEDURE DialogHandler(VAR item,data:LONGINT); {Handles dialog interaction} CONST kColWidth = 235; kColor = 255 * 0.6; VAR i,colNum,kImageCheck,kImageBlank,BSI,choiceCounter,selRow,textOpacity:INTEGER; origClass,targetClass,BSS:STRING; deleteClass,BSB:BOOLEAN; BEGIN CASE item OF SetupDialogC: BEGIN kImageCheck:=AddListBrowserImage(dialog,11,'Vectorworks/Standard Images/Checkmark.png'); kImageBlank:=AddListBrowserImage(dialog,11,'Vectorworks/Standard Images/Blank.png'); colNum:=InsertLBColumn(dialog,11,0,'Select',50); BSB:=SetLBControlType(dialog,11,colNum,5); BSB:=SetLBItemDisplayType(dialog,11,colNum,1); colNum:=InsertLBColumn(dialog,11,1,'Class',kColWidth); BSB:=SetLBControlType(dialog,11,colNum,1); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumn(dialog,11,2,'Transform Class',kColWidth); BSB:=SetLBControlType(dialog,11,colNum,1); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumn(dialog,11,3,'Delete',50); BSB:=SetLBControlType(dialog,11,colNum,3); BSB:=SetLBItemDisplayType(dialog,11,colNum,1); colNum:=InsertLBColumn(dialog,11,4,'Eligible',0); BSB:=SetLBControlType(dialog,11,colNum,5); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumnDataItem(dialog,11,0,'Checked',kImageCheck,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,0,'Unchecked',kImageBlank,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,3,'Checked',kImageCheck,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,3,'Unchecked',kImageBlank,-1,0); AddChoice(dialog,21,'No Transformation',0); BuildClassArray; FOR i:=1 TO ClassNum DO BEGIN colNum:=InsertLBColumnDataItem(dialog,11,1,classArray[i],0,0,0); BSI:=InsertLBItem(dialog,11,colNum,classArray[i]); BSB:=SetLBItemUsingColumnDataItem(dialog,11,colNum,1,colNum); AddChoice(dialog,21,classArray[i],i); END; EnableLBColumnLines(dialog,11,TRUE); BSB:=EnableLBSingleLineSelection(dialog,11,TRUE); END; 1: {OK} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,0,BSS,BSI); IF(BSI = kImageCheck) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,i,1,origClass,BSI); BSB:=GetLBItemInfo(dialog,11,i,2,targetClass,BSI); BSB:=GetLBItemInfo(dialog,11,i,3,BSS,BSI); deleteClass:=(BSI = kImageCheck); TransformClass(origClass,targetClass,deleteClass); END; END; ReDrawAll; END; 2: {Cancel} BEGIN END; 11: {List Browser} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO IF(IsLBItemSelected(dialog,11,i)) THEN selRow:=i; DeleteAllItems(dialog,21); AddChoice(dialog,21,'No Transformation',0); choiceCounter:=1; FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,0,BSS,BSI); IF(BSI <> kImageCheck) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,i,1,BSS,BSI); AddChoice(dialog,21,BSS,choiceCounter); choiceCounter:=choiceCounter + 1; END; END; BSB:=GetLBItemInfo(dialog,11,selRow,4,BSS,BSI); IF(BSI = 0) THEN BEGIN DeleteAllItems(dialog,21); EnableItem(dialog,21,FALSE); END ELSE EnableItem(dialog,21,TRUE); BSB:=GetLBItemInfo(dialog,11,selRow,2,BSS,BSI); IF(BSS = '') THEN SelectChoice(dialog,21,0,TRUE) ELSE BEGIN GetChoiceIndex(dialog,21,BSS,BSI); SelectChoice(dialog,21,BSI,TRUE); END; END; 21: {List Box} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO IF(ISLBItemSelected(dialog,11,i)) THEN selRow:=i; GetSelectedChoiceInfo(dialog,21,0,BSI,targetClass); IF(BSI <> 0) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,selRow,1,origClass,BSI); IF(origClass <> targetClass) THEN BEGIN BSB:=SetLBItemInfo(dialog,11,selRow,0,'Checked',kImageCheck); BSB:=SetLBItemInfo(dialog,11,selRow,2,targetClass,0); BSB:=FindLBColumnItem(dialog,11,1,targetClass,BSI); END ELSE SelectChoice(dialog,21,0,TRUE); END; END; END; {Cleanup List Browser} FOR i:=0 TO GetNumLBItems(dialog,11) DO BSB:=SetLBItemInfo(dialog,11,i,4,'',1); FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,2,BSS,BSI); IF(BSS <> '') THEN BEGIN BSB:=FindLBColumnItem(dialog,11,1,BSS,BSI); BSB:=SetLBItemInfo(dialog,11,BSI,4,'',0); END; END; FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,4,BSS,BSI); IF(BSI <> 0) THEN textOpacity:=0 ELSE textOpacity:=kColor; BSB:=SetLBItemTextColor(dialog,11,i,1,textOpacity,textOpacity,textOpacity); END; END; BEGIN dialog:=DrawDialog('Class Transformer'); layoutDialog:=RunLayoutDialog(dialog,DialogHandler); END; Run(ClassTransformer); There's some funky things in there to handle the error checking between the two boxes. If you would like, I can give you a simpler example with all of that code removed if you're okay with throwing caution to the wind. Let me know if you have any questions. 1 Quote Link to comment
Jesse Cogswell Posted November 6, 2023 Share Posted November 6, 2023 I discovered a small bug with my code pasted above, once you selected a class to transform into, you weren't able to set it back to "No transformation". That is corrected below: PROCEDURE ClassTransformer; {* Converts objects in one class to a different class with options to delete original class Developed by: Jesse Cogswell VW Version: 24 (VW2019) Date: 11/5/2023 Revisions: *} VAR dialog,layoutDialog:LONGINT; classArray:DYNARRAY[] OF STRING; PROCEDURE BuildClassArray; {Builds array of class names and sorts alphabetically} VAR i:INTEGER; BEGIN ALLOCATE classArray[1..ClassNum]; FOR i:=1 TO ClassNum DO classArray[i]:=ClassList(i); SortArray(classArray,ClassNum,0); END; PROCEDURE TransformClass(origClass,targetClass:STRING; deleteClass:BOOLEAN); {Converts objects in origClass to given targetClass, deletes origClass if deleteClass is TRUE} CONST kSymbolDef = 16; kNone = 'None'; kDim = 'Dimension'; VAR resList,numItems:LONGINT; i,insertMode,breakMode:INTEGER; currentClass:STRING; PROCEDURE TransformObjectClass(h:HANDLE); {Converts class of given object to targetClass} BEGIN SetClass(h,targetClass); END; BEGIN ForEachObject(TransformObjectClass,(INSYMBOL & INOBJECT & INVIEWPORT & (C = origClass))); resList:=BuildResourceList(kSymbolDef,0,'',numItems); FOR i:=1 TO numItems DO BEGIN GetSymbolOptionsN(GetNameFromResourceList(resList,i),insertMode,breakMode,currentClass); IF(currentClass = origClass) THEN SetSymbolOptionsN(GetNameFromResourceList(resList,i),insertMode,breakMode,targetClass); END; IF((deleteClass) & (origClass <> kNone) & (origClass <> kDim)) THEN DelClass(origClass); END; FUNCTION DrawDialog(DName:STRING) : LONGINT; {Creates dialog box} CONST kLBWidth = 100; kLBHeight = 50; kListBoxWidth = 50; VAR dia:LONGINT; BEGIN dia:=CreateLayout(DName,FALSE,'OK','Cancel'); CreateLB(dia,11,kLBWidth,kLBHeight); CreateListBoxN(dia,21,kListBoxWidth,kLBHeight,FALSE); CreateGroupBox(dia,101,'Transform From',TRUE); CreateGroupBox(dia,102,'Transform To',TRUE); SetFirstGroupItem(dia,101,11); SetFirstGroupItem(dia,102,21); SetFirstLayoutItem(dia,101); SetRightItem(dia,101,102,0,0); DrawDialog:=dia; END; PROCEDURE DialogHandler(VAR item,data:LONGINT); {Handles dialog interaction} CONST kColWidth = 238; kColor = 255 * 0.6; VAR i,colNum,kImageCheck,kImageBlank,BSI,choiceCounter,selRow,textOpacity:INTEGER; origClass,targetClass,BSS:STRING; deleteClass,BSB:BOOLEAN; BEGIN CASE item OF SetupDialogC: BEGIN kImageCheck:=AddListBrowserImage(dialog,11,'Vectorworks/Standard Images/Checkmark.png'); kImageBlank:=AddListBrowserImage(dialog,11,'Vectorworks/Standard Images/Blank.png'); colNum:=InsertLBColumn(dialog,11,0,'Select',50); BSB:=SetLBControlType(dialog,11,colNum,5); BSB:=SetLBItemDisplayType(dialog,11,colNum,1); colNum:=InsertLBColumn(dialog,11,1,'Class',kColWidth); BSB:=SetLBControlType(dialog,11,colNum,1); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumn(dialog,11,2,'Transform Class',kColWidth); BSB:=SetLBControlType(dialog,11,colNum,1); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumn(dialog,11,3,'Delete',50); BSB:=SetLBControlType(dialog,11,colNum,3); BSB:=SetLBItemDisplayType(dialog,11,colNum,1); colNum:=InsertLBColumn(dialog,11,4,'Eligible',0); BSB:=SetLBControlType(dialog,11,colNum,5); BSB:=SetLBItemDisplayType(dialog,11,colNum,0); colNum:=InsertLBColumnDataItem(dialog,11,0,'Checked',kImageCheck,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,0,'Unchecked',kImageBlank,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,3,'Checked',kImageCheck,-1,0); colNum:=InsertLBColumnDataItem(dialog,11,3,'Unchecked',kImageBlank,-1,0); AddChoice(dialog,21,'No Transformation',0); BuildClassArray; FOR i:=1 TO ClassNum DO BEGIN colNum:=InsertLBColumnDataItem(dialog,11,1,classArray[i],0,0,0); BSI:=InsertLBItem(dialog,11,colNum,classArray[i]); BSB:=SetLBItemUsingColumnDataItem(dialog,11,colNum,1,colNum); AddChoice(dialog,21,classArray[i],i); END; EnableLBColumnLines(dialog,11,TRUE); BSB:=EnableLBSingleLineSelection(dialog,11,TRUE); END; 1: {OK} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,0,BSS,BSI); IF(BSI = kImageCheck) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,i,1,origClass,BSI); BSB:=GetLBItemInfo(dialog,11,i,2,targetClass,BSI); BSB:=GetLBItemInfo(dialog,11,i,3,BSS,BSI); deleteClass:=(BSI = kImageCheck); TransformClass(origClass,targetClass,deleteClass); END; END; ReDrawAll; END; 2: {Cancel} BEGIN END; 11: {List Browser} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO IF(IsLBItemSelected(dialog,11,i)) THEN selRow:=i; DeleteAllItems(dialog,21); AddChoice(dialog,21,'No Transformation',0); choiceCounter:=1; FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,0,BSS,BSI); IF(BSI <> kImageCheck) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,i,1,BSS,BSI); AddChoice(dialog,21,BSS,choiceCounter); choiceCounter:=choiceCounter + 1; END; END; BSB:=GetLBItemInfo(dialog,11,selRow,4,BSS,BSI); IF(BSI = 0) THEN BEGIN DeleteAllItems(dialog,21); EnableItem(dialog,21,FALSE); END ELSE EnableItem(dialog,21,TRUE); BSB:=GetLBItemInfo(dialog,11,selRow,2,BSS,BSI); IF(BSS = '') THEN SelectChoice(dialog,21,0,TRUE) ELSE BEGIN GetChoiceIndex(dialog,21,BSS,BSI); SelectChoice(dialog,21,BSI,TRUE); END; END; 21: {List Box} BEGIN FOR i:=0 TO GetNumLBItems(dialog,11) DO IF(ISLBItemSelected(dialog,11,i)) THEN selRow:=i; GetSelectedChoiceInfo(dialog,21,0,BSI,targetClass); IF(BSI <> 0) THEN BEGIN BSB:=GetLBItemInfo(dialog,11,selRow,1,origClass,BSI); IF(origClass <> targetClass) THEN BEGIN BSB:=SetLBItemInfo(dialog,11,selRow,0,'Checked',kImageCheck); BSB:=SetLBItemInfo(dialog,11,selRow,2,targetClass,0); BSB:=FindLBColumnItem(dialog,11,1,targetClass,BSI); END ELSE SelectChoice(dialog,21,0,TRUE); END ELSE BEGIN BSB:=SetLBItemInfo(dialog,11,selRow,0,'Unchecked',1); BSB:=SetLBItemInfo(dialog,11,selRow,2,'',0); END; END; END; {Cleanup List Browser} FOR i:=0 TO GetNumLBItems(dialog,11) DO BSB:=SetLBItemInfo(dialog,11,i,4,'',1); FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,2,BSS,BSI); IF(BSS <> '') THEN BEGIN BSB:=FindLBColumnItem(dialog,11,1,BSS,BSI); BSB:=SetLBItemInfo(dialog,11,BSI,4,'',0); END; END; FOR i:=0 TO GetNumLBItems(dialog,11) DO BEGIN BSB:=GetLBItemInfo(dialog,11,i,4,BSS,BSI); IF(BSI <> 0) THEN textOpacity:=0 ELSE textOpacity:=kColor; BSB:=SetLBItemTextColor(dialog,11,i,1,textOpacity,textOpacity,textOpacity); END; END; BEGIN dialog:=DrawDialog('Class Transformer'); layoutDialog:=RunLayoutDialog(dialog,DialogHandler); END; Run(ClassTransformer); 1 2 Quote Link to comment
MullinRJ Posted November 6, 2023 Share Posted November 6, 2023 5 hours ago, Jesse Cogswell said: Code is pasted below. List Browsers are fairly complicated and are tedious to code, but there's a terrific primer here: https://developer.vectorworks.net/index.php/User:CBM-c-/VS-List_Browsers_part_1 God bless Carlotta !!! 😇 2 Quote Link to comment
Sam Jones Posted November 6, 2023 Share Posted November 6, 2023 5 hours ago, MullinRJ said: God bless Carlotta !!! 😇 I sooooo miss her! 2 Quote Link to comment
Jesse Cogswell Posted November 6, 2023 Share Posted November 6, 2023 15 hours ago, MullinRJ said: God bless Carlotta !!! 😇 Hear, hear! All of the old Vectorlab documentation is invaluable, and I've been using her Rosetta Stone article to help understand Python implementation in Vectorworks. I do wish it was easier to find her page on the wiki, though. I finally ended up making a bookmark so I could quickly get back to it without having to do a deep search of the wiki or track down one of her forum posts where she linked to one of the articles. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.