;+
; Project     : SOHO - CDS     
;                   
; Name        : CW_PSELECT
;               
; Purpose     : Simplified management of a pulldown selection menu
;               
; Explanation : Often an exclusive button menu takes too much space.  This
;               widget makes it possible to use a pulldown menu for the
;               selection in stead, with automated altering of the top-level
;               button for status change.
;
;               This compound widget is in many respects very similar to the
;               standard IDL library routine CW_BSELECT, except that it is
;               possible to specify both a "menu text" (mtext) and a "button
;               text" (btext). This allows fairly long descriptions of the
;               menu choices, whilst keeping down the space required for the
;               label on the top level button.
;
;               EVENTS
;
;               Another difference from CW_BSELECT is that the returned events
;               are always of standard type {WIDGET_BUTTON}, whose ID refers
;               to the compound widget BASE (not the selected button).  The
;               UVALUE of EVENT.ID is always set to the uvalue of the selected
;               button.
;
;               ALTERING THE CURRENT SELECTION
;
;               It is possible to manipulate the current selection from the
;               main program by setting the compund widget value to the uvalue
;               of the desired selection. The displayed value on the root
;               button will be changed accordingly. E.g.:
;
;               WIDGET_CONTROL,CW_PSEL_ID,SET_VALUE="AA"
;
;               where CW_PSEL_ID is the widget ID returned by CW_PSELECT.
;               This will find the menu entry with UVALUE "AA" and update the
;               display as if the user had selected this menu entry manually.
;
;               (DE)SENSITIZING BUTTONS
;
;               Is possible to turn on/off the sensitivity of specific menu
;               items by e.g.:
;
;               WIDGET_CONTROL,CW_PSEL_ID, $
;                              SET_VALUE={INSENSITIVE:["AA","CC"],$
;                                         SENSITIVE:"BB"}
;
;               This will desensitize the menu items with uvalues "AA" and
;               "BB", and sensitize the menu item with uvalue "BB".
;
; Use         : id = cw_pselect(base,title,pdmenu)
;    
; Inputs      : BASE: The base to put the widget on
;               
;               TITLE: A title to be displayed on the "root" button, normally
;                      indicating what type of data the widget is dealing
;                      with, e.g., "Color chosen:"
;                      
;               PDMENU: An array of structures of the following type:
;
;               {PSELECT_S, btext:'', mtext:'', uvalue:'', flags:0}
;
;               BTEXT is the button text, MTEXT is the menu text (enables
;               longer explanations of the selections), UVALUE is the
;               associated uvalue of the button.  Multi-level pulldown menus
;               are possible with the use of the FLAGS field -- see CW_PDMENU.
;
; Opt. Inputs : None.
;               
; Outputs     : None.
;               
; Opt. Outputs: None.
;               
; Keywords    : INITIAL : The index of the initial selection to be
;               displayed.
;
;               IDS : A named variable into which the button IDs will
;                     be stored as a longword vector.
;
; Calls       : default parcheck cw_pselect() widget_base()
;
; Common      : None.
;               
; Restrictions: UVALUES must be strings.
;               
; Side effects: None...
;               
; Category    : Compound widget.
;               
; Prev. Hist. : None.
;
; Written     : Stein Vidar Hagfors Haugan, 11-December 1994
;               
; Modified    : Version 2, SVHH, 31 May 1996
;                       Added SET_VALUE possibilities and IDS keyword
;               Version 3, SVHH, 16 October 1996
;                       Minor space-saving change.
;               Version 4, SVHH, 23 October 1996
;                       Added /DYNAMIC_RESIZE for IDL v 4.0.1 and later.
;
; Version     : 4, 23 October 1996
;-            


;
; Setting the value of this widget actually means setting the uvalue
; 
; In order to desensitize a menu option, set the value of the widget to
; a structure with a tag named "insensitive" that contains a string array
; with the uvalues of the options to be grayed out.
;
; In order to sensitize an option, set the value to a structure with a tag
; named sensitive, containing a string array with uvalues of options to
; be sensitized.

PRO cw_pselect_setv,id,uvalue
  
  keeper = WIDGET_INFO(id,/child)
  button = WIDGET_INFO(keeper,/child)
  WIDGET_CONTROL,keeper,get_uvalue=info
  
  IF datatype(uvalue) EQ 'STR' THEN BEGIN
     ix = (WHERE(info.menu(*).uvalue EQ uvalue))(0)
     IF ix EQ -1 THEN  $
        MESSAGE,"Cannot set UVALUE="+uvalue+" for button "+info.title,/continue
     
     selection = info.menu(ix).btext
     WIDGET_CONTROL,button,set_value=info.title+selection
  
     WIDGET_CONTROL,id,set_uvalue=info.menu(ix).uvalue
  END ELSE IF datatype(uvalue) EQ 'STC' THEN BEGIN
     
     ;; Sensitize any buttons?
     IF tag_exist(uvalue,"sensitive",/top_level) THEN BEGIN
        sensitive = uvalue.sensitive
        FOR i = 0,N_ELEMENTS(sensitive)-1 DO BEGIN
           ix = WHERE(info.menu(*).uvalue EQ sensitive(i),count)
           IF count GT 0 THEN BEGIN
              FOR ii = 0,N_ELEMENTS(ix)-1 DO BEGIN
                 WIDGET_CONTROL,info.ids(ix(ii)+1),/sensitive
              END
           END
        END
     END
     
     ;; DEsensitize any buttons?
     IF tag_exist(uvalue,"insensitive",/top_level) THEN BEGIN
        insensitive = uvalue.insensitive
        FOR i = 0,N_ELEMENTS(insensitive)-1 DO BEGIN
           ix = WHERE(info.menu(*).uvalue EQ insensitive(i),count)
           IF count GT 0 THEN BEGIN
              FOR ii = 0,N_ELEMENTS(ix)-1 DO BEGIN
                 WIDGET_CONTROL,info.ids(ix(ii)+1),sensitive = 0
              END
           END
        END
     END
  END
  
END



FUNCTION cw_pselect_event,ev
  Widget_CONTROL,ev.id,Get_UVALUE=info
  
  ;; EV.VALUE is INDEX into menu
  selection = info.menu(ev.value-1).btext
  
  ;; Set value of root button
  Widget_CONTROL,widget_info(ev.id,/child),Set_value=info.title+selection
  
  ;; Set UVALUE of the compound widget
  Widget_control,ev.handler,set_uvalue=info.menu(ev.value-1).uvalue
  
  ;; Send on the event, with new ID
  ev.id = ev.handler
  return,ev
END




FUNCTION cw_pselect,base,title,options,initial=initial,IDS=IDS
  
  IF N_params() lt 3 THEN message,"Use: ID = CW_PSELECT(BASE,TITLE,OPTIONS)"
  
  parcheck,base,1,typ(/lon),0,'BASE'
  parcheck,title,2,typ(/str),0,'TITLE'
  parcheck,options,3,typ(/stc),1,'Menu options'
  
  IF tag_names(options,/struct) ne 'PSELECT_S' THEN $
	  message,"OPTIONS must be an array of {PSELECT_S}"
  
  

  default,initial,(WHERE((options.flags AND 1) EQ 0))(0) > 0
  
  parcheck,initial,0,typ(/nat),0,'INITIAL (menu selection)'

  initial = (initial > 0) < (N_elements(options)-1)
  
  dummy = {CW_PDMENU_S, flags:0, name:''}
  
  menu = [{CW_PDMENU_S, 1, title+options(initial).btext},$
	  replicate({CW_PDMENU_S},N_elements(options))]
  
  menu(1:*).flags = options(*).flags
  menu(1:*).name  = options(*).mtext
  menu(N_elements(options)).flags = 2
  
  info = { menu:options, title:title, ids:lonarr(N_ELEMENTS(menu))}
  
  subbase = Widget_BASE(base,event_func='cw_pselect_event',$
                        pro_set_value='cw_pselect_setv')
  
  storage = cw_pdmenu(subbase,menu,IDS=IDS,xoffset = 0,yoffset = 0)
  IF since_version('4.0.1') THEN BEGIN
     widget_control,ids(0),/dynamic_resize
  END
  
  info.ids = ids
  WIDGET_CONTROL,storage,set_uvalue=info
  
  WIDGET_CONTROL,subbase,set_uvalue=options(initial).uvalue
  
  return,subbase
END

; Test program
;----------------------

PRO pselect_event,ev
  WIDGET_CONTROL,ev.id,get_uvalue=uval
  PRINT,"Uvalue :",uval
  
  ab = ['UVALUE_A','UVALUE_B']
  cdequit = "UVALUE_"+['C','D','E','QUIT']
  
  IF total(uval EQ ab) GT 0 THEN BEGIN
     WIDGET_CONTROL,ev.id,set_value={sensitive:cdequit,insensitive:ab}
  END ELSE IF total(uval EQ cdequit) GT 0 THEN BEGIN
     WIDGET_CONTROL,ev.id,set_value={sensitive:ab,insensitive:cdequit}
  END
  
  IF UVAL EQ 'UVALUE_QUIT' THEN WIDGET_CONTROL,ev.top,/destroy
END


PRO pselect
  
  b = Widget_BASE(/column)
  
  dummy = {PSELECT_S, btext:'', mtext:'', uvalue:'', flags:0}
  
  options=[{PSELECT_S, 'Button A', 'Menu A', 'UVALUE_A', 0},$
	   {PSELECT_S, 'Button B', 'Menu B', 'UVALUE_B', 0},$
	   {PSELECT_S, 'Button C', 'Menu C', 'UVALUE_C', 0},$
	   {PSELECT_S, 'Button D', 'Menu D', 'UVALUE_D', 0},$
           {PSELECT_S, 'Button E', 'Menu E', 'UVALUE_E', 0},$
           {PSELECT_S, 'QUIT',     'Menu QUIT', 'UVALUE_QUIT',0}]
  
  c = cw_pselect(b,'Selection:',options)
  WIDGET_CONTROL,c,set_value={insensitive:"UVALUE_"+["C","D","E","QUIT"]}
  
  d = widget_label(b,value='This is a label')
  
  Widget_CONTROL,b,/realize
  
  XMANAGER,'pselect',b,/modal
  
END