Jim Clayton Posted December 12, 2018 Posted December 12, 2018 So I'm very slowly learning Lisps and DCL. Currently I've been piecing a lot of other lisps and DCL's together to get what I'm after. I'm trying to make a DCL where when I make a selection, via check box, or tiles, or radio buttons, it jumps to a second page to make more selections. The ultimate goal is to filter through assembly types, narrow it down, then once it's narrowed down, insert a block or blocks if possible. But I haven't been able to find a clear explanation for the syntax. Would greatly appreciate some help on this. Tks. Quote
Lee Mac Posted December 12, 2018 Posted December 12, 2018 (edited) 3 hours ago, Jim Clayton said: I'm trying to make a DCL where when I make a selection, via check box, or tiles, or radio buttons, it jumps to a second page to make more selections. One method is to make use of the optional status argument for the done_dialog function in order to determine which dialog should be subsequently displayed by the application; this could also be achieved by setting 'flag' variables within the action_tile statements for each control. Consider the following DCL & AutoLISP program that I've quickly assembled as an example: options.dcl dia1 : dialog { spacer_1; label = "Dialog 1"; : boxed_column { label = "Choose an option"; : but { key = "b1"; label = "Option 1"; } : but { key = "b2"; label = "Option 2"; } : but { key = "b3"; label = "Option 3"; } spacer; } spacer; exit; } dia2 : dialog { spacer_1; label = "Dialog 2"; : boxed_radio_column { label = "Choose an option"; : radio_button { key = "r1"; label = "Option 1"; } : radio_button { key = "r2"; label = "Option 2"; } : radio_button { key = "r3"; label = "Option 3"; } spacer; } spacer; exit; } dia3: dialog { spacer_1; label = "Dialog 3"; : boxed_column { label = "Choose an option"; : list_box { key = "lst"; fixed_width = true; fixed_height = true; height = 10; width = 20; alignment = centered; } spacer; } spacer; exit; } but : button { width = 20; height = 2; fixed_width = true; fixed_height = true; alignment = centered; } exit : button { is_cancel = true; is_default = true; key = "cancel"; label = "Exit"; alignment = centered; fixed_width = true; } options.lsp (defun c:test ( / *error* but dcf dch dcl idx lst rad ) (setq dcl "options.dcl") (defun *error* ( msg ) (if (< 0 dch) (setq dch (unload_dialog dch))) (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*")) (princ (strcat "\nError: " msg)) ) (princ) ) (cond ( (not (findfile dcl)) (princ (strcat "\nPlease ensure the file \"" dcl "\" resides in an AutoCAD Support Path.")) ) ( (<= (setq dch (load_dialog dcl)) 0) (princ (strcat "\nUnable to load DCL file \"" dcl "\".")) ) ( t (while (not (member dcf '(1 4))) (cond ( (null dcf) (cond ( (not (new_dialog "dia1" dch)) (princ (strcat "\nUnable to display Dialog 1.")) (setq dcf 1) ) ( t (foreach key '("b1" "b2" "b3") (action_tile key "(setq but $key) (done_dialog 2)")) (setq dcf (start_dialog)) ) ) ) ( (= 2 dcf) (cond ( (not (new_dialog "dia2" dch)) (princ (strcat "\nUnable to display Dialog 2.")) (setq dcf 1) ) ( t (foreach key '("r1" "r2" "r3") (action_tile key "(setq rad $key) (done_dialog 3)")) (setq dcf (start_dialog)) ) ) ) ( (= 3 dcf) (cond ( (not (new_dialog "dia3" dch)) (princ (strcat "\nUnable to display Dialog 3.")) (setq dcf 1) ) ( t (start_list "lst") (foreach itm (setq lst '("Option 1" "Option 2" "Option 3")) (add_list itm)) (end_list) (action_tile "lst" "(setq idx $value) (done_dialog 4)") (setq dcf (start_dialog)) ) ) ) ) ) (if (= 4 dcf) (alert (strcat "The user selected:\n\n" "Button " (substr but 2) "\n" "Radio Button " (substr rad 2) "\n" "List Item " (nth (atoi idx) lst) ) ) (princ "\n*Cancel*") ) ) ) (if (< 0 dch) (setq dch (unload_dialog dch))) (princ) ) Edited December 12, 2018 by Lee Mac Quote
Grrr Posted December 12, 2018 Posted December 12, 2018 (edited) FWIW Alternative approach would be to initially display all the options in their glory, but disable all of them (except the first group) and then re-enable one by one: (defun C:test ( / *error* dcl des dch dcf keys i tmp lst btn radbtn lbitem ) (defun *error* ( msg ) (and (< 0 dch) (unload_dialog dch)) (and (eq 'FILE (type des)) (close des)) (and (eq 'STR (type dcl)) (findfile dcl) (vl-file-delete dcl)) (and msg (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\nError: " msg)))) (princ) ); defun *error* (and (setq dcl (vl-filename-mktemp nil nil ".dcl")) (setq des (open dcl "w")) (progn (foreach row '("test : dialog" "{ label = \"Choose Options\";" " spacer_1;" " : row" " {" " : boxed_column" " { label = \"Choose an option\";" " : button { key = \"b1\"; label = \"Option 1\"; }" " : button { key = \"b2\"; label = \"Option 2\"; }" " : button { key = \"b3\"; label = \"Option 3\"; }" " spacer;" " }" " : boxed_radio_column" " { label = \"Choose an option\";" " : radio_button { key = \"r1\"; label = \"Option 1\"; }" " : radio_button { key = \"r2\"; label = \"Option 2\"; }" " : radio_button { key = \"r3\"; label = \"Option 3\"; }" " spacer;" " }" " : boxed_column" " { label = \"Choose an option\";" " : list_box" " {" " key = \"lst\";" " fixed_width = true;" " fixed_height = true;" " height = 10;" " width = 20;" " multiple_select = true;" ; <- lets allow this " alignment = centered;" " }" " spacer;" " }" " }" " spacer_1; ok_cancel;" "}" ); list (princ (strcat "\n" row) des) ); foreach t ); progn (not (setq des (close des))) (< 0 (setq dch (load_dialog dcl))) (new_dialog "test" dch) (progn ; declare our list of grouped keys: (setq keys '(("b1" "b2" "b3")("r1" "r2" "r3")("lst"))) ; initially populate the list_box: (start_list "lst") (foreach itm (setq lst '("Option 1" "Option 2" "Option 3")) (add_list itm)) (end_list) ; this loop will disable all tiles, except the first group: (foreach group (cdr keys) (foreach key group (mode_tile key 1) ) ) ; this loop will assign actions to the keys in the N'th group, so they will unlock/enable the N+1'th group ; also will store the value from each key grop into an unique variable: (setq i 0) (foreach group keys (setq i (1+ i)) (foreach key group (action_tile key (strcat "(progn" "(foreach key " (if (setq tmp (strcase (vl-prin1-to-string (nth i keys)) t)) (strcat "'" tmp) "nil") " (mode_tile key 0)" ")" "(setq " (vl-prin1-to-string (nth i '(btn btn radbtn lbitem))) " (list $key $value))" ")" ); strcat ); action_tile ) ) (if (/= 1 (setq dcf (start_dialog))) (prompt "\nUser cancelled or terminated the dialog.") (alert (strcat "\nUser Selected: " "\nButton: " (cadr (assoc (car btn) '(("b1" "Option1")("b2" "Option2")("b3" "Option3")(nil "None")))) "\nRadio Button: " (cadr (assoc (car radbtn) '(("r1" "Option1")("r2" "Option2")("r3" "Option3")(nil "None")))) "\nList Item(s): " (cond ( (setq tmp (cadr lbitem)) "oh-noo! its the scary mapcar-lambda-apply part (DO NOT WORRY MUCH, WERE JUST DISPLAYING THE RESULT FROM THE LISTBOX!) :" (apply 'strcat (mapcar '(lambda (x) (strcat "\n" (nth x lst))) (read (strcat "(" tmp ")")))) ) ("None") ) ); strcat ); alert ); if ); progn ); and (*error* nil) (princ) ); defun Although the technique used in here won't temporarily hide the dialog, so you won't be able to prompt for any graphical inputs (like ssget / getpoint and so on). Also tried to make the syntax in a more easy-understandable way (almost no mapcars and lambdas) but I advise one to get drunk, then get mad at them and attempt to learn these scary functions Edited December 12, 2018 by Grrr Quote
Jim Clayton Posted December 13, 2018 Author Posted December 13, 2018 Mr. Mac/Grr, Thank you both for the help. I think I can probably make use of the layout from the first one and dissect it a bit if I run into a problem. I wasn't able to get the second one loaded for one reason or another...most likely user error. I am left with a few questions though that hopefully someone can answer. Keep in mind that I am still very ignorant to all of this. 1) If I make a DCL with "X" number of choices on page 1, and each option takes you to a separate page specified for that choice, is this a problem? 2) Would the increasing size/length of the above scenario (3 choices vs. 1,000 choices) cause any sort of issues, ie; computer lag. 3) This is related to the last intended function, inserting blocks. Am I able to insert more than one at a time? Seems like I've come across this before but I can't find an answer to it. So if the DCL had you make a selection, that took you to another page with a list box where you could add all the blocks that you wanted to insert, could you do that all at once? Thanks again to everyone for their help with all of this. It's very much appreciated. Quote
rlx Posted December 13, 2018 Posted December 13, 2018 (edited) 1) no 2) no 3) yes / yes When I want to make a dialog 1st thing I do is draw it in Autocad (unless I'm sitting on the toilet when creativity starts to flow, then I use a piece of paper , obviously , duh). I don't care about the coding (yet). How do you want your program to look , how do you want it to work , what way or which selection order would be logical for you and will you be the only one to use it or should a newbie (like Grrr) instantly be able to operate it? Design first , coding comes later. Edited December 19, 2018 by rlx Quote
Grrr Posted December 13, 2018 Posted December 13, 2018 19 minutes ago, rlx said: unless I'm sitting on the toilet when creativity starts to flow, then I use a piece of paper I hope you don't have to flush your creativity if the paper roll ends ! 22 minutes ago, rlx said: or should a newbie (like Grrr) instantly be able to operate it? Haha, thanks for the compliment, but I do actually sketch my dialogs on paper and sometimes write summary for every tile/control. For this thread I just checked Lee's suggestion and wrote an alternative (because I'm lazy reading long descriptive requests).. so without Lee's reply, there wouldn't be mine either. Quote
rlx Posted December 13, 2018 Posted December 13, 2018 2 minutes ago, Grrr said: I hope you don't have to flush your creativity if the paper roll ends ! Haha, thanks for the compliment, but I do actually sketch my dialogs on paper and sometimes write summary for every tile/control. For this thread I just checked Lee's suggestion and wrote an alternative (because I'm lazy reading long descriptive requests).. so without Lee's reply, there wouldn't be mine either. darn @#$&*....oh darling! I just ran out of paper haha. It just depends whether I'm @home or @work. @work I usually design on the pc , when I am home , sitting with my laptop on the couch I prefere a piece of paper beside me (and a glass of wine , burp) But if OP wants good advice a design would be helpfull cause one can lose him(her)self with the details of coding while a good design can make or break a program regardless how brilliant the coding is. Quote
Grrr Posted December 13, 2018 Posted December 13, 2018 8 minutes ago, rlx said: But if OP wants good advice a design would be helpfull cause one can lose him(her)self with the details of coding while a good design can make or break a program regardless how brilliant the coding is. I agree with that, as the only user for the things I write for myself, Few times I wrote dialogs with a nice coding and algorithms.. but it turned up that they weren't that user friendly - because from the user perspective I had.. ..so I had to rewrite them until it was clear and easy enough for me on how to use them. Specifically in here with OPs request On 12/12/2018 at 5:25 PM, Jim Clayton said: The ultimate goal is to filter through assembly types, narrow it down, then once it's narrowed down, insert a block or blocks if possible. I think that the keywords "filter", "narrow down" lead one into an iteration of arguments, till the end input (which is filtered). But the question is what kind of data the arguments are? I mean is it linear, or 2D (table), or hierarchical ? • if its linear, like a simple list then Lee's suggestion in here should work fine. • if its 2D/table (matrix list as I call it) then probably LM:ListBox within loop will be enough • for a hirearchical structure DCL List Tile Dependency Let me guess, you're after my listboxes sub aren't you? ;| ; aL - assoc list of: (label multi L) (ListBoxes "Select Stuff" 12 6 (list (list "First" T (mapcar 'chr (vl-string->list "ABCDEFGHIJKL"))) (list "Second" T (mapcar 'chr (vl-string->list "ABCDEFGHIJKL"))) (list "Third" T (mapcar 'chr (vl-string->list "ABCDEFGHIJKL"))) (list "Fourth" T (mapcar 'chr (vl-string->list "ABCDEFGHIJKL"))) (list "Fifth" T (mapcar 'chr (vl-string->list "ABCDEFGHIJKL"))) ) ) |; (defun ListBoxes ( msg w h aL / *error* dcl des dch dcf rtn i ) (defun *error* ( msg ) (and (< 0 dch) (unload_dialog dch)) (and (eq 'FILE (type des)) (close des)) (and (eq 'STR (type dcl)) (findfile dcl) (vl-file-delete dcl)) (and msg (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\nError: " msg)) )) (princ) ); defun *error* (setq i -1) (setq aL (mapcar '(lambda (x) (cons (itoa (setq i (1+ i))) x)) aL)) (and (setq dcl (vl-filename-mktemp nil nil ".dcl")) (setq des (open dcl "w")) (princ (strcat "ListBoxes : dialog " "{ label = \"" (if (eq 'STR (type msg)) msg "") "\"; spacer;" " : row" " {" (apply 'strcat (mapcar (function (lambda (key lbl multi) (strcat "\n" " : list_box { key = \"" key "\"; label = \"" lbl "\"; multiple_select = " (if multi "true" "false") "; allow_accept = false; width = " (itoa w) "; height = " (itoa h) "; }" ) ) ) (mapcar 'car aL) (mapcar 'cadr aL) (mapcar 'caddr aL) ) ) " }" " spacer; ok_cancel;" "}" ); strcat des ); princ (not (setq des (close des))) (setq dch (load_dialog dcl)) (new_dialog "ListBoxes" dch) (progn (mapcar (function (lambda (key L) (start_list key) (mapcar 'add_list L) (end_list) )) (mapcar 'car aL) (mapcar 'cadddr aL) ) (mapcar (function (lambda (key) (action_tile key (vl-prin1-to-string '(cond ( (assoc $key rtn) (setq rtn (subst (cons $key $value) (assoc $key rtn) rtn)) ) ( (setq rtn (cons (cons $key $value) rtn)) ) ); cond ); vl-prin1-to-string ); action_tile ); lambda ); function (mapcar 'car aL) ); mapcar (action_tile "accept" "(done_dialog 1)") ; (action_tile "LB" (vl-prin1-to-string '(setq rtn (mapcar '(lambda (x) (nth x L)) (read (strcat "(" $value ")")))))) (setq dcf (= 1 (start_dialog))) ); progn ); and (*error* nil) (if (and dcf rtn) (reverse (mapcar (function (lambda (k v) (list (cadr (assoc k aL)) (mapcar '(lambda (x) (nth x (cadddr (assoc k aL)))) (read (strcat "(" v ")")))) ); lambda ); function (mapcar 'car rtn) (mapcar 'cdr rtn) ); mapcar ); reverse ); if ); defun ListBoxes Example for your case: (defun C:test ( / f L tmp ) (setq f (lambda ( n ) (mapcar '(lambda (x) (strcat (itoa n) "-" (chr x))) (vl-string->list "ABCDEFGHIJKL")))) (setq L (list (list "First" (f 1)) (list "Second" (f 2)) (list "Third" (f 3)) (list "Fourth" (f 4)) (list "Fifth" (f 5)) ) ) (setq tmp L) (while (setq tmp (ListBoxes "Select Stuff" 12 12 (mapcar '(lambda (x) (append (list (car x) T) (cdr x)))(setq L tmp))))) (alert (apply 'strcat (cons "Choosen Items: " (mapcar '(lambda (x) (strcat "\n" (vl-prin1-to-string x))) L)))) (princ) ) The initial purpose for my subfunction was different, so understand why the cancel button was used as "final accept". Quote
rlx Posted December 13, 2018 Posted December 13, 2018 Oh wow Grrr , that's really original! Only thing I don't like is I didn't come up with this brilliant idea haha. Cool! Certainly a great way to narrow down a list of choices! Gonna play with it tomorrow...time to hit my bed... 1 Quote
Jim Clayton Posted December 14, 2018 Author Posted December 14, 2018 Thanks for the help. Still very much in the planning stages with all of this. Just collecting options and solutions to potential problems. Haven't quite decided the best method of approach for this yet. I think List Boxes will definitely be getting used, just not quite sure where yet. Basically I have a few dozen different assembly types. Each type is made up of different components but they don't always have the same components...it just depends on what the customer wants. I have Dynamic Blocks for those components and BOM Blocks that accompany them so that I can build the BOM as I go. My current train of thought is, Main Page: Choose Assembly Type, that takes you to a page for that Type where there is a List Box and you can select what you need, then hit OK and it inserts them into the drawing. But I also want to incorporate Templates for certain things, so still kicking around some things. Would be great if I could automatically piece the Blocks together too, then I could just sit back and collect a check but that's probably not going to happen. Suppose I'll have to do some work. Anyways, thanks for all the help. Greatly Appreciated. Quote
rlx Posted December 15, 2018 Posted December 15, 2018 (edited) If you have many types list box is probably the best way to go. To make it look sexier you could use slides , something I use in my RlxPaste. Not my field of expertise but do you have one assembly per drawing or can you have more like on a building layout or something , and are we talking 2D or 3D here? You can built up an assembly by inserting all selected parts but you can also take away (first insert the complete assembly and then remove parts not needed, or change visibilitystate). In all cases it would help if each part has its own unique (block) name. Just some random thoughts... Edited December 15, 2018 by rlx Quote
Jim Clayton Posted December 16, 2018 Author Posted December 16, 2018 2d mechanical assemblies for P&ID applications. The current train of thought was to improve my block library and have a stack of Dynamic Blocks for each component rather than a bunch of individual blocks...that was probably going to happen regardless though. It just makes more sense to have a single "Flange" block where I can select the type/size/schedule rather than several sub folders with individual blocks. And Slides were on my short list of considerations...definitely more visually appealing. Just can't decide if List Boxes would be the more functional route. Is it possible to combine the two? Select your assembly type, then load your List Box via Slides, click OK and Insert all of your Blocks? That would be something to see right there. Quote
Jim Clayton Posted December 16, 2018 Author Posted December 16, 2018 ....or is this just common knowledge and I'm late to the party... Quote
rlx Posted December 16, 2018 Posted December 16, 2018 The thing with PID assemblies is how to deal with the tag numbers if it's a smart system. Either case you still allways first have to built a library of templates / symbols and organize them as best you can. A pretty interface only can make it look better. We have a 'smart' PID system where I work (Cadworx) but I'm no fan and glad I don't have to work with it. Did have a basic training session couple of years ago but that was just to see how it looks and feels. It has some nice tricks but also drawings get corrupt when there was a problem with the data base (usually IT changing or blocking things without notice and every file has to be 'white-listed' again). Think the most direct path would be to have a folder with templates , make a nice interface , with some simple slides or with list boxes & toggles and I think erasing the things you dont need, after inserting a complete assembly, is just as fast as selecting with toggles the things you do need. Quote
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.