#include "menupackP.h"

#include "ArgPack.h"
#include "al.h"
#include "useful.h"
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <Xw/Xw.h>
#include <Xw/MenuBtn.h>
#include <Xw/PopupMgr.h>
#include <Xw/Cascade.h>
#include "registry.h"
#include "assert.h"
#include "xstuff.h"
#include "sysdep.h"

/*+++++++ FILE FUNCTIONS +++++++*/
char * MakeMenuMgrName();

#define AL_MENU_POST "<Btn1Down>"
#define AL_MENU_SELECT "<Btn1Down>" 

/*-------------------*/
MenuPack MenuPack_create(w, menuName)
Widget w;
char *menuName;
{
  MenuPack cp;
  cp=(MenuPack)safe_malloc(sizeof(struct MenuPack_str));
  cp->parentW=w;
  cp->menuName=(char *)safe_malloc(strlen(menuName)+1);
  strcpy(cp->menuName,menuName);  /* this will not be freed because it will */
  cp->CascadeW=NULL;
  cp->MList=Darray_create();
  return(cp);                     /*       be used by the widgets           */
}

/*-----------------------*/
void MenuPack_attach_to_widget(mp,w)
MenuPack mp;
Widget w;
{
  mp->parentW=w;
}
/*----------------*/
void MenuPack_destroy(m)
MenuPack m;
{
  MenuPackRec mpRec;
  unsigned i;
  if (m==NULL) return;
  for (i=0;i<Darray_len(m->MList);i++) {
    mpRec=(MenuPackRec)Darray_get(m->MList,i);
    if (mpRec->IsWidget==1 && mpRec->sub_menu!=NULL)
      MenuPack_destroy(mpRec->sub_menu);
    safe_free(mpRec->name);
    safe_free(mpRec);
  }
  safe_free(m->menuName);
  Darray_destroy(m->MList);
  safe_free(m);
}

/*----------------------*/
MenuPackRec MenuPack_create_rec(name,CB,data)
char *name;
XtCallbackProc CB;
caddr_t data;
{
  MenuPackRec mpr;
  mpr=(MenuPackRec)safe_malloc(sizeof(struct MenuPackRec_str));
  if (name==NULL)
      Al_fatal_error("MenuPack: create record: must have either a name or a label\n");
  mpr->name=(char *)safe_malloc(strlen(name)+1);
  strcpy(mpr->name,name); /* not be deleted because Widgets will use it */
  mpr->callback=CB;
  mpr->callback_data=data;
  mpr->IsWidget=(-1);
  mpr->InstanceW=NULL;
  mpr->sub_menu=NULL;
  return(mpr);
}

/*----------------------*/
void MenuPack_add_option(name,mpp,CB,data)
char *name;
MenuPack mpp;
XtCallbackProc CB;
caddr_t data;
{
  MenuPackRec mpRec;
  mpRec=MenuPack_create_rec(name,CB,data);
  mpRec->IsWidget=1;
  mpRec->sub_menu=NULL;
  Darray_addh(mpp->MList,mpRec);
}
  
/*--------------------------------*/
void MenuPack_add_sub_menu(name,mpp,SubMenu)
char *name;
MenuPack mpp, SubMenu;
{
  MenuPackRec mpRec;
  mpRec=MenuPack_create_rec(name,NULL,NULL);
  mpRec->IsWidget=0;
  mpRec->sub_menu=SubMenu;
  Darray_addh(mpp->MList,mpRec);
}



Arg PopupShellArgs[]= {
  { XtNwmTimeout, (XtArgVal) 3 },     /* wait only 3 seconds for the uwm */
  { NULL, (XtArgVal) NULL },
};

Arg PopupMgrArgs[]={
  { XtNassociateChildren, (XtArgVal) FALSE }, 
  { XtNtraversalOn, (XtArgVal) FALSE },
  { NULL, (XtArgVal) NULL },
};

Arg MenuPaneArgs[]={
  { XtNtitlePosition, (XtArgVal) XwTOP },
  { NULL, (XtArgVal) NULL },
};

Arg MenuButtonArgs[]={
  { XtNsetMark, (XtArgVal)  FALSE },
  { XtNlabelLocation, (XtArgVal) XwCENTER },
  { NULL, (XtArgVal) NULL },
};

Arg CascadeOnArgs[]={
  { NULL, NULL },
};

/*----------------------*/
void FormMenu(mpp,MenuCascadeW,TopLevelMgrW)
MenuPack mpp;
Widget MenuCascadeW, TopLevelMgrW;
{
  Widget SubMenuCascadeW, PopShell2W;
  MenuPackRec mpRec;
  MenuPack SubMpp;
  unsigned i;
  ArgPack AP;
 
  for (i=0;i<Darray_len(mpp->MList);i++) {
    mpRec=(MenuPackRec)Darray_get(mpp->MList,i);
    if (mpRec->IsWidget==1) {
      AP=ArgPack_create();
      AP=ArgPack_duplicate_args(MenuButtonArgs);
      ArgPack_add_arg(AP,XtNlabel, (XtArgVal) mpRec->name);
      mpRec->InstanceW=XtCreateManagedWidget(mpRec->name,
					     XwmenubuttonWidgetClass,
					     MenuCascadeW,
					     ArgPack_the_args(AP), ArgPack_num_args(AP));
      if (mpRec->callback!=NULL)
	XtAddCallback(mpRec->InstanceW,XtNselect,mpRec->callback,
		      mpRec->callback_data);
      ArgPack_delete(AP);
    }
    else {
      AP=ArgPack_create();
      AP=ArgPack_duplicate_args(PopupShellArgs);
      PopShell2W=XtCreatePopupShell(NULL,
				    shellWidgetClass,
				    TopLevelMgrW,
				    ArgPack_the_args(AP),ArgPack_num_args(AP));
      ArgPack_delete(AP);

      SubMpp=mpRec->sub_menu;
      AP=ArgPack_create();
      AP=ArgPack_duplicate_args(MenuPaneArgs);
      ArgPack_add_arg(AP, XtNattachTo, (XtArgVal) mpRec->name);
      ArgPack_add_arg(AP, XtNtitleString, (XtArgVal) SubMpp->menuName);
      SubMpp->CascadeW=XtCreateManagedWidget(SubMpp->menuName,
					 XwcascadeWidgetClass,
					 PopShell2W,
					 ArgPack_the_args(AP), ArgPack_num_args(AP));
      ArgPack_delete(AP);

      AP=ArgPack_create();
      AP=ArgPack_duplicate_args(MenuButtonArgs);
      ArgPack_add_arg(AP,XtNlabel, (XtArgVal) mpRec->name);
      ArgPack_add_arg(AP,XtNcascadeOn, (XtArgVal) SubMpp->CascadeW);
      mpRec->InstanceW=XtCreateManagedWidget(mpRec->name,
					     XwmenubuttonWidgetClass,
					     MenuCascadeW,
					     ArgPack_the_args(AP), ArgPack_num_args(AP));
      ArgPack_delete(AP);

      mpRec->sub_menu->parentW=mpRec->InstanceW;
      FormMenu(mpRec->sub_menu,SubMpp->CascadeW,TopLevelMgrW);
    }
  }
}

/*--------------------------------------------------*/
void AddCursorToTop(w,xe,parms,nps)
Widget w;
XEvent *xe;
char **parms;
int    nps;
{
  static int Inited=0;
  static Registry AccountedFor;
  if (Inited==0) {
    Inited=1;
    AccountedFor=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  }
  if (Registry_get(AccountedFor,w)==NULL) {
    AlUI_AttachCursor(w,MENU_BUTTON_CURSOR);
    Registry_add(AccountedFor,(VOIDP)w,(VOIDP)0xffff);
  }
}

static XtActionsRec MenuActions[] = {
  { "AddCursorToTop", AddCursorToTop },
};

static char * MenuTranslations = 
  "<Enter>: AddCursorToTop()";

/*--------------------------*/
void MenuPack_make_menu(mpp)
MenuPack mpp;
{
  ArgPack AP;
  Widget PopShellW, PopMgrW, PopShell2W;
  char *mgrName, *post, *select;
  static int AddedActions=0;
  
  assert(mpp->parentW);
  if (AddedActions==0) {
    AddedActions=1;
    XtAddActions(MenuActions,1);
  }
  XtOverrideTranslations(mpp->parentW,
			XtParseTranslationTable(MenuTranslations));
    
  mgrName=MakeMenuMgrName(mpp->menuName);
  AP=ArgPack_create();
  AP=ArgPack_duplicate_args(PopupShellArgs);
  mpp->ShellW=XtCreatePopupShell(NULL,
				 shellWidgetClass,
				 mpp->parentW,
				 ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);
  
  AP=ArgPack_create();
  AP=ArgPack_duplicate_args(PopupMgrArgs);
  post=XtMalloc(strlen(AL_MENU_POST)+1);
  strcpy(post,AL_MENU_POST);
  select=XtMalloc(strlen(AL_MENU_SELECT)+1);
  strcpy(select,AL_MENU_SELECT);
  ArgPack_add_arg(AP, XtNmenuPost, (XtArgVal) post );
  ArgPack_add_arg(AP, XtNmenuSelect, (XtArgVal) select );
  mpp->PopMgrW=XtCreateManagedWidget(mgrName,
				     XwpopupmgrWidgetClass,
				     mpp->ShellW,
				     ArgPack_the_args(AP),
				     ArgPack_num_args(AP));
  ArgPack_delete(AP);

  AP=ArgPack_create();
  AP=ArgPack_duplicate_args(PopupShellArgs);
  PopShell2W=XtCreatePopupShell(NULL,
				shellWidgetClass,
				mpp->PopMgrW,
				ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  AP=ArgPack_create();
  AP=ArgPack_duplicate_args(MenuPaneArgs);
  ArgPack_add_arg(AP, XtNattachTo, (XtArgVal) mgrName);
  ArgPack_add_arg(AP, XtNtitleString, (XtArgVal) mpp->menuName);
  mpp->CascadeW=XtCreateManagedWidget(mpp->menuName,
				  XwcascadeWidgetClass,
				  PopShell2W,
				  ArgPack_the_args(AP), ArgPack_num_args(AP));
  ArgPack_delete(AP);

  FormMenu(mpp,mpp->CascadeW,mpp->PopMgrW);

  safe_free(mgrName);
}

#define MGR_SUFFIX "_mgr"
/*-----------------*/
char * MakeMenuMgrName(name)
char * name;
{
  char *r;
  r=(char *)safe_malloc(strlen(name)+1+6);
  strcpy(r,name);
  strcpy(&(r[strlen(name)]),MGR_SUFFIX);
  return(r);
}

/*---------------------*/
Widget MenuPack_get_widget(tmp,name)
MenuPack tmp;
char *name;
{
  unsigned i;
  MenuPackRec mpr;
  Widget W;

  if (strcmp(name,tmp->menuName)==0)
    return(tmp->CascadeW);
  for (i=0;i<Darray_len(tmp->MList);i++) {
    mpr=(MenuPackRec)Darray_get(tmp->MList,i);
    if (strcmp(name,mpr->name)==0)
      return(mpr->InstanceW);
    if (mpr->IsWidget==0) {
      if ((W=MenuPack_get_widget(mpr->sub_menu,name))!=NULL)
	return(W);
    }
  }
  return(NULL);
}
      

  
  
/*--------------------------------------------------*/
Widget MenuPack_get_top_level_shellW(mp)
MenuPack mp;
{
  return(mp->ShellW);
}

/*--------------------------------------------------*/
NORET    MenuPack_add_arg_to_all(mp,arg,val)
MenuPack mp;
char* arg;
XtArgVal val;
{
  unsigned i;
  MenuPackRec mpr;
  
  for (i=0;i<Darray_len(mp->MList);i++) {
    mpr=(MenuPackRec)Darray_get(mp->MList,i);
    if (mpr->IsWidget==1) 
      Alxt_SetArg(mpr->InstanceW,arg,val);
    else
      MenuPack_add_arg_to_all(mpr->sub_menu,arg,val);
  }
}
/*--------------------------------------------------*/
void MenuPack_do_nothing(w,xe,p,c)
Widget w;
XEvent *xe;
char*p;
Cardinal *c;
{
}

static XtActionsRec MPDoNothingActions[]={
  {"MenuPack_do_nothing", MenuPack_do_nothing}
};

static String MenuPackDoNothingTT =
  "<Btn1Down>:MenuPack_do_nothing()";
/*--------------------------------------------------*/
NORET MenuPack_detach_menu(mp)
     MenuPack mp;
{
  XtAddActions(MPDoNothingActions,1);
  XtOverrideTranslations(mp->PopMgrW,
			 XtParseTranslationTable(MenuPackDoNothingTT));
}

/*
NORET MenuPack_reattach_menu(mp)
     MenuPack mp;
{
  assert(mp);
  Alxt_SetArg(mp->PopMgrW,XtNmenuPost, (XtArgVal) AL_MENU_POST);
}

*/
