[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Command Menu handlers and Program Frameworks ...



First, a user wanted to be able to specify the documentation on the mouse
line for commands he was specifying. I can find no straight-forward way
of doing that, so ...

So first, we use frameup to create the following framework:

(DW:DEFINE-PROGRAM-FRAMEWORK KASS
  :SELECT-KEY
  #\|
  :COMMAND-DEFINER
   T
  :COMMAND-TABLE
  (:INHERIT-FROM '("colon full command" "standard arguments" "standard scrolling")
   :KBD-ACCELERATOR-P 'NIL)
  :STATE-VARIABLES
  NIL
  :PANES
  ((PANE-1 :TITLE :SIZE-FROM-OUTPUT T :HEIGHT-IN-LINES 1 :REDISPLAY-AFTER-COMMANDS NIL)
   (PANE-3 :DISPLAY) (PANE-2 :COMMAND-MENU :MENU-LEVEL :TOP-LEVEL))
  :CONFIGURATIONS
  '((DW::MAIN (:LAYOUT (DW::MAIN :COLUMN PANE-1 PANE-3 PANE-2))
     (:SIZES
      (DW::MAIN (PANE-1 1 :LINES) (PANE-2 :ASK-WINDOW SELF :SIZE-FOR-PANE PANE-2) :THEN
       (PANE-3 :EVEN))))))

Now, what we'd like to be able to do is define a program command with
menu accelerator AND be able to specify the documentation shown on the
mouse line when the item is being pointed at. This, it turns out, means
you need to write your own handler (ugh!) or otherwise I'm missing some-
thing. So here's a little macro to generate the command and the handler:

(defmacro define-menu-command-with-mouse-documentation
	  ((name program-name documentation &optional (arglist nil)) &body body)
D,#TD1PsT[Begin using 006 escapes](1 0 (NIL 0) (NIL :ITALIC NIL) "CPTFONTI");; This hack builds a presentation translator handler just so that you can specify
;; what gets displayed on the mouse line when an item in a command menu is pointed at.
(2 0 (NIL 0) (NIL NIL NIL) "CPTFONT")  (let* ((com-name-string (concatenate 'string "COM-" (string name)))
	 (com-name (make-symbol com-name-string))
	 (com-handler-name (make-symbol (concatenate 'string com-name-string "-HANDLER"))))
    
    `(progn

1       ;; first we define the command ...
2       (dw::define-program-command (,com-name
				    ,program-name
				    :menu-accelerator t)
				   ,arglist ,@body)

1       ;; then we create the handler needed to get the documentation on the mouse line.
2       (dw::define-presentation-translator ,com-handler-name
	  (dw::command-menu-item
	    cp:command
	    :gesture t				1;available on all gestures ...
2	    :context-independent t		1;except those already defined.
2	    :do-not-compose t			1;don't compute body when pointed to.
2	    :documentation ,documentation
	    :priority .5			1;to override the default handler
2	    :tester ((ignore &key presentation)
1		     ;; without tester, this handler would apply
		     ;; to ALL menu items - system wide!!
2		     (string= ,(string-capitalize (string name))
			      (dw::displayed-string-string
				(dw::displayed-presentation-string-equal-start
				  presentation "")))))
	  ()
	 (cp:build-command
	   ',com-name
	   ,(if arglist `(cp:read-command-arguments ',com-name))))
       )))

Now, cp:read-command-arguments is the wrong function here, what you really
want is cp:choose-command-arguments, an undocumented function (no source either).
But, let's not worry about that. This is not a finished product, I've run into
problems that are beyond me though.

The above works fine unless you want a function that takes parameters.
Read-command-arguments doesn't work; it doesn't seem to know where to deal with
i/o. I've specified the stream (a keyword option), giving it the "display" pane,
but that doesn't seem to help. cp:choose-command-arguments doesn't work either.
The first of these two works fine, the second does not:

(define-menu-command-with-mouse-documentation (example kass "This runs the EXAMPLE command")
					      (print "Example command executed"))

(define-menu-command-with-mouse-documentation
  (params
    kass
    "This command (PARAMS) takes parameters"
    ((arg1 'string :documentation "Enter one string" :prompt "Arg1")
     (arg2 'string :documentation "Enter a second string" :prompt "Arg2")))
  (format *standard-output* "A silly ~a, causes great ~a" arg1 arg2))

In fact, the way I found cp:choose... was in the debugger where I was tossed
when I created the following command and mouse-r'd it. Note: this is the standard
way to use this stuff! and it is completely broken. And here is a definition to
demonstrate this broken behaviour:

(define-kass-command
  (boring :menu-accelerator t)
    ((arg1 'string :documentation "Enter one string" :prompt "Arg1")
     (arg2 'string :documentation "Enter a second string" :prompt "Arg2"))
  (format *standard-output* "A silly ~a, causes great ~a" arg1 arg2))

The error that is reported is that NIL isn't a function. The caller of NIL is
(:internal dw::accept-values-display-exit-boxes 0 dw:with-redisplayable-output).
NIL is called with Arg 0: :set-visibility and Arg 1: NIL.

Now, why didn't I just submit a bug report? c-m blew up about a bad cdr-code.
Why didn't I just use that adorable DW feature where I can mark and yank text
(a bit of a pain when the m-b yields about six screen fulls of stuff, but always
another option, you know)? Well, when I tried one of the first lines seemed to
be too long (array to big or small or something error, but lets worry about
that some other time).

So, is the macro I wrote the only way to accomplish what I set out to do?
If it is, SLUG readers who haven't yet given up on the program framework and
presentation systems are welcome to take it. And, why doesn't 
cp:choose- (or read-) command-arguments work here?