REVISED-SOME BUGS FIXED: How do I initialize capi:radio-button-panel with NO
SELECTION?
Dave/All,
I did some debugging after quickly(?) writing the earlier code (lower below):
This version works much better--allowing the layout-arglist to work pretty well.
Obviously it could be a macro, but started this way and it seemed to be ok.
Easier for me to debug. Always open for improvements.
Tom
Tom G. Stevens PhD
Tom.Stevens@csulb.edu
Website: You Can Choose To Be Happy, www.csulb.edu/~tstevens
;;------------------------ CODE ------------------------------------------
;;
;;MAKE-MY-BUTTON-PANEL
;;
;;ddd
(defun make-my-button-panel (button-panel-name button-parent-layout-name
interface-name
button-text-list button-data-list
&key (close-interface-on-selection-p NIL)
(layout-type (quote (quote capi:column-layout)))
layout-arglist
button-arglist)
"Makes a button 'button-panel-name' which is a customized row or column layout of buttons that allows more options than the standard radio-button or check-button panels. Uses radio buttons as the buttons. All regular initargs to the layout is accessed via layout-arglist, and all radio-button initargs thru the &rest list. Starts with NO DEFAULT PRESELECTED BUTTON-a major change over capi. The arg button-parent-layout-name is the interface layout of which the button layout is an item in the layout-description. Use to create buttons and add to interfaces. Returns a layout. NOTE: THESE FUNCTIONS MUST BE USED AS A PACKAGE. 2 arg lists MUST be in form of '(list \"A\" \"B\" \"C\"). REQUIRES a pre-defined INTERFACE a layout named button-panel-name (can be within another empty layout button-p
arent-layout-name). The arglists must be preceded by double quotes."
(let
((layout-inst)
(global-selected-values-list (my-make-symbol
(format nil "*~A-selected-values-list" button-panel-name)))
)
;;Make the SELECTION CALLBACK
(eval
`(defun my-button-panel-selection-callback (item interface)
"In U-capi-buttons-etc.lisp, MUST use with my-button-panels. MODIFY THIS CALLBACK to get data or actions from the button selection."
(let
((button-value)
(button-data)
)
(with-slots (,button-panel-name ,button-parent-layout-name) interface
(loop
for button in (capi:layout-description ,button-panel-name)
unless (or (equal item button) (null item))
do
(setf (capi:item-selected button) nil)
;;end loop
)
;;added
(setf selected-text (capi:item-text item)
selected-data (capi:item-data item)
selected-button item)
(setf ,global-selected-values-list
(list selected-text selected-data selected-button))
(if ,close-interface-on-selection-p
(capi:destroy interface))
))
;;end defun callback,eval
))
;; make buttons
(defun make-a-button (text data)
(make-instance 'capi:radio-button
:text (format nil "~A" text)
:data data
:selected nil
:selection-callback 'my-button-panel-selection-callback
:callback-type :item-interface))
;;Make the :BEFORE METHOD
;; (setf *mytestvar
(eval
`(defmethod capi:interface-display :before ((interface ,interface-name))
(with-slots (,button-panel-name ,button-parent-layout-name) interface
(setf buttons-list
(loop
for data in ,button-data-list
for text in ,button-text-list
collect (make-a-button text data)))
;;now make the layout
(setf layout-inst ;; ,button-panel-name
(apply #'make-instance ,layout-type
:description (quote ,buttons-list) ,layout-arglist))
(capi:apply-in-pane-process ,button-parent-layout-name ;; ,button-panel-name
#'(setf capi:layout-description)
(list layout-inst) ,button-parent-layout-name)
;;end with-slots,defmethod, eval
)))
;;end defun make-my-button-panel
))
;;TEST FUNCTION
(defun testmb ()
(let
((x)
)
(capi:define-interface test-radio-buttons ()
;;sets the button/item data values
((data :initform (list 1 2 3)))
(:layouts
(row-layout1
capi:row-layout
'(my-button-panel-1)
)
(my-button-panel-1
capi:column-layout
()
)
)
(:default-initargs
:title "TEST INTERFACE"
:visible-min-width 500
:visible-min-height 400
:background :yellow
))
(make-my-button-panel 'my-button-panel-1 'row-layout1 'test-radio-buttons
'(list "A" "B" "C")
'(list 10 20 30)
:close-interface-on-selection-p T
:layout-arglist (quote (quote (:visible-min-width 200
:visible-min-height 300
:background :green
:title "My Test Buttons"
:x 50 :y 50
:internal-border 30
)))
)
(capi:display (setf *mb-testinst (make-instance 'test-radio-buttons)))
))
;;TEST RESULT
;; CL-USER 10 > *my-button-panel-1-selected-values-list
;; ("B" 20 #<CAPI:RADIO-BUTTON "B" 27AA618F>)
;;---------------------------- END CODE ------------------------------------------------
-----Original Message-----
From: owner-lisp-hug@lispworks.com [mailto:owner-lisp-hug@lispworks.com] On Behalf Of Thomas Stevens
Sent: Wednesday, April 23, 2014 3:19 PM
To: davef@lispworks.com; Dmitry Ivanov
Cc: lisp-hug@lispworks.com
Subject: RE: How do I initialize capi:radio-button-panel with NO SELECTION?
Dave,
I took your suggestion below and used it to write a more general function that would allow the user (me) to more simply write a layout with radio-buttons using all regular layout and button initargs and modifying your callback so that it would set a global variable named (format nil "*~A-selected-values-list" button-panel-name) to a list that includes the selected button text, data, and button-instance. Which is all the information I think one would need from a button selection.
By defining his/her own "button panel" it also allows the user to change other features.
NOTE: I haven't adequately tested all the features of this yet, so it probably still has bugs in it. If you or anyone else is interested in modifying or improving my code or features, OR if you know of a better way of doing this that is portable, please let me/us know.
Thanks very much,
Tom
PS. I hope someone from LW is watching and will make changes to CAPI so that we can easily START BUTTON PANELS WITH NO PRECHECKED BUTTONS!!
Tom G. Stevens PhD
Tom.Stevens@csulb.edu
Website: You Can Choose To Be Happy, www.csulb.edu/~tstevens
HERE IS THE CODE: -----------------------------------------------------------------
;;MAKE-MY-BUTTON-PANEL
;;
;;ddd
(defun make-my-button-panel (button-panel-name interface-name
button-text-list button-data-list
&key (close-interface-on-selection-p T)
(layout-type 'capi:column-layout)
layout-arglist
button-arglist) ;;&rest button-arglist) caused error
"Makes a button 'button-panel-name' which is a customized row or column layout of buttons that allows more options than the standard radio-button or check-button panels. Uses radio buttons as the buttons. All regular initargs to the layouts are accessed via layout-arglist, and all radio-button initargs thru the &rest list. Starts with NO DEFAULT PRESELECTED BUTTON-a major change over capi. Use to create buttons and add to interfaces. RETURNS A LAYOUT. NOTE: THESE FUNCTIONS MUST BE USED AS A PACKAGE. 2 arg lists MUST be in form of '(list "A" "B" "C"). REQUIRES a pre-defined INTERFACE a layout named button-panel-name (can be within another layout), but must have its own separate empty slot."
(let
((layout-inst)
(global-selected-values-list (my-make-symbol
(format nil "*~A-selected-values-list" button-panel-name)))
)
(eval
`(defun my-button-panel-selection-callback (item interface)
"In U-capi-buttons-etc.lisp, MUST use with my-button-panels. MODIFY THIS CALLBACK to get data or actions from the button selection."
(let
((button-value)
(button-data)
)
(with-slots (,button-panel-name) interface
(loop
for button in (capi:layout-description ,button-panel-name)
unless (eq item button)
do (setf (capi:item-selected button) nil)
;;end loop
)
;;added
(setf selected-text (capi:item-text item)
selected-data (capi:item-data item)
selected-button item)
(setf ,global-selected-values-list
(list selected-text selected-data selected-button))
(if ,close-interface-on-selection-p
(capi:destroy interface))
;;end callback
)))
;;end defun,eval
)
(defun make-a-button (text data)
(make-instance 'capi:radio-button
:text (format nil "~A" text)
:data data
:selected nil
:selection-callback 'my-button-panel-selection-callback
:callback-type :item-interface))
;; (setf *mytestvar -- used to test simulated "macroexpansion" on this part only
(eval
`(defmethod capi:interface-display :before ((interface ,interface-name))
(with-slots (,button-panel-name) interface
(setf buttons-list ;; ,button-panel-name
(loop
for data in ,button-data-list
for text in ,button-text-list
collect (make-a-button text data)))
;;
(capi:apply-in-pane-process ,button-panel-name
#'(setf capi:layout-description)
buttons-list ;; (list ,button-panel-name)
,button-panel-name))
;;end defmethod, eval
))
(setf layout-inst (apply #'make-instance layout-type layout-arglist))
;;now make the layout
))
;;test
(defun testmb ()
(let
((x)
)
(capi:define-interface test-radio-buttons ()
;;sets the button/item data values
((data :initform (list 1 2 3)))
(:layouts
(row-layout1
capi:row-layout
'(my-button-panel-1)
)
(my-button-panel-1
capi:column-layout
()
)
)
(:default-initargs
:title "TEST INTERFACE"
:visible-min-width 500
:visible-min-height 400
:background :yellow
))
(make-my-button-panel 'my-button-panel-1 'test-radio-buttons '(list "A" "B" "C")
'(list 10 20 30)
:layout-arglist '(:visible-min-width 200 :visible-min-height 300
:background :green
:title "My Test Buttons")
)
(capi:display (setf *mb-testinst (make-instance 'test-radio-buttons)))
))
;;RESULTS OF TEST
CL-USER 12 > *my-button-panel-1-selected-values-list
("B" 20 #<CAPI:RADIO-BUTTON "B" 200F1D83>)
;;------------------------- END OF CODE ----------------------------------
-----Original Message-----
From: Dave Fox [mailto:davef@lispworks.com]
Sent: Tuesday, April 22, 2014 5:32 AM
To: Dmitry Ivanov
Cc: Thomas Stevens; lisp-hug@lispworks.com
Subject: Re: How do I initialize capi:radio-button-panel with NO SELECTION?
> Thomas Stevens wrote on Sat, 19 Apr 2014 00:41:37 +0000 04:41:
>
> | I am converting a java questionnaire I wrote to lisp and a crucial > | element is the capi:radio-button-panel or a substitute that looks almost > just like it (not a > | list panel). It is very important that users do not see any checked > | buttons before they make their own choices-NO DEFAULT SELECTION.
>
> The only way is to use the capi:check-button-panel like this.
>
> (defun force-selection (pane data)
> (setf (capi:choice-selected-items pane) (list data)))
>
> (capi:contain
> (make-instance 'capi:check-button-panel
> :interaction :multiple-selection
> :items '("one" "two" "three")
> :selected-item nil
> :callback-type :collection-data
> :retract-callback 'force-selection
> :selection-callback 'force-selection))
You can also do it like this, with all of the buttons unselected initially, and imitating radio-button-panel's :single-selection interaction subsequently by making their callbacks deselect the other
buttons:
(capi:define-interface radio-buttons ()
((data :initform (list 1 2 3)))
(:layouts
(panel
capi:column-layout)))
(defun switch-other-buttons-off (item interface)
(with-slots (panel) interface
(loop for button in (capi:layout-description panel)
unless (eq item button)
do (setf (capi:item-selected button) nil))))
(defun make-a-button (i)
(make-instance 'capi:radio-button
:text (format nil "~R" i)
:data i
:selected nil
:selection-callback 'switch-other-buttons-off
:callback-type :item-interface))
(defmethod capi:interface-display :before ((self radio-buttons))
(with-slots (data panel) self
(setf (capi:layout-description panel)
(loop for i in data
collect (make-a-button i)))))
(capi:display (make-instance 'radio-buttons))
#| This also seems to work on Windows and Cocoa, but probably should not since radio-button-panel is a :single-selection choice. Does not nullify initial selections on GTK+, so definitely not portable.
(let ((rbp (make-instance 'capi:radio-button-panel
:items (list 1 2 3)
:print-function (lambda (i)
(format nil "~R" i))
:layout-class 'capi:column-layout)))
(setf (capi:choice-selection rbp) nil)
(capi:contain rbp))
|#
--
Dave Fox
LispWorks Ltd
http://www.lispworks.com/
Registered Office: St John's Innovation Centre, Cowley Road, Cambridge CB4 0WS Registered in England: No. 5114963 EC VAT ID: GB 833329531
_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html
_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html