Valid Layers to choose from

Valid Layers to choose from

rapidcad
Collaborator Collaborator
1,141 Views
10 Replies
Message 1 of 11

Valid Layers to choose from

rapidcad
Collaborator
Collaborator

Hi all, I'm trying to add simple foolproof interface enhancements to a program that I have stitched together and I have a simple enough request. Does anyone know how I can take a list of layer names I'm making available to a pop_list and pare it down to display only the layers that are thawed, unlocked, on, and non x-ref layers? I'd like to present the users with only a list of valid layers to place my blocks on.

 

Up to this point, I'm just using this old Autolisp method to get a layer list...

 

(start_list "layer_pop_list")
(setq layer_list '()
      next_list (tblnext "Layer" T)
      index 0
)
(while next_list
  (if (= (getvar "clayer") (cdr (assoc 2 next_list)))
  (setq new_index index
	index (1+ index)
	)
  )
(setq layer_list (append layer_list (list (cdr (assoc 2 next_list))))
      next_list (tblnext "Layer")
  )
)
;try to filter layer list here
;(setq good_layer_list layer_list)
  
(mapcar 'add_list layer_list)

(end_list)

(set_tile "layer_pop_list" (ITOA new_index))

Most programmers would probably know how to do this easily, but I'm getting rusty after spending so much time on building libraries.

 

ADN CAD Developer/Operator
0 Likes
Accepted solutions (1)
1,142 Views
10 Replies
Replies (10)
Message 2 of 11

scot-65
Advisor
Advisor
I'm not versed in VL as much as LISP, so here goes ("old" method)...

Xref has *|* as a WCMATCH pattern to the layer name.
DFX 70 has x = 0 for thaw and on (add 1 for frozen and add 4 for off).
DFX 62 has x < 0 for locked.

Let's try this in one swoop <untested>:
(while (setq a (tblnext "LAYER" (not a)))
(if (not (wcmatch (cdr (assoc 2 a)) "*|*"))
(if (= (cdr (assoc 70 a) 0))
(if (> (cdr (assoc 62 a) 0))
(setq b (list (cons (cdr (assoc 2 a)) b))) ;<--this might be wrong
);if
);if
);if
);while
(setq b (reverse b)) ;or ACAD_STRLSORT

???

Scot-65
A gift of extraordinary Common Sense does not require an Acronym Suffix to be added to my given name.

0 Likes
Message 3 of 11

john.uhden
Mentor
Mentor
Accepted solution

This might work to create a list of layer names that meet your criteria (on, thawed, unlocked, not xref)

 

(defun layers_ok ( / layers okays)
  (setq layers (vlax-get (vla-get-activedocument (vlax-get-acad-object)) 'layers))
  (vlax-for layer layers
    (and
      (= (vlax-get layer 'layeron) -1)
      (= (vlax-get layer 'freeze) 0)
      (= (vlax-get layer 'lock) 0)
      (setq name (vlax-get layer 'name))
      (not (wcmatch name "*|*"))
      (setq okays (cons name okays))
    )
  )
  (reverse okays)
)

John F. Uhden

Message 4 of 11

rapidcad
Collaborator
Collaborator

Thanks Scott! I tried your code but ran into the errors (you thought there might be some though). By stepping through it I found that there were misplaced closing parenthesis in the assoc 70 and assoc 62 lines. However even after fixing them and getting the code to run, I still could not use the function because it returned a strange messed up list...

 

(("XREF" ("TGW-TAG" (...))))

 

instead of a nice list of layer names.

 

Here's my edited version that evaluates but returns this gibberish..

 

(while (setq a (tblnext "LAYER" (not a)))
 (if (not (wcmatch (cdr (assoc 2 a)) "*|*"))
 (if (= (cdr (assoc 70 a)) 0)
 (if (> (cdr (assoc 62 a)) 0)
 (setq b (list (cons (cdr (assoc 2 a)) b))) ;<--this might be wrong
 );if
 );if
 );if
);while
(setq b (reverse b)) ;or ACAD_STRLSORT

 

 

Thank you so much for getting me reacquainted with parsing layer data. Haven't looked at it in a few years..

 

I'll keep plugging away at it.

 

ADN CAD Developer/Operator
Message 5 of 11

rapidcad
Collaborator
Collaborator

John, thanks a bunch for the excellent function. Although not simple Autolisp, the vlisp works flawlessly at what I'm doing and I mix the two quite a lot to get what I need done.  I think I'll try to incorporate this (with credits to you for the function). Works like a charm. Thanks again!

 

Smiley Happy

ADN CAD Developer/Operator
Message 6 of 11

john.uhden
Mentor
Mentor
I love getting good news.
Yes, mixing often yields tasteful (or tasty) results

John F. Uhden

Message 7 of 11

rapidcad
Collaborator
Collaborator

One small improvement if I am not missing some drawback to this method:

 

I like (acad_strlsort okays) instead of (reverse okays) because in my dialog box, I'm allowing users to create layers or add layers and they may be all caps or not. If I reverse the list, it puts any lowercase names at the bottom where you wouldn't think to look for them, while it looks like the acad_strlsort seems to integrate the lowers and uppers perfectly.

 

Let me know if there is some drawback to dong this.

 

Thanks again!

 

(defun layers_ok ( / layers okays name)
  (setq layers (vlax-get (vla-get-activedocument (vlax-get-acad-object)) 'layers))
 
  (vlax-for layer layers
    (and
      (= (vlax-get layer 'layeron) -1)
      (= (vlax-get layer 'freeze) 0)
      (= (vlax-get layer 'lock) 0)
      (setq name (vlax-get layer 'name))
      (not (wcmatch name "*|*"))
      (setq okays (cons name okays))
    )
  )
  (acad_strlsort okays) 
)
ADN CAD Developer/Operator
0 Likes
Message 8 of 11

john.uhden
Mentor
Mentor

Sure.  That will work just fine.  I noticed that you are wise enough to know there is no need for reversing.

 

Maybe it's just me, but I never liked lower case in layer names, or styles, or blocks.

If you are inclined the same way, then:

 

(mapcar 'strcase (acad_strlsort okays)), or

(acad_strlsort (mapcar 'strcase okays))

 

AutoCAD doesn't care about name case.

But I think the snvalid function can be your friend to avoid improper names.

John F. Uhden

0 Likes
Message 9 of 11

rapidcad
Collaborator
Collaborator

Thanks for those ideas. I think I'm going to have to allow the layer names to have different cases just because I'm writing a program for folks in our corporation and for use by distributors as well, so being strict about CAD standards hasn't been incorporated into the program the way I would do it otherwise. However, your tip about snvalid has me thinking how I might incorporate that since I had already considered that any string would be picked up by my dialog box and I knew that some characters are invalid for layer names.

What I asked about originally applied to a tile in the dialog to select a current layer from the list you helped me build, which I am not concerned about now that it works without a problem. However I have a separate tile which adds a new layer for the blocks being inserted which I am concerned about. I see there are easy ways to check through the list and test if a layer name is valid, but for the edit_box tile that just takes in whatever string it is fed, how can I test this and interact with the user if the string is invalid?

I tested this but I'm getting an endless while loop:

 

(defun is_legal_layername ()
  (while (not (snvalid create_layer_box))
	       	(set_tile "error" "Invalid layer name")
    		(setq create_layer_box (get_tile "create_layer_box")) )
  )

(defun saveVars ()
  (setq layer_pop (nth (atoi (get_tile "layer_pop_list")) layer_list))
  (setq create_layer_box (get_tile "create_layer_box"))
  (setq select_layer (get_tile "select_layer"))
  (setq current_layer (get_tile "current_layer"))
  (setq create_layer (get_tile "create_layer"))

  (if create_layer_box (is_legal_layername))
)

Of course, this isn't right, but without launching additional dialog boxes, how can I use errtile to inform the user of the mistake and prompt a correction?

This has been a good learning exercise for me and will certainly be so if this check can be implemented.

Thanks again for any help. I've already learned so much.

ADN CAD Developer/Operator
0 Likes
Message 10 of 11

john.uhden
Mentor
Mentor
(defun check_layer_box (value / done)
  (while (not done)
    (if (snvalid value)
      (progn
        (set_tile "error" "")
        (setq create_layer_box value
                 done 1
        )
      )
      (progn
        (set_tile "error" "Invalid layer name")
        (mode_tile "create_layer_box" 2)  ; focus on tile
      )
    )
  )
)
;; Notice that create_layer_box is global.
;; I would have named it newlayer.

;; Elsewhere:
(action_tile "create_layer_box" "(check_layer_box $value)")

John F. Uhden

0 Likes
Message 11 of 11

rapidcad
Collaborator
Collaborator

Thanks again John, I'll try to implement that. I really appreciate your help on this.

ADN CAD Developer/Operator
0 Likes