Dialog box lisp - multiple selections

Discussion in 'AutoCAD' started by Nick Pirkl, Mar 21, 2005.

  1. Nick Pirkl

    Nick Pirkl Guest

    Hello all, I would love any help you can give. The following lisp uses a
    dialog box to select plant types, input quantity and select size of each
    plant and then creates a schedule. I want to be able to insert only the
    blocks that have been "toggled" not all of them. The final list will be
    about 30 items long. I was thinking of using a condition statement to
    select all items that have been toggled (l1, l2, l3, etc) and then pass the
    2 attribute variables to the insert function for each plant. Not quite sure
    how to do it, but it sounds good ;-) I will also have to figure out how to
    set the insertion points automatically based on the number of items to
    insert, maybe adding the spacing value to the point value and redefining the
    variable over and over again as necessary?

    Any thoughts?

    Nick

    ---------------------------------------------------------------------------

    (defun C:hulcdiag () ;define function

    (setq NAMES '("3\" B&B" "2 1/2\" B&B" "2\" B&B" "1 1/2\" B&B"
    "24\" Box" "4'-6' B&B" "6'-8' B&B" "20 Gal"
    "15 Gal" "5 Gal" "1 Gal" "4\" Pot") ;define list
    ) ;setq

    (setq dcl_id (load_dialog "hulcdiag.dcl")) ;load dialog

    (if (not (new_dialog "hulcdiag" dcl_id) ;test for dialog

    ) ;not

    (exit) ;exit if no dialog

    ) ;if


    (start_list "l1s") ;start the list box
    (mapcar 'add_list NAMES) ;fill the list box
    (end_list) ;end list

    (start_list "l2s")
    (mapcar 'add_list NAMES)
    (end_list)

    (start_list "l3s")
    (mapcar 'add_list NAMES)
    (end_list)

    (action_tile "l1" "(setq l1 $value)") ;get plant 1 toggle value
    (action_tile "l2" "(setq l2 $value)")
    (action_tile "l3" "(setq l3 $value)")

    (action_tile "l1q" "(setq l1q $value)") ;get plant 1 quantity
    (action_tile "l2q" "(setq l2q $value)")
    (action_tile "l3q" "(setq l3q $value)")

    (action_tile "l1s" "(setq l1s $value)") ;get plant 1 size
    (action_tile "l2s" "(setq l2s $value)")
    (action_tile "l3s" "(setq l3s $value)")

    (action_tile
    "cancel" ;if cancel button pressed
    "(done_dialog) (setq userclick nil)" ;close dialog, set flag
    ) ;action_tile

    (action_tile
    "accept" ;if O.K. pressed
    "(done_dialog) (setq userclick T)" ;close dialog, set flag
    ) ;action tile

    (start_dialog) ;start dialog

    (unload_dialog dcl_id) ;unload


    (progn (setq l1s (nth (atoi l1s) names))
    (setq l2s (nth (atoi l2s) names))
    (setq l3s (nth (atoi l3s) names))
    ) ;progn

    (setq pt1 (getpoint "\nPick Landscape Legend insertion point:"))
    (setq spc 0.5)
    (setq pt2 (list (car pt1) (- (cadr pt1) (* spc 2.5)))) ;set pt2 1.25"
    below pt1
    (setq pt3 (list (car pt2) (- (cadr pt2) spc))) ;set pt3 1/2" below pt2
    (setq pt4 (list (car pt3) (- (cadr pt3) spc)))

    (command "-insert" "hd-main" pt1 1 1 0)
    (command "-insert" "hd-l1" pt2 1 1 0 l1q l1s)
    (command "-insert" "hd-l2" pt3 1 1 0 l2q l2s)
    (command "-insert" "hd-l3" pt4 1 1 0 l3q l3s)

    (princ)

    );defun C:hulcdiag
     
    Nick Pirkl, Mar 21, 2005
    #1
  2. Nick Pirkl

    BillZ Guest

    Any thoughts?<<<

    Why not just use one list box and multiple select?

    Code:
    testlist : dialog {
    label = "Test List" ;
    :list_box {
    key  =  "plantlist" ;
    label  =  "Plants"  ;
    height  = 10 ;
    width   = 16 ;
    fixed_width  = true       ;
    alignment   =  centered   ;
    multiple_select  =  true  ;
    }
    ok_cancel ;
    }
    
    Code:
    (defun set_names (/ item numlist)
    (setq numlist (get_tile "plantlist")
    )
    (while (setq item (read numlist))
    (setq plantlist (cons (nth item names) plantlist)
    numlist (substr numlist (+ (strlen (itoa item)) 2))
    )
    )
    (setq plantlist (reverse plantlist))
    )
    
    (defun c:testlist (/ dcl_id plantlist)
    (setq dcl_id (load_dialog "testlist.dcl"))
    (if (not (new_dialog "testlist" dcl_id ""))(exit))
    
    (setq NAMES '("3\" B&B" "2 1/2\" B&B" "2\" B&B" "1 1/2\" B&B"
    "24\" Box" "4'-6' B&B" "6'-8' B&B" "20 Gal"
    "15 Gal" "5 Gal" "1 Gal" "4\" Pot"
    )
    )
    
    (start_list "plantlist")
    (mapcar 'add_list NAMES)
    (end_list)
    
    (action_tile "accept" "(set_names)(done_dialog 1)")
    
    (setq an (start_dialog))
    (unload_dialog dcl_id)
    
    (cond  ((= an 1)
    plantlist  ;do stuff here
    )
    )
    )
    
    Bill
     
    BillZ, Mar 22, 2005
    #2
  3. Nick Pirkl

    Nick Pirkl Guest

    Bill, the only problem with this is that I want the user to be able to
    select, let's say 15 different plants, each plant will have a different
    quantity and a different size. If I use a single list box, I would not be
    able to select the quantity and size for each plant. Right?

    Nick

     
    Nick Pirkl, Mar 22, 2005
    #3
  4. Nick Pirkl

    ECCAD Guest

    Nick,
    Sounds like you need to pick the Plant, then
    have a popup_list for quantity's, and sizes.
    So, they would pick a Plant Type, quantity, and
    size (in that order). Foreach Plant Type. Also,
    include a 'save' button and make up a List of
    Plant Type, Quantity, Size..i.e.
    ("Large Bush" "20" "6foot"). Then, for each
    'sublist' in the List, do your inserts - based on the info.

    Bob
     
    ECCAD, Mar 22, 2005
    #4
  5. Nick Pirkl

    BillZ Guest

    I think Bob's got the right idea.

    Pick a plant off the list, enter a quantity into an edit box, have a list of sizes in a popup list or list box. Then have a botton "build list" with an action tile that reads all 3 tiles and builds a list with ( "Plant type Plant size Quantity") on each line then dynamically list the entries in another list box that updates with each entry.

    HTH

    Bill
     
    BillZ, Mar 22, 2005
    #5
  6. Nick Pirkl

    Nick Pirkl Guest

    Bob and Bill, below is the DCL code I have so far. The users like it
    because all of the plants will be listed at once. I think picking the plant
    and quantity and size and then repeating could lead to confusion as to which
    plants had already been selected and saved. What I have below and is the
    lisp is definately code heavy after I insert all 30 plants. What I was
    trying to do was use the toggle code to justify saving the data and then
    insert all plants that have data, one right below the other.

    Nick

    ---------------------------------------------------------------------------------------
    hulcdiag : dialog {
    label = "Landscape Legend - Insert";
    : boxed_column {
    label = "Plant Type";
    //
    : row {
    : toggle {
    label = "Cercocarpus ledifolios";
    key = "l1";
    width = 30;
    } //end toggle
    : edit_box {
    label = "Quantity:";
    key = "l1q";
    edit_width = 5;
    alignment = right;
    } //end edit box
    : popup_list {
    label = "Sizes";
    key = "l1s";
    value = "1";
    edit_width = 11;
    alignment = right;
    } //end list
    } //end row
    //
    : row {
    : toggle {
    label = "Cercis canadensis";
    key = "l2";
    width = 30;
    } //end toggle
    : edit_box {
    label = "Quantity:";
    key = "l2q";
    edit_width = 5;
    alignment = right;
    } //end edit box
    : popup_list {
    label = "Sizes";
    key = "l2s";
    value = "1";
    edit_width = 11;
    alignment = right;
    } //end list
    } //end row
    //
    : row {
    : toggle {
    label = "Chilopsis linearis";
    key = "l3";
    width = 30;
    } //end toggle
    : edit_box {
    label = "Quantity:";
    key = "l3q";
    edit_width = 5;
    alignment = right;
    } //end edit box
    : popup_list {
    label = "Sizes";
    key = "l3s";
    value = "1";
    edit_width = 11;
    alignment = right;
    } //end list
    } //end row

    } //end boxed column
    ok_cancel_help_errtile;
    } //end dialog
     
    Nick Pirkl, Mar 22, 2005
    #6
  7. Nick Pirkl

    ECCAD Guest

    Your method will work to a point.
    I think you will run out of space (vertically) in the Dialog,
    with about 12 plants - then you max out.
    With a 'list_box', it will automatically expand when needed,
    and no 'code' - just variable names to deal with - and just
    (1) token of info - plant name..along with (2) tokens for
    quantity and size. With your method, if you wanted to add
    in a different plant, it would be 'code' time again...never ends.
    Just my thoughts.
    Bob
     
    ECCAD, Mar 22, 2005
    #7
  8. Nick Pirkl

    Nick Pirkl Guest

    Bob, maybe the dialog box is not the way to go. Another way I could do this
    is to do an attribute extraction for all the plant types in the drawing.
    Then build the legend off of this information only. Again the information
    would be the plant type (block name) number of insertions and the size of
    the plant (an attribute in the block). This would be much cleaner, but I
    have no idea how to do it. That is why I was trying to do the dialog box,
    seemed easier at the time :-(

    Nick
     
    Nick Pirkl, Mar 22, 2005
    #8
  9. Nick Pirkl

    ECCAD Guest

    Me thinks,
    Upon 2nd thought, your method could do say (10) plants at
    a time (using 'text' instead of Label..for the Plants), and
    have an index to the (entire) plant list... Then, (10) toggles,
    and (10) Edit Boxes.....Add a "Next group", and "Previous group" buttons, resetting the index, and refresh the dcl..
    with Plant names (as the text1, text2, text3) tiles, and
    when toggle1 is on, get plant name, quantity, size tiles....
    and make up a 'append' list with the data..
    hmmm.......should work.
    Bob
     
    ECCAD, Mar 22, 2005
    #9
  10. Nick Pirkl

    ECCAD Guest

    Oh,
    I thought you wanted to get a 'list' of the plants, then insert
    them. If you want to go the other way, inserting plants,
    then extract a list of what plants are there, you will need to
    have at least (1) attribute in each plant. (Size).
    Then, it is relatively easy to get blockname (plant), size, and count how many of each you have.
    Is that the route you want to go ?

    Bob
     
    ECCAD, Mar 22, 2005
    #10
  11. Nick Pirkl

    Nick Pirkl Guest

    This is what I had originally wanted to do but had no idea how to do it. I
    already have a simple attribute extraction that is used to count the number
    of plant types. Each block has a size attribute. So....all the information
    is there in the drawing. The nice idea about going this way is that the
    user could just select a button in the menu "Create Legend". I would prefer
    to go this way if possible, but would need a lot of help.

    Nick
     
    Nick Pirkl, Mar 22, 2005
    #11
  12. Nick Pirkl

    Nick Pirkl Guest

    Bob, below is a list of the 48 blocks. The first name "lcbldp02" is the
    block to scan for in the drawing (each block has 2 attrubutes, an "item" and
    "size" attribute, we only need the "size" value). The second name "L4" will
    be the block that inserts into the legend with an attribute for quantity and
    for size.


    lcbldp02-L4

    lcblsp01-L7

    lcblsp02-L28

    lcblsp03-L8

    lcblsp04--L14

    lcblsp08-L39

    lcblsp09-L6

    lcblsp13-L1

    lcblsp18-L12

    lcblsp20-L2

    lcblsp24-L13

    lcblsp25-L15

    lcblsp26-L9

    lcblsp28-L3

    lcblsp40-L5

    lccnsp01-L30

    lccnsp02-L10

    lccnsp06-L16

    lccnsp07-L17

    lccnsp09-L11

    lcpcsp03-L29

    lcpcsp04-L47

    lcshdp01-L37

    lcshdp02-L25

    lcshdp11-L45

    lcshdp17-L20

    lcshdp23-L48

    lcshsp01-L31

    lcshsp02-L42

    lcshsp03-L38

    lcshsp04-L44

    lcshsp05-L43

    lcshsp06-L22

    lcshsp07-L27

    lcshsp08-L23

    lcshsp09-L40

    lcshsp11-L35

    lcshsp12-L24

    lcshsp14-L41

    lcshsp15-L46

    lcshsp17-L19

    lcshsp18-L21

    lcshsp19-L33

    lcshsp20-L26

    lcbldp01-L18

    lcbldp06-L32

    lcbldp11-L34

    lcblsp11-L36


    Thanks for offering to help Bob!

    Nick
     
    Nick Pirkl, Mar 22, 2005
    #12
  13. Nick Pirkl

    ECCAD Guest

    Ok,
    I think we need to go off-line to finish up.
    Please give me an E-Mail at:

    (remove the nospam + ".")

    I will need a sample .dwg with a few of your
    blocks inserted, and a sample legend - or at least
    the dimensions for placements..
    Sounds like a fun little project.

    Bob
     
    ECCAD, Mar 22, 2005
    #13
  14. Nick Pirkl

    ECCAD Guest

    Nick,
    Thanks for the E-Mail.
    Here is a working version.

    (defun c:plant_legend ()
    ; extract plant information, make a list of quantity / plants / sizes
    ; Build a 'list' of the plant (block names)
    (setq plant_blocknames (list
    "LCBLDP02"
    "LCBLSP01"
    "LCBLSP02"
    "LCBLSP03"
    "LCBLSP04"
    "LCBLSP08"
    "LCBLSP09"
    "LCBLSP13"
    "LCBLSP18"
    "LCBLSP20"
    "LCBLSP24"
    "LCBLSP25"
    "LCBLSP26"
    "LCBLSP28"
    "LCBLSP40"
    "LCCNSP01"
    "LCCNSP02"
    "LCCNSP06"
    "LCCNSP07"
    "LCCNSP09"
    "LCPCSP03"
    "LCPCSP04"
    "LCSHDP01"
    "LCSHDP02"
    "LCSHDP11"
    "LCSHDP17"
    "LCSHDP23"
    "LCSHSP01"
    "LCSHSP02"
    "LCSHSP03"
    "LCSHSP04"
    "LCSHSP05"
    "LCSHSP06"
    "LCSHSP07"
    "LCSHSP08"
    "LCSHSP09"
    "LCSHSP11"
    "LCSHSP12"
    "LCSHSP14"
    "LCSHSP15"
    "LCSHSP17"
    "LCSHSP18"
    "LCSHSP19"
    "LCSHSP20"
    "LCBLDP01"
    "LCBLDP06"
    "LCBLDP11"
    "LCBLSP11"
    ))
    (setq legend_blocknames (list
    "L4"
    "L7"
    "L28"
    "L8"
    "L14"
    "L39"
    "L6"
    "L1"
    "L12"
    "L2"
    "L13"
    "L15"
    "L9"
    "L3"
    "L5"
    "L30"
    "L10"
    "L16"
    "L17"
    "L11"
    "L29"
    "L47"
    "L37"
    "L25"
    "L45"
    "L20"
    "L48"
    "L31"
    "L42"
    "L38"
    "L44"
    "L43"
    "L22"
    "L27"
    "L23"
    "L40"
    "L35"
    "L24"
    "L41"
    "L46"
    "L19"
    "L21"
    "L33"
    "L26"
    "L18"
    "L32"
    "L34"
    "L36"
    ))
    ;;
    ;; define dxf function
    ;;
    (defun dxf (code elist)
    (cdr (assoc code elist)); Find association pair, strip first element
    ); end function
    ;;

    ; Function to sort the list, make final list..
    (defun sort_the_list ()
    (setq blocks_lst (list)); empty list
    (foreach blname plant_blocknames
    (setq Q 0 types_lst nil); quantity / types
    (foreach sublst all_plants
    (setq block (car sublst))
    (setq typex (car (cdr sublst)))
    (if (= block blname)
    (progn
    (if (member (strcat block typex) types_lst)
    (setq Q (+ Q 1)); count matching types
    ); if
    (if (not (member (strcat block typex) types_lst))
    (progn
    (setq types_lst (cons (strcat block typex) types_lst)); add to list
    (setq Q 1 otypex typex); first of this type
    ); progn
    ); if
    ); progn
    ); if
    ); foreach sublst
    (setq types_lst nil)
    (if (> Q 0)
    (progn
    (setq Q (itoa Q))
    (setq final_lst (cons (list blname otypex Q) final_lst))
    (setq Q 0 otypex "")
    ); progn
    ); if
    ); foreach
    ); function


    ;; Begin Process
    ;; Init variables used
    (setq final_lst nil types_lst nil all_plants nil)

    ;; Foreach plant name in the 'list', get type, make a list

    (foreach plant plant_blocknames
    (setq ss nil)
    (setq ss (ssget "X" (list (cons 2 plant))))
    (if ss
    (progn
    (setq c 0 lst nil bn plant)
    (repeat (sslength ss)
    (setq plant_info (entget (ssname ss c)))
    (setq attr (entget (entnext (dxf -1 plant_info))))
    (setq size (cdr (assoc 1 attr)))
    (setq all_plants (cons (list bn size) all_plants))
    (setq c (+ c 1))
    ); repeat
    ); progn
    ); if
    ); foreach

    ;; Now that we have some plants in 'all_plants' list, let's sort that

    (if all_plants
    (sort_the_list)
    ); if

    ;; And if we have the final_lst list, let's build a Legend..

    (if final_lst
    (progn
    ; Insert the Header first, drag mode..
    (setq P1 (getpoint "\nPick a Point for the Legend Header Block:"))
    (if P1
    (progn
    (command "_-insert" "l-main" P1 "1" "1" "0"); Header
    (setq IP (list (+ (car P1) 0.0)(- (cadr P1) 1.125))); First 'data' IP
    (command "_limits" "_off"); case we run off the bottom of the sheet..
    (foreach data final_lst
    (setq block_to_insert ""); unless on list..
    (setq blockname (car data)); blockname of insert
    (setq typex (cadr data)); type
    (setq Quant (caddr data)); string format of Q
    (setq c 0)
    (foreach blk plant_blocknames
    (if (= blk blockname)
    (setq block_to_insert (nth C legend_blocknames)); Link to 'L4' name
    ); if
    (setq c (+ c 1)); counter
    ); foreach
    (if (/= block_to_insert "")
    (progn
    (command "_-insert" block_to_insert IP "1" "1" "0" Quant typex); Insert Legend
    (setq IP (list (+ (car IP) 0.0)(- (cadr IP) 0.500)))
    ); progn
    ); if
    ); foreach
    ); progn
    ); if
    ); progn
    ); if
    ); function plant_legend
    (princ); silent load
    (c:plant_legend); and self-run it

    ---------------------

    Cheers: )

    Bob Shaw
    www.bobscadshop.com
     
    ECCAD, Mar 22, 2005
    #14
  15. Nick Pirkl

    Nick Pirkl Guest

    Bob, thank you for all of your hard work on this. There is no way I could
    have done this so fast, if at all!

    In simplistic terms, I believe the routine does the following:

    Creates 2 lists of block names.
    Searches drawing for first list block names
    associates the first list to the second
    gather the number of occurances for each block
    gather the attribute value to fill in
    sort the list
    insert the Header
    insert the data, resetting the insertion point for each block insertion as
    many times as is necessary.

    Most of the commands I have used in various routines before except
    "foreach". The way I read it, it allows you to assign the same variable to
    all items in a list over and over again as it steps through each list item?
    Is that correct?

    Nick
     
    Nick Pirkl, Mar 23, 2005
    #15
  16. Nick Pirkl

    ECCAD Guest

    Nick,
    Glad you like it.
    I think you have a good handle on what it is up to. Yes, makes (2) list of blocknames, gathers selection set(s) of plant blocks, gets the legend block (as same index number) to legend block list, foreach 'block' in plant_blocknames..gathers the attribute required, places all info into the all_lst, which is then sorted to make quantities of each 'blockname' and 'type', and finally, if there is a final_lst..builds the legend, and fills in
    the Quantity and 'type'.
    Having said that, yes, you are correct on what the foreach..
    function does. It loops from top to bottom of a 'list' of items,
    and references each item. Example:
    Foreach lay layers_lst
    .... would set 'lay' to the first value of 'layers_lst', then
    you perform checks / changes on 'lay', then, the foreach
    keeps on going, getting each item of 'layers_lst', in turn..
    Kinda like a [For I = 0 to 10] loop in Basic, where I is incremented 0, 1, 2, 3..etc.
    Bob
     
    ECCAD, Mar 23, 2005
    #16
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.