[mcclim-devel] Listener menus

Christophe Rhodes csr21 at cantab.net
Wed Jan 3 12:27:06 EST 2007


Hi,

The attached restores working menus to the Listener.  (It's not
completely clean; I'll try to explain why).

The first thing to do, done in the middle hunk of the three-hunk
patch, is to put back the listener-view specializations to the
interactor and the pointer documentation.  (The latter isn't
necessary, but I think it's right anyway).

The first hunk is the magical one: it defines a command-or-form accept
method which treats menu-items specially.  The problem is that a
menu-item is a perfectly good form, at least according to the various
presentation translators around; therefore, the command-or-form input
context "captures" the menu item.  I'm not sure that this is ever
desired behaviour, but it's certainly not desired behaviour inside
read-frame-command of the listener, so we reintroduce an input context
for menu-item inside the command-or-form context, and throw to the
outer context handler established by the McCLIM-provided
read-frame-command :around method.

As I say, I'm not sure that it's ever desireable for 'expression or
'form input contexts to capture menu-items; if it isn't, then probably
mcclim itself ought to prevent it from happening, maybe by a similar
trick inside the system accept methods?  It all looks a bit horrible,
though.  It's not great for the user as it stands, though, because as
far as I can tell there's no standard menu-item presentation type --
the one that McCLIM implements is good, but it's not in Gilbert's
annotatable spec -- and the contents of *input-context* are explicitly
unspecified.

The third hunk of this diff is an alternative approach, handling
menu-items specially if they're returned from read-frame-command.
This feels clunkier somehow -- for instance, the menu-item objects are
printed at the repl -- but seems to violate fewer abstractions.

Comments?

Cheers,

Christophe

PS: when I apply this patch and click on a menu item for, say, Show
Class Subclasses, the resulting dialog box eats my first keystroke
using Drei, but not using Goatee.

-------------- next part --------------
Index: listener.lisp
===================================================================
RCS file: /project/mcclim/cvsroot/mcclim/Apps/Listener/listener.lisp,v
retrieving revision 1.31
diff -u -r1.31 listener.lisp
--- listener.lisp	3 Dec 2006 22:56:46 -0000	1.31
+++ listener.lisp	3 Jan 2007 17:14:37 -0000
@@ -155,6 +155,42 @@
 	  (values result ptype)
 	  (input-not-of-required-type result ptype)))))
 
+(define-presentation-method accept :around
+  ((type command-or-form) stream (view listener-view) &key)
+  (let ((command-ptype `(command :command-table ,command-table)))
+    (with-input-context (`(or ,command-ptype form))
+        (object type event options)
+        ;; FIXME: this is not really right.  The problem is that a
+        ;; MENU-ITEM is a STANDARD-OBJECT, which has a
+        ;; presentation-to-command translator to FORM.  The normal
+        ;; menu item handling is in an :AROUND method on
+        ;; READ-FRAME-COMMAND, but this means that the inner accept
+        ;; method for FORM implicit in COMMAND-OR-FORM shadows that
+        ;; handling.
+        ;;
+        ;; This input context restores menu-item as overriding form,
+        ;; which is probably what we want; the way it does it is
+        ;; sensitive to McCLIM internals, which is less like what we
+        ;; want.
+        ;;
+        ;; (one McCLIM internal is the existence of a MENU-ITEM
+        ;; presentation type at all; I couldn't find it in the spec;
+        ;; another is the existence of a handler for menu-item in
+        ;; *input-context*.)
+        (with-input-context ('menu-item)
+            (object type event options)
+            (let ((initial-char (read-gesture :stream stream :peek-p t)))
+              (if (member initial-char *command-dispatchers*)
+                  (progn
+                    (read-gesture :stream stream)
+                    (accept command-ptype :stream stream :view view :prompt nil))
+                  (accept 'form :stream stream :view view :prompt nil)))
+          (menu-item
+           (funcall (cdr (find 'menu-item *input-context* :key #'car))
+                    object type event options)))
+      (t
+       (funcall (cdar *input-context*) object type event options)))))
+
 ;;; Listener interactor stream.  If only STREAM-PRESENT were
 ;;; specializable on the VIEW argument, this wouldn't be necessary.
 ;;; However, it isn't, so we have to play this game.  We currently
@@ -181,8 +217,9 @@
   (:panes (interactor-container
            (make-clim-stream-pane
             :type 'listener-interactor-pane
-            :name 'interactor :scroll-bars t))
-          (doc :pointer-documentation)
+            :name 'interactor :scroll-bars t
+            :default-view +listener-view+))
+          (doc :pointer-documentation :default-view +listener-pointer-documentation-view+)
           (wholine (make-pane 'wholine-pane
                      :display-function 'display-wholine :scroll-bars nil
                      :display-time :command-loop :end-of-line-action :allow)))
@@ -229,12 +266,28 @@
 (defmethod read-frame-command ((frame listener) &key (stream *standard-input*))  
   "Specialized for the listener, read a lisp form to eval, or a command."
   (multiple-value-bind (object type)
-      (accept 'command-or-form :stream stream :prompt nil)
+      (let ((*command-dispatchers* '(#\,)))
+        (accept 'command-or-form :stream stream :prompt nil))
     (format *trace-output* "~&object=~W~%" object)
     (if (presentation-subtypep type 'command)
         object
         `(com-eval ,object))))
 
+#|
+        ;; FIXME: CLIM:MENU-ITEM isn't actually a defined type by the
+        ;; standard.  This stuff is hidden by the input context for
+        ;; FORM implicit in the COMMAND-OR-FORM acceptor
+        (if (typep object 'menu-item)
+            (let ((command (command-menu-item-value object)))
+              (unless (listp command)
+                (setq command (list command)))       
+              (if (and (typep stream 'interactor-pane)
+                       (member *unsupplied-argument-marker* command :test #'eq))
+                  (command-line-read-remaining-arguments-for-partial-command
+                   (frame-command-table frame) stream command 0)
+                  command))
+|#
+
 (defun print-listener-prompt (stream frame)
   (declare (ignore frame))
   (with-text-face (stream :italic)


More information about the mcclim-devel mailing list