Optional user input

Optional user input

Anonymous
Not applicable
3,021 Views
26 Replies
Message 1 of 27

Optional user input

Anonymous
Not applicable

Hello,

I'm not exactly sure what the term is, but I want to learn how to add the option for user input, similar to many of the standard AutoCAD commands, such as "ZOOM" or "FILLET", that have a default setting with the option to modify the command in the middle.

Annotation 2019-10-01 102634.png

Example: call the fillet command and you can fillet immediately or press "M" for multiple fillets or "R" to change the radius and continue with the command. I have used the "getkword" function a little bit, but it seems like it behaves differently. How would I go about, for a simple example, adding the option to press "M" to add "MULTIPLE" to this program which just changes the current layer, calls the "POINT" command and pauses for location input and then changes the layer back. I want to have the option to call "vportpoint" and be able to have the option to press "M" for multiple, and maybe "T" or something for "M2P", if that's possible.

 

 

(defun c:vportpoint ( / oldlayer)
  (setq oldlayer (getvar "clayer"))
  (command "-layer" "set" "_VPORT" "")
  (command "point" pause)
  (setvar "clayer" oldlayer)
  
   (princ)
  )

 

 

If you have done something like this with a custom lisp command before your help would be much appreciated!

 

Thank you,

Michael

0 Likes
Accepted solutions (2)
3,022 Views
26 Replies
Replies (26)
Message 2 of 27

Jonathan3891
Advisor
Advisor

There are a few ways to do this. Here is an example I use for printing.

 

(defun c:iplot (/ psize)
   (initget 1 "11x17 24x36 PDF") ; [1 = no enter allowed]
   (setq psize (getkword (strcat "\nSelect Plot [11x17/24x36/PDF]:")))
   (cond
      ((= psize "11x17") (iplot_11x17))
      ((= psize "24x36") (iplot_24x36))
      ((= psize "PDF")  (iplot_PDF))
      )
	  )
 

Jonathan Norton
Blog | Linkedin
0 Likes
Message 3 of 27

johnyDFFXO
Advocate
Advocate
(defun c:vportpoint ( / oldlayer)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
  (initget "Multiple")
  (setq pnt (getpoint "\nSpecify a point [Multiple]: "))
  (if (= pnt "Multiple")
    (while (setq pnt (getpoint "\nSpecify a point <exit>: "))
      (command "point" "non" pnt))
    (command "point" "non" pnt))

  (setvar "clayer" oldlayer)
   (princ)
  )

 

You don't need to have (getkword) - you can add these options to ANY use prompt function - getpoint, getint, getdist, entsel...,  getstring (a bit specific) look HERE , the first column... "honors key words..."

...BUT!  the command function and its derivatives such as command-s and vl-cmdf... You cannot add an option to that: (command "point" [Multiple]...) - that's not possible.

For M2p option you don't need to do anything, it's honored by default.

About the "T"... not sure what that should stand for... but it's the same case as "Multiple"...

 

Or... since the option is just the only one and your routine has no specific function under <enter>... just use that... I would consider that more user friendly way...

(defun c:vportpoint ( / oldlayer pnt)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
  (setq pnt (getpoint "\nSpecify a point <multiple>: "))
  (if pnt
    (command "point" "non" pnt)
    (while (setq pnt (getpoint "\nSpecify a point <exit>: "))
      (command "point" "non" pnt))
    )

  (setvar "clayer" oldlayer)
   (princ)
  )
0 Likes
Message 4 of 27

Anonymous
Not applicable

Hi, thanks for your reply!

I'm a little confused as to how to apply this to my lisp. So I don't want it to pause for getkword. I want it to function the same way the fillet command works, where you can continue with the fillet command without giving input, but if you want to modify the command by adding "multiple" fillets or changing the radius you can. I'm also not sure how to call the "multiple" option in the middle of a command.

 

Thanks,

Michael

0 Likes
Message 5 of 27

Anonymous
Not applicable

Oh man this is exactly it! Thank you!

Okay, so if I wanted to add the "Undo" function - similar to the one in fillet and copy and so forth - how could I do that?

 

Thank you!

Michael

0 Likes
Message 6 of 27

johnyDFFXO
Advocate
Advocate

It's the same.................

Just a little trick with (progn) needed to wrap (initget) and (getpoint) into (while) condition.

 

(defun c:vportpoint ( / oldlayer pnt)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
  (setq pnt (getpoint "\nSpecify a point <multiple>: "))
  (if pnt
    (command "point" "non" pnt)
    (while (progn
	     (initget "Undo")
	     (setq pnt (getpoint "\nSpecify a point [Undo] <exit>: "))
	     )
      (if (= pnt "Undo")
	(command "erase" "last" "")
	(command "point" "non" pnt)))
    )

  (setvar "clayer" oldlayer)
   (princ)
  )
0 Likes
Message 7 of 27

Jonathan3891
Advisor
Advisor

Holy cow, @johnyDFFXO and I think alike!!

 

(defun c:ttt (/ oldlayers)
  (setq oldlayer (getvar 'clayer))
  (if (tblsearch "layer" "_VPORT")
    (command "_layer" "S" "_VPORT" "")
    (command "_layer" "M" "_VPORT" "")
    )
  (initget "Multiple M2P")
  (setq PNT (getpoint "\nSpecify a Point [Multiple/M2P]: "))
  (if (= PNT "Multiple")
    (while (setq PNT (getpoint "\nSpecify Points: "))
    (command "point" "non" PNT))
    (command "point" "non" PNT))
  (if (= PNT "M2P")
    (command "point" "m2p"))
  (setvar 'clayer oldlayer)
  (princ)
  )

Jonathan Norton
Blog | Linkedin
0 Likes
Message 8 of 27

johnyDFFXO
Advocate
Advocate

@Jonathan3891 wrote:

Holy cow, @johnyDFFXO and I think alike!!

 

Good to know... especially when I invent the perpetuum mobile I'll be better prepared.

0 Likes
Message 9 of 27

Anonymous
Not applicable

Hmm, it didn't quite work this time... was there something left out of this second iteration? It looks like a couple things were different that maybe shouldn't be?

 

(defun c:vportpoint ( / oldlayer pnt)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
(initget "Multiple") ;;; shouldn't this still be here? it wasn't here anymore (setq pnt (getpoint "\nSpecify a point <multiple>: ")) ;;; This should be [Multiple]? (if pnt ;;; Should this be (= pnt "Multiple") still? (command "point" "non" pnt) ;;; Should this be inside the "(while...)" condition? (while (progn (initget "Undo") (setq pnt (getpoint "\nSpecify a point [Undo] <exit>: ")) ) (if (= pnt "Undo") (command "erase" "last" "") (command "point" "non" pnt))) ) (setvar "clayer" oldlayer) (princ) )

 Also, would it be beneficial to use "cond" instead of "if" if I wanted to have both Undo and M2P show up after inputting "multiple".

 

Thanks,

Michael

0 Likes
Message 10 of 27

Sea-Haven
Mentor
Mentor

Posted reply at Cadtutor you may like to have a look at.

0 Likes
Message 11 of 27

johnyDFFXO
Advocate
Advocate

It did work as intended - read my first post about the difference between [Multiple] and <multiple>, examples of both are there. It's more about personal preferences than what 'should' be. 

 


(defun c:vportpoint ( / oldlayer pnt)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
(initget "Multiple") ;;; shouldn't this still be here? it wasn't here anymore (setq pnt (getpoint "\nSpecify a point <multiple>: ")) ;;; This should be [Multiple]? (if pnt ;;; Should this be (= pnt "Multiple") still? No when considering my original code without (initget "Multiple"). Otherwise could be.
...

 Also, would it be beneficial to use "cond" instead of "if" if I wanted to have both Undo and M2P show up after inputting "multiple". Sure. 

 

Thanks,

Michael

 

Something to play with....

(defun c:vportpoint ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")

  (initget 1 "Multiple")
  (setq pnt (getpoint "\nSpecify a point [Multiple]: "))
  (if (= pnt "Multiple")
    (while (progn
	     (initget "Undo T-for-m2p")
	     (setq pnt (getpoint "\nSpecify a point [Undo/T-for-m2p] <exit>: "))
	     )
      (cond ((= pnt "T-for-m2p") 
	     (setq m2p (not m2p))) 				;toggle m2p
	    ((= pnt "Undo")
	     (command "erase" "last" ""))
	    (T 
	     (command-s "point" (if m2p "m2p" "non") pnt))))
    (command "point" "non" pnt) 				; single point mode
    )

  (setvar "clayer" oldlayer)
   (princ)
  )


0 Likes
Message 12 of 27

Anonymous
Not applicable

This looks great! Thank you, Johny!

I kept thinking, "it's not working", but it the m2p was toggling and I couldn't tell, since the prompt was the same: "Specify a point".  How would I add a change the first prompt when m2p is toggled: "First point of mid"? Still very new to all of this and have learned very minimal base fundamentals of LISP language. But it's super interesting and I have a job where the work gets super busy and then slow, so learning about LISP seems like as good of a thing as any to spend my extra time on.

 

Thanks you!

Michael

0 Likes
Message 13 of 27

Anonymous
Not applicable

So I came up with this code, but I have another problem with it:

 

(defun c:t3 ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")

  (initget 1 "Multiple")
  (setq pnt (getpoint "\nSpecify a point [Multiple]: "))
  (if (= pnt "Multiple")
    (while (progn
	     (initget "Undo T-for-m2p")
	     (setq pnt (getpoint "\nSpecify a point [Undo/T-for-m2p] <exit>: "))
	     )
      (cond ((= pnt "T-for-m2p") 
	     ((setq m2p (not m2p))
	       (while (progn
			(initget "Undo T-for-m2p")
			(setq mid1 (getpoint "\nFirst point of mid [Undo/T-for-m2p] <exit>: "))
			(setq mid2 (getpoint "\nSecond point of mid [Undo/T-for-m2p] <exit>: "))
			)
		   (command "point" "m2p" "non" mid1 mid2)
		 )
	       )
	     ) 				;toggle m2p
	    ((= pnt "Undo")
	     (command "erase" "last" ""))
	    (T 
	     (command-s "point" (if m2p "m2p" "non") pnt))))
    (command "point" "non" pnt) 				; single point mode
    )

  (setvar "clayer" oldlayer)
   (princ)
  )

 

It works to get into the m2p prompts, but I can't toggle off the m2p again.

 

Message 14 of 27

johnyDFFXO
Advocate
Advocate
(defun c:vportpoint ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")

  (initget 1 "Multiple")
  (setq pnt (getpoint "\nSpecify a point [Multiple]: "))
  (if (= pnt "Multiple")
    (while (progn
	     (initget "Undo T-for-m2p")
	     (setq pnt (getpoint (strcat "\n" (if m2p "First point of mid" "Specify a point") " [Undo/T-for-m2p]: "))) ; <exit> still possible, just not announced since it's common...
	     )
      (cond ((= pnt "T-for-m2p") 
	     (setq m2p (not m2p))) 				;toggle m2p
	    ((= pnt "Undo")
	     (command "erase" "last" ""))
	    (T 
	     (command-s "point" (if m2p "m2p" "non") pnt))))
    (command "point" "non" pnt) 				; single point mode
    )

  (setvar "clayer" oldlayer)
   (princ)
  )

 

0 Likes
Message 15 of 27

Anonymous
Not applicable
Accepted solution

Ahah! I figured that last issue out.

Here is what I have so far:

 

(defun c:t3 ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")

  (initget 1 "Multiple")
  (setq pnt (getpoint "\nSpecify a point [Multiple]: "))
  (if (= pnt "Multiple")
    (while (progn
	     (initget "Undo T-for-m2p")
	     (setq pnt
		    (if m2p
		      (getpoint "\nFirst point of mid [Undo/T-for-m2p] <exit>: ")
		      (getpoint "\nSpecify a point [Undo/T-for-m2p] <exit>: ")
		      );if
		   );setq
	     );progn
      (cond ((= pnt "T-for-m2p") 
	     (setq m2p (not m2p))) 				;toggle m2p
	    ((= pnt "Undo")
	     (command "erase" "last" ""))
	    (T 
	       (command-s "point" (if m2p "m2p" "non") pnt)	     
	     );T
	    );cond
      );while
    (command "point" "non" pnt) 				; single point mode
    );if

  (setvar "clayer" oldlayer)
   (princ)
  );defun
0 Likes
Message 16 of 27

Anonymous
Not applicable

Great! Your edit with (strcat...) worked identically. Is there any reason why I would use either of those methods rather than the other? Other than a little less code?

Thank you for the quick replies and walking me through this! I'm learning! hah

 

Thanks,

Michael

0 Likes
Message 17 of 27

johnyDFFXO
Advocate
Advocate

Or like this.

    (while (progn
             (setq msg (if m2p 
"First point of mid"
"Specify a point"))
(initget "Undo T-for-m2p") (setq pnt (getpoint (strcat "\n" msg " [Undo/T-for-m2p] <exit>:"))) )

You should avoid the redundancy.. like (if m2p (getpoint...) (getpoint ...). On the other hand the code should be "readable.." I would probably consider the code above easier to read than my previous version. But its all about personal preferences... how you get use to it.

 

You're welcome, glad to help. If there is something you don't understand, don't hesitate to ask.

 

0 Likes
Message 18 of 27

Anonymous
Not applicable
Accepted solution

You're welcome, glad to help. If there is something you don't understand, don't hesitate to ask.

 


Thanks again, it's really satisfying getting a lisp routine to work, and I really appreciate this forum for guidance on learning more!

I did decide to get rid of the "multiple" user input and removed the conditional on the (while) funtion/conditional...? I'm sure I don't have the terms right, but here is the current interation:

 

(defun c:at nil (c:vportpoint))
(defun c:vportpoint ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
  (while (progn
	   (initget "Undo Toggle-m2p")
	   (setq pnt (getpoint (strcat "\n" (if m2p "First point of mid" "Specify a point") " [Undo/Toggle-m2p]: ")))
	   )
    (cond ((= pnt "Toggle-m2p")
	   (setq m2p (not m2p))) 				;toggle m2p
	  ((= pnt "Undo")
	   (command "erase" "last" ""))
	  (T
	   (command-s "point" (if m2p "m2p" "non") pnt))))
  (command "point" "non" pnt) 				; single point mode

  (setvar "clayer" oldlayer)
   (princ)
  )

I changed "T-for-m2p" to "Toggle-m2p" and it sparked the question: how would one make the "dash" a "space" instead? Do I understand right that a space in the code would not work properly? Is there a designation for a space, like a period or something?

 

Anyway, the program works for me!

 

Thanks!

Michael

0 Likes
Message 19 of 27

johnyDFFXO
Advocate
Advocate

@Anonymous wrote:

You're welcome, glad to help. If there is something you don't understand, don't hesitate to ask.

 


Thanks again, it's really satisfying getting a lisp routine to work, and I really appreciate this forum for guidance on learning more!

I did decide to get rid of the "multiple" user input and removed the conditional on the (while) funtion/conditional...? I'm sure I don't have the terms right, but here is the current interation:

 

(defun c:at nil (c:vportpoint))
(defun c:vportpoint ( / oldlayer pnt m2p)

  (setq oldlayer (getvar "clayer"))
  (command "-layer" "_make" "_VPORT" "")
  (while (progn
	   (initget "Undo Toggle M2P") ; Toggle and M2P are 2 different key words.
	   (setq pnt (getpoint (strcat "\n" (if m2p "First point of mid" "Specify a point") " [Undo/Toggle m2p]: ")))
	   )
    (cond ((or (= pnt "Toggle") (= pnt "M2P"))
	   (setq m2p (not m2p))) 				;toggle m2p
	  ((= pnt "Undo")
	   (command "erase" "last" ""))
	  (T
	   (command-s "point" (if m2p "m2p" "non") pnt))))
  ;(command "point" "non" pnt) 				; remove this line too

  (setvar "clayer" oldlayer)
   (princ)
  )

I changed "T-for-m2p" to "Toggle-m2p" and it sparked the question: how would one make the "dash" a "space" instead? Do I understand right that a space in the code would not work properly? Is there a designation for a space, like a period or something?

 

Anyway, the program works for me!

 

Thanks!

Michael


The limitation is the initget function where a space is a delimiter. Don't think there is a way around this.

But the actual prompt can be a bit different - unless it contains the key word, or at least the Capital letter... 

 

Paste this line into the command-line and feel free to experiment.

(progn (initget "Test") (getkword "[this is Test]:")) 

(progn (initget "T") (getkword "[This is test]:")) 

(progn (initget "Test") (getkword "[This]:")) 

............
So the way as the code is written you can type: T, Toggle, M, M2P (not case-sensitive) or pick a choice by a mouse.........
0 Likes
Message 20 of 27

Sea-Haven
Mentor
Mentor

I re-read the 1st post and something I have is the answer to one of your questions, yes you can type f124 and the fillet command will start with radius set to 124, the same with offset 045 will set offset to just that 45. A circle the same C56 pick a point and a circle appears with radius 56. Basically it can be any number following the F C or O fxxx

 

Its a case of using reactors and it checks the error for 1st character.

 

If you want it just post.

0 Likes