//===============================================================
// vMenu.cxx - vMenuPane class functions - X11R5
//
// Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vos2.h>		// for OS/2 stuff
#include <v/vmenu.h>		// our header
#include <v/vcmdwin.h>		// we need access to vcmdwin
#include <stdlib.h>

// Define static data of the class
  static char curLbl[100];	// for fixed labels

//==================>>> vMenuPane::vMenuPane <<<===========================
  vMenuPane::vMenuPane(VCONST vMenu* menu) : vPane(P_Menu)
  {
    int i;
    char *ch;
    // set up menus -----------------------------------------------
    SysDebug(Constructor,"vMenuPane::vMenuPane() constructor\n")
    _nextMenuButton = 0;	// no menus defined so far
    for (i = 0 ; i < MAX_MENU_BUTTONS ; ++i)
    {
      _mb[i].label[0] = 0; // null out menu button array
      _mb[i].menuId = 0;
      _mb[i].SubMenu = 0;
      _mb[i].hPullDown = 0;
    }
    // copy the menus as defined to our array
    for (i = 0 ; i < MAX_MENU_BUTTONS && &menu[i] != 0 && menu[i].label; ++i)
    {
//      _mb[i].label = menu[i].label;
      strcpy(_mb[i].label, menu[i].label);
      _mb[i].menuId = menu[i].menuId;
      _mb[i].SubMenu = menu[i].SubMenu;

      // translate V '&' for OS/2 '~' in labels for menu accelerators
      for (ch  = _mb[i].label; *ch != 0; ch++)
      {
        if (*ch == '&')
        *ch = '~';
      }
    }
    _nextSubMenu = i;		// we will start submenus here
    _nextMenuButton = i;	// this many menus defined
    _topLevelMenu = 0;
  }
//==================>>> vMenuPane::vMenuPane <<<===========================
  vMenuPane::vMenuPane(const vMenuPane& m) : vPane(m)
  {
    vSysError("V Semantics do not allow copy constructors.");
  }
//====================>>> vMenuPane::~vMenuPane <<<=======================
  vMenuPane::~vMenuPane()			// destructor
  {
    SysDebug(Destructor,"vMenuPane::~vMenuPane() destructor\n")
    WinDestroyWindow(_topLevelMenu);	// Start with the top
    for (int i = _nextSubMenu - 1 ; i >= 0 ; --i)	// all menus
    {
	  WinDestroyWindow(_mb[i].hPullDown);
	  delete _mb[i].mInfo;		// free the space
    }
  }
//======================>>> vMenuPane::initialize <<<=======================
  void vMenuPane::initialize(vWindow* pWin, HWND hMenu)
  {
    vPane::initialize(pWin, hMenu);		// initialize these
    _topLevelMenu = (HWND)hMenu;		// handle to menu bar
    // Now we have to add our menus
    for (int i = 0 ; i < _nextMenuButton ; ++i)
    {
      doAddMenu(i, _topLevelMenu);
    }
//    pWin->_WindowMenuIndex = _nextMenuButton - 1; // Window menu for MDI
  }
//======================>>> vMenuPane::fixLabel <<<========================
  void vMenuPane::fixLabel(VCONST char* lbl, VCONST char* key)
  {
    // copy label to global curLbl
    VCONST char* cp;
    int ix = 0;
    for (cp = lbl ; *cp && ix < 99 ; ++cp)     // Scan label
    {
      curLbl[ix++] = *cp;
    }
    if (key && *key)
    {
      curLbl[ix++] = ' '; curLbl[ix++] = ' '; curLbl[ix++] = '\t';
      for (cp = key ; *cp && ix < 99 ; ++cp)
      {
        curLbl[ix++] = *cp;
      }
    }
    curLbl[ix] = 0;      // finish off

    // translate V '&' for OS/2 '~' in labels for menu accelerators
    char *ch;
    for (ch  = curLbl; *ch != 0; ch++)
    {
      if (*ch == '&')
      *ch = '~';
    }
  }

//======================>>> vMenuPane::doAddMenu <<<========================
  void vMenuPane::doAddMenu(int id, HWND parent)
  {
    MENUITEM mi;

    // create a drop down window on the menu bar
    _mb[id].hPullDown = WinCreateWindow (HWND_OBJECT, WC_MENU, NULL,
                             WS_CLIPSIBLINGS, 0, 0, 0, 0, HWND_OBJECT,
                             HWND_BOTTOM, _mb[id].menuId, NULL, NULL);

    // loop through the list
    _mb[id].mInfo = 0;              // empty list so far
    vMenu* item = _mb[id].SubMenu;  // The first item in list
    MenuInfo* info;                 // for current info
    for (int ix = 0 ; item[ix].label != 0 ; ++ix)
    {
      info = new MenuInfo;            //  new space for current item
      info->NxtInfo = _mb[id].mInfo;  // add to front of list
      _mb[id].mInfo = info;           // fix front pointer
      info->ItemIndex = ix;                // index to item list
      info->SubMenuIndex = 0;              // no submenu normally
      if (item[ix].menuId == M_Line)
      {
        mi.iPosition = MIT_END;
        mi.afStyle = MIS_SEPARATOR;
        mi.afAttribute = 0;
        mi.id = 0;
        mi.hwndSubMenu = NULLHANDLE;
        mi.hItem = 0;
        WinSendMsg (_mb[id].hPullDown, MM_INSERTITEM, (MPARAM) &mi, NULL);
      }
      else if (item[ix].SubMenu != 0)     // a submenu
      {
        if(_nextSubMenu >= MAX_MENU_BUTTONS)
        {
          SysDebug(BadVals,"Too many submenus!\n");
          continue;
        }
        // we will create a submenu
        // copy the definitions, track the new index
        int sub = _nextSubMenu++;        // get our index, bump for next time

//      _mb[sub].label = item[ix].label;
        strcpy(_mb[sub].label,  item[ix].label);

        // translate V '&' for OS/2 '~' in labels for menu accelerators
        char *ch;
        for (ch  = _mb[sub].label; *ch != 0; ch++)
        {
          if (*ch == '&')
            *ch = '~';
        }
        _mb[sub].menuId = item[ix].menuId;
        _mb[sub].SubMenu = item[ix].SubMenu;
        info->SubMenuIndex = sub;

        // Now, recursively call doAddMenu with the submenu
        doAddMenu(sub, _mb[id].hPullDown);
      }
      else
      {
        // create the item
        fixLabel(item[ix].label,item[ix].keyLabel);
        mi.iPosition = MIT_END;
        mi.afStyle = MIS_TEXT;
        mi.afAttribute = 0;
        mi.id = item[ix].menuId;
        mi.hwndSubMenu = NULLHANDLE;
        mi.hItem = 0;
        WinSendMsg(_mb[id].hPullDown, MM_INSERTITEM,
                  (MPARAM) &mi, (MPARAM) curLbl);

        WinCheckMenuItem(_mb[id].hPullDown,
          item[ix].menuId,
          (item[ix].checked ? TRUE : FALSE));

        WinEnableMenuItem (_mb[id].hPullDown, item[ix].menuId,
          item[ix].sensitive ? TRUE : FALSE);
      }
    }
    mi.iPosition = MIT_END;
    mi.afStyle = MIS_SUBMENU;
    mi.afAttribute = 0;
    mi.id = _mb[id].menuId;
    mi.hwndSubMenu = _mb[id].hPullDown;
    mi.hItem = 0;
    WinSendMsg(parent, MM_INSERTITEM, (MPARAM) &mi, (MPARAM) _mb[id].label);
  }

//====================>>> vMenuPane::CheckAccel <<<======================
  int vMenuPane::CheckAccel(vKey vkey, unsigned int shift, ItemVal& id) VCONST
  {
    // scan all menus in this window to see if this keystroke
    // matches an accelerator key
    vMenu* item;
    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info
	// scan the list of info for each menu entry
	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].accel == vkey
		 && item[info->ItemIndex].kShift == shift)
	      {
		id = item[info->ItemIndex].menuId;
		return 1;
	      }
	  }
      }
    id = 0;
    return 0;		// assume 0 if not found
  }
//====================>>> vMenuPane::GetPaneValue <<<======================
  int vMenuPane::GetPaneValue(ItemVal id, int& val) VCONST
  {
    // scan all menus in this window to retrieve the what value
    // then scan button bar if not found
    vMenu* item;
    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info
	// scan the list of info for each menu entry
	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].menuId == id)
	      {
		// Ah Ha! We found the value we want
		val = item[info->ItemIndex].checked;
		return 1;
	      }
	  }
      }
    val = 0;
    return 0;		// assume 0 if not found
  }
//==================>>> vMenuPane::SetPaneValue <<<========================
  void vMenuPane::SetPaneValue(ItemVal id, int val, ItemSetType setType)
  {
    // Set the given item on or off
    vMenu* item;
    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info
	// scan the list of info for each menu entry
	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].menuId == id)
	      {
		// Ah Ha! We found the value we want
		switch (setType)
		  {
		    case Value:			// check box
		    case Checked:		// check box
		      {
			item[info->ItemIndex].checked = val;
			WinCheckMenuItem (_mb[ix].hPullDown,
			    item[info->ItemIndex].menuId,
			    val ? TRUE : FALSE);
			break;
		      }
		    case Sensitive:			// sensitive
		      {
			item[info->ItemIndex].sensitive = val;
			WinEnableMenuItem (_mb[ix].hPullDown,
			    item[info->ItemIndex].menuId,
			    val ? TRUE : FALSE);
			break;
		      }
		  }	// end switch
	      }
	  }
      }
  }
//================>>> vMenuPane::SetPaneString <<<========================
  void vMenuPane::SetPaneString(ItemVal id, VCONST char* str)
  {
    // Set the given item on or off
    vMenu* item;
    // Search all menus in this window
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
    {
      MenuInfo* info;			// for current info
      // scan the list of info for each menu entry
      for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
      {
        item = _mb[ix].SubMenu;	// The current item in list
	if (item[info->ItemIndex].menuId == id)
	{
	  // Ah Ha! We found the value we want
	  item[info->ItemIndex].label = str;
	  WinSetMenuItemText (_mb[ix].hPullDown,	     // the menu
	  		      item[info->ItemIndex].menuId,  // same id
	  		      item[info->ItemIndex].label);  // new label

	  WinSendMsg (theApp->_Frame, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), MPVOID);
	}
      }
    }
  }
