Received: from BBN.COM by LABS-N.BBN.COM id aa27648; 23 Jul 91 17:16 EDT Received: from SAPSUCKER.SCRC.Symbolics.COM by BBN.COM id aa29453; 23 Jul 91 17:04 EDT Received: from EVENING-GROSBEAK.SCRC.Symbolics.COM by SAPSUCKER.SCRC.Symbolics.COM via INTERNET with SMTP id 409177; 23 Jul 1991 16:18:57-0400 Date: Tue, 23 Jul 1991 16:18-0400 From: Scott McKay Subject: Is there a CLIM version of tv:momentary-multiple-menu? To: jd05@gte.com, clim@BBN.COM In-Reply-To: <19910723180220.8.JOHND@babar.gte.com> Message-ID: <19910723201859.2.SWM@EVENING-GROSBEAK.SCRC.Symbolics.COM> Date: Tue, 23 Jul 1991 14:02 EDT From: jd05@gte.com I need to display a list of items, and let the user select as many as needed, press DO IT and return a list of the items selected. If I were in DW, I would do this with tv:momentary-multiple-menu But I want to use CLIM. Is there an easy way to do it with CLIM? Since a number of people have asked for this, I guess it's time to just forward the hack I wrote to do it. Here it is. To paraphrase: the code expressed below is mine, not necessarily that of my employer. No warranties offered or implied. ---------------- ;;; -*- Base: 10; Package: CLIM; Mode: LISP; Syntax: Common-Lisp; Lowercase: Yes -*- (export 'clim::(menu-multiple-choose) 'clim) (define-presentation-type menu-multiple-choose-selection ()) (defun menu-multiple-choose (item-list &key (associated-window (frame-top-level-window *application-frame*)) default-style label (printer #'print-menu-item) max-width max-height n-rows n-columns inter-column-spacing inter-row-spacing (cell-align-x ':left) (cell-align-y ':top)) (with-menu (stream associated-window) (setf (window-label stream) label) (with-end-of-page-action (:allow stream) (with-end-of-line-action (:allow stream) (with-text-style (default-style stream) (let ((selections (mapcar #'(lambda (x) (list x nil)) item-list)) (selection-pieces ()) ;;--- Need this first-piece kludge to work around a redisplay ;;--- bug that causes the first item to be erased whenever ;;--- any other item is redisplayed. (first-piece nil)) ;; Display all the selections, collecting redisplay pieces as we go (formatting-item-list (stream :max-width max-width :max-height max-height :n-rows n-rows :n-columns n-columns :inter-column-spacing inter-column-spacing :inter-row-spacing inter-row-spacing) (dolist (selection selections) (formatting-cell (stream :align-x cell-align-x :align-y cell-align-y) (let ((piece (let ((selection selection)) (updating-output (stream) (updating-output (stream :unique-id selection :cache-value (second selection)) (with-output-as-presentation (:stream stream :object selection :type 'menu-multiple-choose-selection) (if (second selection) (with-text-face (:bold stream) (funcall printer (first selection) stream)) (funcall printer (first selection) stream)))))))) (when (null first-piece) (setq first-piece piece)) (push (list selection piece) selection-pieces))))) ;; Display the exit boxes (let ((exit " uses these values") (abort " aborts")) (terpri stream) (updating-output (stream :unique-id stream :cache-value 'exit-boxes) (with-output-as-presentation (:stream stream :type 'accept-values-exit-box :object ':abort) (write-string abort stream)) (write-string ", " stream) (with-output-as-presentation (:stream stream :type 'accept-values-exit-box :object ':exit) (write-string exit stream))) (terpri stream)) ;; Size and expose the multiple-choice menu (size-menu-appropriately stream) (multiple-value-bind (x y) (stream-pointer-position-in-window-coordinates (window-parent stream)) (position-window-near-carefully stream x y)) (window-expose stream) ;; Now read from the menu (with-input-focus (stream) (loop (with-input-context ('accept-values-exit-box :override t) (exit) (with-input-context ('menu-multiple-choose-selection) (selection) (read-gesture :stream stream) (menu-multiple-choose-selection (setf (second selection) (not (second selection))) (let ((piece (second (assoc selection selection-pieces)))) (when piece (redisplay piece stream) (unless (eql piece first-piece) (replay first-piece stream)))))) (accept-values-exit-box (ecase exit (:abort (return-from menu-multiple-choose nil)) (:exit (return-from menu-multiple-choose (mapcan #'(lambda (selection) (and (second selection) (list (menu-item-value (first selection))))) selections)))))))))))))) #| (menu-multiple-choose (loop for i below 40 collect (cons (format nil "~R" i) i))) |#