// http://akelpad.sourceforge.net/en/plugins.php#Scripts
// Version: 1.1
// Author: Shengalts Aleksander aka Instructor
//
//
// Description(1033): Show custom popup menu. Script implemented as the library for using in other scripts.
// Description(2052): 显示自定义弹出菜单。脚本可以当作库而在其它脚本中使用。
//
// Menu example at caret position (CaretMenu.js):
// 在插入点位置的菜单示例 (CaretMenu.js):
//
//  //包含
//  if (!AkelPad.Include("ShowMenu.js")) WScript.Quit();
//
//  //变量
//  var lpItems;
//  var nItem;
//
//  lpItems=[["ItemA", MF_NORMAL, 101],
//           ["ItemB", MF_SUBMENU],
//             ["ItemB-1", MF_NORMAL, 102],
//             ["ItemB-2", MF_NORMAL, 103],
//             ["ItemB-3", MF_NORMAL|MF_LAST, 104],
//           ["ItemC", MF_NORMAL, 105],
//           ["", MF_SEPARATOR],
//           ["ItemD", MF_NORMAL|MF_GRAYED, 106],
//           ["ItemF", MF_SUBMENU],
//             ["ItemF-1", MF_NORMAL|MF_CHECKED, 107],
//             ["ItemF-2", MF_NORMAL, 108],
//             ["ItemF-3", MF_SUBMENU|MF_LAST],
//               ["ItemF-3a", MF_NORMAL, 109],
//               ["ItemF-3b", MF_NORMAL|MF_LAST, 110]];
//
//  nItem=ShowMenu(lpItems, POS_CARET, POS_CARET);
//  if (nItem == -1)
//    WScript.Echo("Nothing selected");
//  else
//    WScript.Echo("Item index: " + nItem + "\nItem name: " + lpItems[nItem][0] + "\nItem ID: " + lpItems[nItem][2]);

//菜单项目标记
var MF_NORMAL          =0x00000; //标准项目。
var MF_SEPARATOR       =0x00800; //分隔线项目。
var MF_SUBMENU         =0x00010; //子菜单项目。
var MF_LAST            =0x10000; //子菜单最后一项。
var MF_DEFAULT         =0x20000; //为指定菜单设置默认的菜单项目。
var MF_GRAYED          =0x00001; //灰度状态。
var MF_DISABLED        =0x00002; //禁用状态。
var MF_CHECKED         =0x00008; //复选状态。
var MF_USECHECKBITMAPS =0x00200; //若与 MF_CHECKED 联合使用，显示单选按钮。
var MF_MENUBREAK       =0x00040; //放置项目到新一栏。
var MF_MENUBARBREAK    =0x00020; //与 MF_MENUBREAK 相同，但新一栏与旧的以一条垂直线分隔。
var MF_HILITE          =0x00080; //高亮显示项目。

//ShowMenu 函数专用的 X 或 Y 位置
var POS_CARET   =-1; //在插入点位置下。
var POS_CURSOR  =-2; //鼠标指针位置。

//函数
function ShowMenu(lpItemsArray, X, Y)
{
  //变量
  var hMainWnd=AkelPad.GetMainWnd();
  var hWndEdit=AkelPad.GetEditWnd();
  var oSys=AkelPad.SystemFunction();
  var hInstanceDLL=AkelPad.GetInstanceDll();
  var lpMenuArray=[];
  var nMenuCount;
  var nItemCount;
  var ptPoint=[];
  var hWndContainer;
  var nResult=0;
  var i;

  //菜单数组
  var MENU=0;
  var ITEM=1;

  //项目数组
  var NAME=0;
  var FLAGS=1;

  //菜单标记
  var MF_NORMAL   =0x00000;
  var MF_SEPARATOR=0x00800;
  var MF_SUBMENU  =0x00010;
  var MF_LAST     =0x10000;
  var MF_DEFAULT  =0x20000;

  //菜单坐标
  var POS_CARET   =-1;
  var POS_CURSOR  =-2;

  if (lpItemsArray.length > 0)
  {
    //创建菜单
    nMenuCount=0;
    lpMenuArray[nMenuCount]=[oSys.Call("user32::CreatePopupMenu"), 0];

    //填充菜单
    for (nItemCount=0; nItemCount < lpItemsArray.length; ++nItemCount)
    {
      if (lpItemsArray[nItemCount][FLAGS] & MF_SEPARATOR)
      {
        oSys.Call("user32::AppendMenu" + _TCHAR, lpMenuArray[nMenuCount][MENU], 0x800 /*MF_SEPARATOR*/, nItemCount + 1, lpItemsArray[nItemCount][NAME]);
      }
      else if (lpItemsArray[nItemCount][FLAGS] & MF_SUBMENU)
      {
        lpMenuArray[nMenuCount + 1]=[oSys.Call("user32::CreatePopupMenu"), 0];
        oSys.Call("user32::AppendMenu" + _TCHAR, lpMenuArray[nMenuCount][MENU], 0x10 /*MF_POPUP*/, lpMenuArray[nMenuCount + 1][MENU], lpItemsArray[nItemCount][NAME]);
      }
      else
      {
        oSys.Call("user32::AppendMenu" + _TCHAR, lpMenuArray[nMenuCount][MENU], lpItemsArray[nItemCount][FLAGS], nItemCount + 1, lpItemsArray[nItemCount][NAME]);
        if (lpItemsArray[nItemCount][FLAGS] & MF_DEFAULT)
          oSys.Call("user32::SetMenuDefaultItem", lpMenuArray[nMenuCount][MENU], lpMenuArray[nMenuCount][ITEM], true);
      }

      if (lpItemsArray[nItemCount][FLAGS] & MF_LAST)
        lpMenuArray[nMenuCount][ITEM]=-1;
      else
        lpMenuArray[nMenuCount][ITEM]+=1;

      if (!(lpItemsArray[nItemCount][FLAGS] & MF_SUBMENU))
      {
        if (lpItemsArray[nItemCount][FLAGS] & MF_LAST)
        {
          while (--nMenuCount >= 0)
          {
            if (lpMenuArray[nMenuCount][ITEM] != -1)
              break;
          }
          if (nMenuCount < 0) break;
        }
      }
      else ++nMenuCount;
    }

    if (lpMenuArray[0][MENU])
    {
      //创建菜单窗体
      if (hWndContainer=oSys.Call("user32::CreateWindowEx" + _TCHAR, 0, "Static", 0, 0x50000000 /*WS_VISIBLE|WS_CHILD*/, 0, 0, 0, 0, hMainWnd, 0, hInstanceDLL, 0))
      {
        oSys.Call("user32::SetFocus", hWndContainer);
        //Mouse can make incorrect hot selection without Sleep
        WScript.Sleep(0);

        //显示菜单
        if (X < 0 || Y < 0)
        {
          if (X == POS_CARET || Y == POS_CARET)
            GetCaretPos(hWndEdit, ptPoint);
          else if (X == POS_CURSOR || Y == POS_CURSOR)
            GetCursorPos(ptPoint);

          if (X < 0) X=ptPoint.x;
          if (Y < 0) Y=ptPoint.y;
        }
        nResult=oSys.Call("user32::TrackPopupMenu", lpMenuArray[0][MENU], 0x182 /*TPM_RETURNCMD|TPM_NONOTIFY|TPM_RIGHTBUTTON*/, X, Y, 0, hWndContainer, 0);

        oSys.Call("user32::DestroyWindow", hWndContainer);
      }
      oSys.Call("user32::DestroyMenu", lpMenuArray[0][MENU]);
    }
  }
  return nResult - 1;
}

function GetCaretPos(hWndEdit, ptPoint)
{
  var lpPoint;

  ptPoint.x=0;
  ptPoint.y=0;

  if (hWndEdit)
  {
    if (lpPoint=AkelPad.MemAlloc(8 /*sizeof(POINT)*/))
    {
      //插入点位置
      AkelPad.SendMessage(hWndEdit, 3190 /*AEM_GETCARETPOS*/, lpPoint, 0);
      ptPoint.x=AkelPad.MemRead(_PtrAdd(lpPoint, 0) /*offsetof(POINT, x)*/, 3 /*DT_DWORD*/);
      ptPoint.y=AkelPad.MemRead(_PtrAdd(lpPoint, 4) /*offsetof(POINT, y)*/, 3 /*DT_DWORD*/);
      AkelPad.MemFree(lpPoint);

      //插入点底部
      ptPoint.y+=AkelPad.SendMessage(hWndEdit, 3188 /*AEM_GETCHARSIZE*/, 0 /*AECS_HEIGHT*/, 0);

      //屏幕坐标
      ClientToScreen(hWndEdit, ptPoint);
    }
  }
}

function GetCursorPos(ptPoint)
{
  var oSys=AkelPad.SystemFunction();
  var lpPoint;

  ptPoint.x=0;
  ptPoint.y=0;

  if (lpPoint=AkelPad.MemAlloc(8 /*sizeof(POINT)*/))
  {
    if (oSys.Call("user32::GetCursorPos", lpPoint))
    {
      ptPoint.x=AkelPad.MemRead(_PtrAdd(lpPoint, 0) /*offsetof(POINT, x)*/, 3 /*DT_DWORD*/);
      ptPoint.y=AkelPad.MemRead(_PtrAdd(lpPoint, 4) /*offsetof(POINT, y)*/, 3 /*DT_DWORD*/);
    }
    AkelPad.MemFree(lpPoint);
  }
}

function GetToolbarBottonPos(hToolbarHandle, nToolbarItemID)
{
  var ptPoint=[];
  var lpRect;

  ptPoint.x=0;
  ptPoint.y=0;

  if (hToolbarHandle && nToolbarItemID)
  {
    if (lpRect=AkelPad.MemAlloc(16 /*sizeof(RECT)*/))
    {
      //获取 Toolbar 按钮位置
      AkelPad.SendMessage(hToolbarHandle, 1075 /*TB_GETRECT*/, nToolbarItemID, lpRect);
      ptPoint.x=AkelPad.MemRead(_PtrAdd(lpRect, 0) /*offsetof(RECT, left)*/, 3 /*DT_DWORD*/);
      ptPoint.y=AkelPad.MemRead(_PtrAdd(lpRect, 12) /*offsetof(RECT, bottom)*/, 3 /*DT_DWORD*/);
      AkelPad.MemFree(lpRect);

      //屏幕坐标
      ClientToScreen(hToolbarHandle, ptPoint);
    }
  }
  return ptPoint;
}

function ClientToScreen(hWnd, ptPoint)
{
  var oSys=AkelPad.SystemFunction();
  var lpPoint;

  if (lpPoint=AkelPad.MemAlloc(8 /*sizeof(POINT)*/))
  {
    AkelPad.MemCopy(_PtrAdd(lpPoint, 0) /*offsetof(POINT, x)*/, ptPoint.x, 3 /*DT_DWORD*/);
    AkelPad.MemCopy(_PtrAdd(lpPoint, 4) /*offsetof(POINT, y)*/, ptPoint.y, 3 /*DT_DWORD*/);
    oSys.Call("user32::ClientToScreen", hWnd, lpPoint);
    ptPoint.x=AkelPad.MemRead(_PtrAdd(lpPoint, 0) /*offsetof(POINT, x)*/, 3 /*DT_DWORD*/);
    ptPoint.y=AkelPad.MemRead(_PtrAdd(lpPoint, 4) /*offsetof(POINT, y)*/, 3 /*DT_DWORD*/);
    AkelPad.MemFree(lpPoint);
  }
}
