CLIM mail archive


Is there a CLIM version of tv:momentary-multiple-menu?

    Date: Tue, 23 Jul 1991 14:02 EDT

    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 


    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)

(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))
					 (: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  "<End> uses these values")
		  (abort "<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)
		(with-input-context ('accept-values-exit-box :override t)
		     (with-input-context ('menu-multiple-choose-selection)
			  (read-gesture :stream stream)
			  (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))))))
		     (ecase exit
			 (return-from menu-multiple-choose nil))
			 (return-from menu-multiple-choose
			   (mapcan #'(lambda (selection)
				       (and (second selection)
					    (list (menu-item-value (first selection)))))
#| (menu-multiple-choose (loop for i below 40 collect (cons (format nil "~R" i) i)))  |#


Main Index | Thread Index