#include "snd.h"
#include <X11/cursorfont.h>

enum {menu_menu,
        file_menu,f_cascade_menu,
          f_open_menu,f_close_menu,f_save_menu,f_save_as_menu,f_revert_menu,f_exit_menu,f_new_menu,
          f_view_menu,f_print_menu,f_mix_menu,f_update_menu,f_record_menu,
        edit_menu,e_cascade_menu,
          e_cut_menu,e_paste_menu,e_mix_menu,e_play_menu,e_save_as_menu,e_undo_menu,e_redo_menu,e_find_menu,e_edenv_menu,
        help_menu,h_cascade_menu,
          h_click_for_help_menu,h_about_snd_menu,h_fft_menu,h_find_menu,h_undo_menu,h_sync_menu,h_speed_menu,
          h_expand_menu,h_contrast_menu,h_reverb_menu,h_env_menu,h_marks_menu,h_sound_files_menu,h_init_file_menu,
          h_ufun_menu,h_mix_menu,h_recording_menu,
        option_menu,o_cascade_menu,
          o_fft_size_menu,o_fft_peaks_menu,o_fft_logx_menu,o_fft_db_menu,
          o_fft_style_menu,o_fft_style_cascade_menu,
            o_fft_simple_menu,o_fft_sonogram_menu,o_fft_spectrogram_menu,
          o_fft_window_menu,o_fft_beta_menu,
          o_focus_style_menu,o_focus_cascade_menu,
            o_focus_right_menu,o_focus_left_menu,o_focus_middle_menu,o_focus_active_menu,
          o_subsampling_menu,o_save_menu,o_session_menu,
          o_speed_menu,o_speed_cascade_menu,
            o_speed_float_menu,o_speed_ratio_menu,o_speed_semitone_menu,
          o_transform_type_menu,o_transform_type_cascade_menu,
            o_transform_fourier_menu,o_transform_hankel_menu,o_transform_wavelet_menu,o_transform_chebyshev_menu,o_transform_legendre_menu,
        view_menu,v_cascade_menu,
          v_normalize_menu, v_dots_menu, v_marks_menu, v_zero_menu, v_cursor_menu, v_ctrls_menu, 
          v_region_menu, v_info_menu, 
          v_combine_menu, v_combine_cascade_menu,
            v_combine_separate_menu,v_combine_combined_menu,v_combine_superimposed_menu,
          v_color_menu, v_orientation_menu, 
          v_files_menu, v_groups_menu, v_consoles_menu,
          v_x_axis_menu,v_x_axis_cascade_menu,
            v_x_axis_seconds_menu,v_x_axis_samples_menu,v_x_axis_percentage_menu
};
#define NUM_MENU_WIDGETS 104
static Widget mw[NUM_MENU_WIDGETS];

enum {W_pop_menu,W_pop_sep,W_pop_play,W_pop_undo,W_pop_redo,W_pop_save,W_pop_normalize,W_pop_info};
#define NUM_POPUP_CHILDREN 8
static Widget popup_menu = NULL;
static Widget popup_children[NUM_POPUP_CHILDREN];

static char search_string[256];

void reflect_file_open_in_menu (void)
{
  XtSetSensitive(mw[f_close_menu],TRUE);
  XtSetSensitive(mw[f_print_menu],TRUE);
  XtSetSensitive(mw[f_mix_menu],TRUE);
  XtSetSensitive(mw[f_save_as_menu],TRUE);
  XtSetSensitive(mw[f_update_menu],TRUE);  
  XtSetSensitive(mw[v_normalize_menu],TRUE);  
  XtSetSensitive(mw[v_info_menu],TRUE);
  XtSetSensitive(mw[e_find_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_normalize],TRUE);
  XtSetSensitive(popup_children[W_pop_play],TRUE);
  XtSetSensitive(popup_children[W_pop_info],TRUE);
}

void reflect_file_change_in_menu (void)
{
  XtSetSensitive(mw[f_save_menu],TRUE);
  XtSetSensitive(mw[f_revert_menu],TRUE);
  XtSetSensitive(mw[e_undo_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_undo],TRUE);
  XtSetSensitive(popup_children[W_pop_save],TRUE);
  XtSetSensitive(popup_children[W_pop_play],TRUE);
}

void reflect_file_lack_in_menu (void)
{
  XtSetSensitive(mw[f_close_menu],FALSE);
  XtSetSensitive(mw[f_save_as_menu],FALSE);
  XtSetSensitive(mw[f_save_menu],FALSE);
  XtSetSensitive(mw[f_revert_menu],FALSE);
  XtSetSensitive(mw[f_print_menu],FALSE);
  XtSetSensitive(mw[f_mix_menu],FALSE);
  XtSetSensitive(mw[f_update_menu],FALSE);
  XtSetSensitive(mw[e_undo_menu],FALSE);
  XtSetSensitive(mw[e_redo_menu],FALSE);
  XtSetSensitive(mw[v_normalize_menu],FALSE);
  XtSetSensitive(mw[v_info_menu],FALSE);
  XtSetSensitive(mw[e_find_menu],FALSE);
  XtSetSensitive(popup_children[W_pop_undo],FALSE);
  XtSetSensitive(popup_children[W_pop_redo],FALSE);
  XtSetSensitive(popup_children[W_pop_save],FALSE);
  XtSetSensitive(popup_children[W_pop_play],FALSE);
  XtSetSensitive(popup_children[W_pop_info],FALSE);
  XtSetSensitive(popup_children[W_pop_normalize],FALSE);
}

void set_normalize_option(int on)
{
  XtSetSensitive(mw[v_normalize_menu],on);
}

static int find_any_edits (chan_info *cp, void *ptr)
{
  return(cp->edit_ctr);
}

void reflect_file_revert_in_menu (snd_state *ss)
{
  int editing;
  editing = map_over_chans(ss,find_any_edits,NULL);
  if (!editing)
    {
      XtSetSensitive(mw[f_save_menu],FALSE);
      XtSetSensitive(mw[f_revert_menu],FALSE);
      XtSetSensitive(mw[e_undo_menu],FALSE);
      XtSetSensitive(popup_children[W_pop_undo],FALSE);
      XtSetSensitive(popup_children[W_pop_save],FALSE);
    }
  XtSetSensitive(mw[e_redo_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_redo],TRUE);
}

void reflect_file_save_in_menu (snd_state *ss)
{
  int editing;
  editing = map_over_chans(ss,find_any_edits,NULL);
  if (!editing)
    {
      XtSetSensitive(mw[f_save_menu],FALSE);
      XtSetSensitive(mw[f_revert_menu],FALSE);
      XtSetSensitive(mw[e_undo_menu],FALSE);
      XtSetSensitive(popup_children[W_pop_undo],FALSE);
      XtSetSensitive(popup_children[W_pop_save],FALSE);
      XtSetSensitive(mw[e_redo_menu],FALSE);
      XtSetSensitive(popup_children[W_pop_redo],FALSE);
    }
}

void reflect_file_revert_in_label (snd_info *sp)
{
  int editing;
  editing = map_over_sound_chans(sp,find_any_edits,NULL);
  if (!editing)
    {
      make_name_label(snd_widget(sp,W_snd_name),sp->shortname);
      make_a_big_star_outa_me(sp->state,sp->shortname,0);
    }
}

void reflect_no_more_redo_in_menu(void)
{
  XtSetSensitive(mw[e_redo_menu],FALSE);
  XtSetSensitive(popup_children[W_pop_redo],FALSE);
}

void reflect_edit_with_selection_in_menu (void)
{
  XtSetSensitive(mw[e_cut_menu],TRUE);
  XtSetSensitive(mw[e_play_menu],TRUE);
  XtSetSensitive(mw[e_mix_menu],TRUE);
  XtSetSensitive(mw[e_save_as_menu],TRUE);
}

void reflect_edit_without_selection_in_menu (void)
{
  XtSetSensitive(mw[e_cut_menu],FALSE);
  XtSetSensitive(mw[e_play_menu],FALSE);
}

void reflect_undo_in_menu(void)
{
  XtSetSensitive(mw[e_redo_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_redo],TRUE);
}

void reflect_redo_in_menu(void)
{
  XtSetSensitive(mw[e_undo_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_undo],TRUE);
  reflect_file_change_in_menu();
}

void reflect_undo_ok_in_menu(void)
{
  XtSetSensitive(mw[e_undo_menu],TRUE);
  XtSetSensitive(popup_children[W_pop_undo],TRUE);
}

void reflect_undo_or_redo_in_menu(chan_info *cp)
{
  int undoable,redoable;
  if (cp)
    {
      undoable = (cp->edit_ctr > 0);
      redoable = (!(((cp->edit_ctr+1) == cp->edit_size) || (!(cp->edits[cp->edit_ctr+1]))));
      XtSetSensitive(mw[e_undo_menu],undoable);
      XtSetSensitive(popup_children[W_pop_undo],undoable);
      XtSetSensitive(mw[e_redo_menu],redoable);
      XtSetSensitive(popup_children[W_pop_redo],redoable);
    }
}

static void reflect_beta_window_in_menu(void)
{
  XtSetSensitive(mw[o_fft_beta_menu],TRUE);
}

static void reflect_non_beta_window_in_menu(void)
{
  XtSetSensitive(mw[o_fft_beta_menu],FALSE);
}

void reflect_regions_in_menu(void)
{
  XtSetSensitive(mw[v_region_menu],TRUE);
  XtSetSensitive(mw[e_save_as_menu],TRUE);
}

void reflect_no_regions_in_menu(void)
{
  XtSetSensitive(mw[v_region_menu],FALSE);
  XtSetSensitive(mw[e_save_as_menu],FALSE);
}

static void dkms(void) {finish_keyboard_selection();}



/* -------------------------------- FILE MENU -------------------------------- */

static void color_file_selection_box(Widget w, snd_state *ss)
{
  Widget wtmp,ftmp;
  if (!(ss->using_schemes)) 	
    {
      map_over_children(w,set_main_color_of_widget,(void *)ss);
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_DIR_LIST),XmNbackground,(ss->sgx)->white,NULL);
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_LIST),XmNbackground,(ss->sgx)->white,NULL);
#ifndef LESSTIF_VERSION
      XtVaSetValues(XtNameToWidget(w,"Apply"),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XtNameToWidget(w,"Cancel"),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XtNameToWidget(w,"Help"),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XtNameToWidget(w,"OK"),XmNarmColor,(ss->sgx)->text,NULL);
      wtmp = XtNameToWidget(w,"Text");
      ftmp = XtNameToWidget(w,"FilterText");
#else
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_APPLY_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmFileSelectionBoxGetChild(w,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      wtmp = XmFileSelectionBoxGetChild(w,XmDIALOG_TEXT);
      ftmp = XmFileSelectionBoxGetChild(w,XmDIALOG_FILTER_TEXT);	
#endif
      XtAddCallback(wtmp,XmNfocusCallback,textfield_focus_Callback,ss);
      XtAddCallback(wtmp,XmNlosingFocusCallback,textfield_unfocus_Callback,ss);
      XtAddCallback(ftmp,XmNfocusCallback,textfield_focus_Callback,ss);
      XtAddCallback(ftmp,XmNlosingFocusCallback,textfield_unfocus_Callback,ss);
    }
}

static void File_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
          "File Menu",
"The File menu provides one way to open,\n\
close, and save files. Its options are:\n\
\n",
get_file_menu_help(),
"\n\
The Print option produces a Postscript file;\n\
you can print it with lpr.\n",
NULL);
}

static int is_directory(char *filename)
{
  struct stat statbuf;
  if (lstat(filename,&statbuf) >= 0) return(S_ISDIR(statbuf.st_mode));
  return(0);
}

#if 0
static int is_regular_file(char *filename)
{
  struct stat statbuf;
  if ((lstat(fullpath,&statbuf) >= 0) && (S_ISDIR(statbuf.st_mode) == 0))
    return((statbuf.st_mode & S_IFMT) == S_IFREG);
  return(0);
}
#endif

static void File_Open_OK_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_info *sp;
  snd_state *ss = (snd_state *)clientData;
  XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *) callData;
  char *fileName;
  XtUnmanageChild(w);
  XmStringGetLtoR (cbs->value,XmFONTLIST_DEFAULT_TAG,&fileName);
  /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */
  if (!(is_directory(fileName)))
    {
      sp = snd_open_file(fileName,ss);
      if (sp) select_channel(sp,0);           /* add_sound_window (snd-xsnd.c) will report reason for error, if any */
    }
  else
    {
      sprintf(search_string,snd_string_is_a_directory,fileName);
      snd_printf(ss,search_string);
    }
}

static void File_Open_Help_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
       "File Open",
"If you click the 'Sound Files Only'\n\
button, only those files in the current\n\
directory that look vaguely like sound\n\
files will be displayed.\n\
");
}

static void File_Open_Cancel_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  XtUnmanageChild (w);
}

static Widget open_dialog = NULL; 
static XmSearchProc default_search_proc;

static int string_compare(const void *ss1, const void *ss2)
{
  return(strcmp((*((char **)ss1)),(*((char **)ss2)))); /* sweet baby jesus... ain't C grand? */
}

static void just_sounds_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Sound Files Only",
"If you click the 'Sound Files Only'\n\
button, only those files in the current\n\
directory that look vaguely like sound\n\
files will be displayed.  The decision\n\
is based on the file's extension.\n\
");
}

static char *fullpathname = NULL;
static int file_SB_list_needs_update = 0; /* browser list needs update (new 'filter' or whatever) */
static int new_file_written = 0;          /* sound file list needs update because we wrote a new file */

void alert_new_file(void) {new_file_written = 1;}

static void sound_file_search(Widget FSB_w, XmFileSelectionBoxCallbackStruct *callData)
{
  /* generate list of sound files, set XmNfileListItems, XmNfileListItemCount, XmNlistUpdated
   * the latter if new file list generated -- if no files, XmNfileListItems NULL, Count 0
   * can also set XmNdirSpec to full file spec of dir.  The callbackstruct is:
   *    typedef struct
   *    {
   *      int      reason;         Why called
   *      XEvent   * event;  
   *      XmString value;          current value of XmNdirSpec
   *      int      length;         number of bytes in value
   *      XmString mask;           current value of XmNdirMask
   *      int      mask_length;    number of bytes in mask
   *      XmString dir;            current base directory
   *      int      dir_length;     number of bytes in dir
   *      XmString pattern;        current search pattern
   *      int      pattern_length; number of bytes in pattern
   *    } XmFileSelectionBoxCallbackStruct;
   *
   * proc should stick to XmNfileTypeMask (type unsigned char): 
   *   XmFILE_REGULAR -- regular files
   *   XmFILE_DIRECTORY -- directories
   *   XmFILE_ANY_TYPE 
   *
   * the pattern (file name mask) only matters if the filter button is hit, 
   * it appears to be "*" until the filter is invoked.
   */

  /* alphabetize list ? */

  char *pattern,*our_dir,*sp,*sn;
  static char *save_dir = NULL;
  static char *last_dir = NULL;
  static dir *sound_files,*current_files;
  static char *last_pattern = NULL;
  dir *cdp;
  XmFileSelectionBoxCallbackStruct *data = (XmFileSelectionBoxCallbackStruct *)callData;
  XmString *names = NULL;
  int i,filter_callback,need_update;

  XmStringGetLtoR (data->pattern,XmFONTLIST_DEFAULT_TAG,&pattern);
  XmStringGetLtoR (data->dir,XmFONTLIST_DEFAULT_TAG,&our_dir);

  if (!fullpathname) fullpathname = (char *)calloc(FILENAME_MAX,sizeof(char));
  filter_callback = (strcmp(pattern,"*") != 0);
  need_update = file_SB_list_needs_update;
  file_SB_list_needs_update = 0;
  if (!filter_callback)
    {
      if ((!last_dir) || (strcmp(our_dir,last_dir) != 0) || (new_file_written))
	{
	  if (current_files) current_files = free_dir(current_files);
	  if (last_dir) {free(last_dir); last_dir = NULL;}
	  last_dir = (char *)calloc(strlen(our_dir)+1,sizeof(char));
	  strcpy(last_dir,our_dir);
	  strcpy(fullpathname,our_dir);
	  save_dir = (char *)(fullpathname+strlen(our_dir));
	  sound_files = find_sound_files_in_dir(our_dir);
	  need_update = 1;
	}
      if (last_pattern)
	{
	  free(last_pattern);
	  last_pattern = NULL;
	}
      cdp = sound_files;
    }
  else 
    {
      if ((!last_pattern) || (strcmp(pattern,last_pattern) != 0) || (new_file_written))
	  {
	    if (last_pattern) {free(last_pattern); last_pattern = NULL;}
	    last_pattern = (char *)calloc(strlen(pattern)+1,sizeof(char));
	    strcpy(last_pattern,pattern);
	    if (current_files)  current_files = free_dir(current_files);
	    if ((sound_files) && (sound_files->len > 0)) current_files = filter_sound_files(sound_files,pattern);
	    need_update = 1;
	  }
      cdp = current_files;
    }  
  new_file_written = 0;
  if (need_update)
    {
      if ((cdp) && (cdp->len > 0))
	{
	  qsort((void *)(cdp->files),cdp->len,sizeof(char *),string_compare);
	  names = (XmString *)calloc(cdp->len,sizeof(XmString));
	  for (i=0;i<cdp->len;i++) 
	    {
	      for (sp=save_dir,sn=cdp->files[i];((*sp)=(*sn)) != '\0';sp++,sn++) ;
	      names[i] = XmStringCreate(fullpathname,XmFONTLIST_DEFAULT_TAG);
	    }
	}
      else names=NULL;
      if (cdp) XtVaSetValues(FSB_w,XmNfileListItems,names,XmNfileListItemCount,cdp->len,XmNlistUpdated,TRUE,NULL);
      if (names)
	{
	  for (i=0;i<cdp->len;i++) if (names[i]) XmStringFree(names[i]);
	  free(names);
	}
    }
}

static void force_directory_reread(void)
{
  XmString dirmask;
  XtVaGetValues(open_dialog,XmNdirMask,&dirmask,NULL);
  XmFileSelectionDoSearch(open_dialog,dirmask);
  XmStringFree(dirmask);
}

static void just_sounds_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  if (cb->set)
    XtVaSetValues(open_dialog,XmNfileSearchProc,sound_file_search,NULL);
  else 
    {
      XtVaSetValues(open_dialog,XmNfileSearchProc,default_search_proc,NULL);
      file_SB_list_needs_update = 1;
    }
  force_directory_reread();
}

static Widget just_sounds_button = NULL;
static int just_sounds_state = FALSE;

void toggle_just_sounds(int n)
{
  if (just_sounds_button)
    XmToggleButtonSetState(just_sounds_button,n,TRUE);
  just_sounds_state = n;
}

void textfield_focus_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  if (!(ss->using_schemes)) XtVaSetValues(w,XmNbackground,(ss->sgx)->white,NULL);
}

void textfield_unfocus_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  if (!(ss->using_schemes)) XtVaSetValues(w,XmNbackground,(ss->sgx)->main,NULL);
}

static char TextTrans2[] =
       "Ctrl <Key>b:            backward-character()\n\
        Alt <Key>b:             backward-word()\n\
        Ctrl <Key>a:            beginning-of-line()\n\
        Shift Ctrl <Key>a:      beginning-of-line(extend)\n\
        Ctrl <Key>d:            delete-next-character()\n\
        Ctrl <Key>e:            end-of-line()\n\
        Shift Ctrl <Key>e:      end-of-line(extend)\n\
        Ctrl <Key>f:            forward-character()\n\
        Ctrl Alt <Key>f:        forward-word()\n\
        Ctrl Meta <Key>f:       forward-word()\n\
        Ctrl <Key>g:            activate()\n\
        <Key>Return:            activate()\n";
static XtTranslations transTable2 = NULL;

static XtTranslations get_textfield_translations(void)
{
  if (!transTable2) transTable2 = XtParseTranslationTable(TextTrans2);
  return(transTable2);
}

static void remember_event(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *)callData;
  (ss->sgx)->text_activate_event = cb->event;
}

Widget sndCreateTextFieldWidget(snd_state *ss, char *name, Widget parent, Arg *args, int n)
{
  /* white background when active, emacs translations, text_activate_event in ss->sgx for subsequent activation check */
  Widget df;
  XtSetArg(args[n],XmNactivateCallback,make_callback_list(remember_event,(XtPointer)ss)); n++;
  df = XtCreateManagedWidget(name,xmTextFieldWidgetClass,parent,args,n);
  XtAddCallback(df,XmNfocusCallback,textfield_focus_Callback,ss);
  XtAddCallback(df,XmNlosingFocusCallback,textfield_unfocus_Callback,ss);
  XtOverrideTranslations(df,get_textfield_translations());
  return(df);
}


Boolean CreateOpenDialog(Widget w,XtPointer clientData)
{
  /* file selection dialog box with added "Just Sound Files" toggle button */
  Arg args[20];
  int n;
  XmString s1;
  snd_state *ss = (snd_state *)clientData;
  n=0;
  if (!open_dialog)
    {
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      if (just_sounds_state)
	{
	  XtSetArg(args[n],XmNfileSearchProc,sound_file_search); n++;
	}
      s1 = XmStringCreate(snd_string_open_p,XmFONTLIST_DEFAULT_TAG);
      XtSetArg(args[n],XmNselectionLabelString,s1); n++;
      open_dialog = XmCreateFileSelectionDialog(w,snd_string_File,args,n);
      XmStringFree(s1);
#ifdef LESSTIF_VERSION
      XtManageChild(open_dialog);
#endif
      just_sounds_button = XtVaCreateManagedWidget(snd_string_Sound_Files_Only,xmToggleButtonWidgetClass,open_dialog,
						   XmNset,just_sounds_state,
						   XmNalignment,XmALIGNMENT_BEGINNING,
						   NULL);
      color_file_selection_box(open_dialog,ss);
      if (!(ss->using_schemes)) 
	{
	  XtVaSetValues(just_sounds_button,XmNselectColor,(ss->sgx)->text,NULL);
#if 0
	  XtVaSetValues(XtNameToWidget(open_dialog,"DirList"),XmNbackground,(ss->sgx)->white,NULL);
	  XtVaSetValues(XtNameToWidget(open_dialog,"ItemsList"),XmNbackground,(ss->sgx)->white,NULL);
	  fprintf(stderr,"Dirlist: %s, List: %s ",
		  XtName(XmFileSelectionBoxGetChild(open_dialog,XmDIALOG_DIR_LIST)),
		  XtName(XmFileSelectionBoxGetChild(open_dialog,XmDIALOG_LIST)));
#endif
	  /* on both the SGI and in Linux, this reports the names "DirList" and "ItemsList" but they are not accesible via XtNameToWidget?!? */
	}
      XtVaGetValues(open_dialog,XmNfileSearchProc,&default_search_proc,NULL);
      XtAddCallback(open_dialog,XmNokCallback,File_Open_OK_Callback,clientData);
      XtAddCallback(open_dialog,XmNcancelCallback,File_Open_Cancel_Callback,clientData);
      XtAddCallback(open_dialog,XmNhelpCallback,File_Open_Help_Callback,clientData);
      XtAddCallback(just_sounds_button,XmNvalueChangedCallback,just_sounds_Callback,NULL);
      XtAddCallback(just_sounds_button,XmNhelpCallback,just_sounds_help_Callback,clientData);
    }
  return(TRUE);
}

static void File_New_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_new_file((snd_state *)clientData);
}

static void File_Record_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_record_file((snd_state *)clientData);
}

static void File_Open_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* clientData is assumed to be a snd_state pointer */
  /* called from File/Open menu choice */
  dkms();
  if (!open_dialog) CreateOpenDialog(w,clientData);
  if (new_file_written) 
    {
      force_directory_reread();
      new_file_written = 0;
    }
  if (!(XtIsManaged(open_dialog))) XtManageChild(open_dialog);
}

static void File_View_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  ss->viewing = 1;
  dkms();
  if (!open_dialog) CreateOpenDialog(w,clientData);
  if (new_file_written) 
    {
      force_directory_reread();
      new_file_written = 0;
    }
  if (!(XtIsManaged(open_dialog))) XtManageChild(open_dialog);
}


/* ---------------- print ---------------- */

static Widget file_print_dialog = NULL;
static Widget file_print_name = NULL;
static Widget file_print_eps_or_lpr = NULL;

static void file_print_help_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "File Print",
"Print causes the currently active display to be\n\
either printed (via the lpr command) or saved as\n\
an eps file.  In the latter case, the file name\n\
is set either by the dialog, or taken from the\n\
resource epsFile (normally snd.eps).\n\
");
}

static void file_print_cancel_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  ss->print_choice = PRINT_SND;
  XtUnmanageChild(file_print_dialog);
}

static int lpr (char *name)
{
  /* make some desultory effort to print the file */
  sprintf(search_string,"lpr %s",name);
  return(system(search_string));
}

static void file_print_ok_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  int print_it,quit;
  char *name;
  dkms();
  print_it = XmToggleButtonGetState(file_print_eps_or_lpr);
  quit = (ss->print_choice == PRINT_ENV);
  if (print_it)
    {
      name = tempnam(ss->temp_dir,"snd_");
      switch (ss->print_choice)
	{
	case PRINT_SND: snd_print(ss,name,1); break;
	case PRINT_ENV: env_print(ss,name); break;
	}
      lpr(name);
      remove(name);
    }
  else 
    {
      /* TODO: if name field is null, exit or complain or use default?? */
      switch (ss->print_choice)
	{
	case PRINT_SND: snd_print(ss,XmTextGetString(file_print_name),1); break;
	case PRINT_ENV: env_print(ss,XmTextGetString(file_print_name)); break;
	}
    }
  ss->print_choice = PRINT_SND;
  if (quit) XtUnmanageChild(file_print_dialog);
}

void File_Print_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  Arg args[20];
  int n;
  Widget dl,rc;
  XmString xmstr1,xmstr2,xmstr3,xmstr4,titlestr;
  snd_info *nsp;
  snd_state *ss = (snd_state *)clientData;
  if (ss->print_choice == PRINT_SND)
    {
      nsp = any_selected_sound(ss);
      sprintf(search_string,snd_string_printing,nsp->shortname);
      xmstr4 = XmStringCreateLocalized(search_string);
    }
  else xmstr4 = XmStringCreateLocalized(snd_string_print_env);

  if (!file_print_dialog)
    {
      n=0;
      xmstr1=XmStringCreateLocalized(snd_string_Ok);
      xmstr2=XmStringCreateLocalized(snd_string_Help);
      xmstr3=XmStringCreateLocalized(snd_string_Dismiss);
      titlestr = XmStringCreateLocalized(snd_string_Print);

      XtSetArg(args[n],XmNmessageString,xmstr4); n++;
      XtSetArg(args[n],XmNokLabelString,xmstr1); n++;
      XtSetArg(args[n],XmNhelpLabelString,xmstr2); n++;
      XtSetArg(args[n],XmNcancelLabelString,xmstr3); n++;
      XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
      XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
      file_print_dialog = XmCreateMessageDialog(w,snd_string_eps_file_p,args,n);
      XmStringFree(xmstr1);
      XmStringFree(xmstr2);
      XmStringFree(xmstr3);
      XmStringFree(xmstr4);
      XmStringFree(titlestr);
      XtUnmanageChild(XmMessageBoxGetChild(file_print_dialog,XmDIALOG_SYMBOL_LABEL));
      XtAddCallback(file_print_dialog,XmNhelpCallback,file_print_help_callback,ss);
      XtAddCallback(file_print_dialog,XmNcancelCallback,file_print_cancel_callback,ss);
      XtAddCallback(file_print_dialog,XmNokCallback,file_print_ok_callback,ss);

      rc = XtCreateManagedWidget("form",xmFormWidgetClass,file_print_dialog,NULL,0);

      n=0;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      dl = XtCreateManagedWidget(snd_string_eps_file_p,xmLabelWidgetClass,rc,args,n);

      n=0;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,dl); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNvalue,ss->eps_file); n++;
      file_print_name = sndCreateTextFieldWidget(ss,"text",rc,args,n);

      n=0;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,file_print_name); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      file_print_eps_or_lpr = XtCreateManagedWidget(snd_string_direct_to_printer,xmToggleButtonWidgetClass,rc,args,n);

#if MANAGE_DIALOG
      XtManageChild(file_print_dialog);
#endif

      if (!(ss->using_schemes))	
	{
	  map_over_children(file_print_dialog,set_main_color_of_widget,(void *)clientData);
	  XtVaSetValues(XmMessageBoxGetChild(file_print_dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(file_print_dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(file_print_dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(file_print_eps_or_lpr,XmNselectColor,(ss->sgx)->text,NULL);
	}
    }
  else
    {
      XtVaSetValues(file_print_dialog,XmNmessageString,xmstr4,NULL);
      XmStringFree(xmstr4);
      raise_dialog(file_print_dialog);
    }
  if (!XtIsManaged(file_print_dialog)) XtManageChild(file_print_dialog);
}


static void File_Close_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  dkms();
  sp = any_selected_sound(ss);
  if (!sp) return;
  snd_close_file(sp,ss);
}

static void File_Save_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_info *sp;
  snd_state *ss = (snd_state *)clientData;
  dkms();
  sp = any_selected_sound(ss);
  save_edits(sp,NULL);
}

static void File_Update_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  dkms();
  sp = any_selected_sound(ss);
  if (!sp) return;
  snd_update(ss,sp);
}


/* -------- save as dialog (file and edit menus) -------- */
/* 
 * changed 19-June-97 to simply save the current state under the new name and return
 * to the current state/file (different from emacs) -- this keeps mix console intact
 * across backups and so on, and seems more useful to me than switching to the new file.
 */

typedef struct {
  Widget dialog;
  Widget header_list; 
  Widget data_list;
  Widget text;
  Widget srtext;
  snd_state *state;
  int type;
  int header_choice,data_choice;
} save_as_info;

static save_as_info *save_as_dialog = NULL;

#define FILE_SAVE_AS 1
#define EDIT_SAVE_AS 2

#define NUM_HEADER_TYPES 5
#define NUM_NEXT_FORMATS 8
#define NUM_IRCAM_FORMATS 5
#define NUM_WAVE_FORMATS 5
#define NUM_AIFF_FORMATS 6

static char *next_data_formats[NUM_NEXT_FORMATS] = {"short","mulaw",  "signed byte  ","float","long","alaw","24 bit int","double"};
static char *ircam_data_formats[NUM_IRCAM_FORMATS] = {"short","mulaw","float        ","long","alaw"};
static char *wave_data_formats[NUM_WAVE_FORMATS] = {"mulaw","alaw",   "unsigned byte","short","long"};
static char *aiff_data_formats[NUM_AIFF_FORMATS] = {"short","mulaw",  "signed byte  ","long","alaw","24 bit int"};

static int next_dfs[NUM_NEXT_FORMATS] = {snd_16_linear,snd_8_mulaw,snd_8_linear,snd_32_float,snd_32_linear,snd_8_alaw,snd_24_linear,snd_64_double};
static int ircam_dfs[NUM_IRCAM_FORMATS] = {snd_16_linear,snd_8_mulaw,snd_32_float,snd_32_linear,snd_8_alaw};
static int wave_dfs[NUM_WAVE_FORMATS] = {snd_8_mulaw,snd_8_alaw,snd_8_unsigned,snd_16_linear_little_endian,snd_32_linear_little_endian};
static int aiff_dfs[NUM_AIFF_FORMATS] = {snd_16_linear,snd_8_mulaw,snd_8_linear,snd_32_linear,snd_8_alaw,snd_24_linear};

#define NUM_DATA_FORMATS 17
static char *data_formats[NUM_DATA_FORMATS] = {
  "16 bit big-endian int",
  "8 bit mulaw",
  "8 bit signed int",
  "32 bit big-endian float",
  "32 bit big-endian int",
  "8 bit alaw",
  "8 bit unsigned int",
  "24 bit big-endian int",
  "64 bit big-endian double",
  "16 bit little-endian int",
  "32 bit little-endian int",
  "32 bit little-endian float",
  "64 bit little-endian double",
  "16 bit big-endian unsigned int",
  "16 bit little-endian unsigned int",
  "24 bit little-endian int",
  "32 bit vax float"};

/* must parallel sound_types.h definitions */

static int get_header_type_from_position(int position)
{
  switch (position)
    {
    case 1: return(NeXT_sound_file); break;
    case 2: return(AIFF_sound_file); break;
    case 3: return(RIFF_sound_file); break;
    case 4: return(IRCAM_sound_file); break;
    case 5: return(raw_sound_file); break;
    }
  return(raw_sound_file);
}

static int get_data_format_from_header_and_position(int header, int position)
{
  switch (header)
    {
    case NeXT_sound_file: return(next_dfs[position-1]); break;
    case AIFF_sound_file: return(aiff_dfs[position-1]); break;
    case RIFF_sound_file: return(wave_dfs[position-1]); break;
    case IRCAM_sound_file: return(ircam_dfs[position-1]); break;
    case raw_sound_file: return(position); break;
    }
  return(position);
}

typedef struct {
  snd_info *sp;
  char *fullname;
  int edits;
} same_name_info;

static int check_for_same_name(snd_info *sp1, void *ur_info)
{
  int i;
  chan_info *cp;
  same_name_info *info = (same_name_info *)ur_info;
  if ((sp1) && (strcmp(sp1->fullname,info->fullname) == 0))
    {
      
      info->sp = sp1;
      for (i=0;i<sp1->nchans;i++) 
	{
	  cp = sp1->chans[i];
	  if (info->edits < cp->edit_ctr) info->edits = cp->edit_ctr;
	}
      return(1); /* stop immediately and deal with this one */
    }
  return(0);
}

void read_file_data_choices(Widget stext, Widget ctext, Widget hlist, Widget dlist, int *srate, int *chans, int *type, int *format)
{
  char *str;
  int n;
#if HAVE_SELECTED_POSITION_COUNT
  unsigned int *ns;
#else
  int *ns;
#endif
  if (stext) {str = XmTextGetString(stext); if (str) {sscanf(str,"%d",&n); (*srate) = n;}}
  if (ctext) {str = XmTextGetString(ctext); if (str) {sscanf(str,"%d",&n); (*chans) = n;}}
#if HAVE_SELECTED_POSITION_COUNT
  if (hlist)
    {
      XtVaGetValues(hlist,XmNselectedPositionCount,&n,NULL);
      if (n>0)
	{
	  XtVaGetValues(hlist,XmNselectedPositions,&ns,NULL);
	  (*type) = get_header_type_from_position(ns[0]);
	}
    }
  if (dlist)
    {
      XtVaGetValues(dlist,XmNselectedPositionCount,&n,NULL);
      if (n>0)
	{
	  XtVaGetValues(dlist,XmNselectedPositions,&ns,NULL);
	  (*format) = get_data_format_from_header_and_position((*type),ns[0]);
	}
    }
#else
  if (hlist)
    {
      XmListGetSelectedPos(hlist,&ns,&n);
      if (n>0)
	(*type) = get_header_type_from_position(ns[0]);
    }
  if (dlist)
    {
      XmListGetSelectedPos(dlist,&ns,&n);
      if (n>0)
	(*format) = get_data_format_from_header_and_position((*type),ns[0]);
    }
#endif
}

static void save_as_ok_callback(Widget w,XtPointer clientData,XtPointer callData)
{ /* called from both save as options */
  save_as_info *fd = (save_as_info *)clientData;
  Widget text;
  char *str,*str1,*fullname;
  same_name_info *collision = NULL;
  snd_info *sp;
  int result,fil;
  snd_state *ss;
  int type,format,srate;
  str = XmTextGetString(fd->srtext);
  sscanf(str,"%d",&srate);
  type = get_header_type_from_position(fd->header_choice);
  format = get_data_format_from_header_and_position(type,fd->data_choice);
  text = fd->text;
  ss = fd->state;
  str = XmTextGetString(text);
  sp = any_selected_sound(ss);
  if ((str) && (*str))
    {
      if (sp) clear_minibuffer(sp);
      alert_new_file();
      /* now check in-core files -- need to close any of same name -- if edited what to do? */
      str1 = copy_string(str);
      fullname = copy_string(complete_filename(str1));
      free(str1);
      if (ss->ask_before_overwrite)
	{
	  fil = open(fullname,O_RDONLY,0);
	  if (fil != -1) 
	    {
	      close(fil);
	      sprintf(search_string,snd_string_exists_overwrite,str);
	      if (!(snd_yes_or_no_p(ss,search_string))) {free(fullname); return;}
	    }
	}
      collision = (same_name_info *)calloc(1,sizeof(same_name_info));
      collision->fullname = fullname;
      collision->edits = 0;
      collision->sp = NULL;
      map_over_sounds(ss,check_for_same_name,(void *)collision);
      if (collision->sp)
	{
	  /* if no edits, we'll just close, overwrite, reopen */
	  /* if edits, we need to ask luser what to do */
	  /* we don't need to check for overwrites at this point */
	  if (collision->edits > 0)
	    {
	      sprintf(search_string,snd_string_has_unsaved_edits,str,str);
	      if (!(snd_yes_or_no_p(ss,search_string))) {free(fullname); free(collision); return;}
	    }
	  snd_close_file(collision->sp,ss);
	}
      if (fd->type == FILE_SAVE_AS)
	{
	  result = save_edits_2(sp,str,type,format,srate); /* save_edits_2 called only here (and in clm_save_as, snd-clm.c) */
	  XmTextSetString(text,NULL);
	  if (result != snd_no_error)
	    {
	      sprintf(search_string,"%s: %s (%s)",sp->fullname,strerror(errno),snd_error_name(result));
	      report_in_minibuffer(sp,search_string);
	    }
	}
      else
	{
	  save_selection(ss,str,type,format,srate);
	}
      if (collision->sp) snd_open_file(fullname,ss);
      free(fullname);
      free(collision);
    }
  else if (sp) report_in_minibuffer(sp,snd_string_not_saved_no_name_given);
} 

static void save_as_help_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Save As",
"You can save the current state of a file or region\n\
under a different file name using the Save\n\
As option.  The output header type, data format,\n\
and sampling rate can also be set.  The data formats\n\
are big-endian where relevant except for 'wave'\n\
output.  If a file by the chosen name already exists\n\
it is silently overwritten, unless that file is\n\
already open in Snd and has edits.  In that case,\n\
you'll be asked what to do.  If you want to be warned\n\
whenever a file is about to be overwritten by this\n\
option, set the resource overwriteCheck to 1.\n\
");
}

static void save_as_cancel_callback(Widget w,XtPointer clientData,XtPointer callData)
{ 
  save_as_info *fd = (save_as_info *)clientData;
  XtUnmanageChild(fd->dialog);
} 

void load_header_and_data_lists(Widget hlist, Widget dlist, int type, int format, int *hpos, int *dpos)
{
  int dformats = 0,header_pos = 0,data_pos = 0,i;
  char **fl = NULL;
  XmString *strs;
  switch (type)
    {
    case AIFF_sound_file: 
      dformats = NUM_AIFF_FORMATS; 
      fl = aiff_data_formats; 
      header_pos = 2; 
      data_pos = 1;
      for (i=0;i<NUM_AIFF_FORMATS;i++) if (format == aiff_dfs[i]) {data_pos = i+1; break;}
      break;
    case RIFF_sound_file: 
      dformats = NUM_WAVE_FORMATS; 
      fl = wave_data_formats; 
      header_pos = 3;
      data_pos = 4;
      for (i=0;i<NUM_WAVE_FORMATS;i++) if (format == wave_dfs[i]) {data_pos = i+1; break;}
      break;
    case IRCAM_sound_file: 
      dformats =NUM_IRCAM_FORMATS; 
      fl = ircam_data_formats; 
      header_pos = 4; 
      data_pos = 1;
      for (i=0;i<NUM_IRCAM_FORMATS;i++) if (format == ircam_dfs[i]) {data_pos = i+1; break;}
      break;
    case NeXT_sound_file:
      dformats = NUM_NEXT_FORMATS; 
      fl = next_data_formats; 
      header_pos = 1; 
      data_pos = 1;
      for (i=0;i<NUM_NEXT_FORMATS;i++) if (format == next_dfs[i]) {data_pos = i+1; break;}
      break;
    case raw_sound_file:
      dformats = NUM_DATA_FORMATS; 
      fl = data_formats; 
      header_pos = 5; 
      data_pos = format;
      break;
    }
  XmListSelectPos(hlist,header_pos,FALSE);
  strs = (XmString *)calloc(dformats,sizeof(XmString)); 
  for (i=0;i<dformats;i++) strs[i] = XmStringCreate(fl[i],XmFONTLIST_DEFAULT_TAG);
  XtVaSetValues(dlist,XmNitems,strs,XmNitemCount,dformats,NULL);
  for (i=0;i<dformats;i++) XmStringFree(strs[i]);
  free(strs);
  XmListSelectPos(dlist,data_pos,FALSE);
  (*hpos) = header_pos;
  (*dpos) = data_pos;
}

static void Save_as_Header_type_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* set fdw->header_choice, if needed reload data_formats window */
  int pos;
  file_info *hdr;
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  save_as_info *fdw = (save_as_info *)clientData;
  pos = cbs->item_position;
  if (fdw->header_choice != pos)
    {
      hdr = (file_info *)calloc(1,sizeof(file_info));
      switch (pos)
	{
	case 1: hdr->type = NeXT_sound_file; hdr->format = snd_16_linear; break;
	case 2: hdr->type = AIFF_sound_file; hdr->format = snd_16_linear; break;
	case 3: hdr->type = RIFF_sound_file; hdr->format = snd_16_linear_little_endian; break;
	case 4: hdr->type = IRCAM_sound_file; hdr->format = snd_16_linear; break;
	case 5: hdr->type = raw_sound_file; hdr->format = snd_16_linear; break;
	}
      load_header_and_data_lists(fdw->header_list,fdw->data_list,hdr->type,hdr->format,&(fdw->header_choice),&(fdw->data_choice));
      free(hdr);
    }
}

static void Save_as_Data_format_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  save_as_info *fdw = (save_as_info *)clientData;
  fdw->data_choice = cbs->item_position;
}

static void file_header_help_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "File Header Type",
"This list shows the output header types that\n\
Snd is willing to write.\n\
");
}

static void file_data_help_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "File Data Format",
"This list shows the data format choices\n\
available with the currently selected header\n\
choice.  'Short' means 16-bit two's complement\n\
integer.  'Mulaw' and 'Alaw' are common 8-bit\n\
compression schemes. 'Long' is 32-bit integer.\n\
'Float' is 32-bit float.  In each case, the\n\
decision as to byte order ('endianess') depends\n\
on the header type.\n\
");
}

static void file_srate_help_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "File Srate",
"This field sets the nominal file sampling\n\
rate.\n\
");
} 

static void file_chans_help_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "File Srate",
"This field sets the number of channels\n\
in the output file.\n\
");
} 

Widget *sndCreateFileDataForm(snd_state *ss, Widget parent, char *name, Arg *args, int n, int with_chan, int header_type, int data_format)
{
  Widget *arr;
  XmString *strs;
  int dformats = 0;
  char **formats = NULL;
  int *dfs = NULL;
  int i,header_pos= 0,data_pos = 0;
  switch (header_type)
    {
    case NeXT_sound_file: dformats = NUM_NEXT_FORMATS; formats = next_data_formats; dfs = next_dfs; header_pos = 1; break;
    case AIFF_sound_file: dformats = NUM_AIFF_FORMATS; formats = aiff_data_formats; header_pos = 2; dfs = aiff_dfs; break;
    case RIFF_sound_file: dformats = NUM_WAVE_FORMATS; formats = wave_data_formats; header_pos = 3; dfs = wave_dfs; break;
    case IRCAM_sound_file: dformats = NUM_IRCAM_FORMATS; formats = ircam_data_formats; header_pos = 4; dfs = ircam_dfs; break;
    case raw_sound_file: dformats = NUM_DATA_FORMATS; formats = data_formats; header_pos = 5; dfs = NULL; data_pos = data_format; break;
    }
  if (header_type != raw_sound_file)
    {
      data_pos = 1;
      for (i=0;i<dformats;i++) if (data_format == dfs[i]) {data_pos = i+1; break;}
    }

  arr = (Widget *)calloc(FILE_DATA_WIDGETS,sizeof(Widget));
  arr[fdata_form] = XtCreateManagedWidget(name,xmFormWidgetClass,parent,args,n);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
  XtSetArg(args[n],XmNwidth,5); n++;
  XtSetArg(args[n],XmNseparatorType,XmNO_LINE); n++;
  arr[fdata_sep1] = XtCreateManagedWidget("sep1",xmSeparatorWidgetClass,arr[fdata_form],args,n);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep1]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  arr[fdata_hlab] = XtCreateManagedWidget(snd_string_header,xmLabelWidgetClass,arr[fdata_form],args,n);
  XtAddCallback(arr[fdata_hlab],XmNhelpCallback,file_header_help_callback,ss);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,arr[fdata_hlab]); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep1]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(args[n],XmNrightWidget,arr[fdata_hlab]); n++;
  XtSetArg(args[n],XmNlistMarginWidth,1); n++;
  /* what is selected depends on current type */
  strs = (XmString *)calloc(NUM_HEADER_TYPES,sizeof(XmString)); 
  strs[0] = XmStringCreate("Next ",XmFONTLIST_DEFAULT_TAG);
  strs[1] = XmStringCreate("AIFF ",XmFONTLIST_DEFAULT_TAG);
  strs[2] = XmStringCreate("Wave ",XmFONTLIST_DEFAULT_TAG);
  strs[3] = XmStringCreate("IRCAM",XmFONTLIST_DEFAULT_TAG);
  strs[4] = XmStringCreate("raw",XmFONTLIST_DEFAULT_TAG);
  XtSetArg(args[n],XmNitems,strs); n++;
  XtSetArg(args[n],XmNitemCount,NUM_HEADER_TYPES); n++;
  XtSetArg(args[n],XmNvisibleItemCount,NUM_HEADER_TYPES); n++;
  arr[fdata_hlist] = XmCreateScrolledList(arr[fdata_form],"header type",args,n);
  XtAddCallback(arr[fdata_hlist],XmNhelpCallback,file_header_help_callback,ss);
  XtManageChild(arr[fdata_hlist]);
  for (i=0;i<NUM_HEADER_TYPES;i++) XmStringFree(strs[i]);
  free(strs);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_hlab]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
  XtSetArg(args[n],XmNwidth,15); n++;
  XtSetArg(args[n],XmNseparatorType,XmNO_LINE); n++;
  arr[fdata_sep2] = XtCreateManagedWidget("sep2",xmSeparatorWidgetClass,arr[fdata_form],args,n);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep2]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  arr[fdata_dlab] = XtCreateManagedWidget(snd_string_data,xmLabelWidgetClass,arr[fdata_form],args,n);
  XtAddCallback(arr[fdata_dlab],XmNhelpCallback,file_data_help_callback,ss);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,arr[fdata_dlab]); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep2]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  arr[fdata_dlist] = XmCreateScrolledList(arr[fdata_form],"data format",args,n);
  /* what is displayed and selected depends on current type */
  XtAddCallback(arr[fdata_dlist],XmNhelpCallback,file_data_help_callback,ss);

  XmListSelectPos(arr[fdata_hlist],header_pos,FALSE);
  strs = (XmString *)calloc(dformats,sizeof(XmString)); 
  for (i=0;i<dformats;i++) strs[i] = XmStringCreate(formats[i],XmFONTLIST_DEFAULT_TAG);
  XtVaSetValues(arr[fdata_dlist],XmNitems,strs,XmNitemCount,dformats,NULL);
  for (i=0;i<dformats;i++) XmStringFree(strs[i]);
  free(strs);
  XmListSelectPos(arr[fdata_dlist],data_pos,FALSE);
  XtManageChild(arr[fdata_dlist]);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
#ifndef LESSTIF_VERSION
  XtSetArg(args[n],XmNleftWidget,arr[fdata_dlist]); n++;
#else
  XtSetArg(args[n],XmNleftWidget,XtParent(arr[fdata_dlist])); n++;
#endif
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
  XtSetArg(args[n],XmNwidth,15); n++;
  XtSetArg(args[n],XmNseparatorType,XmNO_LINE); n++;
  arr[fdata_sep3] = XtCreateManagedWidget("sep3",xmSeparatorWidgetClass,arr[fdata_form],args,n);

  n=0;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep3]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  arr[fdata_slab] = XtCreateManagedWidget(snd_string_srate_p,xmLabelWidgetClass,arr[fdata_form],args,n);
  XtAddCallback(arr[fdata_slab],XmNhelpCallback,file_srate_help_callback,ss);

  n=0;
  XtSetArg(args[n],XmNcolumns,6); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,arr[fdata_slab]); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,arr[fdata_sep3]); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
  arr[fdata_stext] = sndCreateTextFieldWidget(ss,"text",arr[fdata_form],args,n);
  XtAddCallback(arr[fdata_stext],XmNhelpCallback,file_srate_help_callback,ss);

  if (with_chan)
    {
      n=0;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,arr[fdata_stext]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,arr[fdata_sep3]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      arr[fdata_clab] = XtCreateManagedWidget(snd_string_chans_p,xmLabelWidgetClass,arr[fdata_form],args,n);
      XtAddCallback(arr[fdata_clab],XmNhelpCallback,file_chans_help_callback,ss);

      n=0;
      XtSetArg(args[n],XmNcolumns,6); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,arr[fdata_clab]); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,arr[fdata_sep3]); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;	
      arr[fdata_ctext] = sndCreateTextFieldWidget(ss,"text",arr[fdata_form],args,n);
      XtAddCallback(arr[fdata_ctext],XmNhelpCallback,file_chans_help_callback,ss);
    }
  return(arr);
}

static void make_save_as_dialog(Widget w,save_as_info *fdw, char *name, file_info *hdr)
{
  Arg args[32];
  int n;
  Widget *wids;
  snd_state *ss;
  XmString xmstr1,xmstr2,s1;
  ss=fdw->state;

  n=0;
  s1 = XmStringCreate(snd_string_save_as_p,XmFONTLIST_DEFAULT_TAG);
  XtSetArg(args[n],XmNselectionLabelString,s1); n++;
  xmstr1=XmStringCreateLocalized(snd_string_Save);
  XtSetArg(args[n],XmNokLabelString,xmstr1); n++;
  sprintf(search_string,snd_string_saving,name);
  xmstr2 = XmStringCreateLocalized(search_string);
  XtSetArg(args[n],XmNdialogTitle,xmstr2); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
  XtSetArg(args[n],XmNautoUnmanage,TRUE); n++;
  XtSetArg(args[n],XmNchildPlacement,XmPLACE_ABOVE_SELECTION); n++;
  XtSetArg(args[n],XmNallowOverlap,FALSE); n++;
  fdw->dialog = XmCreateFileSelectionDialog(w,"save-as",args,n);
  XtManageChild(fdw->dialog);
  XmStringFree(s1);
  XmStringFree(xmstr1);
  XmStringFree(xmstr2);
#ifndef LESSTIF_VERSION
  fdw->text = XtNameToWidget(fdw->dialog,"Text");
#else
  fdw->text = XmFileSelectionBoxGetChild(fdw->dialog,XmDIALOG_TEXT);
#endif

  XtAddCallback(fdw->dialog,XmNhelpCallback,save_as_help_callback,ss);
  XtAddCallback(fdw->dialog,XmNcancelCallback,save_as_cancel_callback,fdw);
  XtAddCallback(fdw->dialog,XmNokCallback,save_as_ok_callback,fdw);

  n=0;
#ifdef LESSTIF_VERSION
  XtSetArg(args[n],XmNheight,100); n++;
#endif
  wids = sndCreateFileDataForm(ss,fdw->dialog,"data-form",args,n,FALSE,NeXT_sound_file,snd_16_linear);
  fdw->header_list = wids[fdata_hlist];
  XtAddCallback(fdw->header_list,XmNbrowseSelectionCallback,Save_as_Header_type_Callback,fdw);
  fdw->data_list = wids[fdata_dlist];
  XtAddCallback(fdw->data_list,XmNbrowseSelectionCallback,Save_as_Data_format_Callback,fdw);
  fdw->srtext = wids[fdata_stext];
  sprintf(search_string,"%d",(hdr) ? hdr->srate : region_srate(0));
  XmTextSetString(fdw->srtext,search_string);
  load_header_and_data_lists(fdw->header_list,fdw->data_list,
			     (hdr) ? hdr->type : NeXT_sound_file,(hdr) ? hdr->format : snd_16_linear,
			     &(fdw->header_choice),&(fdw->data_choice));
  color_file_selection_box(fdw->dialog,ss);
  if (!(ss->using_schemes))	
    {
      XtVaSetValues(fdw->data_list,XmNbackground,(ss->sgx)->white,NULL);
      XtVaSetValues(fdw->header_list,XmNbackground,(ss->sgx)->white,NULL);
    }
}

static void File_Save_As_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* save old as new, close old, open new */
  snd_info *sp;
  XmString xmstr2;
  file_info *hdr;
  snd_state *ss = (snd_state *)clientData;
  dkms();
  sp = any_selected_sound(ss);
  if (!save_as_dialog)
    {
      save_as_dialog = (save_as_info *)calloc(1,sizeof(save_as_info));
      save_as_dialog->state = ss;
      make_save_as_dialog(w,save_as_dialog,sp->shortname,sp->hdr);
    }
  else
    {
      sprintf(search_string,snd_string_saving,sp->shortname);
      xmstr2 = XmStringCreateLocalized(search_string);
      XtVaSetValues(save_as_dialog->dialog,XmNtitleString,xmstr2,NULL);
      XmStringFree(xmstr2);
      hdr = sp->hdr;
      load_header_and_data_lists(save_as_dialog->header_list,save_as_dialog->data_list,
				 hdr->type,hdr->format,
				 &(save_as_dialog->header_choice),&(save_as_dialog->data_choice));
    }
  save_as_dialog->type = FILE_SAVE_AS;
  if (!XtIsManaged(save_as_dialog->dialog)) XtManageChild(save_as_dialog->dialog);
}

static void File_Revert_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  int i;
  dkms();
  sp = any_selected_sound(ss);
  for (i=0;i<sp->nchans;i++) revert_edits(sp->chans[i],NULL);
  reflect_file_revert_in_label(sp);
  reflect_file_revert_in_menu(ss);
}

static void File_Exit_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  dkms();
  snd_exit_cleanly((snd_state *)clientData);
  exit(1);
}


static Widget file_mix_dialog = NULL;
static Widget file_mix_name = NULL;

static void file_mix_help_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "File Mix",
"The file you specify to the mix file prompt\n\
will be mixed into the current active sound at\n\
the current cursor location of the active channel.\n\
The equivalent keyboard command is C-x C-q.\n\
");
}

static void file_mix_cancel_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  XtUnmanageChild(w);
}

static void file_mix_ok_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  XtUnmanageChild(w);
  mix_complete_file(any_selected_sound((snd_state *)clientData),XmTextGetString(file_mix_name),FROM_FILE_MENU);
}

static void File_Mix_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  Arg args[20];
  int n;
  XmString s1;
  snd_state *ss = (snd_state *)clientData;
  if (!file_mix_dialog)
    {
      n=0;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
      s1 = XmStringCreate(snd_string_mix_in_p,XmFONTLIST_DEFAULT_TAG);
      XtSetArg(args[n],XmNselectionLabelString,s1); n++;
      file_mix_dialog = XmCreateFileSelectionDialog(w,snd_string_mix_file_p,args,n);
      XmStringFree(s1);
      XtAddCallback(file_mix_dialog,XmNhelpCallback,file_mix_help_callback,ss);
      XtAddCallback(file_mix_dialog,XmNcancelCallback,file_mix_cancel_callback,ss);
      XtAddCallback(file_mix_dialog,XmNokCallback,file_mix_ok_callback,ss);
      XtManageChild(file_mix_dialog);
      color_file_selection_box(file_mix_dialog,ss);
#ifndef LESSTIF_VERSION
      file_mix_name = XtNameToWidget(file_mix_dialog,"Text");
#else
      file_mix_name = XmFileSelectionBoxGetChild(file_mix_dialog,XmDIALOG_TEXT);
#endif

    }
  if (!XtIsManaged(file_mix_dialog)) XtManageChild(file_mix_dialog);
}



/* -------------------------------- EDIT MENU -------------------------------- */


static void Edit_Mix_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  chan_info *cp;
  dkms();
  cp = selected_channel((snd_state *)clientData);
  if (cp) AddSelection(w,cp);
}



/* -------- edit history browser -------- */
/* on long-term hold */

#if 0
static void Edit_History_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
}
#endif


/* -------- envelope editor -------- */

static void Edit_Envelope_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  create_envelope_editor((snd_state *)clientData);
}


static void Edit_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	    "Edit Menu",
"The Edit Menu options apply to the\n\
current selection in most cases.  The\n\
successive selections are saved on a stack\n\
of 'regions' accessible via ctrl-Y.\n\
The selection can be retrieved by or\n\
from other programs or within Snd with\n\
the middle mouse button.  The options are:\n\
\n",
get_edit_menu_help(),
NULL);
}

static void Edit_Cut_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dkms();
  if (selection_is_ours())
    {
      CopyToClipboard(w,(snd_state *)clientData);
      delete_selection();
    }
}

static void Edit_Paste_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  chan_info *cp;
  dkms();
  cp = selected_channel((snd_state *)clientData);
  if (cp) PasteSelection(w,cp);
}

static void Edit_Save_As_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* refers to the selection */
  XmString xmstr2;
  snd_state *ss = (snd_state *)clientData;
  dkms();
  if (!save_as_dialog)
    {
      save_as_dialog = (save_as_info *)calloc(1,sizeof(save_as_info));
      save_as_dialog->state = ss;
      make_save_as_dialog(w,save_as_dialog,snd_string_current_selection,NULL);
    }
  else
    {
      sprintf(search_string,snd_string_saving,snd_string_current_selection);
      xmstr2 = XmStringCreateLocalized(search_string);
      XtVaSetValues(save_as_dialog->dialog,XmNmessageString,xmstr2,NULL);
      XmStringFree(xmstr2);
      load_header_and_data_lists(save_as_dialog->header_list,save_as_dialog->data_list,
				 0,1,
				 &(save_as_dialog->header_choice),&(save_as_dialog->data_choice));
    }
  save_as_dialog->type = EDIT_SAVE_AS;
  if (!XtIsManaged(save_as_dialog->dialog)) XtManageChild(save_as_dialog->dialog);
}

static void Edit_Undo_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dkms();
  undo_EDIT((void *)clientData,1);
}

static void Edit_Redo_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dkms();
  redo_EDIT((void *)clientData,1);
}


/* -------- edit find -------- */

typedef struct {
  int size; 
  int window; 
  float beta; 
  Widget dialog;
  Widget list; 
  Widget scale; 
  Widget cancelB;
  snd_state *state;
  int type;
} dialog_info;

static void edit_find_cancel_callback(Widget w,XtPointer clientData,XtPointer callData)
{ /* "Done" */
  dialog_info *fd = (dialog_info *)clientData;
  snd_state *ss;
  ss = fd->state;
  if (ss->checking_explicitly)
    ss->stopped_explicitly = 1;
  else XtUnmanageChild(fd->dialog);
} 

static void Edit_Play_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dkms();
  if (selection_is_ours()) play_region((snd_state *)clientData,0,NULL);
}

static void edit_find_help_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Global Find",
"This search travels through all the current channels\n\
in parallel until a match is found.  The expression\n\
uses a C-like syntax.  y>.1, for example, searches\n\
until a sample is found greater than .1.\n\
");
} 

static void edit_find_ok_callback(Widget w,XtPointer clientData,XtPointer callData)
{ /* "Find" is the label here */
  dialog_info *fd = (dialog_info *)clientData;
  Widget text;
  char *str;
  XmString s1;
  snd_state *ss;
  text = fd->list;
  ss = fd->state;
  str = XmTextGetString(text);
  if ((str) && (*str))
    {
      if (ss->search_tree) free_sop(ss->search_tree);
      if (ss->search_expr) free(ss->search_expr);
      ss->search_expr = str;
      ss->search_tree = sop_parse(str);
      if (!ss->search_tree)
	{
	  sprintf(search_string,"%s: %s",str,sop_parse_error_name());
	  make_button_label(fd->scale,search_string);
	}
      else 
	{
	  sprintf(search_string,snd_string_find_s,str);
	  make_button_label(fd->scale,search_string);
	}
      XmTextSetString(text,NULL);
    }
  if (ss->search_tree) 
    {
      s1 = XmStringCreate(snd_string_Stop,XmFONTLIST_DEFAULT_TAG);
      XtVaSetValues(fd->cancelB,XmNlabelString,s1,NULL);
      XmStringFree(s1);
      str = global_search(ss);
      s1 = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG);
      XtVaSetValues(fd->cancelB,XmNlabelString,s1,NULL);
      XmStringFree(s1);
      if ((str) && (*str)) make_button_label(fd->scale,str);
    }
} 

static void make_edit_find_dialog(Widget w,dialog_info *fdw)
{
  Arg args[20];
  int n;
  Widget df,dl,rc,ds;
  XmString xmstr1,xmstr2,titlestr;

  n=0;
  xmstr1=XmStringCreateLocalized(snd_string_Find);
  xmstr2=XmStringCreateLocalized(snd_string_Dismiss);
  titlestr=XmStringCreateLocalized(snd_string_Find);
  XtSetArg(args[n],XmNokLabelString,xmstr1); n++;
  XtSetArg(args[n],XmNcancelLabelString,xmstr2); n++;
  XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
  XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
  fdw->dialog = XmCreateMessageDialog(w,snd_string_find,args,n);
#if UNSET_TRANSIENT
  add_dialog(fdw->state,fdw->dialog);
#endif

  XmStringFree(xmstr1);
  XmStringFree(xmstr2);
  XmStringFree(titlestr);

  XtUnmanageChild(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_SYMBOL_LABEL));
  XtUnmanageChild(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_MESSAGE_LABEL));

  XtAddCallback(fdw->dialog,XmNhelpCallback,edit_find_help_callback,fdw->state);
  XtAddCallback(fdw->dialog,XmNcancelCallback,edit_find_cancel_callback,fdw);
  XtAddCallback(fdw->dialog,XmNokCallback,edit_find_ok_callback,fdw);

  rc = XtCreateManagedWidget("row",xmFormWidgetClass,fdw->dialog,NULL,0);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  dl = XtCreateManagedWidget(snd_string_find_p,xmLabelWidgetClass,rc,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,dl); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  df = sndCreateTextFieldWidget(fdw->state,"text",rc,args,n);
  fdw->list = df;

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,df); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  ds = XtCreateManagedWidget(snd_string_global_search,xmLabelWidgetClass,rc,args,n);
  fdw->scale = ds;
}

static void Edit_Find_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  static dialog_info *fdw;
  snd_state *ss = (snd_state *)clientData;
  dkms();
  if (!fdw) 
    {
      fdw = (dialog_info *)calloc(1,sizeof(dialog_info));
      fdw->state = ss;
      make_edit_find_dialog(w,fdw);
#if MANAGE_DIALOG
      XtManageChild(fdw->dialog);
#endif
      if (!(ss->using_schemes)) 
	{
	  map_over_children(fdw->dialog,set_main_color_of_widget,(void *)clientData);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	}
      fdw->cancelB = XmMessageBoxGetChild(fdw->dialog,XmDIALOG_CANCEL_BUTTON);
    }
  else raise_dialog(fdw->dialog);
  if (!XtIsManaged(fdw->dialog)) XtManageChild(fdw->dialog);
}



/* -------------------------------- VIEW MENU -------------------------------- */

static void View_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	    "View Menu",
"The View Menu affects the overall Snd display.\n\
Its options are:\n\
\n\
",
get_view_menu_help(),
NULL);
}

static void update_all_graphs(snd_state *ss)
{
  map_over_chans(ss,update_graph,NULL);
}

static int update_sound(snd_info *sp, void *ptr)
{
  snd_state *ss = (snd_state *)ptr;
  if (sp)
    {
      switch (ss->global_combining)
	{
	case CHANNELS_SEPARATE: separate_sound(sp); break;
	case CHANNELS_COMBINED: combine_sound(sp); break;
	case CHANNELS_SUPERIMPOSED: superimpose_sound(sp); break;
	}
    }
  return(0);
}

static void update_all_sounds(snd_state *ss)
{
  map_over_sounds(ss,update_sound,(void *)ss);
}

void set_global_combine(snd_state *ss, int val)
{
  switch (ss->global_combining)
    {
    case CHANNELS_SEPARATE: XtSetSensitive(mw[v_combine_separate_menu],TRUE); break;
    case CHANNELS_COMBINED: XtSetSensitive(mw[v_combine_combined_menu],TRUE); break;
    case CHANNELS_SUPERIMPOSED: XtSetSensitive(mw[v_combine_superimposed_menu],TRUE); break;
    }
  ss->global_combining = val;
  switch (ss->global_combining)
    {
    case CHANNELS_SEPARATE: XtSetSensitive(mw[v_combine_separate_menu],FALSE); break;
    case CHANNELS_COMBINED: XtSetSensitive(mw[v_combine_combined_menu],FALSE); break;
    case CHANNELS_SUPERIMPOSED: XtSetSensitive(mw[v_combine_superimposed_menu],FALSE); break;
    }
  update_all_sounds(ss);
  update_all_graphs(ss);
}

static void View_Separate_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  set_global_combine(ss,CHANNELS_SEPARATE);
}

static void View_Combined_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  set_global_combine(ss,CHANNELS_COMBINED);
}

static void View_Superimposed_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  set_global_combine(ss,CHANNELS_SUPERIMPOSED);
}


static void View_Normalize_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  normalize_all_sounds((snd_state *)clientData);
}

static void View_Info_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  sp = selected_sound(ss);
  if (sp) display_info(sp);
}

void view_dots (snd_state *ss)
{
  ss->graph_style = graph_dots;
  make_name_label(mw[v_dots_menu],snd_string_Lines);
  update_all_graphs(ss);
}

void view_lines(snd_state *ss)
{
  ss->graph_style = graph_lines;
  make_name_label(mw[v_dots_menu],snd_string_Dots);
  update_all_graphs(ss);
}

static void View_Dots_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  if (ss->graph_style == graph_lines) view_dots(ss);
  else view_lines(ss);
}

void show_marks(snd_state *ss)
{
  if (!(ss->marks_visible))
    {
      ss->marks_visible = 1;
      make_name_label(mw[v_marks_menu],snd_string_Hide_marks);
      update_all_graphs(ss);
    }
}

void hide_marks(snd_state *ss)
{
  if (ss->marks_visible)
    {
      ss->marks_visible = 0;
      make_name_label(mw[v_marks_menu],snd_string_Show_marks);
      update_all_graphs(ss);
    }
}

static void View_Marks_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* similar to subsampling or dots menus */
  snd_state *ss = (snd_state *)clientData;
  ss->marks_visible = (!ss->marks_visible);
  make_name_label(w,(ss->marks_visible) ? snd_string_Hide_marks : snd_string_Show_marks);
  update_all_graphs(ss);
}

void show_y_zero(snd_state *ss)
{
  if (!(ss->zero_visible))
    {
      ss->zero_visible = 1;
      make_name_label(mw[v_zero_menu],snd_string_Hide_Y0);
      update_all_graphs(ss);
    }
}

void hide_y_zero(snd_state *ss)
{
  if (ss->zero_visible)
    {
      ss->zero_visible = 0;
      make_name_label(mw[v_zero_menu],snd_string_Show_Y0);
      update_all_graphs(ss);
    }
}

static void View_Zero_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  ss->zero_visible = (!ss->zero_visible);
  make_name_label(w,(ss->zero_visible) ? snd_string_Hide_Y0 : snd_string_Show_Y0);
  update_all_graphs(ss);
}

void verbose_cursor(snd_state *ss)
{
  if (!(ss->cursor_talks))
    {
      ss->cursor_talks = 1;
      make_name_label(mw[v_cursor_menu],snd_string_Silent_cursor);
    }
}

static int clrmini(snd_info *sp, void *ptr) {clear_minibuffer(sp); return(0);}

void silent_cursor(snd_state *ss)
{
  if (ss->cursor_talks)
    {
      map_over_sounds(ss,clrmini,NULL);
      ss->cursor_talks = 0;
      make_name_label(mw[v_cursor_menu],snd_string_Verbose_cursor);
    }
}

static void View_Cursor_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  ss->cursor_talks = (!(ss->cursor_talks));
  if (!(ss->cursor_talks)) map_over_sounds(ss,clrmini,NULL);
  make_name_label(w,(ss->cursor_talks) ? snd_string_Silent_cursor : snd_string_Verbose_cursor);
}

void set_view_ctrls_label(char *lab)
{
  make_name_label(mw[v_ctrls_menu],lab);
}

static void View_Ctrls_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  if (ss->ctrls_height < 100) show_controls(ss); else hide_controls(ss);
}


void show_consoles(snd_state *ss)
{
  if (!(ss->consoling))
    {
      ss->consoling = 1;
      make_name_label(mw[v_consoles_menu],snd_string_Hide_consoles);
      update_all_consoles(ss);
    }
}

void hide_consoles(snd_state *ss)
{
  if (ss->consoling)
    {
      ss->consoling = 0;
      make_name_label(mw[v_consoles_menu],snd_string_Show_consoles);
      update_all_consoles(ss);
    }
}

static void View_Groups_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  fire_up_group_browser((snd_state *)clientData);
}

static void View_Consoles_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  if (ss->consoling) hide_consoles(ss); else show_consoles(ss);
}


/* -------- color browser -------- */

typedef struct {
  Widget dialog;
  Widget list; 
  Widget scale; 
  Widget invert;
  Widget cutoff;
  snd_state *state;
} color_chooser_info;

static color_chooser_info *ccd = NULL;

static void Invert_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss;
  color_chooser_info *cd = (color_chooser_info *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  ss = cd->state;
  ss->color_inverted = (!(cb->set));
  map_over_chans(ss,update_graph,NULL);
}

static void Scale_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss;
  float val;
  int scale_val;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  color_chooser_info *cd = (color_chooser_info *)clientData;
  ss = cd->state;
  scale_val = cbs->value;
  if (scale_val <= 50) 
    val = (float)(scale_val+1)/51.0;
  else val = 1.0 + (float)(scale_val-50)*20.0;
  ss->color_scale = val;
  map_over_chans(ss,update_graph,NULL);
}

static void List_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss;
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  color_chooser_info *cd = (color_chooser_info *)clientData;
  ss = cd->state;
  ss->sonogram_color = (cbs->item_position - 1);
  ss->spectrogram_color = ss->sonogram_color;
  map_over_chans(ss,update_graph,NULL);
}

static void Cutoff_Color_Callback(Widget w,XtPointer clientData,XtPointer callData) /* cutoff point */
{
  /* cutoff point for color chooser */
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  color_chooser_info *cd = (color_chooser_info *)clientData;
  ss = cd->state;
  ss->color_cutoff = (float)(cbs->value)/1000.0;
  map_over_chans(ss,update_graph,NULL);
}

static void Dismiss_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  color_chooser_info *cd = (color_chooser_info *)clientData;
  XtUnmanageChild(cd->dialog);
}

static void Help_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss;
  color_chooser_info *cd = (color_chooser_info *)clientData;
  ss = cd->state;
  snd_help(ss,
       "View Color",
"This dialog sets the colormap and associated\n\
variables used during sonogram, spectrogram,\n\
and perhaps wavogram display. The cutoff scale refers\n\
to the minimum data value to be displayed.\n\
");	   
}

#define NUM_COLORMAPS 9
static char *colormaps[] = {"gray","hsv","hot","cool","bone","copper","pink","jet","prism"};
/* I tried a scrolled window with each colormap name in an appropriate color, but it looked kinda dumb */

static void View_Color_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  Arg args[32];
  int n,i;
  XmString xhelp,xdismiss,xcutoff,xinvert,titlestr;
  XmString *cmaps;
  Widget mainform,list_label,light_label,sep,sep1;
  snd_state *ss = (snd_state *)clientData;
  if (!ccd)
    {
      /* create color chooser dialog window */
      ccd = (color_chooser_info *)calloc(1,sizeof(color_chooser_info));
      ccd->state = ss;

      xdismiss = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG); /* needed by template dialog */
      xhelp = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
      titlestr = XmStringCreateLocalized(snd_string_Color_Editor);
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNcancelLabelString,xdismiss); n++;
      XtSetArg(args[n],XmNhelpLabelString,xhelp); n++;
      XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
      XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
      XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
      ccd->dialog = XmCreateTemplateDialog(main_SHELL(ss),snd_string_Color,args,n);
#if UNSET_TRANSIENT
      add_dialog(ss,ccd->dialog);
#endif

      XtAddCallback(ccd->dialog,XmNcancelCallback,Dismiss_Color_Callback,ccd);
      XtAddCallback(ccd->dialog,XmNhelpCallback,Help_Color_Callback,ccd);
      XmStringFree(xhelp);
      XmStringFree(xdismiss);
      XmStringFree(titlestr);

      if (!(ss->using_schemes))
	{
	  XtVaSetValues(XmMessageBoxGetChild(ccd->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(ccd->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	}

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,XmMessageBoxGetChild(ccd->dialog,XmDIALOG_SEPARATOR)); n++;
      mainform = XtCreateManagedWidget("formd",xmFormWidgetClass,ccd->dialog,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      list_label = XtCreateManagedWidget(snd_string_colormap,xmLabelWidgetClass,mainform,args,n);
      
      n=0;
      cmaps = (XmString *)calloc(NUM_COLORMAPS,sizeof(XmString));
      for (i=0;i<NUM_COLORMAPS;i++) cmaps[i] = XmStringCreate(colormaps[i],XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,list_label); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNlistMarginWidth,3); n++;
      ccd->list = XmCreateScrolledList(mainform,"colormap-list",args,n);
      if (!(ss->using_schemes)) XtVaSetValues(ccd->list,XmNbackground,(ss->sgx)->white,NULL);
      XtVaSetValues(ccd->list,XmNitems,cmaps,XmNitemCount,NUM_COLORMAPS,XmNvisibleItemCount,6,NULL);
      XtAddCallback(ccd->list,XmNbrowseSelectionCallback,List_Color_Callback,ccd);
      for (i=0;i<NUM_COLORMAPS;i++) XmStringFree(cmaps[i]);
      free(cmaps);
      XtManageChild(ccd->list);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
#ifdef LESSTIF_VERSION
      XtSetArg(args[n],XmNrightWidget,XtParent(ccd->list)); n++;
#else
      XtSetArg(args[n],XmNrightWidget,ccd->list); n++;
#endif
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
#ifdef LESSTIF_VERSION
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
#else
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,XmMessageBoxGetChild(ccd->dialog,XmDIALOG_SEPARATOR)); n++;
#endif
      XtSetArg(args[n],XmNseparatorType,XmNO_LINE); n++;
      XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
      XtSetArg(args[n],XmNwidth,10); n++;
      sep = XtCreateManagedWidget("sep",xmSeparatorWidgetClass,mainform,args,n);

      /* this horizontal separator exists solely to keep the "light" label from clobbering the "dark" label! */
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNseparatorType,XmNO_LINE); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNwidth,250); n++;
      XtSetArg(args[n],XmNheight,10); n++;
      sep1 = XtCreateManagedWidget("sep1",xmSeparatorWidgetClass,mainform,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sep); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,sep1); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->color_scale*100)); n++;
      ccd->scale = XtCreateManagedWidget("ccdscl",xmScaleWidgetClass,mainform,args,n);
      XtAddCallback(ccd->scale,XmNvalueChangedCallback,Scale_Color_Callback,ccd);
      XtAddCallback(ccd->scale,XmNdragCallback,Scale_Color_Callback,ccd);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,ccd->scale); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      light_label = XtCreateManagedWidget(snd_string_light,xmLabelWidgetClass,mainform,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sep); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,ccd->scale); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtCreateManagedWidget(snd_string_dark,xmLabelWidgetClass,mainform,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNrightWidget,sep); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,light_label); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNmaximum,250); n++;
      XtSetArg(args[n],XmNdecimalPoints,3); n++;
      xcutoff = XmStringCreate(snd_string_cutoff,XmFONTLIST_DEFAULT_TAG);
      XtSetArg(args[n],XmNtitleString,xcutoff); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->color_cutoff * 1000)); n++;
      ccd->cutoff = XtCreateManagedWidget("cutoff",xmScaleWidgetClass,mainform,args,n);
      XtAddCallback(ccd->cutoff,XmNvalueChangedCallback,Cutoff_Color_Callback,ccd);
      XtAddCallback(ccd->cutoff,XmNdragCallback,Cutoff_Color_Callback,ccd);
      XmStringFree(xcutoff);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      if (!(ss->using_schemes)) {XtSetArg(args[n],XmNselectColor,(ss->sgx)->text); n++;}
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNtopWidget,ccd->cutoff); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNset,(ss->color_inverted) ? FALSE : TRUE); n++;
      xinvert = XmStringCreate(snd_string_invert,XmFONTLIST_DEFAULT_TAG);
      XtSetArg(args[n],XmNlabelString,xinvert); n++;
      ccd->invert = XtCreateManagedWidget(snd_string_invert,xmToggleButtonWidgetClass,mainform,args,n);
      XtAddCallback(ccd->invert,XmNvalueChangedCallback,Invert_Color_Callback,ccd);
      XmStringFree(xinvert);
    }
  else raise_dialog(ccd->dialog);
  if (!XtIsManaged(ccd->dialog)) XtManageChild(ccd->dialog);
}


/* -------- orientation browser -------- */

typedef struct {
  Widget dialog;
  Widget ax,ay,az,sx,sy,sz,hop,cut; 
  snd_state *state;
} orientation_info;

static orientation_info *oid = NULL;

static void AX_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_xangle = (float)(cbs->value);
  map_over_chans(ss,update_graph,NULL);
}

static void AX_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"x angle slider","This slider causes the graph to rotate\naround the x axis.\n");
}

static void AY_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_yangle = (float)(cbs->value);
  map_over_chans(ss,update_graph,NULL);
}

static void AY_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"y angle slider","This slider causes the graph to rotate\naround the y axis.\n");
}

static void AZ_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_zangle = (float)(cbs->value);
  map_over_chans(ss,update_graph,NULL);
}

static void AZ_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"z angle slider","This slider causes the graph to rotate\naround the z axis.\n");
}

static void SX_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_xscl = (float)(cbs->value)*0.02;
  map_over_chans(ss,update_graph,NULL);
}

static void SX_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"x scale slider","This slider causes the graph to expand or\ncontract along the x axis.\n");
}

static void SY_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_yscl = (float)(cbs->value)*0.02;
  map_over_chans(ss,update_graph,NULL);
}

static void SY_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"y scale slider","This slider causes the graph to expand or\ncontract along the y axis.\n");
}

static void SZ_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  ss->spectro_zscl = (float)(cbs->value)*0.01;
  map_over_chans(ss,update_graph,NULL);
}

static void SZ_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"z scale slider","This slider causes the graph to expand or\ncontract along the z axis.\n");
}

static void Hop_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  if (cbs->value <= 0) 
    ss->spectro_hop = 1;
  else ss->spectro_hop = cbs->value;
  map_over_chans(ss,update_graph,NULL);
}

static void Hop_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"hop slider","This slider changes the hop size.\n");
}

static void Cut_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* y axis limit */
  snd_state *ss;
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)callData;
  orientation_info *od = (orientation_info *)clientData;
  ss = od->state;
  set_sonogram_cutoff(ss,(float)(cbs->value)*0.01);
} 

static void Cut_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,"% of spectrum slider","This slider determines how much of\nthe spectrum is displayed\n");
}

static void Help_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
       "View Orientation",
"This dialog sets the rotation and scaling\n\
variables used during sonogram, spectrogram,\n\
and wavogram display.\n\
");	   
}

static void Dismiss_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  orientation_info *od = (orientation_info *)clientData;
  XtUnmanageChild(od->dialog);
}

static int fixup_angle(float ang)
{
  int na;
  na = ang;
  na = na%360;
  if (na < 0) na+=360;
  return(na);
}

void reflect_spectro(snd_state *ss)
{
  /* set color/orientaton widget values */
  if (ccd) 
    {
      XmToggleButtonSetState(ccd->invert,(!(ss->color_inverted)),FALSE);
      XtVaSetValues(ccd->cutoff,XmNvalue,(int)((ss->color_cutoff)*1000),NULL);
      if (ss->color_scale<=1.0) 
	XtVaSetValues(ccd->scale,XmNvalue,(int)((ss->color_scale)*51.0 - 1),NULL);
      else XtVaSetValues(ccd->scale,XmNvalue,(int)((ss->color_scale-1.0)/20.0 + 50.0),NULL);
    }
  if (oid) 
    {
      XtVaSetValues(oid->ax,XmNvalue,fixup_angle(ss->spectro_xangle),NULL);
      XtVaSetValues(oid->ay,XmNvalue,fixup_angle(ss->spectro_yangle),NULL);
      XtVaSetValues(oid->az,XmNvalue,fixup_angle(ss->spectro_zangle),NULL);
      XtVaSetValues(oid->sx,XmNvalue,(int)(ss->spectro_xscl * 50),NULL);
      XtVaSetValues(oid->sy,XmNvalue,(int)(ss->spectro_yscl * 50),NULL);
      XtVaSetValues(oid->sz,XmNvalue,(int)(ss->spectro_zscl * 100),NULL);
      XtVaSetValues(oid->hop,XmNvalue,(ss->spectro_hop > 100) ? 100 : (ss->spectro_hop),NULL);
      XtVaSetValues(oid->cut,XmNvalue,(int)(ss->sonogram_cutoff * 100),NULL);
    }
}

static void Reset_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  orientation_info *od = (orientation_info *)clientData;
  /* put everything back the way it was at the start */
  ss = od->state;
  reset_spectro(ss);
  reflect_spectro(ss);
  map_over_chans(ss,update_graph,NULL);
}

static void View_Orientation_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  Widget mainform,rightbox,leftbox;
  XmString xdismiss,xhelp,xstr,xreset,titlestr;
  int n;
  Arg args[20];
  if (!oid)
    {
      /* create orientation window */
      oid = (orientation_info *)calloc(1,sizeof(orientation_info));
      oid->state = ss;

      xdismiss = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG); /* needed by template dialog */
      xhelp = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
      xreset = XmStringCreate(snd_string_Reset,XmFONTLIST_DEFAULT_TAG);
      titlestr = XmStringCreateLocalized(snd_string_FFT_Orientation);
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNcancelLabelString,xdismiss); n++;
      XtSetArg(args[n],XmNhelpLabelString,xhelp); n++;
      XtSetArg(args[n],XmNokLabelString,xreset); n++;
      XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
      XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
      XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
      oid->dialog = XmCreateTemplateDialog(main_SHELL(ss),snd_string_Orientation,args,n);
#if UNSET_TRANSIENT
      add_dialog(ss,oid->dialog);
#endif

      XtAddCallback(oid->dialog,XmNcancelCallback,Dismiss_Orientation_Callback,oid);
      XtAddCallback(oid->dialog,XmNhelpCallback,Help_Orientation_Callback,ss);
      XtAddCallback(oid->dialog,XmNokCallback,Reset_Orientation_Callback,oid);
      XmStringFree(xhelp);
      XmStringFree(xdismiss);
      XmStringFree(titlestr);
      XmStringFree(xreset);

      if (!(ss->using_schemes))
	{
	  XtVaSetValues(XmMessageBoxGetChild(oid->dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(oid->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(oid->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	}

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,XmMessageBoxGetChild(oid->dialog,XmDIALOG_SEPARATOR)); n++;
      mainform = XtCreateManagedWidget("formd",xmFormWidgetClass,oid->dialog,args,n);
      
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNrightPosition,50); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
      leftbox = XtCreateManagedWidget("leftb",xmRowColumnWidgetClass,mainform,args,n);
      
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,leftbox); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
      rightbox = XtCreateManagedWidget("rightb",xmRowColumnWidgetClass,mainform,args,n);
      
      /* left box */
      n=0;
      xstr = XmStringCreate(snd_string_x_angle,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,fixup_angle(ss->spectro_xangle)); n++;
      XtSetArg(args[n],XmNmaximum,360); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->ax = XtCreateManagedWidget("ax",xmScaleWidgetClass,leftbox,args,n);
      XtAddCallback(oid->ax,XmNvalueChangedCallback,AX_Orientation_Callback,oid);
      XtAddCallback(oid->ax,XmNdragCallback,AX_Orientation_Callback,oid);
      XtAddCallback(oid->ax,XmNhelpCallback,AX_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_y_angle,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,fixup_angle(ss->spectro_yangle)); n++;
      XtSetArg(args[n],XmNmaximum,360); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->ay = XtCreateManagedWidget("ay",xmScaleWidgetClass,leftbox,args,n);
      XtAddCallback(oid->ay,XmNvalueChangedCallback,AY_Orientation_Callback,oid);
      XtAddCallback(oid->ay,XmNdragCallback,AY_Orientation_Callback,oid);
      XtAddCallback(oid->ay,XmNhelpCallback,AY_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_z_angle,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,fixup_angle(ss->spectro_zangle)); n++;
      XtSetArg(args[n],XmNmaximum,360); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->az = XtCreateManagedWidget("az",xmScaleWidgetClass,leftbox,args,n);
      XtAddCallback(oid->az,XmNvalueChangedCallback,AZ_Orientation_Callback,oid);
      XtAddCallback(oid->az,XmNdragCallback,AZ_Orientation_Callback,oid);
      XtAddCallback(oid->az,XmNhelpCallback,AZ_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_hop,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(ss->spectro_hop > 100) ? 100 : ss->spectro_hop); n++;
      XtSetArg(args[n],XmNmaximum,100); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->hop = XtCreateManagedWidget("hop",xmScaleWidgetClass,leftbox,args,n);
      XtAddCallback(oid->hop,XmNvalueChangedCallback,Hop_Orientation_Callback,oid);
      XtAddCallback(oid->hop,XmNdragCallback,Hop_Orientation_Callback,oid);
      XtAddCallback(oid->hop,XmNhelpCallback,Hop_Help_Callback,ss);
      XmStringFree(xstr);

      /* right box */
      n=0;
      xstr = XmStringCreate(snd_string_x_scale,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->spectro_xscl * 50)); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->sx = XtCreateManagedWidget("xs",xmScaleWidgetClass,rightbox,args,n);
      XtAddCallback(oid->sx,XmNvalueChangedCallback,SX_Orientation_Callback,oid);
      XtAddCallback(oid->sx,XmNdragCallback,SX_Orientation_Callback,oid);
      XtAddCallback(oid->sx,XmNhelpCallback,SX_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_y_scale,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->spectro_yscl * 50)); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->sy = XtCreateManagedWidget("ys",xmScaleWidgetClass,rightbox,args,n);
      XtAddCallback(oid->sy,XmNvalueChangedCallback,SY_Orientation_Callback,oid);
      XtAddCallback(oid->sy,XmNdragCallback,SY_Orientation_Callback,oid);
      XtAddCallback(oid->sy,XmNhelpCallback,SY_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_z_scale,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->spectro_zscl * 100)); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->sz = XtCreateManagedWidget("zs",xmScaleWidgetClass,rightbox,args,n);
      XtAddCallback(oid->sz,XmNvalueChangedCallback,SZ_Orientation_Callback,oid);
      XtAddCallback(oid->sz,XmNdragCallback,SZ_Orientation_Callback,oid);
      XtAddCallback(oid->sz,XmNhelpCallback,SZ_Help_Callback,ss);
      XmStringFree(xstr);

      n=0;
      xstr = XmStringCreate(snd_string_percent_of_spectrum,XmFONTLIST_DEFAULT_TAG);
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
      XtSetArg(args[n],XmNshowValue,TRUE); n++;
      XtSetArg(args[n],XmNvalue,(int)(ss->sonogram_cutoff * 100)); n++;
      XtSetArg(args[n],XmNtitleString,xstr); n++;
      oid->cut = XtCreateManagedWidget("cut",xmScaleWidgetClass,rightbox,args,n);
      XtAddCallback(oid->cut,XmNvalueChangedCallback,Cut_Orientation_Callback,oid);
      XtAddCallback(oid->cut,XmNdragCallback,Cut_Orientation_Callback,oid);
      XtAddCallback(oid->cut,XmNhelpCallback,Cut_Help_Callback,ss);
      XmStringFree(xstr);
    }
  else raise_dialog(oid->dialog);
  if (!XtIsManaged(oid->dialog)) XtManageChild(oid->dialog);
}


/* -------- files browser -------- */
/*
 * the region and file browsers share much widgetry -- they are supposed to look the same
 */

typedef struct {
  Widget rw,nm,pl,sv;
  int pos;
  snd_state *ss;
} regrow;

typedef struct {
  Widget ww;
  Widget list;
  Widget plw;
  Widget svw;
  Widget dbline;
} ww_info;

typedef struct {
  Widget dialog;
  Widget curlst;
  Widget prevlst;
  Widget curww; /* work area of scrolled window */
  Widget prevww;
  int selected_file;
  snd_state *state;
} fb_info;

static fb_info *fbd = NULL;

#define MAX_FILE_LIST_SIZE 256
static char *curnames[MAX_FILE_LIST_SIZE];
static char *prevnames[MAX_FILE_LIST_SIZE];
static char *prevfullnames[MAX_FILE_LIST_SIZE];
static int a_big_star[MAX_FILE_LIST_SIZE];
static int curfile_end = 0;
static int prevfile_end = -1;
static int max_curfile_end = 0;
static int max_prevfile_end = -1;

static void make_curfiles_list (snd_state *ss);
static void make_prevfiles_list (snd_state *ss);  /* these are needed as local forward declarations */

static regrow *cur_name_row[MAX_FILE_LIST_SIZE];
static regrow *prev_name_row[MAX_FILE_LIST_SIZE];

static ww_info *make_title_row(snd_state *ss, Widget formw, char *first_str, char *second_str, char *main_str, int pad)
{
  int n;
  Arg args[32];
  Widget plw,svw,rlw,sep1;
  ww_info *wwi;

  wwi = (ww_info *)calloc(1,sizeof(ww_info));
  
  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_CENTER); n++;	
  rlw = XtCreateManagedWidget(main_str,xmLabelWidgetClass,formw,args,n);
      
  n=0;
  if (!(ss->using_schemes)) n = background_white_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,rlw); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
  XtSetArg(args[n],XmNseparatorType,XmDOUBLE_LINE); n++;
  sep1 = XtCreateManagedWidget("sep",xmSeparatorWidgetClass,formw,args,n);
  wwi->dbline = sep1;

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  if (pad == 2)
    {
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,5); n++;
    }
  else
    {
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
    }
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,sep1); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,button_FONT(ss)); n++;
  svw = XtCreateManagedWidget(first_str,xmLabelWidgetClass,formw,args,n);
  make_button_label(svw,first_str);
  wwi->svw = svw;

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,svw); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,sep1); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,button_FONT(ss)); n++;
  plw = XtCreateManagedWidget(second_str,xmLabelWidgetClass,formw,args,n);
  make_button_label(plw,second_str);
  wwi->plw = plw;
  
  n=0;
  if (pad == 2) /* pad on left */
    {
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNleftPosition,5); n++;
    }
  else
    {
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
    }
  if (pad == 1) /* pad on right */
    {
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNrightPosition,95); n++;
    }
  else
    {
      if (pad == 2)
	{
	  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
	}
      else
	{
	  XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); n++;
	  XtSetArg(args[n],XmNrightPosition,70); n++;
	}
    }
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,svw); n++;
  if (pad == 0)
    {
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNbottomPosition,40); n++;
    }
  else
    {
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
    }
  XtSetArg(args[n],XmNscrollingPolicy,XmAUTOMATIC); n++;
  XtSetArg(args[n],XmNscrollBarDisplayPolicy,XmSTATIC); n++;
  wwi->list = XmCreateScrolledWindow(formw,"reglist",args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  wwi->ww = XtCreateManagedWidget("ww",xmFormWidgetClass,wwi->list,args,n);
  XtVaSetValues(wwi->list,XmNworkWindow,wwi->ww,NULL);
  
  return(wwi);
}

static regrow *make_regrow(snd_state *ss, Widget ww, Widget last_row, 
			   XtCallbackProc first_callback, XtCallbackProc second_callback, XtCallbackProc third_callback)
{
  int n;
  Arg args[32];
  regrow *r;
  XmString s1;
  s1 = XmStringCreateLtoR("",XmFONTLIST_DEFAULT_TAG);
  r = (regrow *)calloc(1,sizeof(regrow));

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,(last_row) ? XmATTACH_WIDGET : XmATTACH_FORM); n++;
  if (last_row) {XtSetArg(args[n],XmNtopWidget,last_row); n++;}
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
#if defined(LINUX) || defined(SCO5) || defined(UW2) || defined(SUN)
  XtSetArg(args[n],XmNheight,17); n++; 
#else
  XtSetArg(args[n],XmNheight,20); n++; 
#endif
  r->rw = XtCreateWidget("rw",xmFormWidgetClass,ww,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  if (!(ss->using_schemes)) {XtSetArg(args[n],XmNselectColor,(ss->sgx)->text); n++;}
  XtSetArg(args[n],XmNlabelString,s1); n++;
  XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(first_callback,(XtPointer)r)); n++;
#if NEED_TOGGLE_SIZE
  XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
  r->sv = XtCreateManagedWidget("sv",xmToggleButtonWidgetClass,r->rw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,r->sv); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  if (!(ss->using_schemes)) {XtSetArg(args[n],XmNselectColor,(ss->sgx)->text); n++;}
  XtSetArg(args[n],XmNlabelString,s1); n++;
  XtSetArg(args[n],XmNvalueChangedCallback,make_callback_list(second_callback,(XtPointer)r)); n++;
#if NEED_TOGGLE_SIZE
  XtSetArg(args[n],XmNindicatorSize,TOGGLE_SIZE); n++;
#endif
  r->pl = XtCreateManagedWidget("pl",xmToggleButtonWidgetClass,r->rw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,r->pl); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNshadowThickness,0); n++;
  XtSetArg(args[n],XmNhighlightThickness,0); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;
  XtSetArg(args[n],XmNfillOnArm,FALSE); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNrecomputeSize,FALSE); n++;
  XtSetArg(args[n],XmNwidth,300); n++;
  XtSetArg(args[n],XmNactivateCallback,make_callback_list(third_callback,(XtPointer)r)); n++;
  r->nm = XtCreateManagedWidget("nm",xmPushButtonWidgetClass,r->rw,args,n);
  XmStringFree(s1);
  return(r);
}

static void make_row_name(regrow *r, char *name, int big_star)
{
  if (big_star)
    {
      sprintf(search_string,"%s*",name);
      make_bold_button_label(r->nm,search_string);
    }
  else make_bold_button_label(r->nm,name);
}

static void fill_in_row(regrow *r, char *name, int big_star)
{
  make_row_name(r,name,big_star);
  XmToggleButtonSetState(r->sv,FALSE,FALSE);
  XmToggleButtonSetState(r->pl,FALSE,FALSE);
  XtManageChild(r->rw);
}

static int find_curfile_regrow(char *shortname)
{
  int i;
  for (i=0;i<curfile_end;i++)
    {
      if (strcmp(curnames[i],shortname) == 0) return(i);
    }
  return(-1);
}

static int find_prevfile_regrow(char *shortname)
{
  int i;
  for (i=0;i<=prevfile_end;i++)
    {
      if (strcmp(prevnames[i],shortname) == 0) return(i);
    }
  return(-1);
}

static void file_uncurlist(char *filename)
{
  int i,j;
  i = find_curfile_regrow(filename);
  if (i != -1)
    {
      free(curnames[i]);
      curnames[i] = NULL;
      for (j=i;j<curfile_end-1;j++) 
	{
	  curnames[j] = curnames[j+1];
	  a_big_star[j] = a_big_star[j+1];
	}
      curfile_end--;
    }
}

static void file_unprevlist(char *filename)
{
  int i,j;
  i = find_prevfile_regrow(filename);
  if (i != -1)
    {
      free(prevnames[i]);
      prevnames[i] = NULL;
      free(prevfullnames[i]);
      prevfullnames[i] = NULL;
      for (j=i;j<prevfile_end;j++) {prevnames[j] = prevnames[j+1]; prevfullnames[j] = prevfullnames[j+1];}
      prevfile_end--;
    }
}

static void clear_prevlist(void)
{
  int i;
  for (i=0;i<=prevfile_end;i++)
    {
      if (prevnames[i]) 
	{
	  free(prevnames[i]); prevnames[i]=NULL;
	  free(prevfullnames[i]); prevfullnames[i]=NULL;
	}
    }
  prevfile_end = -1;
}

static void update_prevlist(void)
{
  /* here we need the file's full name */
  int i,j,fd;
  for (i=0;i<=prevfile_end;i++)
    {
      if (prevnames[i]) 
	{
	  fd = open(prevfullnames[i],O_RDONLY,0);
	  if (fd == -1) 
	    {
	      free(prevnames[i]); prevnames[i]=NULL;
	      free(prevfullnames[i]); prevfullnames[i]=NULL;
	    }
	  else close(fd);
	}
    }
  for (i=0,j=0;i<=prevfile_end;i++)
    {
      if (prevnames[i])
	{
	  if (i != j) {prevnames[j] = prevnames[i]; prevfullnames[j] = prevfullnames[i];}
	  j++;
	}
    }
  prevfile_end = j-1;
}

static void file_curlist(char *filename)
{
  if (curfile_end == MAX_FILE_LIST_SIZE) 
    {
      curfile_end--;
      if (curnames[curfile_end]) free(curnames[curfile_end]);
    }
  curnames[curfile_end] = copy_string(filename);
  a_big_star[curfile_end] = 0;
  curfile_end++;
  if (max_curfile_end < curfile_end) max_curfile_end = curfile_end;
}

static void file_prevlist(char *filename, char *fullname) /* called in snd-clm.c for prev preload */
{
  int k;
  prevfile_end++;
  if (prevfile_end == MAX_FILE_LIST_SIZE) 
    {
      prevfile_end--;
      if (prevnames[prevfile_end]) {free(prevnames[prevfile_end]); free(prevfullnames[prevfile_end]);}
    }
  for (k=prevfile_end;k>0;k--) {prevnames[k]=prevnames[k-1]; prevfullnames[k]=prevfullnames[k-1];}
  prevnames[0] = copy_string(filename);
  prevfullnames[0] = copy_string(fullname);
  if (max_prevfile_end < prevfile_end) max_prevfile_end = prevfile_end;
}

void add_files_to_prevlist(snd_state *ss, char **shortnames, char **longnames, int len)
{
  int i,k;
  for (i=0,k=prevfile_end+1;((i<len) && (k < MAX_FILE_LIST_SIZE));i++,k++)
    {
      prevnames[k] = copy_string(shortnames[i]);
      prevfullnames[k] = copy_string(longnames[i]);
    }
  prevfile_end = k-1;
  max_prevfile_end = prevfile_end;
  if ((fbd) && (XtIsManaged(fbd->dialog))) make_prevfiles_list(ss);
}

void add_directory_to_prevlist(snd_state *ss, char *dirname)
{
  dir *sound_files = NULL;
  char *fullpathname = NULL;
  char **fullnames;
  int i,end;
  sound_files = find_sound_files_in_dir(dirname);
  if ((sound_files) && (sound_files->len > 0))
    {
      fullpathname = (char *)calloc(FILENAME_MAX,sizeof(char));
      strcpy(fullpathname,dirname);
      if (dirname[strlen(dirname)-1] != '/') strcat(fullpathname,"/");
      end = strlen(fullpathname);
      fullnames = (char **)calloc(sound_files->len,sizeof(char *));
      for (i=0;i<sound_files->len;i++) 
	{
	  fullnames[i] = copy_string(strcat(fullpathname,sound_files->files[i]));
	  fullpathname[end] = '\0';
	}
      add_files_to_prevlist(ss,sound_files->files,fullnames,sound_files->len);
      for (i=0;i<sound_files->len;i++) {free(fullnames[i]); fullnames[i]=NULL;}
      free(fullnames);
      free_dir(sound_files);
      free(fullpathname);
    }
  if ((fbd) && (XtIsManaged(fbd->dialog))) make_prevfiles_list(ss);
}

void remember_me(snd_state *ss, char *shortname,char *fullname)
{
  file_prevlist(shortname,fullname);
  file_uncurlist(shortname);
  if ((fbd) && (XtIsManaged(fbd->dialog)))
    {
      make_curfiles_list(ss);
      make_prevfiles_list(ss);
    }
}

void greet_me(snd_state *ss, char *shortname)
{
  file_curlist(shortname);
  file_unprevlist(shortname);
  if ((fbd) && (XtIsManaged(fbd->dialog)))
    {
      make_curfiles_list(ss);
      make_prevfiles_list(ss);
    }
}

void make_a_big_star_outa_me(snd_state *ss, char *shortname, int big_star)
{
  int i;
  regrow *r;
  i = find_curfile_regrow(shortname);
  if ((i != -1) && (a_big_star[i] != big_star))
    {
      if ((fbd) && (XtIsManaged(fbd->dialog)))
	{
	  r = cur_name_row[i];
	  make_row_name(r,curnames[i],big_star);
	}
      a_big_star[i] = big_star;
    }
}

static void View_Files_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
       "File Browser",
"This dialog provides two lists, one of\n\
the currently active files in Snd, and\n\
the other of previously active files.\n\
The save button saves current edits, the\n\
play button plays the file, and the\n\
unlist button removes a file from the\n\
previous files list.  If a file is deleted\n\
while Snd is running, it will not notice\n\
its deletion automatically.  To update the\n\
previous files list to account for such\n\
actions, click on the 'update' button.\n\
To reopen a previous file, simply select\n\
that file from the previous files list.\n\
To remove all files from the previous files\n\
list, click the 'clear' button.  To select\n\
one of the current files in Snd, opening\n\
its associated windows, select it in the\n\
current files list.\n\
\n\
To preload all the sound files in a directory\n\
into the previous files list, use either the\n\
command (preload dir), as in\n\
\n\
  M-x (preload /usr/people/bil/hdr)\n\
\n\
or give the directory name to the -p flag\n\
when starting Snd:\n\
\n\
  snd -p . oboe.snd\n\
\n\
To preload a specific list of files, pass\n\
the list of unquoted names to the command\n\
preload-files-browser.\n\
");	   
}

static void View_Files_Dismiss_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  fb_info *fd = (fb_info *)clientData;
  XtUnmanageChild(fd->dialog);
}

static void View_Files_Clear_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* clear previous files list and associated widget list */
  clear_prevlist();
  make_prevfiles_list((snd_state *)clientData);
}

static void View_Files_Update_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* run through previous files list looking for any that have been deleted behind our back */
  update_prevlist();
  make_prevfiles_list((snd_state *)clientData);
}

static void View_CurFiles_Save_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  snd_info *sp;
  sp = find_sound(r->ss,curnames[r->pos]);
  if (sp)
    {
      dkms();
      save_edits(sp,NULL);
    }
  XmToggleButtonSetState(r->sv,FALSE,FALSE);
}

void set_file_browser_play_button(char *name, int state)
{
  int i,list;
  regrow *r;
  list = 0;
  if ((fbd) && (XtIsManaged(fbd->dialog)))
    {
      i=find_curfile_regrow(name); 
      if (i != -1) list = 1; else i=find_prevfile_regrow(name);
      if (i != -1)
	{
	  if (list) r=cur_name_row[i]; else r=prev_name_row[i];
	  XmToggleButtonSetState(r->pl,state,FALSE);
	}
    }
}

static void View_CurFiles_Play_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  snd_info *sp;
  sp = find_sound(r->ss,curnames[r->pos]);
  if (sp)
    {
      if (sp->playing) stop_playing(sp->playing);
      if (cb->set)
	{
	  start_playing(sp,0);
	  set_play_button(sp,1);
	}
      else set_play_button(sp,0);
    }
}

static void curfile_unhighlight(snd_state *ss)
{
  regrow *r;
  if ((fbd) && (XtIsManaged(fbd->dialog)))
    {
      if ((!(ss->using_schemes)) && (fbd->selected_file != -1))
	{
	  r = cur_name_row[fbd->selected_file];
	  XtVaSetValues(r->rw,XmNbackground,(ss->sgx)->high,NULL);
	  XtVaSetValues(r->nm,XmNbackground,(ss->sgx)->high,NULL);
	  fbd->selected_file = -1;
	}
    }
}

static void curfile_highlight(snd_state *ss, int i)
{
  regrow *r;
  if ((fbd) && (XtIsManaged(fbd->dialog)))
    {
      if (!(ss->using_schemes)) 
	{
	  if (fbd->selected_file != -1) curfile_unhighlight(ss);
	  r = cur_name_row[i];
	  XtVaSetValues(r->rw,XmNbackground,(ss->sgx)->zoom,NULL);
	  XtVaSetValues(r->nm,XmNbackground,(ss->sgx)->zoom,NULL);
	  fbd->selected_file = i;
	}
    }
}

static void View_CurFiles_Select_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  snd_info *sp,*osp;
  snd_state *ss;
  ss = r->ss;
  curfile_highlight(ss,r->pos);
  sp = find_sound(ss,curnames[r->pos]);
  osp = any_selected_sound(ss);
  if (sp != osp)
    {
      select_channel(sp,0);
      normalize_sound(ss,sp,osp,sp->chans[0]);
      goto_graph(sp->chans[0]);
    }
}

static void View_PrevFiles_Unlist_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  file_unprevlist(prevnames[r->pos]);
  make_prevfiles_list(r->ss);
}

static void View_PrevFiles_Play_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* open and play -- close at end or when button off toggled */
  regrow *r = (regrow *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  static snd_info *play_sp;
  int play;
  play = cb->set;
  if (play)
    {
      if (play_sp)
	{
	  if (play_sp->playing) {XmToggleButtonSetState(w,FALSE,FALSE); return;} /* can't play two of these at once */
	  if (strcmp(play_sp->shortname,prevnames[r->pos]) != 0)
	    {
	      free_snd_info(play_sp);
	      play_sp = NULL;
	    }
	}
      if (!play_sp) play_sp = make_sound_readable(r->ss,prevfullnames[r->pos],FALSE);
      if (play_sp)
	{
	  play_sp->shortname = prevnames[r->pos];
	  play_sp->fullname = NULL;
	  start_playing(play_sp,0);
	}
      else
	{ /* can't find or setup file */
	  XmToggleButtonSetState(w,FALSE,FALSE);
	  play = 0;
	}
    }
  else
    { /* play toggled off */
      if ((play_sp) && (play_sp->playing)) {stop_playing(play_sp->playing); play_sp->playing = 0;}
    }
}

static void View_PrevFiles_Select_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  /* open and set as selected */
  regrow *r = (regrow *)clientData;
  snd_info *sp;
  sp = snd_open_file(prevfullnames[r->pos],r->ss);
  if (sp) select_channel(sp,0); 
}

void highlight_selected_sound(snd_state *ss)
{
  snd_info *sp;
  int i;
  sp = selected_sound(ss);
  if (sp)
    {
      i = find_curfile_regrow(sp->shortname);
      if (i != -1) curfile_highlight(ss,i); else curfile_unhighlight(ss);
    }
  else curfile_unhighlight(ss);
}

static void make_curfiles_list (snd_state *ss)
{
  int i;
  Widget last_row = NULL;
  regrow *r;
  for (i=0;i<curfile_end;i++)
    {
      if (!(r = cur_name_row[i]))
	{
	  r = make_regrow(ss,fbd->curww,last_row,View_CurFiles_Save_Callback,View_CurFiles_Play_Callback,View_CurFiles_Select_Callback);
	  cur_name_row[i] = r;
	  r->pos = i;
	  r->ss = ss;
	}
      fill_in_row(r,curnames[i],a_big_star[i]);
      last_row = r->rw;
    }
  for (i=curfile_end;i<max_curfile_end;i++)
    {
      if ((r = cur_name_row[i]))
	{
	  if (XtIsManaged(r->rw)) XtUnmanageChild(r->rw);
	}
    }
  max_curfile_end = curfile_end;
  highlight_selected_sound(ss);
  XtManageChild(fbd->curlst);
}

static void make_prevfiles_list (snd_state *ss)
{
  int i;
  Widget last_row = NULL;
  regrow *r;
  for (i=0;i<=prevfile_end;i++)
    {
      if (!((r = prev_name_row[i])))
	{
	  r = make_regrow(ss,fbd->prevww,last_row,View_PrevFiles_Unlist_Callback,View_PrevFiles_Play_Callback,View_PrevFiles_Select_Callback);
	  prev_name_row[i] = r;
	  r->pos = i;
	  r->ss = ss;
	}
      fill_in_row(r,prevnames[i],0);
      last_row = r->rw;
    }
  for (i=prevfile_end+1;i<=max_prevfile_end;i++)
    {
      if ((r = prev_name_row[i]))
	{
	  if (XtIsManaged(r->rw)) XtUnmanageChild(r->rw);
	}
    }
  max_prevfile_end = prevfile_end;
  XtManageChild(fbd->prevlst);
}


/* play open unlist for prevfile, play save select for curfile, preload process for prevfile (snd-clm) */

static void View_Files_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* fire up a dialog window with a list of currently open files, 
   * currently selected file also selected in list --
   * if user selects one (browse mode), so does Snd (via normalize_sound etc)
   * use snd_info label as is (short-form with '*' etc) -- snd_widget(sp,W_snd_name)
   * secondary list of previously edited files (if still in existence) --
   * click here re-opens the file.  (The overall form is similar to the regions browser).
   * The previous files list requires that we keep such a list as we go along, on the
   * off-chance this browser will be fired up.  (Such files may be subsequently moved or deleted).
   */
  snd_state *ss = (snd_state *)clientData;
  int n,i;
  Arg args[20];
  ww_info *wwl;
  regrow *r;
  XmString xdismiss,xhelp,xclear,titlestr;
  Widget mainform,curform,prevform,updateB,sep;
  if (!fbd)
    {
      fbd = (fb_info *)calloc(1,sizeof(fb_info));
      fbd->state = ss;
      fbd->selected_file = -1;
      for (i=0;i<MAX_FILE_LIST_SIZE;i++) /* paranoia */
	{ 
	  cur_name_row[i] = NULL;
	  prev_name_row[i] = NULL;
	}
      xdismiss = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG);
      xhelp = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
      xclear = XmStringCreate(snd_string_Clear,XmFONTLIST_DEFAULT_TAG);
      titlestr = XmStringCreateLocalized(snd_string_Files);
      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNcancelLabelString,xclear); n++;
      XtSetArg(args[n],XmNhelpLabelString,xhelp); n++;
      XtSetArg(args[n],XmNokLabelString,xdismiss); n++;
      XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
      XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
      XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif

      fbd->dialog = XmCreateTemplateDialog(main_SHELL(ss),snd_string_File_Browser,args,n);
#if UNSET_TRANSIENT
      add_dialog(ss,fbd->dialog);
#endif

      XtAddCallback(fbd->dialog,XmNcancelCallback,View_Files_Clear_Callback,ss);
      XtAddCallback(fbd->dialog,XmNhelpCallback,View_Files_Help_Callback,ss);
      XtAddCallback(fbd->dialog,XmNokCallback,View_Files_Dismiss_Callback,fbd);
      XmStringFree(xhelp);
      XmStringFree(xdismiss);
      XmStringFree(xclear);
      XmStringFree(titlestr);

      if (!(ss->using_schemes))
	{
	  XtVaSetValues(XmMessageBoxGetChild(fbd->dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fbd->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fbd->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	}

      n=0;
      if (!(ss->using_schemes)) 
	{
	  n = background_main_color(args,n,ss);
	  XtSetArg(args[n],XmNarmColor,(ss->sgx)->text); n++;
	}
      updateB = XtCreateManagedWidget(snd_string_Update,xmPushButtonWidgetClass,fbd->dialog,args,n);
      XtAddCallback(updateB,XmNactivateCallback,View_Files_Update_Callback,ss);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNbottomWidget,XmMessageBoxGetChild(fbd->dialog,XmDIALOG_SEPARATOR)); n++;
      mainform = XtCreateManagedWidget("formd",xmFormWidgetClass,fbd->dialog,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_POSITION); n++;
      XtSetArg(args[n],XmNrightPosition,49); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      curform = XtCreateManagedWidget("curform",xmFormWidgetClass,mainform,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,curform); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
      XtSetArg(args[n],XmNseparatorType,XmSHADOW_ETCHED_IN); n++;
      sep = XtCreateManagedWidget("sep",xmSeparatorWidgetClass,mainform,args,n);

      n=0;
      if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
      XtSetArg(args[n],XmNleftWidget,sep); n++;
      XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
      XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
      prevform = XtCreateManagedWidget("prevform",xmFormWidgetClass,mainform,args,n);


      /* current files section: save play current files | files */
      wwl = make_title_row(ss,curform,snd_string_save,snd_string_play,snd_string_current_files,1);
      fbd->curww = wwl->ww;
      fbd->curlst = wwl->list;
      if (!(ss->using_schemes)) map_over_children(fbd->curlst,set_main_color_of_widget,(void *)clientData);
      free(wwl); 
      wwl=NULL;
      if (curfile_end == 0) /* apparently we need at least one row to get Motif to allocate the outer widgets correctly */
	{
	  r = make_regrow(ss,fbd->curww,NULL,View_CurFiles_Save_Callback,View_CurFiles_Play_Callback,View_CurFiles_Select_Callback);
	  cur_name_row[0] = r;
	  r->pos = 0;
	  r->ss = ss;
	}

      /* previous files section: unlist play previous files | files */
      wwl = make_title_row(ss,prevform,snd_string_unlist,snd_string_play,snd_string_previous_files,2);
      fbd->prevww = wwl->ww;
      fbd->prevlst = wwl->list;
      if (!(ss->using_schemes)) map_over_children(fbd->prevlst,set_main_color_of_widget,(void *)clientData);
      free(wwl); 
      wwl=NULL;
      if (prevfile_end == -1)
	{
	  r = make_regrow(ss,fbd->prevww,NULL,View_PrevFiles_Unlist_Callback,View_PrevFiles_Play_Callback,View_PrevFiles_Select_Callback);
	  prev_name_row[0] = r;
	  r->pos = 0;
	  r->ss = ss;
	}
    }
  else raise_dialog(fbd->dialog);
  make_curfiles_list(ss);
  make_prevfiles_list(ss);
  if (!XtIsManaged(fbd->dialog)) XtManageChild(fbd->dialog);
  highlight_selected_sound(ss);
}



/* -------- region browser -------- */

static regrow *region_rows[REGIONS];
static snd_info *reg_sp = NULL;
static dialog_info *reg_fd = NULL;
static int current_region = -1;
static Widget selectw,reg_srtxt,reg_lentxt,reg_chntxt,reg_maxtxt;

static void make_region_element(region_state *rs, int i)
{
  regrow *r;
  r = region_rows[i];
  make_bold_button_label(r->nm,rs->name[i]);
  XmToggleButtonSetState(r->sv,rs->save[i],FALSE);
  XmToggleButtonSetState(r->pl,FALSE,FALSE);
  XtManageChild(r->rw);
}

static void unhighlight_region(snd_state *ss)
{
  regrow *oldr;
  if (current_region != -1)
    {
      oldr = region_rows[current_region];
      if (!(ss->using_schemes)) 
	{
	  XtVaSetValues(oldr->rw,XmNbackground,(ss->sgx)->high,NULL);
	  XtVaSetValues(oldr->nm,XmNbackground,(ss->sgx)->high,NULL);
	}
    }
}

static void unmake_region_labels (void)
{
  make_bold_button_label(reg_srtxt,snd_string_srate_p);
  make_bold_button_label(reg_chntxt,snd_string_chans_p);
  make_bold_button_label(reg_lentxt,snd_string_length_p);
  make_bold_button_label(reg_maxtxt,snd_string_maxamp_p);
}

static void highlight_region(snd_state *ss)
{
  regrow *oldr;
  if (current_region != -1)
    {
      oldr = region_rows[current_region];
      if (!(ss->using_schemes)) 
	{
	  XtVaSetValues(oldr->rw,XmNbackground,(ss->sgx)->zoom,NULL);
	  XtVaSetValues(oldr->nm,XmNbackground,(ss->sgx)->zoom,NULL);
	}
    }
}

static void make_region_labels(file_info *hdr)
{
  sprintf(search_string,snd_string_srate,hdr->srate);
  make_bold_button_label(reg_srtxt,search_string);
  sprintf(search_string,snd_string_chans,hdr->chans);
  make_bold_button_label(reg_chntxt,search_string);
  sprintf(search_string,snd_string_length,(float)(hdr->samples)/(float)(hdr->chans * hdr->srate));
  make_bold_button_label(reg_lentxt,search_string);
  sprintf(search_string,snd_string_maxamp,region_maxamp(current_region));
  make_bold_button_label(reg_maxtxt,search_string);
}

void update_region_browser(int grf_too)
{
  int i,len;
  region_state *rs;
  snd_state *ss;
  chan_info *cp;
  rs = region_report();
  len = rs->len;
  for (i=0;i<len;i++) make_region_element(rs,i);
  for (i=len;i<REGIONS;i++) XtUnmanageChild(region_rows[i]->rw);
  free_region_state(rs);
  if (len == 0) return;
  XtManageChild(reg_fd->list);
  ss = reg_fd->state;
  if (grf_too)
    {
      unhighlight_region(ss);
      current_region = 0;
      highlight_region(ss);
      goto_window(region_rows[0]->nm);
      cp = reg_sp->chans[0];
      if (cp) 
	{
	  cp->chan = 0;
	  XtSetSensitive(chan_widget(cp,W_chn_f),FALSE);
	  XtSetSensitive(chan_widget(cp,W_chn_w),(region_chans(0) > 1));
	  if (selection_is_ours()) 
	    {
	      reg_sp->hdr = fixup_region_data(cp,0,0);
	      make_region_labels(reg_sp->hdr);
	      update_graph(cp,ss);
	    }
	  else unmake_region_labels();
	}
    }
}

static void region_ok_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dialog_info *fd = (dialog_info *)clientData;
  XtUnmanageChild(fd->dialog);
}

int region_browser_is_active(void)
{
  return((reg_fd) && (XtIsRealized(reg_fd->dialog)));
}

static void region_resize_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  update_graph((chan_info *)clientData,NULL);
}

static void region_delete_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  int act;
  snd_state *ss = (snd_state *)clientData;
  if (current_region != -1)
    {
      act = delete_region(current_region);
      if (act != -1)
	{
	  current_region = 0;
	  highlight_region(ss);
	  goto_window(region_rows[0]->nm);
	}
      else 
	{
	  unhighlight_region(ss);
	  current_region = -1;
	}
      update_region_browser(1);
    }
}

static void region_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dialog_info *fd = (dialog_info *)clientData;
  snd_help(fd->state,snd_string_Region_Browser,get_region_browser_help());
}

static void region_select_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  deactivate_selection();  /* just in case there's a region being highlighted */
  if (current_region != -1)
    {
      unhighlight_region(ss);
      select_region(current_region);
      current_region = 0;
      highlight_region(ss);
      goto_window(region_rows[0]->nm);
      XtSetSensitive(selectw,FALSE);
      update_region_browser(0);
    }
}

static void region_up_arrow_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  chan_info *cp;
  cp = reg_sp->chans[0];
  if (cp->chan > 0)
    {
      cp->chan--;
      XtSetSensitive(chan_widget(cp,W_chn_f),(cp->chan > 0));
      XtSetSensitive(chan_widget(cp,W_chn_w),TRUE);
      fixup_region_data(cp,cp->chan,current_region);
      update_graph(cp,NULL);
    }
}

static void region_down_arrow_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  chan_info *cp;
  cp = reg_sp->chans[0];
  if ((cp->chan+1) < region_chans(current_region))
    {
      cp->chan++;
      XtSetSensitive(chan_widget(cp,W_chn_f),TRUE);
      XtSetSensitive(chan_widget(cp,W_chn_w),(region_chans(current_region) > (cp->chan+1)));
      fixup_region_data(cp,cp->chan,current_region);
      update_graph(cp,NULL);
    }
}

static void region_focus_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  chan_info *cp;
  regrow *r = (regrow *)clientData;
  ss = r->ss;
  unhighlight_region(ss);
  current_region=r->pos;
  cp = reg_sp->chans[0];
  cp->chan  = 0;
  highlight_region(ss);
  XtSetSensitive(chan_widget(cp,W_chn_f),FALSE);
  XtSetSensitive(chan_widget(cp,W_chn_w),(region_chans(current_region) > 1));
  XtSetSensitive(selectw,(current_region != 0));
  reg_sp->hdr = fixup_region_data(cp,0,current_region);
  make_region_labels(reg_sp->hdr);
  update_graph(cp,NULL);
}


void reflect_play_region_stop(region_info *r)
{
  regrow *rg;
  rg = (r->rg);
  if (rg) XmToggleButtonSetState(rg->pl,FALSE,FALSE);
}

static void region_play_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  play_region(r->ss,r->pos,(void *)r);
}

static void region_save_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  regrow *r = (regrow *)clientData;
  XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)callData;
  protect_region(r->pos,cb->set);
}

static void region_print_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  region_print(ss->eps_file,"region",reg_sp->chans[0]);
}

static void make_region_dialog(Widget w, dialog_info *fd)
{
  int n,i;
  Arg args[32];
  Widget formw,last_row,ww,sep,infosep,prtb;
  XmString xok,xdelete,xhelp,titlestr;
  regrow *r;
  snd_state *ss;
  chan_info *cp;
  file_info *hdr;
  ww_info *wwl;

  ss = fd->state;
  reg_fd = fd;

  xok = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG);
  xhelp = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
  xdelete = XmStringCreate(snd_string_Delete,XmFONTLIST_DEFAULT_TAG);
  titlestr = XmStringCreateLocalized(snd_string_Regions);

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNcancelLabelString,xdelete); n++;
  XtSetArg(args[n],XmNhelpLabelString,xhelp); n++;
  XtSetArg(args[n],XmNokLabelString,xok); n++;
  XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
  XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
  fd->dialog = XmCreateTemplateDialog(w,snd_string_Regions,args,n);
#if UNSET_TRANSIENT
  add_dialog(ss,fd->dialog);
#endif

  XtAddCallback(fd->dialog,XmNokCallback,region_ok_Callback,fd);
  XtAddCallback(fd->dialog,XmNcancelCallback,region_delete_Callback,ss);
  XtAddCallback(fd->dialog,XmNhelpCallback,region_help_Callback,fd);
  XmStringFree(xhelp);
  XmStringFree(xok);
  XmStringFree(xdelete);
  XmStringFree(titlestr);

  if (!(ss->using_schemes))
    {
      XtVaSetValues(XmMessageBoxGetChild(fd->dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmMessageBoxGetChild(fd->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmMessageBoxGetChild(fd->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
    }

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  selectw = XtCreateManagedWidget(snd_string_Select,xmPushButtonWidgetClass,fd->dialog,args,n);
  XtAddCallback(selectw,XmNactivateCallback,region_select_Callback,ss);
  XtSetSensitive(selectw,FALSE);

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNbottomWidget,XmMessageBoxGetChild(fd->dialog,XmDIALOG_SEPARATOR)); n++;
  formw = XtCreateManagedWidget("formw",xmFormWidgetClass,fd->dialog,args,n);

  wwl = make_title_row(ss,formw,snd_string_save,snd_string_play,snd_string_regions,0);
  ww = wwl->ww;
  fd->list = wwl->list;
  if (!(ss->using_schemes)) map_over_children(fd->list,set_main_color_of_widget,(void *)ss);
  last_row = NULL;
  
  for (i=0;i<REGIONS;i++)
    {
      r = make_regrow(ss,ww,last_row,region_save_Callback,region_play_Callback,region_focus_Callback);
      region_rows[i] = r;
      r->pos = i;
      r->ss = ss;
      last_row = r->rw;
    }

  update_region_browser(0);

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,fd->list); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
  XtSetArg(args[n],XmNseparatorType,XmSHADOW_ETCHED_IN); n++;
  XtSetArg(args[n],XmNwidth,5); n++;
  sep = XtCreateManagedWidget("sep",xmSeparatorWidgetClass,formw,args,n);


  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,fd->list); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,wwl->dbline); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNbottomWidget,sep); n++;
  XtSetArg(args[n],XmNorientation,XmVERTICAL); n++;
  XtSetArg(args[n],XmNseparatorType,XmSHADOW_ETCHED_IN); n++;
  infosep = XtCreateManagedWidget("infosep",xmSeparatorWidgetClass,formw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,infosep); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,wwl->dbline); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;
  reg_srtxt = XtCreateManagedWidget(snd_string_srate_p,xmLabelWidgetClass,formw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,infosep); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,reg_srtxt); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;
  reg_chntxt = XtCreateManagedWidget(snd_string_chans_p,xmLabelWidgetClass,formw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,infosep); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,reg_chntxt); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;
  reg_lentxt = XtCreateManagedWidget(snd_string_length_p,xmLabelWidgetClass,formw,args,n);

  n=0;
  if (!(ss->using_schemes)) n = background_high_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,infosep); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,reg_lentxt); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_BEGINNING); n++;
  reg_maxtxt = XtCreateManagedWidget(snd_string_maxamp_p,xmLabelWidgetClass,formw,args,n);

  n=0;
  if (!(ss->using_schemes)) 
    {
      n = background_main_color(args,n,ss);
      XtSetArg(args[n],XmNarmColor,(ss->sgx)->text); n++;
    }
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,infosep); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,reg_maxtxt); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNbottomWidget,sep); n++;
  XtSetArg(args[n],XmNfontList,bold_button_FONT(ss)); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_CENTER); n++;
  prtb = XtCreateManagedWidget(snd_string_print,xmPushButtonWidgetClass,formw,args,n);
  XtAddCallback(prtb,XmNactivateCallback,region_print_Callback,(XtPointer)ss);

  n=0;
  if (!(ss->using_schemes)) n = background_white_color(args,n,ss);
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,sep); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  fd->scale = XtCreateManagedWidget("grf",xmFormWidgetClass,formw,args,n);

  free(wwl); 
  wwl=NULL;

  XtManageChild(fd->dialog);

  if (!reg_sp) 
    { /* just a place holder, I think -- see make_region_readable in snd-clip.c */
      reg_sp = (snd_info *)calloc(1,sizeof(snd_info));
      reg_sp->s_type = make_snd_pointer_type(SND_INFO);
      reg_sp->nchans = 1;
      reg_sp->chans = (chan_info **)calloc(1,sizeof(chan_info *));
      reg_sp->sx_scroll_max = 100;
      reg_sp->hdr = (file_info *)calloc(1,sizeof(file_info));
      hdr = reg_sp->hdr;
      hdr->s_type = make_snd_pointer_type(FILE_INFO);
      hdr->samples = region_len(0)-1;
      hdr->srate = region_srate(0);
      hdr->chans = 1;
      current_region = 0;
    }

  add_channel_window(reg_sp,0,ss,0,0,fd->scale,WITH_ARROWS);
  cp = reg_sp->chans[0];
  if (!(ss->using_schemes)) XtVaSetValues(region_rows[0]->nm,XmNbackground,(ss->sgx)->white,NULL);

  XtAddCallback(chan_widget(cp,W_chn_graph),XmNresizeCallback,region_resize_Callback,(XtPointer)cp);
  XtAddCallback(chan_widget(cp,W_chn_graph),XmNexposeCallback,region_resize_Callback,(XtPointer)cp);

  /* chn_f is up arrow, chn_w is down arrow */
  XtAddCallback(chan_widget(cp,W_chn_f),XmNactivateCallback,region_up_arrow_Callback,(XtPointer)ss);
  XtAddCallback(chan_widget(cp,W_chn_w),XmNactivateCallback,region_down_arrow_Callback,(XtPointer)ss);
  XtSetSensitive(chan_widget(cp,W_chn_f),FALSE);
  if (region_chans(0) > 1) XtSetSensitive(chan_widget(cp,W_chn_w),TRUE);
  cp->chan = 0;
  reg_sp->hdr = fixup_region_data(cp,0,0);
  make_region_labels(reg_sp->hdr);
  highlight_region(ss);
  update_graph(cp,NULL);
}

static void View_Region_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* put up scrollable dialog describing/playing/editing the region list */
  static dialog_info *fd;
  snd_state *ss = (snd_state *)clientData;
  if (!fd)
    {
      fd = (dialog_info *)calloc(1,sizeof(dialog_info));
      fd->size = 0;
      fd->state = ss;
      make_region_dialog(w,fd);
    }
  else raise_dialog(fd->dialog);
  if (!XtIsManaged(fd->dialog)) {current_region = 0; XtManageChild(fd->dialog);}
}


/* -------------------------------- OPTIONS MENU -------------------------------- */

static void Options_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	   "Options Menu",
"The Options menu items affect how the FFT\n\
operates, and whatnot.  The items are:\n\
\n\
",
get_options_menu_help(),
NULL);
}

/* Save Options */

static void Options_Save_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  save_snd_options((snd_state *)clientData);
}


/* Session (a more sophisticated version of save options) */

static Widget session_dialog = NULL;
static Widget session_text = NULL;
static Widget session_loadB = NULL;
static Widget session_error = NULL;

static void Options_Session_Cancel_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XtUnmanageChild(session_dialog);
}

static void Options_Session_Load_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  int err;
  char *name;
  XmString s1;
  name = XmTextGetString(session_text);
  err = snd_load_file((snd_state *)clientData,name);
  if (err == -1)
    {
      sprintf(search_string,"%s: %s",name,strerror(errno));
      s1 = XmStringCreate(search_string,XmFONTLIST_DEFAULT_TAG);
      XtVaSetValues(session_error,XmNlabelString,s1,NULL);
      XmStringFree(s1);
    }
  else XtUnmanageChild(session_dialog);
}

static void Options_Session_Save_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  state_context *sgx;
  XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *)callData;
  sgx = ss->sgx;
  if (cb->event != sgx->text_activate_event)
    {
      save_state((snd_state *)clientData,XmTextGetString(session_text));
      XtUnmanageChild(session_dialog);
    }
}

static void Options_Session_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Sessions",
"You can save the current state of Snd by giving a\n\
file name and clicking 'save'.  You can start Snd\n\
in this state by invoking it with this file name\n\
and the '-l' switch: snd -l name. This 'session\n\
file' is in the same format as the customization\n\
file (normally '.snd').  To load such a file after\n\
startup, use the command load: M-x (load name) or\n\
click 'load' in this dialog.\n\
");
}

static void make_session_dialog(snd_state *ss)
{
  Arg args[20];
  int n;
  XmString xmstr1,titlestr;
  Widget rc,dl;

  n=0;
  xmstr1=XmStringCreateLocalized(snd_string_Save);
  titlestr=XmStringCreateLocalized(snd_string_Session);
  XtSetArg(args[n],XmNokLabelString,xmstr1); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
  XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
  session_dialog = XmCreateMessageDialog(main_PANE(ss),snd_string_session,args,n);

  XmStringFree(xmstr1);
  XmStringFree(titlestr);
  XtUnmanageChild(XmMessageBoxGetChild(session_dialog,XmDIALOG_SYMBOL_LABEL));
  XtAddCallback(session_dialog,XmNhelpCallback,Options_Session_Help_Callback,ss);
  XtAddCallback(session_dialog,XmNokCallback,Options_Session_Save_Callback,ss);
  XtAddCallback(session_dialog,XmNcancelCallback,Options_Session_Cancel_Callback,ss);

  n=0;
  session_loadB = XtCreateManagedWidget(snd_string_Load,xmPushButtonWidgetClass,session_dialog,args,n);
  XtAddCallback(session_loadB,XmNactivateCallback,Options_Session_Load_Callback,ss);
  
  n=0;
  rc = XtCreateManagedWidget("session-form",xmFormWidgetClass,session_dialog,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  dl = XtCreateManagedWidget(snd_string_session_p,xmLabelWidgetClass,rc,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,dl); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  session_text = sndCreateTextFieldWidget(ss,"text",rc,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,session_text); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  session_error = XtCreateManagedWidget("",xmLabelWidgetClass,rc,args,n);
}

static void Options_Session_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  if (!session_dialog) 
    {
      make_session_dialog(ss);
#if MANAGE_DIALOG
      XtManageChild(session_dialog);
#endif
      if (!(ss->using_schemes)) 
	{
	  map_over_children(session_dialog,set_main_color_of_widget,(void *)clientData);
	  XtVaSetValues(XmMessageBoxGetChild(session_dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(session_dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(session_dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(session_loadB,XmNarmColor,(ss->sgx)->text,NULL);
	}
    }
  else raise_dialog(session_dialog);
  XtVaSetValues(session_error,XmNlabelString,NULL,NULL);
  if (!XtIsManaged(session_dialog)) XtManageChild(session_dialog);
}


void subsampling_off(snd_state *ss)
{
  if (ss->subsampling)
    {
      ss->subsampling = 0;
      make_name_label(mw[o_subsampling_menu],snd_string_Subsampling_on);
    }
}

void subsampling_on(snd_state *ss)
{
  if (!(ss->subsampling))
    {
      ss->subsampling = 1;
      make_name_label(mw[o_subsampling_menu],snd_string_Subsampling_off);
    }
}

static void Options_Subsampling_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  ss->subsampling = (!ss->subsampling);
  make_name_label(w,(ss->subsampling) ? snd_string_Subsampling_off : snd_string_Subsampling_on);
}


static void activate_focus_menu(snd_state *ss, int new_focus)
{
  switch (ss->zoom_focus_anchor)
    {
    case FOCUS_LEFT: XtSetSensitive(mw[o_focus_left_menu],TRUE); break;
    case FOCUS_RIGHT: XtSetSensitive(mw[o_focus_right_menu],TRUE); break;
    case FOCUS_MIDDLE: XtSetSensitive(mw[o_focus_middle_menu],TRUE); break;
    case FOCUS_ACTIVE: XtSetSensitive(mw[o_focus_active_menu],TRUE); break;
    }
  ss->zoom_focus_anchor = new_focus;
  switch (ss->zoom_focus_anchor)
    {
    case FOCUS_LEFT: XtSetSensitive(mw[o_focus_left_menu],FALSE); break;
    case FOCUS_RIGHT: XtSetSensitive(mw[o_focus_right_menu],FALSE); break;
    case FOCUS_MIDDLE: XtSetSensitive(mw[o_focus_middle_menu],FALSE); break;
    case FOCUS_ACTIVE: XtSetSensitive(mw[o_focus_active_menu],FALSE); break;
    }
}  

static void Options_Focus_Right_Callback(Widget w,XtPointer clientData,XtPointer Data) {activate_focus_menu((snd_state *)clientData,FOCUS_RIGHT);}
static void Options_Focus_Left_Callback(Widget w,XtPointer clientData,XtPointer Data) {activate_focus_menu((snd_state *)clientData,FOCUS_LEFT);}
static void Options_Focus_Middle_Callback(Widget w,XtPointer clientData,XtPointer Data) {activate_focus_menu((snd_state *)clientData,FOCUS_MIDDLE);}
static void Options_Focus_Active_Callback(Widget w,XtPointer clientData,XtPointer Data) {activate_focus_menu((snd_state *)clientData,FOCUS_ACTIVE);}


void activate_speed_in_menu(snd_state *ss, int newval)
{
  switch (ss->speed_style)
    {
    case SPEED_AS_RATIO: XtSetSensitive(mw[o_speed_ratio_menu],TRUE); break;
    case SPEED_AS_SEMITONE: XtSetSensitive(mw[o_speed_semitone_menu],TRUE); break;
    default: XtSetSensitive(mw[o_speed_float_menu],TRUE); break;
    }
  ss->speed_style = newval;
  switch (ss->speed_style)
    {
    case SPEED_AS_RATIO: XtSetSensitive(mw[o_speed_ratio_menu],FALSE); break;
    case SPEED_AS_SEMITONE: XtSetSensitive(mw[o_speed_semitone_menu],FALSE); break;
    default: XtSetSensitive(mw[o_speed_float_menu],FALSE); break;
    }
}

static void Options_Speed_Float_Callback(Widget w,XtPointer cD,XtPointer Data) {activate_speed_in_menu((snd_state *)cD,SPEED_AS_FLOAT);}
static void Options_Speed_Ratio_Callback(Widget w,XtPointer cD,XtPointer Data) {activate_speed_in_menu((snd_state *)cD,SPEED_AS_RATIO);}
static void Options_Speed_Semitone_Callback(Widget w,XtPointer cD,XtPointer Data) {activate_speed_in_menu((snd_state *)cD,SPEED_AS_SEMITONE);}


void show_peaks(snd_state *ss)
{
  if (!(ss->peaking))
    {
      ss->peaking = 1;
      make_name_label(mw[o_fft_peaks_menu],snd_string_Hide_peaks);
    }
}

void hide_peaks(snd_state *ss)
{
  if (ss->peaking)
    {
      ss->peaking = 0;
      make_name_label(mw[o_fft_peaks_menu],snd_string_Show_peaks);
    }
}

static void Options_FFT_Peaks_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  ss->peaking = (!ss->peaking);
  make_name_label(w,(ss->peaking) ? snd_string_Hide_peaks : snd_string_Show_peaks);
}

static int set_fft_size (chan_info *cp, void *fd)
{
  fft_info *fp;
  int flen;
  if (cp->fft) 
    {
      flen = (int)(((dialog_info *)fd)->size);
      fp=cp->fft;
      if (fp->size < flen) fp->ok = 0; /* "dirty" flag for fft data array = needs reallocation */
      fp->size = flen;
    }
  return(0);
}

static int set_fft_window (chan_info *cp, void *fd)
{
  if (cp->fft) (cp->fft)->window = ((dialog_info *)fd)->window;
  return(0);
}

#define NUM_FFT_SIZES 14
static char *FFT_SIZES[NUM_FFT_SIZES] = {"16","32","64","128","256","512","1024","2048","4096","8192","16384","65536","262144","1048576"};
static int NFFT_SIZES[NUM_FFT_SIZES] = {16,32,64,128,256,512,1024,2048,4096,8192,16384,65536,262144,1048576};

static void fft_size_browse_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  char *text;
  Boolean result;
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  dialog_info *fd = (dialog_info *)clientData;
  result = XmStringGetLtoR(cbs->item,XmFONTLIST_DEFAULT_TAG,&text);
  if (result == TRUE)
    {
      sscanf(text,"%d",&(fd->size));
      if (fd->size != 0)
	{
	  map_over_chans(fd->state,set_fft_size,(void *)fd);
	  (fd->state)->global_fft_size = fd->size;
	  /* this choice needs to be remembered in case no fft windows are currently in existence */
	}
    }
  map_over_chans(fd->state,calculate_fft,NULL);
}

static void fft_window_browse_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  dialog_info *fd = (dialog_info *)clientData;
  fd->window = (cbs->item_position - 1); /* make these numbers 0-based as in mus.lisp */
  (fd->state)->global_fft_window = fd->window;
  if (fft_window_needs_beta(fd->window)) reflect_beta_window_in_menu(); else reflect_non_beta_window_in_menu();
  map_over_chans(fd->state,set_fft_window,(void *)fd);
  map_over_chans(fd->state,calculate_fft,NULL);
}

static int position_of_fft_size(snd_state *ss)
{
  int i;
  for (i=0;i<NUM_FFT_SIZES;i++)
    {
      if (NFFT_SIZES[i] == ss->global_fft_size) return(i+1);
    }
  return(5);
}

static void fft_size_cancel_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  dialog_info *fd = (dialog_info *)clientData;
  XtUnmanageChild(fd->dialog);
}

static void fft_size_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "FFT Size",
"Any size FFT can be accomodated here, as long\n\
as it will fit in memory somehow.  The larger\n\
the FFT, the longer it takes to compute.\n\
The size must be a power of 2.\n\
");
}

static void fft_window_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "FFT Window",
"The FFT window names are taken from the article\n\
of Harris that discusses most FFT windows\n\
at great length.  The default window\n\
is a second order Blackman window.\n\
");
}

static void make_fft_list_dialog(Widget w, dialog_info *fd, char **choices, int nchoices, char *name,
				 XtCallbackProc browseCallback, XtCallbackProc cancelCallback, XtCallbackProc helpCallback)
{
  XmString *sizes;
  XmString xstr1,xstr2,titlestr;
  snd_state *ss;
  int i,n;
  Arg args[20];
  n=0;
  ss = (snd_state *)(fd->state);
  xstr1 = XmStringCreate(snd_string_Dismiss,XmFONTLIST_DEFAULT_TAG); /* needed by template dialog */
  xstr2 = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
  titlestr = XmStringCreateLocalized(name);
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNcancelLabelString,xstr1); n++;
  XtSetArg(args[n],XmNhelpLabelString,xstr2); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
  sizes = (XmString *)calloc(nchoices,sizeof(XmString));
  for (i=0;i<nchoices;i++) sizes[i] = XmStringCreate(choices[i],XmFONTLIST_DEFAULT_TAG);
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
  XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
  fd->dialog = XmCreateTemplateDialog(w,name,args,n); /* might use XmCreateSelectionDialog instead here */
#if UNSET_TRANSIENT
  add_dialog(ss,fd->dialog);
#endif

  if (!(ss->using_schemes))
    {
      XtVaSetValues(XmMessageBoxGetChild(fd->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmMessageBoxGetChild(fd->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
    }

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  fd->list = XmCreateScrolledList(fd->dialog,"fft-list",args,n);
  if (!(ss->using_schemes)) XtVaSetValues(fd->list,XmNbackground,(ss->sgx)->white,NULL);
  XtAddCallback(fd->dialog,XmNcancelCallback,cancelCallback,fd);
  XtAddCallback(fd->dialog,XmNhelpCallback,helpCallback,ss);

  XmStringFree(xstr1);
  XmStringFree(xstr2);
  XmStringFree(titlestr);
  XtVaSetValues(fd->list,XmNitems,sizes,XmNitemCount,nchoices,XmNvisibleItemCount,6,NULL);
  XtManageChild(fd->list); 
  XtAddCallback(fd->list,XmNbrowseSelectionCallback,browseCallback,fd);
  for (i=0;i<nchoices;i++) XmStringFree(sizes[i]);
  free(sizes);
}

static void Options_FFT_Size_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  static dialog_info *fd;
  snd_state *ss = (snd_state *)clientData;
  if (!fd) 
    {
      fd = (dialog_info *)calloc(1,sizeof(dialog_info));
      fd->size = 0;
      fd->state = ss;
      make_fft_list_dialog(w,fd,FFT_SIZES,NUM_FFT_SIZES,snd_string_fft_size,
			   fft_size_browse_Callback,fft_size_cancel_Callback,fft_size_help_Callback);
    }
  else raise_dialog(fd->dialog);
  XmListSelectPos(fd->list,position_of_fft_size(ss),FALSE);
  if (!XtIsManaged(fd->dialog)) XtManageChild(fd->dialog);
}

#define NUM_FFT_WINDOWS 16
static char *COPY_OF_FFT_WINDOWS[NUM_FFT_WINDOWS] = 
     {"rectangular","hanning","welch","parzen","bartlett","hamming","blackman2","blackman3","blackman4",
      "exponential","riemann","kaiser","cauchy","poisson","gaussian","tukey"};

static void Options_FFT_Window_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  static dialog_info *fdw;
  snd_state *ss = (snd_state *)clientData;
  if (!fdw) 
    {
      fdw = (dialog_info *)calloc(1,sizeof(dialog_info));
      fdw->size = 0;
      fdw->state = ss;
      make_fft_list_dialog(w,fdw,COPY_OF_FFT_WINDOWS,NUM_FFT_WINDOWS,snd_string_fft_window,
			   fft_window_browse_Callback,fft_size_cancel_Callback,fft_window_help_Callback);
      XmListSelectPos(fdw->list,default_fft_window(ss)+1,FALSE);
    }
  else raise_dialog(fdw->dialog);
  if (!XtIsManaged(fdw->dialog)) XtManageChild(fdw->dialog);
}

static void fft_beta_help_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_help((snd_state *)clientData,
	   "FFT Window Parameter",
"This dialog sets the FFT window parameter\n\
sometimes known as alpha or beta.  The\n\
scale tries to provide access to 'normal'\n\
values, given the current FFT window.\n\
");
} 

static void fft_beta_ok_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  dialog_info *fd = (dialog_info *)clientData;
  Widget text,scale;
  char *str;
  snd_state *ss;
  float val;
  int ival,smax;
  /* now decide whether it's the text or the scale that sent us here */
  text = fd->list;
  scale = fd->scale;
  ss = fd->state;
  str = XmTextGetString(text);
  if ((str) && (*str))
    {
      sscanf(str,"%f",&val);
      free(str);
      XmTextSetString(text,NULL);
    }
  else 
    {
      XtVaGetValues(scale,XmNvalue,&ival,XmNmaximum,&smax,NULL); 
      val = ((float)ival/(float)smax) * fft_window_beta_max(ss->global_fft_window);
    }
  fd->beta = val;
  fft_set_current_window_beta(fd->beta,ss->global_fft_window);
  XtUnmanageChild(fd->dialog);
} 

void fft_dB(snd_state *ss)
{
  if (!(ss->dBing))
    {
      ss->dBing = 1;
      make_name_label(mw[o_fft_db_menu],snd_string_FFT_linear);
    }
}

void fft_linear(snd_state *ss)
{
  if (ss->dBing)
    {
      ss->dBing = 0;
      make_name_label(mw[o_fft_db_menu],snd_string_FFT_in_dB);
    }
}

static void Options_FFT_dB_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* similar to subsampling or dots menus */
  snd_state *ss = (snd_state *)clientData;
  ss->dBing = (!ss->dBing);
  make_name_label(w,(ss->dBing) ? snd_string_FFT_linear : snd_string_FFT_in_dB);
  map_over_chans(ss,calculate_fft,NULL);
}

void fft_log_freq(snd_state *ss)
{
  if (!(ss->logxing))
    {
      ss->logxing = 1;
      make_name_label(mw[o_fft_logx_menu],snd_string_FFT_linear_freq);
    }
}

void fft_linear_freq(snd_state *ss)
{
  if (ss->logxing)
    {
      ss->logxing = 0;
      make_name_label(mw[o_fft_logx_menu],snd_string_FFT_log_freq);
    }
}

static void Options_FFT_logx_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  /* similar to subsampling or dots menus */
  snd_state *ss = (snd_state *)clientData;
  ss->logxing = (!ss->logxing);
  make_name_label(w,(ss->logxing) ? snd_string_FFT_linear_freq : snd_string_FFT_log_freq);
  map_over_chans(ss,calculate_fft,NULL);
}

static void fft_beta_cancel_callback(Widget w,XtPointer clientData,XtPointer callData)
{
  dialog_info *fd = (dialog_info *)clientData;
  XtUnmanageChild(fd->dialog);
} 

static char beta_window_label[32];

static void make_fft_beta_dialog(Widget w,dialog_info *fdw)
{
  Arg args[20];
  int n;
  Widget ds,df,dl,rc;
  snd_state *ss;
  float smax;
  XmString xstr1,titlestr;

  ss=fdw->state;
  fftwincpy(beta_window_label,ss->global_fft_window);
  strcat(beta_window_label," ");
  strcat(beta_window_label,snd_string_window_parameter);
  xstr1 = XmStringCreate(beta_window_label,XmFONTLIST_DEFAULT_TAG);
  titlestr = XmStringCreateLocalized(snd_string_FFT_Window_Parameter);
  
  n=0;
  XtSetArg(args[n],XmNmessageString,xstr1); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
  XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
  fdw->dialog = XmCreateMessageDialog(w,snd_string_fft_beta,args,n);
#if UNSET_TRANSIENT
  add_dialog(ss,fdw->dialog);
#endif

  XmStringFree(xstr1);
  XmStringFree(titlestr);

  XtUnmanageChild(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_SYMBOL_LABEL));

  XtAddCallback(fdw->dialog,XmNhelpCallback,fft_beta_help_callback,ss);
  XtAddCallback(fdw->dialog,XmNcancelCallback,fft_beta_cancel_callback,fdw);
  XtAddCallback(fdw->dialog,XmNokCallback,fft_beta_ok_callback,fdw);

  rc = XtCreateManagedWidget("row",xmFormWidgetClass,fdw->dialog,NULL,0);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  dl = XtCreateManagedWidget(snd_string_beta_p,xmLabelWidgetClass,rc,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,dl); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  df = sndCreateTextFieldWidget(ss,"text",rc,args,n);
  fdw->list = df;

  n=0;
  XtSetArg(args[n],XmNorientation,XmHORIZONTAL); n++;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,df); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNshowValue,TRUE); n++;
  XtSetArg(args[n],XmNdecimalPoints,2); n++;
  smax=fft_window_beta_max(ss->global_fft_window);
  XtSetArg(args[n],XmNminimum,0); n++;
  XtSetArg(args[n],XmNmaximum,(int)(100*smax)); n++;
  XtSetArg(args[n],XmNvalue,(int)(100*fft_window_beta(ss->global_fft_window))); n++;
  ds = XtCreateManagedWidget("scale",xmScaleWidgetClass,rc,args,n);
  fdw->scale = ds;
}

static void Options_FFT_Beta_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  static dialog_info *fdw;
  float smax;
  XmString xstr1;
  snd_state *ss = (snd_state *)clientData;
  if (!fdw) 
    {
      fdw = (dialog_info *)calloc(1,sizeof(dialog_info));
      fdw->beta = 0.0;
      fdw->state = ss;
      make_fft_beta_dialog(w,fdw);
#if MANAGE_DIALOG
      XtManageChild(fdw->dialog);
#endif
      if (!(ss->using_schemes)) 
	{
	  map_over_children(fdw->dialog,set_main_color_of_widget,(void *)clientData);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	  XtVaSetValues(XmMessageBoxGetChild(fdw->dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
	}
    }
  else
    {
      fftwincpy(beta_window_label,ss->global_fft_window);
      strcat(beta_window_label," ");
      strcat(beta_window_label,snd_string_window_parameter);
      xstr1 = XmStringCreate(beta_window_label,XmFONTLIST_DEFAULT_TAG);
      smax=fft_window_beta_max(ss->global_fft_window);
      XtVaSetValues(fdw->dialog,XmNmessageString,xstr1,NULL);
      XtVaSetValues(fdw->scale,XmNmaximum,(int)(100*smax),XmNvalue,(int)(100*fft_window_beta(ss->global_fft_window)),NULL);
      XmStringFree(xstr1);
      raise_dialog(fdw->dialog);
    }
  if (!XtIsManaged(fdw->dialog)) XtManageChild(fdw->dialog);
}

void fft_style(snd_state *ss, int style)
{
  switch (ss->fft_style)
    {
    case normal_fft: XtSetSensitive(mw[o_fft_simple_menu],TRUE); break;
    case sonogram: XtSetSensitive(mw[o_fft_sonogram_menu],TRUE); break;
    case spectrogram: XtSetSensitive(mw[o_fft_spectrogram_menu],TRUE); break;
    }
  if ((style == normal_fft) || (style == sonogram) || (style == spectrogram))
    {
      ss->fft_style = style;
      switch (ss->fft_style)
	{
	case normal_fft: XtSetSensitive(mw[o_fft_simple_menu],FALSE); break;
	case sonogram: XtSetSensitive(mw[o_fft_sonogram_menu],FALSE); break;
	case spectrogram: XtSetSensitive(mw[o_fft_spectrogram_menu],FALSE); break;
	}
    }
  else snd_printf(ss,"bad fft style");
}

static void Options_FFT_Simple_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  fft_style(ss,normal_fft);
  map_over_chans(ss,calculate_fft,NULL);
}

static void Options_FFT_Sonogram_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  fft_style(ss,sonogram);
  map_over_chans(ss,calculate_fft,NULL);
}

static void Options_FFT_Spectrogram_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  fft_style(ss,spectrogram);
  map_over_chans(ss,calculate_fft,NULL);
}

void reflect_x_axis_unit_change_in_menu(int oldval, int newval)
{
  switch (oldval)
    {
    case X_IN_SECONDS: XtSetSensitive(mw[v_x_axis_seconds_menu],TRUE); break;
    case X_IN_SAMPLES: XtSetSensitive(mw[v_x_axis_samples_menu],TRUE); break;
    case X_TO_ONE: XtSetSensitive(mw[v_x_axis_percentage_menu],TRUE); break;
    default: XtSetSensitive(mw[v_x_axis_seconds_menu],TRUE); break;
    }
  switch (newval)
    {
    case X_IN_SECONDS: XtSetSensitive(mw[v_x_axis_seconds_menu],FALSE); break;
    case X_IN_SAMPLES: XtSetSensitive(mw[v_x_axis_samples_menu],FALSE); break;
    case X_TO_ONE: XtSetSensitive(mw[v_x_axis_percentage_menu],FALSE); break;
    default: XtSetSensitive(mw[v_x_axis_seconds_menu],FALSE); break;
    }
}
  
static void Options_X_Axis_Seconds_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  reflect_x_axis_unit_change_in_menu(ss->x_axis_style,X_IN_SECONDS);
  ss->x_axis_style = X_IN_SECONDS;
}

static void Options_X_Axis_Samples_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  reflect_x_axis_unit_change_in_menu(ss->x_axis_style,X_IN_SAMPLES);
  ss->x_axis_style = X_IN_SAMPLES;
}

static void Options_X_Axis_Percentage_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  reflect_x_axis_unit_change_in_menu(ss->x_axis_style,X_TO_ONE);
  ss->x_axis_style = X_TO_ONE;
}


/* ---------------- transform types ---------------- */

static int force_fft_clear(chan_info *cp, void *ptr)
{
  if ((cp->cgx) && ((cp->cgx)->fft_in_progress))
    {
      XtRemoveWorkProc((cp->cgx)->fft_in_progress);
      (cp->cgx)->fft_in_progress = 0;
    }
  if (cp->fft) cp->fft = free_fft_info(cp->fft);
  if (cp->fft_data) {free(cp->fft_data); cp->fft_data = NULL;}
  /* this may leave ->wp window unfreed? -- see snd-fft.c free_fft_state */
  return(0);
}

void transform_type(snd_state *ss, int type)
{
  map_over_chans(ss,force_fft_clear,NULL);
  switch (ss->transform_type)
    {
    case fourier: 
      XtSetSensitive(mw[o_transform_fourier_menu],TRUE);
      fft_linear_freq(ss);
      XtSetSensitive(mw[o_fft_logx_menu],FALSE);
      break;
    case hankel:  XtSetSensitive(mw[o_transform_hankel_menu],TRUE); break;
    case wavelet: XtSetSensitive(mw[o_transform_wavelet_menu],TRUE); break;
    case chebyshev: XtSetSensitive(mw[o_transform_chebyshev_menu],TRUE); break;
    case legendre: XtSetSensitive(mw[o_transform_legendre_menu],TRUE); break;
    }
  ss->transform_type = type;
  switch (type)
    {
    case fourier: 
      XtSetSensitive(mw[o_transform_fourier_menu],FALSE); 
      XtSetSensitive(mw[o_fft_logx_menu],TRUE);
      break;
    case hankel:  XtSetSensitive(mw[o_transform_hankel_menu],FALSE); break;
    case wavelet: XtSetSensitive(mw[o_transform_wavelet_menu],FALSE); break;
    case chebyshev: XtSetSensitive(mw[o_transform_chebyshev_menu],FALSE); break;
    case legendre: XtSetSensitive(mw[o_transform_legendre_menu],FALSE); break;
    }
}

static void Options_Transform_Fourier_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  transform_type(ss,fourier);
  map_over_chans(ss,calculate_fft,NULL);
}

static void Options_Transform_Hankel_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  transform_type(ss,hankel);
  map_over_chans(ss,calculate_fft,NULL);
}

static void Options_Transform_Chebyshev_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  transform_type(ss,chebyshev);
  map_over_chans(ss,calculate_fft,NULL);
}

static void Options_Transform_Legendre_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  snd_state *ss = (snd_state *)clientData;
  transform_type(ss,legendre);
  map_over_chans(ss,calculate_fft,NULL);
}

static void wavelet_window_browse_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss;
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  dialog_info *fd = (dialog_info *)clientData;
  ss = fd->state;
  ss->wavelet_choice = (cbs->item_position - 1); /* make these numbers 0-based as in mus.lisp */
  transform_type(ss,wavelet);
  map_over_chans(ss,calculate_fft,NULL);
}

static void wavelet_window_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
	   "Wavelet Choice",
"These names refer to various standard wavelets.\n\
The actual coefficients are in snd-fft.c.\n\
");
}

#define NUM_WAVELETS 20
static char *COPY_OF_WAVELETS[NUM_WAVELETS]={
  "daub4","daub6","daub8","daub10","daub12","daub14","daub16","daub18","daub20",
  "battle_lemarie","burt_adelson","beylkin","coif2","coif4","coif6",
  "sym2","sym3","sym4","sym5","sym6"};

static void Options_Transform_Wavelet_Callback(Widget w,XtPointer clientData,XtPointer callData)
{
  static dialog_info *fdw;
  snd_state *ss = (snd_state *)clientData;
  if (!fdw) 
    {
      fdw = (dialog_info *)calloc(1,sizeof(dialog_info));
      fdw->size = 0;
      fdw->state = ss;
      make_fft_list_dialog(w,fdw,COPY_OF_WAVELETS,NUM_WAVELETS,snd_string_wavelet_window,
			   wavelet_window_browse_Callback,fft_size_cancel_Callback,wavelet_window_help_Callback);
      XmListSelectPos(fdw->list,1,FALSE);
    }
  else raise_dialog(fdw->dialog);
  if (!XtIsManaged(fdw->dialog)) XtManageChild(fdw->dialog);
  transform_type(ss,wavelet);
  map_over_chans(ss,calculate_fft,NULL);
}



/* -------------------------------- HELP MENU -------------------------------- */

static void Help_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
          "Help Menu",
"The Help menu tries to provide quick\n\
help for the most common Snd operations.\n\
The menu items are:\n\
\n",
get_help_menu_help(),
NULL);
}

static void Help_Context_Help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)callData;
  Widget selectedWidget = NULL;
  static Cursor cursor = 0;
  Widget parent = XtParent(w);
  snd_state *ss = (snd_state *)clientData;
  Widget mainWindow;
  mainWindow = main_PANE(ss);
  if (!cursor) cursor = XCreateFontCursor(XtDisplay(parent),XC_question_arrow); 
  selectedWidget = XmTrackingLocate(mainWindow,cursor,FALSE);
  if (selectedWidget)
    {
      XmAnyCallbackStruct cb;
      cb.reason = XmCR_HELP;
      cb.event = cbs->event;
      do
        {
	  if ((XtHasCallbacks(selectedWidget,XmNhelpCallback) == XtCallbackHasSome))
            {
	      XtCallCallbacks(selectedWidget,XmNhelpCallback,&cb);
	      return;
            }
	  else
	    selectedWidget = XtParent(selectedWidget);
        } while (selectedWidget != NULL);
    }
}

static void Help_About_Snd_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
               "Snd",
get_about_snd_help(),
"The various Help menu items are:\n\
\n",
get_help_menu_help(),
"\n",
"The main menu items are:\n\
  File: operations on files.\n\
  Edit: operations on the current selection.\n\
  View: change Snd display choices.\n\
  Options: change Snd analysis choices.\n\
  Help: this menu.\n\
The main menu bar itself is Snd's 'drop' box.\n\
\n\
The File menu's options are:\n\
",
get_file_menu_help(),
"\n\
The Edit menu's options are:\n\
",
get_edit_menu_help(),
"\n\
The View menu's options are:\n\
",
get_view_menu_help(),
"\n\
The Options menu's items are:\n\
",
get_options_menu_help(),
"\n\
The graph editing commands are:\n\
",
get_graph_help(),
"\n\
",
get_fft_keypad_help(),
"\n\
",
get_mark_help(),
"\n\
",
get_init_file_help(),
"\n\
",
get_resource_help(),
"\n\
",
get_ufun_help(),
"\n\
Expressions in the minibuffer use a\n\
C-like syntax. ",
get_expression_help(),
NULL);
}

static void Help_FFT_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	    snd_string_FFT,
get_fft_menu_help(),
"\n\
",
get_fft_keypad_help(),
NULL);
}

static void Help_Find_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	    snd_string_Find,
get_find_menu_help(),
"\n\
",
get_expression_help(),
NULL);
}

static void Help_Undo_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Undo,get_undo_menu_help());
}

static void Help_Sync_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Sync,get_sync_menu_help());
}

static void Help_Speed_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Speed,get_speed_menu_help());
}

static void Help_Expand_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Expand,get_expand_menu_help());
}

static void Help_Reverb_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Reverb,get_reverb_menu_help());
}

static void Help_Contrast_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Contrast,get_contrast_menu_help());
}

static void Help_Env_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,
	    snd_string_Envelope,
get_env_menu_help(),
"\n\
The simplest way to define and apply envelopes\n\
is to use the envelope editor via the Edit menu.\n\
\n\
",
get_envelope_editor_help(),
NULL);
}

static void Help_Marks_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Marks,get_mark_help());
}

static void Help_Mix_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,snd_string_Mixing,get_mixing_help(),"\n",get_grouping_help(),NULL);
}

static void Help_Sound_Files_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Format,get_format_menu_help());
}

static void Help_Init_File_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  ssnd_help((snd_state *)clientData,snd_string_Customization,get_init_file_help(),"\n",get_resource_help(),NULL);
}

static void Help_Ufun_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_User_functions,get_ufun_help());
}

static void Help_Recording_Callback (Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,snd_string_Recording,get_recording_help());
}



/* -------------------------------- MAIN MENU -------------------------------- */

Widget get_menubar(void) {return(mw[menu_menu]);}

Widget add_menu(snd_state *state)
{
  static Arg main_args[6];
  static Arg in_args[6];
  static Arg high_args[12];
  int in_n,n,high_n,main_n,start_high_n,k;
  /* this mainly passes the global data pointer (state) to all the menu-related callbacks */
  
  in_n=0;
  main_n=0;
  high_n=0;
  if (!(state->using_schemes))
    {
      main_n = background_main_color(main_args,main_n,state);
      high_n = background_high_color(high_args,high_n,state);
      in_n = background_main_color(in_args,in_n,state);
    }
  start_high_n = high_n;
  XtSetArg(in_args[in_n],XmNsensitive,FALSE); in_n++;
  
  n = high_n;
  XtSetArg(high_args[n],XmNuserData,state); n++; /* used in snd-xclip by drop site to get main state data from whatever widget got the drop */
  mw[menu_menu] = XmCreateMenuBar(main_PANE(state),"menuBar",high_args,n);


  /* FILE MENU */
  mw[file_menu] = XmCreatePulldownMenu(mw[menu_menu],"filem",main_args,main_n);
  
  high_n = start_high_n;
  XtSetArg(high_args[high_n],XmNsubMenuId,mw[file_menu]); high_n++;
  XtSetArg(high_args[high_n],XmNmnemonic,'F'); high_n++;
  mw[f_cascade_menu] = XtCreateManagedWidget(snd_string_File,xmCascadeButtonWidgetClass,mw[menu_menu],high_args,high_n);
  XtAddCallback(mw[f_cascade_menu],XmNhelpCallback,File_Help_Callback,state);

  mw[f_open_menu] = XtCreateManagedWidget(snd_string_Open,xmPushButtonWidgetClass,mw[file_menu],main_args,main_n);
  XtAddCallback(mw[f_open_menu],XmNactivateCallback,File_Open_Callback,state);
  XtVaSetValues(mw[f_open_menu],XmNmnemonic,'O',NULL);

  mw[f_close_menu] = XtCreateManagedWidget(snd_string_Close,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_close_menu],XmNactivateCallback,File_Close_Callback,state);
  XtVaSetValues(mw[f_close_menu],XmNmnemonic,'C',NULL);
  
  mw[f_save_menu] = XtCreateManagedWidget(snd_string_Save,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_save_menu],XmNactivateCallback,File_Save_Callback,state);
  XtVaSetValues(mw[f_save_menu],XmNmnemonic,'S',NULL);
  
  mw[f_save_as_menu] = XtCreateManagedWidget(snd_string_Save_as,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_save_as_menu],XmNactivateCallback,File_Save_As_Callback,state);
  XtVaSetValues(mw[f_save_as_menu],XmNmnemonic,'a',NULL);
  
  mw[f_revert_menu] = XtCreateManagedWidget(snd_string_Revert,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_revert_menu],XmNactivateCallback,File_Revert_Callback,state);
  XtVaSetValues(mw[f_revert_menu],XmNmnemonic,'R',NULL);
  
  mw[f_mix_menu] = XtCreateManagedWidget(snd_string_Mix,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_mix_menu],XmNactivateCallback,File_Mix_Callback,state);
  XtVaSetValues(mw[f_mix_menu],XmNmnemonic,'M',NULL);

  mw[f_update_menu] = XtCreateManagedWidget(snd_string_Update,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_update_menu],XmNactivateCallback,File_Update_Callback,state);
  XtVaSetValues(mw[f_update_menu],XmNmnemonic,'U',NULL);

  mw[f_new_menu] = XtCreateManagedWidget(snd_string_New,xmPushButtonWidgetClass,mw[file_menu],main_args,main_n);
  XtAddCallback(mw[f_new_menu],XmNactivateCallback,File_New_Callback,state);
  XtVaSetValues(mw[f_new_menu],XmNmnemonic,'N',NULL);

  mw[f_record_menu] = XtCreateManagedWidget(snd_string_Record,xmPushButtonWidgetClass,mw[file_menu],main_args,main_n);
  XtAddCallback(mw[f_record_menu],XmNactivateCallback,File_Record_Callback,state);

  mw[f_view_menu] = XtCreateManagedWidget(snd_string_View,xmPushButtonWidgetClass,mw[file_menu],main_args,main_n);
  XtAddCallback(mw[f_view_menu],XmNactivateCallback,File_View_Callback,state);
  XtVaSetValues(mw[f_view_menu],XmNmnemonic,'V',NULL);

  mw[f_print_menu] = XtCreateManagedWidget(snd_string_Print,xmPushButtonWidgetClass,mw[file_menu],in_args,in_n);
  XtAddCallback(mw[f_print_menu],XmNactivateCallback,File_Print_Callback,state);
  XtVaSetValues(mw[f_print_menu],XmNmnemonic,'P',NULL);

  mw[f_exit_menu] = XtCreateManagedWidget(snd_string_Exit,xmPushButtonWidgetClass,mw[file_menu],main_args,main_n);
  XtAddCallback(mw[f_exit_menu],XmNactivateCallback,File_Exit_Callback,state);
  XtVaSetValues(mw[f_exit_menu],XmNmnemonic,'E',NULL);


  /* EDIT MENU */
  mw[edit_menu] = XmCreatePulldownMenu(mw[menu_menu],"editm",main_args,main_n);

  high_n = start_high_n;
  XtSetArg(high_args[high_n],XmNsubMenuId,mw[edit_menu]); high_n++;
  XtSetArg(high_args[high_n],XmNmnemonic,'E'); high_n++;
  mw[e_cascade_menu] = XtCreateManagedWidget(snd_string_Edit,xmCascadeButtonWidgetClass,mw[menu_menu],high_args,high_n);
  XtAddCallback(mw[e_cascade_menu],XmNhelpCallback,Edit_Help_Callback,state);
  
  mw[e_undo_menu] = XtCreateManagedWidget(snd_string_Undo,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_undo_menu],XmNactivateCallback,Edit_Undo_Callback,state);
  XtVaSetValues(mw[e_undo_menu],XmNmnemonic,'U',NULL);

  mw[e_redo_menu] = XtCreateManagedWidget(snd_string_Redo,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_redo_menu],XmNactivateCallback,Edit_Redo_Callback,state);
  XtVaSetValues(mw[e_redo_menu],XmNmnemonic,'R',NULL);

  mw[e_find_menu] = XtCreateManagedWidget(snd_string_Find,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_find_menu],XmNactivateCallback,Edit_Find_Callback,state);
  XtVaSetValues(mw[e_find_menu],XmNmnemonic,'F',NULL);

  mw[e_cut_menu] = XtCreateManagedWidget(snd_string_Cut,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_cut_menu],XmNactivateCallback,Edit_Cut_Callback,state);
  XtVaSetValues(mw[e_cut_menu],XmNmnemonic,'C',NULL);

  mw[e_paste_menu] = XtCreateManagedWidget(snd_string_Paste,xmPushButtonWidgetClass,mw[edit_menu],main_args,main_n);
  /* not in-args because the clipboard (for paste) might at any time have data */
  XtAddCallback(mw[e_paste_menu],XmNactivateCallback,Edit_Paste_Callback,state);
  XtVaSetValues(mw[e_paste_menu],XmNmnemonic,'P',NULL);

  mw[e_mix_menu] = XtCreateManagedWidget(snd_string_Mix_Selection,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_mix_menu],XmNactivateCallback,Edit_Mix_Callback,state);
  XtVaSetValues(mw[e_mix_menu],XmNmnemonic,'M',NULL);

  mw[e_play_menu] = XtCreateManagedWidget(snd_string_Play_selection,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_play_menu],XmNactivateCallback,Edit_Play_Callback,state);
  XtVaSetValues(mw[e_play_menu],XmNmnemonic,'P',NULL);

  mw[e_save_as_menu] = XtCreateManagedWidget(snd_string_Save_selection,xmPushButtonWidgetClass,mw[edit_menu],in_args,in_n);
  XtAddCallback(mw[e_save_as_menu],XmNactivateCallback,Edit_Save_As_Callback,state);
  XtVaSetValues(mw[e_save_as_menu],XmNmnemonic,'S',NULL);

  mw[e_edenv_menu] = XtCreateManagedWidget(snd_string_Edit_Envelope,xmPushButtonWidgetClass,mw[edit_menu],main_args,main_n);
  XtAddCallback(mw[e_edenv_menu],XmNactivateCallback,Edit_Envelope_Callback,state);
  XtVaSetValues(mw[e_edenv_menu],XmNmnemonic,'E',NULL);


  /* VIEW MENU */
  mw[view_menu] = XmCreatePulldownMenu(mw[menu_menu],"viewm",main_args,main_n);

  high_n = start_high_n;
  XtSetArg(high_args[high_n],XmNsubMenuId,mw[view_menu]); high_n++;
  XtSetArg(high_args[high_n],XmNmnemonic,'V'); high_n++;
  mw[v_cascade_menu] = XtCreateManagedWidget(snd_string_View,xmCascadeButtonWidgetClass,mw[menu_menu],high_args,high_n);
  XtAddCallback(mw[v_cascade_menu],XmNhelpCallback,View_Help_Callback,state);

  mw[v_ctrls_menu] = XtCreateManagedWidget(snd_string_Show_controls,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_ctrls_menu],XmNactivateCallback,View_Ctrls_Callback,state);
  XtVaSetValues(mw[v_ctrls_menu],XmNmnemonic,'S',NULL);

  mw[v_normalize_menu] = XtCreateManagedWidget(snd_string_Normalize,xmPushButtonWidgetClass,mw[view_menu],in_args,in_n);
  XtAddCallback(mw[v_normalize_menu],XmNactivateCallback,View_Normalize_Callback,state);
  XtVaSetValues(mw[v_normalize_menu],XmNmnemonic,'N',NULL);

  mw[v_combine_menu] = XmCreatePulldownMenu(mw[view_menu],"combine",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[v_combine_menu]); k++;
  mw[v_combine_cascade_menu] = XtCreateManagedWidget(snd_string_Channel_style,xmCascadeButtonWidgetClass,mw[view_menu],main_args,k);

  mw[v_combine_separate_menu] = XtCreateManagedWidget(snd_string_separate,xmPushButtonWidgetClass,mw[v_combine_menu],main_args,main_n);
  XtAddCallback(mw[v_combine_separate_menu],XmNactivateCallback,View_Separate_Callback,state); 
  if (state->global_combining == CHANNELS_SEPARATE) XtSetSensitive(mw[v_combine_separate_menu],FALSE);

  mw[v_combine_combined_menu] = XtCreateManagedWidget(snd_string_combined,xmPushButtonWidgetClass,mw[v_combine_menu],main_args,main_n);
  XtAddCallback(mw[v_combine_combined_menu],XmNactivateCallback,View_Combined_Callback,state);  
  if (state->global_combining == CHANNELS_COMBINED) XtSetSensitive(mw[v_combine_combined_menu],FALSE);

  mw[v_combine_superimposed_menu] = XtCreateManagedWidget(snd_string_superimposed,xmPushButtonWidgetClass,mw[v_combine_menu],main_args,main_n);
  XtAddCallback(mw[v_combine_superimposed_menu],XmNactivateCallback,View_Superimposed_Callback,state);  
  if (state->global_combining == CHANNELS_SUPERIMPOSED) XtSetSensitive(mw[v_combine_superimposed_menu],FALSE);

  mw[v_info_menu] = XtCreateManagedWidget(snd_string_Info,xmPushButtonWidgetClass,mw[view_menu],in_args,in_n);
  XtAddCallback(mw[v_info_menu],XmNactivateCallback,View_Info_Callback,state);
  XtVaSetValues(mw[v_info_menu],XmNmnemonic,'I',NULL);

  mw[v_dots_menu] = XtCreateManagedWidget(snd_string_Dots,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_dots_menu],XmNactivateCallback,View_Dots_Callback,state);
  XtVaSetValues(mw[v_dots_menu],XmNmnemonic,'D',NULL);

  mw[v_cursor_menu] = XtCreateManagedWidget(snd_string_Verbose_cursor,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_cursor_menu],XmNactivateCallback,View_Cursor_Callback,state);

  mw[v_region_menu] = XtCreateManagedWidget(snd_string_Regions,xmPushButtonWidgetClass,mw[view_menu],in_args,in_n);
  XtAddCallback(mw[v_region_menu],XmNactivateCallback,View_Region_Callback,state);
  XtVaSetValues(mw[v_region_menu],XmNmnemonic,'R',NULL);

  mw[v_files_menu] = XtCreateManagedWidget(snd_string_Files,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_files_menu],XmNactivateCallback,View_Files_Callback,state);
  XtVaSetValues(mw[v_files_menu],XmNmnemonic,'F',NULL);

  mw[v_color_menu] = XtCreateManagedWidget(snd_string_Color,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_color_menu],XmNactivateCallback,View_Color_Callback,state);

  mw[v_orientation_menu] = XtCreateManagedWidget(snd_string_Orientation,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_orientation_menu],XmNactivateCallback,View_Orientation_Callback,state);
  XtVaSetValues(mw[v_orientation_menu],XmNmnemonic,'O',NULL);

  mw[v_groups_menu] = XtCreateManagedWidget(snd_string_Groups,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_groups_menu],XmNactivateCallback,View_Groups_Callback,state);

  mw[v_marks_menu] = XtCreateManagedWidget((state->marks_visible) ? snd_string_Hide_marks : snd_string_Show_marks,
					   xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_marks_menu],XmNactivateCallback,View_Marks_Callback,state);
  XtVaSetValues(mw[v_marks_menu],XmNmnemonic,'m',NULL);

  mw[v_zero_menu] = XtCreateManagedWidget(snd_string_Show_Y0,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_zero_menu],XmNactivateCallback,View_Zero_Callback,state);
  XtVaSetValues(mw[v_zero_menu],XmNmnemonic,'y',NULL);

  mw[v_consoles_menu] = XtCreateManagedWidget(snd_string_Hide_consoles,xmPushButtonWidgetClass,mw[view_menu],main_args,main_n);
  XtAddCallback(mw[v_consoles_menu],XmNactivateCallback,View_Consoles_Callback,state);

  mw[v_x_axis_menu] = XmCreatePulldownMenu(mw[view_menu],"xaxis",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[v_x_axis_menu]); k++;
  mw[v_x_axis_cascade_menu] = XtCreateManagedWidget(snd_string_X_axis_units,xmCascadeButtonWidgetClass,mw[view_menu],main_args,k);

  mw[v_x_axis_seconds_menu] = XtCreateManagedWidget(snd_string_seconds,xmPushButtonWidgetClass,mw[v_x_axis_menu],main_args,main_n);
  XtAddCallback(mw[v_x_axis_seconds_menu],XmNactivateCallback,Options_X_Axis_Seconds_Callback,state);  
  XtSetSensitive(mw[v_x_axis_seconds_menu],FALSE);

  mw[v_x_axis_samples_menu] = XtCreateManagedWidget(snd_string_samples,xmPushButtonWidgetClass,mw[v_x_axis_menu],main_args,main_n);
  XtAddCallback(mw[v_x_axis_samples_menu],XmNactivateCallback,Options_X_Axis_Samples_Callback,state);  

  mw[v_x_axis_percentage_menu] = XtCreateManagedWidget(snd_string_percentage,xmPushButtonWidgetClass,mw[v_x_axis_menu],main_args,main_n);
  XtAddCallback(mw[v_x_axis_percentage_menu],XmNactivateCallback,Options_X_Axis_Percentage_Callback,state);  



  /* OPTIONS MENU */
  mw[option_menu] = XmCreatePulldownMenu(mw[menu_menu],"optionm",main_args,main_n);

  high_n = start_high_n;
  XtSetArg(high_args[high_n],XmNsubMenuId,mw[option_menu]); high_n++;
  XtSetArg(high_args[high_n],XmNmnemonic,'O'); high_n++;
  mw[o_cascade_menu] = XtCreateManagedWidget(snd_string_Options,xmCascadeButtonWidgetClass,mw[menu_menu],high_args,high_n);
  XtAddCallback(mw[o_cascade_menu],XmNhelpCallback,Options_Help_Callback,state);

  mw[o_fft_size_menu] = XtCreateManagedWidget(snd_string_FFT_size,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_size_menu],XmNactivateCallback,Options_FFT_Size_Callback,state);
  XtVaSetValues(mw[o_fft_size_menu],XmNmnemonic,'s',NULL);

  mw[o_fft_peaks_menu] = XtCreateManagedWidget(snd_string_Show_peaks,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_peaks_menu],XmNactivateCallback,Options_FFT_Peaks_Callback,state);
  XtVaSetValues(mw[o_fft_peaks_menu],XmNmnemonic,'p',NULL);

  mw[o_fft_logx_menu] = XtCreateManagedWidget(snd_string_FFT_log_freq,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_logx_menu],XmNactivateCallback,Options_FFT_logx_Callback,state);
  XtVaSetValues(mw[o_fft_logx_menu],XmNmnemonic,'l',NULL);

  mw[o_fft_db_menu] = XtCreateManagedWidget(snd_string_FFT_in_dB,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_db_menu],XmNactivateCallback,Options_FFT_dB_Callback,state);
  XtVaSetValues(mw[o_fft_db_menu],XmNmnemonic,'d',NULL);


  mw[o_fft_style_menu] = XmCreatePulldownMenu(mw[option_menu],"fftstyle",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[o_fft_style_menu]); k++;
  mw[o_fft_style_cascade_menu] = XtCreateManagedWidget(snd_string_FFT_style,xmCascadeButtonWidgetClass,mw[option_menu],main_args,k);

  mw[o_fft_simple_menu] = XtCreateManagedWidget(snd_string_Just_FFT,xmPushButtonWidgetClass,mw[o_fft_style_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_simple_menu],XmNactivateCallback,Options_FFT_Simple_Callback,state);  
  XtSetSensitive(mw[o_fft_simple_menu],FALSE);

  mw[o_fft_sonogram_menu] = XtCreateManagedWidget(snd_string_Sonogram,xmPushButtonWidgetClass,mw[o_fft_style_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_sonogram_menu],XmNactivateCallback,Options_FFT_Sonogram_Callback,state);  

  mw[o_fft_spectrogram_menu] = XtCreateManagedWidget(snd_string_Spectrogram,xmPushButtonWidgetClass,mw[o_fft_style_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_spectrogram_menu],XmNactivateCallback,Options_FFT_Spectrogram_Callback,state);  


  mw[o_speed_menu] = XmCreatePulldownMenu(mw[option_menu],"speedstyle",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[o_speed_menu]); k++;
  mw[o_speed_cascade_menu] = XtCreateManagedWidget(snd_string_Speed_style,xmCascadeButtonWidgetClass,mw[option_menu],main_args,k);

  mw[o_speed_float_menu] = XtCreateManagedWidget(snd_string_float,xmPushButtonWidgetClass,mw[o_speed_menu],in_args,in_n);
  XtAddCallback(mw[o_speed_float_menu],XmNactivateCallback,Options_Speed_Float_Callback,state);  

  mw[o_speed_semitone_menu] = XtCreateManagedWidget(snd_string_semitone,xmPushButtonWidgetClass,mw[o_speed_menu],main_args,main_n);
  XtAddCallback(mw[o_speed_semitone_menu],XmNactivateCallback,Options_Speed_Semitone_Callback,state);  

  mw[o_speed_ratio_menu] = XtCreateManagedWidget(snd_string_ratio,xmPushButtonWidgetClass,mw[o_speed_menu],main_args,main_n);
  XtAddCallback(mw[o_speed_ratio_menu],XmNactivateCallback,Options_Speed_Ratio_Callback,state);  


  mw[o_focus_style_menu] = XmCreatePulldownMenu(mw[option_menu],"focusstyle",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[o_focus_style_menu]); k++;
  mw[o_focus_cascade_menu] = XtCreateManagedWidget(snd_string_Focus_style,xmCascadeButtonWidgetClass,mw[option_menu],main_args,k);

  mw[o_focus_left_menu] = XtCreateManagedWidget(snd_string_focus_left,xmPushButtonWidgetClass,mw[o_focus_style_menu],main_args,main_n);
  XtAddCallback(mw[o_focus_left_menu],XmNactivateCallback,Options_Focus_Left_Callback,state);  

  mw[o_focus_right_menu] = XtCreateManagedWidget(snd_string_focus_right,xmPushButtonWidgetClass,mw[o_focus_style_menu],main_args,main_n);
  XtAddCallback(mw[o_focus_right_menu],XmNactivateCallback,Options_Focus_Right_Callback,state);  

  mw[o_focus_middle_menu] = XtCreateManagedWidget(snd_string_focus_middle,xmPushButtonWidgetClass,mw[o_focus_style_menu],main_args,main_n);
  XtAddCallback(mw[o_focus_middle_menu],XmNactivateCallback,Options_Focus_Middle_Callback,state);  

  mw[o_focus_active_menu] = XtCreateManagedWidget(snd_string_focus_active,xmPushButtonWidgetClass,mw[o_focus_style_menu],main_args,main_n);
  XtAddCallback(mw[o_focus_active_menu],XmNactivateCallback,Options_Focus_Active_Callback,state);  
  activate_focus_menu(state,state->zoom_focus_anchor);

  mw[o_subsampling_menu] = XtCreateManagedWidget(snd_string_Subsampling_off,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_subsampling_menu],XmNactivateCallback,Options_Subsampling_Callback,state);
  XtVaSetValues(mw[o_subsampling_menu],XmNmnemonic,'o',NULL);

  mw[o_save_menu] = XtCreateManagedWidget(snd_string_Save_options,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_save_menu],XmNactivateCallback,Options_Save_Callback,state);
  XtVaSetValues(mw[o_save_menu],XmNmnemonic,'a',NULL);

  mw[o_fft_window_menu] = XtCreateManagedWidget(snd_string_FFT_window,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_window_menu],XmNactivateCallback,Options_FFT_Window_Callback,state);
  XtVaSetValues(mw[o_fft_window_menu],XmNmnemonic,'w',NULL);

  mw[o_fft_beta_menu] = XtCreateManagedWidget(snd_string_FFT_beta,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_fft_beta_menu],XmNactivateCallback,Options_FFT_Beta_Callback,state);
  XtVaSetValues(mw[o_fft_beta_menu],XmNmnemonic,'b',XmNsensitive,FALSE,NULL);

  mw[o_session_menu] = XtCreateManagedWidget(snd_string_Session,xmPushButtonWidgetClass,mw[option_menu],main_args,main_n);
  XtAddCallback(mw[o_session_menu],XmNactivateCallback,Options_Session_Callback,state);


  mw[o_transform_type_menu] = XmCreatePulldownMenu(mw[option_menu],"transformtype",main_args,main_n);

  k=main_n;
  XtSetArg(main_args[k],XmNsubMenuId,mw[o_transform_type_menu]); k++;
  mw[o_transform_type_cascade_menu] = XtCreateManagedWidget(snd_string_Transform_type,xmCascadeButtonWidgetClass,mw[option_menu],main_args,k);

  mw[o_transform_fourier_menu] = XtCreateManagedWidget(snd_string_Fourier,xmPushButtonWidgetClass,mw[o_transform_type_menu],main_args,main_n);
  XtAddCallback(mw[o_transform_fourier_menu],XmNactivateCallback,Options_Transform_Fourier_Callback,state);  
  XtSetSensitive(mw[o_transform_fourier_menu],FALSE);

  mw[o_transform_wavelet_menu] = XtCreateManagedWidget(snd_string_Wavelet,xmPushButtonWidgetClass,mw[o_transform_type_menu],main_args,main_n);
  XtAddCallback(mw[o_transform_wavelet_menu],XmNactivateCallback,Options_Transform_Wavelet_Callback,state);  

  mw[o_transform_hankel_menu] = XtCreateManagedWidget(snd_string_Hankel,xmPushButtonWidgetClass,mw[o_transform_type_menu],main_args,main_n);
  XtAddCallback(mw[o_transform_hankel_menu],XmNactivateCallback,Options_Transform_Hankel_Callback,state); 
 
  mw[o_transform_chebyshev_menu] = XtCreateManagedWidget(snd_string_Chebyshev,xmPushButtonWidgetClass,mw[o_transform_type_menu],main_args,main_n);
  XtAddCallback(mw[o_transform_chebyshev_menu],XmNactivateCallback,Options_Transform_Chebyshev_Callback,state); 
 
  mw[o_transform_legendre_menu] = XtCreateManagedWidget(snd_string_Legendre,xmPushButtonWidgetClass,mw[o_transform_type_menu],main_args,main_n);
  XtAddCallback(mw[o_transform_legendre_menu],XmNactivateCallback,Options_Transform_Legendre_Callback,state); 
 


  /* HELP MENU */
  mw[help_menu] = XmCreatePulldownMenu(mw[menu_menu],"helpm",main_args,main_n);

  high_n = start_high_n;
  XtSetArg(high_args[high_n],XmNsubMenuId,mw[help_menu]); high_n++;
  XtSetArg(high_args[high_n],XmNmnemonic,'H'); high_n++;
  mw[h_cascade_menu] = XtCreateManagedWidget(snd_string_Help,xmCascadeButtonWidgetClass,mw[menu_menu],high_args,high_n);
  XtAddCallback(mw[h_cascade_menu],XmNhelpCallback,Help_Help_Callback,state);

  mw[h_click_for_help_menu] = XtCreateManagedWidget(snd_string_Click_for_help,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_click_for_help_menu],XmNactivateCallback,Help_Context_Help_Callback,state);
  XtVaSetValues(mw[h_click_for_help_menu],XmNmnemonic,'C',NULL);

  mw[h_about_snd_menu] = XtCreateManagedWidget(snd_string_Overview,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_about_snd_menu],XmNactivateCallback,Help_About_Snd_Callback,state);
  XtVaSetValues(mw[h_about_snd_menu],XmNmnemonic,'O',NULL);

  mw[h_fft_menu] = XtCreateManagedWidget(snd_string_FFT,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_fft_menu],XmNactivateCallback,Help_FFT_Callback,state);

  mw[h_find_menu] = XtCreateManagedWidget(snd_string_Find,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_find_menu],XmNactivateCallback,Help_Find_Callback,state);

  mw[h_undo_menu] = XtCreateManagedWidget(snd_string_Undo_and_redo,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_undo_menu],XmNactivateCallback,Help_Undo_Callback,state);

  mw[h_sync_menu] = XtCreateManagedWidget(snd_string_Sync,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_sync_menu],XmNactivateCallback,Help_Sync_Callback,state);

  mw[h_speed_menu] = XtCreateManagedWidget(snd_string_Speed,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_speed_menu],XmNactivateCallback,Help_Speed_Callback,state);

  mw[h_expand_menu] = XtCreateManagedWidget(snd_string_Expand,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_expand_menu],XmNactivateCallback,Help_Expand_Callback,state);

  mw[h_reverb_menu] = XtCreateManagedWidget(snd_string_Reverb,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_reverb_menu],XmNactivateCallback,Help_Reverb_Callback,state);

  mw[h_contrast_menu] = XtCreateManagedWidget(snd_string_Contrast,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_contrast_menu],XmNactivateCallback,Help_Contrast_Callback,state);

  mw[h_env_menu] = XtCreateManagedWidget(snd_string_Envelope,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_env_menu],XmNactivateCallback,Help_Env_Callback,state);

  mw[h_marks_menu] = XtCreateManagedWidget(snd_string_Marks,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_marks_menu],XmNactivateCallback,Help_Marks_Callback,state);

  mw[h_mix_menu] = XtCreateManagedWidget(snd_string_Mixing,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_mix_menu],XmNactivateCallback,Help_Mix_Callback,state);

  mw[h_sound_files_menu] = XtCreateManagedWidget(snd_string_Formats,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_sound_files_menu],XmNactivateCallback,Help_Sound_Files_Callback,state);

  mw[h_init_file_menu] = XtCreateManagedWidget(snd_string_Customization,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_init_file_menu],XmNactivateCallback,Help_Init_File_Callback,state);

  mw[h_ufun_menu] = XtCreateManagedWidget(snd_string_User_functions,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_ufun_menu],XmNactivateCallback,Help_Ufun_Callback,state);

  mw[h_recording_menu] = XtCreateManagedWidget(snd_string_Recording,xmPushButtonWidgetClass,mw[help_menu],main_args,main_n);
  XtAddCallback(mw[h_recording_menu],XmNactivateCallback,Help_Recording_Callback,state);

  XtVaSetValues(mw[menu_menu],XmNmenuHelpWidget,mw[h_cascade_menu],NULL);
  XtManageChild(mw[menu_menu]);

  return(mw[menu_menu]);
}


/* -------------------------------- POPUP MENU -------------------------------- */

static void Popup_Play_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  start_playing(sp=any_selected_sound(ss),0);
  set_play_button(sp,1);
}

static void Popup_Save_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  save_edits(any_selected_sound(ss),NULL);
}

static void Popup_Undo_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  undo_EDIT((void *)clientData,1);
}

static void Popup_Redo_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  redo_EDIT((void *)clientData,1);
}

static void Popup_Normalize_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  normalize_all_sounds((snd_state *)clientData);
}

static void Popup_Info_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  snd_info *sp;
  sp = selected_sound(ss);
  if (sp) display_info(sp);
}

static void Post_Popup_Menu(Widget w,XtPointer clientData,XEvent *event,Boolean *flag)
{
  if (event->xbutton.button == Button3)
    {
      XmMenuPosition(popup_menu,(XButtonPressedEvent *)event);
      XtManageChild(popup_menu);
    }
}

void create_popup_menu(snd_state *ss)
{
  /* make it a child of the main window */
  Widget mainp;
  Arg args[20];
  int n;
  if (!popup_menu)
    {
      n=0;
      if (!ss->using_schemes) n = background_main_color(args,n,ss); else n=0;
      mainp = main_PANE(ss);
      popup_menu = XmCreatePopupMenu(mainp,"popup-menu",args,n);
      XtAddEventHandler(mainp,ButtonPressMask,FALSE,Post_Popup_Menu,popup_menu);

      popup_children[W_pop_menu] = XtCreateManagedWidget("snd",xmLabelWidgetClass,popup_menu,args,n);
      popup_children[W_pop_sep] = XtCreateManagedWidget("sep",xmSeparatorWidgetClass,popup_menu,args,n);
      popup_children[W_pop_play] = XtCreateManagedWidget(snd_string_Play,xmPushButtonWidgetClass,popup_menu,args,n);
      XtAddCallback(popup_children[W_pop_play],XmNactivateCallback,Popup_Play_Callback,ss);
      popup_children[W_pop_undo] = XtCreateManagedWidget(snd_string_Undo,xmPushButtonWidgetClass,popup_menu,args,n);
      XtVaSetValues(popup_children[W_pop_undo],XmNsensitive,FALSE,NULL);
      XtAddCallback(popup_children[W_pop_undo],XmNactivateCallback,Popup_Undo_Callback,ss);
      popup_children[W_pop_redo] = XtCreateManagedWidget(snd_string_Redo,xmPushButtonWidgetClass,popup_menu,args,n);
      XtVaSetValues(popup_children[W_pop_redo],XmNsensitive,FALSE,NULL);
      XtAddCallback(popup_children[W_pop_redo],XmNactivateCallback,Popup_Redo_Callback,ss);
      popup_children[W_pop_save] = XtCreateManagedWidget(snd_string_Save,xmPushButtonWidgetClass,popup_menu,args,n);
      XtAddCallback(popup_children[W_pop_save],XmNactivateCallback,Popup_Save_Callback,ss);
      popup_children[W_pop_normalize] = XtCreateManagedWidget(snd_string_Normalize,xmPushButtonWidgetClass,popup_menu,args,n);
      XtVaSetValues(popup_children[W_pop_normalize],XmNsensitive,FALSE,NULL);
      XtAddCallback(popup_children[W_pop_normalize],XmNactivateCallback,Popup_Normalize_Callback,ss);
      popup_children[W_pop_info] = XtCreateManagedWidget(snd_string_Info,xmPushButtonWidgetClass,popup_menu,args,n);
      XtVaSetValues(popup_children[W_pop_info],XmNsensitive,FALSE,NULL);
      XtAddCallback(popup_children[W_pop_info],XmNactivateCallback,Popup_Info_Callback,ss);
    }
}



/* -------------------------------- Raw Data Dialog -------------------------------- */
/*
 * used also by New File menu option
 */

static Widget raw_data_dialog = NULL;
static Widget raw_srate_text,raw_chans_text;
static int raw_srate = 44100;
static int raw_chans = 1;
static int raw_format = snd_16_linear;
static int raw_defaults = 0;
static int new_type = NeXT_sound_file;       /* new file can set output type */

void set_raw_data_defaults(int srate, int chans, int dformat, int defaults)
{
  if (srate != -1) raw_srate = srate;
  if (chans != -1) raw_chans = chans;
  if (dformat != -1) raw_format = dformat;
  if (defaults != -1) raw_defaults = defaults;
}

void set_new_header_type(int type) {new_type = type;}
int get_new_header_type(void) {return(new_type);}

void get_raw_data_defaults(int *dat)
{
  dat[0] = raw_srate;
  dat[1] = raw_chans;
  dat[2] = raw_format;
  dat[3] = raw_defaults;
}

static int new_ctr = 0;

static void cancel_new_file(snd_state *ss)
{
  if (ss->pending_new)
    {
      remove(ss->pending_new);
      ss->pending_new = NULL;
      new_ctr--;
    }
}

static snd_info *finish_new_file(snd_state *ss)
{
  snd_info *sp;
  int chan,size;
  unsigned char* buf;
  if (output_type_and_format_ok(new_type,raw_format))
    {
      snd_write_header(ss,ss->pending_new,new_type,raw_srate,raw_chans,28,raw_chans*2,raw_format,NULL,0);
      chan = snd_reopen_write(ss,ss->pending_new);
      lseek(chan,c_snd_header_data_location(),0L);
      size = raw_chans * c_snd_bytes(raw_format,2);
      buf = (unsigned char *)calloc(size,sizeof(unsigned char));
      write(chan,buf,size);
      close(chan);
      free(buf);
      sp = snd_open_file(ss->pending_new,ss);
      ss->pending_new = NULL;
      return(sp);
    }
  else 
    {
      sprintf(search_string,snd_string_cant_write_type_with_format,
	      (new_type == AIFF_sound_file) ? "an" : "a",
	      sound_type(new_type),
	      data_formats[raw_format-1]);
      snd_printf(ss,search_string);
      cancel_new_file(ss);
      return(NULL);
    }
}

static void raw_data_ok_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  state_context *sgx;
  snd_info *sp;
  char *str;
  XmAnyCallbackStruct *cb = (XmAnyCallbackStruct *)callData;
  sgx = ss->sgx;
  if (cb->event != sgx->text_activate_event)
    {
      str = XmTextGetString(raw_srate_text);
      if ((str) && (*str)) sscanf(str,"%d",&raw_srate);
      str = XmTextGetString(raw_chans_text);
      if ((str) && (*str)) sscanf(str,"%d",&raw_chans);
      /* format is set by browse callback below */
      if (ss->pending_new)
	sp = finish_new_file(ss);
      else sp = snd_open_file(ss->pending_open,ss);
      if (sp) select_channel(sp,0);
      XtSetSensitive(mw[f_open_menu],TRUE);
      XtSetSensitive(mw[f_view_menu],TRUE);
      XtSetSensitive(mw[f_new_menu],TRUE);
      XtUnmanageChild(w);
    }
}

static void raw_data_help_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_help((snd_state *)clientData,
       snd_string_Raw_Data,
"To display and edit sound data, Snd needs\n\
to know how the data's sampling rate, number\n\
of channels, and numerical format.  This dialog\n\
gives you a chance to set those fields.\n\
To make the current settings the default\n\
for any future headerless files, click the\n\
'Default' button.\n\
");
}

static void raw_data_cancel_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  ss->pending_open = NULL;
  if (ss->pending_new) cancel_new_file(ss);
  XtSetSensitive(mw[f_open_menu],TRUE);
  XtSetSensitive(mw[f_view_menu],TRUE);
  XtSetSensitive(mw[f_new_menu],TRUE);
  XtUnmanageChild(raw_data_dialog);
}

static void raw_data_default_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  raw_defaults = 1;
  raw_data_ok_Callback(w,clientData,callData);
}

static void raw_data_browse_Callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  XmListCallbackStruct *cbs = (XmListCallbackStruct *)callData;
  raw_format = cbs->item_position;
}


static char dfs_str[8];
static char dfc_str[4];

static void make_raw_data_dialog(char *filename, snd_state *ss)
{
  XmString *formats;
  XmString xstr1,xstr2,xstr3,xstr4,titlestr;
  int i,n;
  Arg args[20];
  Widget lst,rws,defw,dls,dfs,dfc,rform,dlab;
  n=0;
  xstr1 = XmStringCreate(snd_string_Cancel,XmFONTLIST_DEFAULT_TAG); /* needed by template dialog */
  xstr2 = XmStringCreate(snd_string_Help,XmFONTLIST_DEFAULT_TAG);
  xstr3 = XmStringCreate(snd_string_Ok,XmFONTLIST_DEFAULT_TAG);
  titlestr = XmStringCreateLocalized(snd_string_No_Header_on_File);
  sprintf(search_string,snd_string_No_header_found_for,filename_without_home_directory(filename));
  xstr4 = XmStringCreate(search_string,XmFONTLIST_DEFAULT_TAG);
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  XtSetArg(args[n],XmNcancelLabelString,xstr1); n++;
  XtSetArg(args[n],XmNhelpLabelString,xstr2); n++;
  XtSetArg(args[n],XmNokLabelString,xstr3); n++;
  XtSetArg(args[n],XmNmessageString,xstr4); n++;
  XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
  XtSetArg(args[n],XmNautoUnmanage,FALSE); n++;
#if RESIZE_DIALOG
  XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
  XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
  XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
  raw_data_dialog = XmCreateTemplateDialog(main_SHELL(ss),snd_string_raw_data,args,n);
#if UNSET_TRANSIENT
  add_dialog(ss,raw_data_dialog);
#endif

  XtAddCallback(raw_data_dialog,XmNcancelCallback,raw_data_cancel_Callback,ss);
  XtAddCallback(raw_data_dialog,XmNhelpCallback,raw_data_help_Callback,ss);
  XtAddCallback(raw_data_dialog,XmNokCallback,raw_data_ok_Callback,ss);
  XmStringFree(xstr1);
  XmStringFree(xstr2);
  XmStringFree(xstr3);
  XmStringFree(xstr4);
  XmStringFree(titlestr);

  n=0;
  if (!(ss->using_schemes)) n = background_main_color(args,n,ss);
  defw = XtCreateManagedWidget(snd_string_Default,xmPushButtonWidgetClass,raw_data_dialog,args,n);
  XtAddCallback(defw,XmNactivateCallback,raw_data_default_Callback,ss);

  rform = XtCreateManagedWidget("sretc",xmFormWidgetClass,raw_data_dialog,NULL,0);

  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  rws = XtCreateManagedWidget("srow",xmFormWidgetClass,rform,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  dls = XtCreateManagedWidget(snd_string_srate_p,xmLabelWidgetClass,rws,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNleftWidget,dls); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNcolumns,6); n++;
  XtSetArg(args[n],XmNresizeWidth,FALSE); n++;
  dfs = sndCreateTextFieldWidget(ss,"text",rws,args,n);
  if (raw_srate < 100000) sprintf(dfs_str," %d",raw_srate); else sprintf(dfs_str,"%d",raw_srate);
  XmTextSetString(dfs,dfs_str);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNcolumns,3); n++;
  XtSetArg(args[n],XmNresizeWidth,FALSE); n++;
  dfc = sndCreateTextFieldWidget(ss,"text",rws,args,n);
  if (raw_chans < 10) sprintf(dfc_str,"  %d",raw_chans); else sprintf(dfc_str," %d",raw_chans);
  XmTextSetString(dfc,dfc_str);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNrightWidget,dfc); n++;
  XtSetArg(args[n],XmNalignment,XmALIGNMENT_END); n++;	
  XtCreateManagedWidget(snd_string_chans_p,xmLabelWidgetClass,rws,args,n);
  
  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_NONE); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,rws); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
  dlab = XtCreateManagedWidget(snd_string_data_format_p,xmLabelWidgetClass,rform,args,n);

  n=0;
  XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
  XtSetArg(args[n],XmNtopAttachment,XmATTACH_WIDGET); n++;
  XtSetArg(args[n],XmNtopWidget,dlab); n++;
  XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;

  formats = (XmString *)calloc(NUM_DATA_FORMATS,sizeof(XmString));
  for (i=0;i<NUM_DATA_FORMATS;i++) formats[i] = XmStringCreate(data_formats[i],XmFONTLIST_DEFAULT_TAG);
  lst = XmCreateScrolledList(rform,"raw-data-format-list",args,n);
  XtVaSetValues(lst,XmNitems,formats,XmNitemCount,NUM_DATA_FORMATS,XmNvisibleItemCount,6,NULL);
  XtManageChild(lst); 
  XmListSelectPos(lst,raw_format,FALSE);
  for (i=0;i<NUM_DATA_FORMATS;i++) XmStringFree(formats[i]);
  free(formats);
  XtAddCallback(lst,XmNbrowseSelectionCallback,raw_data_browse_Callback,ss);

#if MANAGE_DIALOG
      XtManageChild(raw_data_dialog);
#endif

  if (!(ss->using_schemes)) 
    {
      map_over_children(rform,set_main_color_of_widget,(void *)ss);
      XtVaSetValues(lst,XmNbackground,(ss->sgx)->white,NULL);
      XtVaSetValues(XmMessageBoxGetChild(raw_data_dialog,XmDIALOG_OK_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmMessageBoxGetChild(raw_data_dialog,XmDIALOG_CANCEL_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(XmMessageBoxGetChild(raw_data_dialog,XmDIALOG_HELP_BUTTON),XmNarmColor,(ss->sgx)->text,NULL);
      XtVaSetValues(defw,XmNselectColor,(ss->sgx)->text,NULL);
    }

  raw_srate_text = dfs;
  raw_chans_text = dfc;
}

file_info *get_file_info(char *filename, snd_state *ss)
{
  /* put up dialog for srate, chans, data format */
  XmString xstr;
  if ((ss->pending_open) || (raw_defaults))
    {
      c_set_snd_header(raw_srate,raw_chans,raw_format);
      return(make_file_info_1(filename,ss));
    }
  if (!raw_data_dialog) 
    make_raw_data_dialog(filename,ss);
  else
    {
      /* set filename in label */
      sprintf(search_string,snd_string_No_header_found_for,filename_without_home_directory(filename));
      xstr = XmStringCreate(search_string,XmFONTLIST_DEFAULT_TAG);
      XtVaSetValues(raw_data_dialog,XmNmessageString,xstr,NULL);
      XmStringFree(xstr);
      raise_dialog(raw_data_dialog);
    }
  if (!XtIsManaged(raw_data_dialog)) XtManageChild(raw_data_dialog);
  if (!(ss->pending_new))
    {
      snd_IO_error = snd_pending_open;
      ss->pending_open = filename;
    }
  /* we don't want to lock out the main program (or the dialog help window), but
   * it would be very confusing to have two file openings in progress.
   */
  XtSetSensitive(mw[f_open_menu],FALSE);
  XtSetSensitive(mw[f_view_menu],FALSE);
  XtSetSensitive(mw[f_new_menu],FALSE);
  return(NULL);
}

/* new file needs raw data dialog to get file description */

static char new_file_name[MAX_FILE_NAME];

void snd_new_file(snd_state *ss)
{
  file_info *hdr;
  finish_keyboard_selection();
  sprintf(new_file_name,"new-%d.snd",new_ctr++);
  snd_create(ss,new_file_name); /* needs to exist for get_file_info */
  ss->pending_new = new_file_name;
  hdr = get_file_info(new_file_name,ss);
  if (hdr) finish_new_file(ss);
}

void save_dialog_state (snd_state *ss, int fd) 
{
  /* save as much as possible of the current dialog state */
  /* to conjure up a plausible region dialog would require saving at least one region */
  int i;
  /* file browser */
  if (prevfile_end >= 0)
    {
      /* preload-file-browser [name] */
      sprintf(search_string,"(preload-file-browser");
      write(fd,search_string,strlen(search_string));
      for (i=0;i<=prevfile_end;i++)
	{
	  sprintf(search_string," %s",prevfullnames[i]);
	  write(fd,search_string,strlen(search_string));
	}
      write(fd,")\n",2);
    }
  /* just sounds button on file selection box */
  if (just_sounds_state)
    {
      sprintf(search_string,"(just-sounds)\n");
      write(fd,search_string,strlen(search_string));
    }
  /* raw data dialog */
  sprintf(search_string,"(raw-sound %d %d %d %d)\n",raw_srate,raw_chans,raw_format,raw_defaults);
  write(fd,search_string,strlen(search_string));
  /* color browser */
  if (ccd)
    {
      sprintf(search_string,"(color-dialog %d %d)\n",get_window_width(ccd->dialog),get_window_height(ccd->dialog));
      write(fd,search_string,strlen(search_string));
    }
  /* orientation browser */
  if (oid)
    {
      sprintf(search_string,"(orientation-dialog %d %d)\n",get_window_width(oid->dialog),get_window_height(oid->dialog));
      write(fd,search_string,strlen(search_string));
    }
  /* files browser */
  if (fbd)
    {
      sprintf(search_string,"(file-dialog %d %d)\n",get_window_width(fbd->dialog),get_window_height(fbd->dialog));
      write(fd,search_string,strlen(search_string));
    }
}

void start_color_dialog(snd_state *ss, int width, int height)
{
  View_Color_Callback(NULL,(XtPointer)ss,NULL);
  XtVaSetValues(ccd->dialog,XmNwidth,(Dimension)width,XmNheight,(Dimension)height,NULL);
}

void start_orientation_dialog(snd_state *ss, int width, int height)
{
  View_Orientation_Callback(NULL,(XtPointer)ss,NULL);
  XtVaSetValues(oid->dialog,XmNwidth,(Dimension)width,XmNheight,(Dimension)height,NULL);
}

void start_file_dialog(snd_state *ss, int width, int height)
{
  View_Files_Callback(NULL,(XtPointer)ss,NULL);
  XtVaSetValues(fbd->dialog,XmNwidth,(Dimension)width,XmNheight,(Dimension)height,NULL);
}

