; Copyright (c) 1993, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ;+ ; NAME: ; CW_BSELECTOR ; ; PURPOSE: ; CW_BSELECTOR is a compound widget that appears as a pull-down ; menu whose label shows the widget's current value. When the button ; is pressed, the menu appears and the newly selected value becomes ; the new title of the pull-down menu. ; ; CATEGORY: ; Compound widgets. ; ; CALLING SEQUENCE: ; widget = CW_BSELECTOR(Parent, Names) ; ; To get or set the value of a CW_BSELECTOR, use the GET_VALUE and ; SET_VALUE keywords to WIDGET_CONTROL. The value of a CW_BSELECTOR ; is the index of the selected item. ; ; INPUTS: ; Parent: The ID of the parent widget. ; Names: A string array, containing one string per button, ; giving the name of each button. ; ; KEYWORD PARAMETERS: ; EVENT_FUNCT: The name of an optional user-supplied event function ; for buttons. This function is called with the return ; value structure whenever a button is pressed, and ; follows the conventions for user-written event ; functions. ; FONT: The name of the font to be used for the button ; titles. If this keyword is not specified, the default ; font is used. ; FRAME: Specifies the width of the frame to be drawn around ; the base. ; IDS: A named variable into which the button IDs will be ; stored, as a longword vector. ; LABEL_LEFT: Creates a text label to the left of the buttons. ; LABEL_TOP: Creates a text label above the buttons. ; MAP: If set, the base will be mapped when the widget ; is realized (the default). ; RETURN_ID: If set, the VALUE field of returned events will be ; the widget ID of the button. ; RETURN_INDEX: If set, the VALUE field of returned events will be ; the zero-based index of the button within the base. ; THIS IS THE DEFAULT. ; RETURN_NAME: If set, the VALUE field of returned events will be ; the name of the button within the base. ; RETURN_UVALUE: An array of user values to be associated with ; each button. Selecting the button sets the uvalue ; of the CW_BSELECTOR to the button's uvalue and ; returns the uvalue in the value field of the event ; structure. If this keyword isn't specified, the ; CW_BSELECTOR's uvalue remains unchanged. ; SET_VALUE: The initial value of the buttons. This keyword is ; set to the index of the Names array element desired. ; So if it is desired that the initial value be the ; second element of the Names array, SET_VALUE would ; be set equal to 1. This is equivalent to the later ; statement: ; ; WIDGET_CONTROL, widget, set_value=value ; ; UVALUE: The user value to be associated with the widget. ; XOFFSET: The X offset of the widget relative to its parent. ; YOFFSET: The Y offset of the widget relative to its parent. ; ; OUTPUTS: ; The ID of the created widget is returned. ; ; SIDE EFFECTS: ; This widget generates event structures with the following definition: ; ; event = { ID:0L, TOP:0L, HANDLER:0L, INDEX:0, VALUE:0 } ; ; The INDEX field is the index (0 based) of the menu choice. VALUE is ; either the INDEX, ID, NAME, or BUTTON_UVALUE of the button, ; depending on how the widget was created. ; ; RESTRICTIONS: ; Only buttons with textual names are handled by this widget. ; Bitmaps are not understood. ; ; MODIFICATION HISTORY: ; 1 April 1993, DMS, Adapted from CW_BGROUP. ; 22 Dec. 1993, KDB, Corrected documentation for keyword SET_VALUE. ; 11 Aug. 1994, Scott Paswaters (NRL) ; 1) Added MENU=2 to differentiate a pd menu from a button under Motif. ; 2) Modified the CW_BSELECTOR_SETV procedure to allow changing the labels ; of the buttons. Example if you had a pd menu with two buttons 'b1' & 'b2': ; WIDGET_CONTROL, cw_bselector_base, SET_VALUE=['b3','b4'] ;** change labels ; WIDGET_CONTROL, cw_bselector_base, SET_VALUE=0 ;** to select 'b3' ;- pro CW_BSELECTOR2_SETV, id, value ON_ERROR, 2 ;return to caller stash = WIDGET_INFO(id, /CHILD) ;Get state from 1st child WIDGET_CONTROL, stash, GET_UVALUE=s, /NO_COPY sz = SIZE(value) IF (sz(N_ELEMENTS(sz)-2) EQ 7) THEN BEGIN ;** value is a string, create new buttons IF (N_ELEMENTS(value) NE N_ELEMENTS(s.ids)) THEN $ MESSAGE, 'New button name array must have same elements as original.', /INFO $ ELSE FOR i=0, N_ELEMENTS(s.ids)-1 DO $ WIDGET_CONTROL, s.ids(i), SET_VALUE=value(i) ;Set menu label ENDIF ELSE BEGIN ;** value not a string, select a current button if value lt 0 or value ge n_elements(s.ids) then $ MESSAGE, 'Button value must be from 0 to n_buttons -1.', /INFO $ ELSE BEGIN WIDGET_CONTROL, s.ids(value), GET_VALUE=v ;Get button label WIDGET_CONTROL, s.menu, SET_VALUE=v ;Set menu label if s.uvret then WIDGET_CONTROL, id, SET_UVALUE=s.ret_arr(value) s.select = value ;save button that's selected ENDELSE ENDELSE WIDGET_CONTROL, stash, SET_UVALUE=s, /NO_COPY end function CW_BSELECTOR2_GETV, id ON_ERROR, 2 ;return to caller stash = WIDGET_INFO(id, /CHILD) ;Get state from 1st child WIDGET_CONTROL, stash, GET_UVALUE=s, /NO_COPY ret = s.select WIDGET_CONTROL, stash, SET_UVALUE=s, /NO_COPY return, ret end function CW_BSELECTOR2_EVENT, ev base = ev.handler stash = WIDGET_INFO(base, /CHILD) ;Get state from 1st child WIDGET_CONTROL, stash, GET_UVALUE=s, /NO_COPY WIDGET_CONTROL, ev.id, get_uvalue=uvalue ;The button index s.select = uvalue ;Save the selected index rvalue = s.ret_arr(uvalue) WIDGET_CONTROL, ev.id, GET_VALUE = v ;Copy button's label to menu WIDGET_CONTROL, s.menu, SET_VALUE = v if s.uvret then WIDGET_CONTROL, base, SET_UVALUE=rvalue efun = s.efun WIDGET_CONTROL, stash, SET_UVALUE = s, /NO_COPY st = { ID:base, TOP:ev.top, HANDLER:0L, INDEX: uvalue, $ ;Return value VALUE: rvalue } if efun ne '' then return, CALL_FUNCTION(efun, st) $ else return, st end function CW_BSELECTOR2, parent, names, EVENT_FUNCT = efun, $ RETURN_UVALUE = return_uvalue, no_release=no_release,$ FONT=font, FRAME=frame, IDS=ids, LABEL_TOP=label_top, $ LABEL_LEFT=label_left, MAP=map, RETURN_ID=return_id, $ RETURN_INDEX=return_index, RETURN_NAME=return_name, $ SET_VALUE=sval, UVALUE=uvalue, $ XOFFSET=xoffset, XSIZE=xsize, $ YOFFSET=yoffset, YSIZE=ysize ; ON_ERROR, 2 ;return to caller ; Set default values for the keywords version = WIDGET_INFO(/version) if (version.toolkit eq 'OLIT') then def_space_pad = 4 else def_space_pad = 3 IF (N_ELEMENTS(frame) eq 0) then framet = 0 else framet = frame IF (N_ELEMENTS(map) eq 0) then map=1 IF (N_ELEMENTS(uvalue) eq 0) then uvalue = 0 IF (N_ELEMENTS(xoffset) eq 0) then xoffset=0 IF (N_ELEMENTS(xsize) eq 0) then xsize = 0 IF (N_ELEMENTS(yoffset) eq 0) then yoffset=0 IF (N_ELEMENTS(ysize) eq 0) then ysize = 0 top_base = 0L next_base = parent if (n_elements(label_top) ne 0) then begin next_base = WIDGET_BASE(next_base, XOFFSET=xoffset, YOFFSET=yoffset, $ FRAME=framet, /COLUMN) top_base = next_base framet = 0 ;Only one frame if n_elements(font) eq 1 then $ junk = WIDGET_LABEL(next_base, value=label_top,font=font) else $ junk = WIDGET_LABEL(next_base, value=label_top) endif else next_base = parent if (n_elements(label_left) ne 0) then begin next_base = WIDGET_BASE(next_base, XOFFSET=xoffset, YOFFSET=yoffset, $ FRAME=framet, /ROW) if n_elements(font) eq 1 then $ junk = WIDGET_LABEL(next_base, value=label_left,font=font) else $ junk = WIDGET_LABEL(next_base, value=label_left) framet = 0 ;Only one frame if (top_base eq 0L) then top_base = next_base endif ; We need some kind of outer base to hold the users UVALUE if (top_base eq 0L) then begin top_base = WIDGET_BASE(next_base, XOFFSET=xoffset, YOFFSET=yoffset, $ FRAME = framet) next_base = top_base endif ; Set top level base attributes WIDGET_CONTROL, top_base, MAP=map, EVENT_FUNC='CW_BSELECTOR2_EVENT', $ FUNC_GET_VALUE='CW_BSELECTOR2_GETV', PRO_SET_VALUE='CW_BSELECTOR2_SETV', $ SET_UVALUE=uvalue if n_elements(sval) le 0 then sval = 0 ;Default selection index len = max(strlen(names), i) ;Longest string = 1st value len1 = strlen(names(sval)) ;Initial string length if len gt len1 then $ i = names(sval) + string(replicate(32B, len-len1+2)) $ ;+ slop else i = names(sval) if n_elements(font) eq 1 then $ menu = WIDGET_BUTTON(next_base, MENU=2, value = i,font=font) else $ menu = WIDGET_BUTTON(next_base, MENU=2, value = i) n = n_elements(names) ids = lonarr(n) for i = 0, n-1 do begin if (n_elements(font) eq 0) then begin ids(i) = WIDGET_BUTTON(menu, value=names(i), UVALUE=i) endif else begin ids(i) = WIDGET_BUTTON(menu, value=names(i), FONT=font, UVALUE=i) endelse endfor ;Make returned value array return_uvals = 0 if KEYWORD_SET(RETURN_ID) then ret_arr = ids $ else if KEYWORD_SET(RETURN_NAME) then ret_arr = names $ else if KEYWORD_SET(RETURN_UVALUE) then begin ret_arr = return_uvalue return_uvals = 1 endif else ret_arr = indgen(n) stash = WIDGET_INFO(top_base, /CHILD) ;Affix state to 1st child if n_elements(efun) le 0 then efun = '' WIDGET_CONTROL, stash, SET_UVALUE= { $ menu: menu, $ efun : efun, $ ; Name of event fcn ret_arr: ret_arr, $ ; Vector of event values select : sval, $ uvret : return_uvals, $ ids:ids } ; Ids of buttons return, top_base END