Viewing contents of file '../idllib/contrib/tappin/graffer/cw_bbselector.pro'
; $Id: cw_bbselector.pro,v 1.6 1993/12/22 23:34:09 kirk Exp $

; Copyright (c) 1993, Research Systems, Inc.  All rights reserved.
;	Unauthorized reproduction prohibited.
;+
; NAME:
;	CW_BBSELECTOR
;
; PURPOSE:
;	CW_BBSELECTOR 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_BBSELECTOR(Parent, Names)
;
;	To get or set the value of a CW_BBSELECTOR, use the GET_VALUE and
;	SET_VALUE keywords to WIDGET_CONTROL. The value of a CW_BBSELECTOR
;	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 --
;			N.B. this is ignored if the button has a
;			bitmap label.
;	RETURN_UVALUE:	An array of user values to be associated with
;			each button. Selecting the button sets the uvalue
;			of the CW_BBSELECTOR 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_BBSELECTOR'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
;
;	TRACKING_EVENTS: Return tracking events
;	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.
;	X_BITMAP_EXTRA	Number of bits at the end of each row of a
;			bitmap label to ignore, only used for bitmap
;			buttons.
;	
;
; 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:
;	Bitmap restriction removed, but return_name and bitmap are
;	still incompatible.
;
; MODIFICATION HISTORY:
;	1 April 1993, DMS,  Adapted from CW_BGROUP.
;	22 Dec. 1993, KDB,  Corrected documentation for keyword SET_VALUE.
;	Sept 95, SJT (U. of B'ham) Modify to allow bitmap buttons
;	(rename CW_BBSELECTOR to avoid potential confusion)
;	4/12/95; SJT: Add the tracking_events keyword.
;-


pro Cw_bbselector_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

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
    if (s.bits) then $
      WIDGET_CONTROL, s.menu, SET_VALUE = s.names(*, *, value), $
      x_bitmap_extra = s.x_bm_ex $
                                ;Set menu label
    else WIDGET_CONTROL, s.menu, SET_VALUE = s.names(value) 
    s.select = value            ;save button that's selected
ENDELSE

WIDGET_CONTROL, stash, SET_UVALUE = s, /NO_COPY  

end



function Cw_bbselector_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_bbselector_event, ev

base = ev.handler
stash = WIDGET_INFO(base, /CHILD) ;Get state from 1st child

WIDGET_CONTROL, stash, GET_UVALUE = s, /NO_COPY
if (ev.id eq s.menu) then begin
    st = ev
    st.id = base
    st.handler = 0l
    efun = s.efun
    WIDGET_CONTROL, stash, SET_UVALUE = s, /NO_COPY
    if efun ne '' then return, CALL_FUNCTION(efun, st) $
    else return, st
endif
WIDGET_CONTROL, ev.id, get_uvalue = uvalue ;The button index

s.select = uvalue               ;Save the selected index
rvalue = s.ret_arr(uvalue)

if (s.bits) then WIDGET_CONTROL, s.menu, SET_VALUE =  $
  s.names(*, *, uvalue), x_bitmap_extra = s.x_bm_ex $ 
                                ;Copy button's label to menu
else WIDGET_CONTROL, s.menu, SET_VALUE = s.names(uvalue)

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_bbselector, parent, names, EVENT_FUNCT=efun, $
                        RETURN_UVALUE=return_uvalue, $
                        FONT=font, FRAME=frame, IDS=ids, $
                        LABEL_TOP=label_top, LABEL_LEFT=label_left, $
                        MAP=map, RETURN_ID=return_id, $
                        RETURN_NAME=return_name, $
                        RETURN_INDEX=return_index, SET_VALUE=sval, $
                        UVALUE=uvalue, $ XOFFSET=xoffset, XSIZE=xsize, $
                        YOFFSET=yoffset, YSIZE=ysize, $
                        x_bitmap_extra=xbme, $
                        tracking_events=tracking_events



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
if (n_elements(xbme) eq 0)              then xbme = 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
    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)
    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_BBSELECTOR_EVENT', FUNC_GET_VALUE = 'CW_BBSELECTOR_GETV', $
  PRO_SET_VALUE = 'CW_BBSELECTOR_SETV', SET_UVALUE = uvalue
if n_elements(sval) le 0 then sval = 0 ;Default selection index


s = size(names)
n = s(s(0))

if (s(s(0)+1) eq 1) then begin  ; Bitmap buttons
    i = names(*, *, sval)
    menu = WIDGET_BUTTON(next_base, /MENU, value = i, x_bitmap_extra = $
                         xbme, tracking_events = $
                         keyword_set(tracking_events))
    
    ids = lonarr(n)
    for i = 0, n-1 do  $
      ids(i) = WIDGET_BUTTON(menu, value = names(*, *, i), UVALUE = i, $
                             x_bitmap_extra = xbme)
    bitflag = 1b
endif else if (s(s(0)+1) eq 7) then begin
    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 0) then $
      menu = WIDGET_BUTTON(next_base, /MENU, value = i, tracking_events $
                           = keyword_set(tracking_events))  $
    else menu = WIDGET_BUTTON(next_base, /MENU, value = i, tracking_events $
                           = keyword_set(tracking_events), font = font)
    
    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
    bitflag = 0b
endif else message, "Illegal type for names array."

                                ;Make returned value array
return_uvals = 0
if KEYWORD_SET(RETURN_ID) then ret_arr = ids $
else if KEYWORD_SET(RETURN_NAME) and not bitflag 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, $
                 Names:names, $ ; Button names must be stored as there
                                ; is no way to get_value a bitmap
                                ; button
                 Bits:bitflag, $ ; Is it a bitmap array?
                 X_bm_ex: xbme, $ ; pad bits for bitmap labels.
                 Ids:ids }      ; Ids of buttons
                 
return, top_base

END