Advertisement
Alexey_B

runScript.js

Apr 7th, 2022
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // http://akelpad.sourceforge.net/forum/viewtopic.php?p=11863#11863
  2. // http://infocatcher.ucoz.net/js/akelpad_scripts/runScript.js
  3. // https://github.com/Infocatcher/AkelPad_scripts/blob/master/runScript.js
  4.  
  5. // (c) Infocatcher 2011-2021
  6. // Version: 0.2.9pre2 - 2021-05-03
  7. // Author: Infocatcher
  8.  
  9. //===================
  10. //// Run script from AkelFiles\Plugs\Scripts\ directory
  11. // Required timer.js library (to disable Exec button right after click):
  12. // http://akelpad.sourceforge.net/forum/viewtopic.php?p=24559#24559
  13. // https://github.com/Infocatcher/AkelPad_scripts/blob/master/Include/timer.js
  14.  
  15. // Hotkeys:
  16. //   Enter                        - Ok
  17. //   Ctrl+Enter (Shift+Enter), F3 - Exec
  18. //   Shift+Enter                  - Insert newline in multiline arguments text field
  19. //   F4, Ctrl+E                   - Edit
  20. //   F2, Ctrl+S                   - Rewrite options (and remove arguments for removed files)
  21. //   F1, Shift+F1                 - Next/previous script
  22. //   F5                           - Refresh scripts list
  23. //   Ctrl++                       - increase lines count for arguments text field
  24. //   Ctrl+-                       - decrease lines count for arguments text field
  25. //   Ctrl+Shift++                 - set lines count for arguments text field to max value
  26. //   Ctrl+Shift+-                 - set lines count for arguments text field to 1
  27. //   Escape                       - Cancel
  28.  
  29. // Arguments:
  30. //   -saveOptions=1               - save options:
  31. //                                    0 - don't save
  32. //                                    1 - save only for runned scripts
  33. //                                    2 - always save
  34. //   -savePosition=true           - save last window position
  35. //   -saveSize=true               - save last window size
  36. //   -saveArgsLines=true          - save lines count for arguments text field
  37. //   -selectOpenedScript=5        - select currently opened script in the list, sum of flags:
  38. //                                    1 - select on startup,
  39. //                                    2 - select on window focus,
  40. //                                    4 - select on window focus only after second runScript.js call
  41. //   -selectContext=3             - show N items before/after selected, 0 to disable
  42. //   -argsLines=1                 - force specify lines count for arguments text field
  43. //   -script="someScript.js"      - select someScript.js in the list
  44.  
  45. // Usage:
  46. //   Call("Scripts::Main", 1, "runScript.js")
  47. //   Call("Scripts::Main", 1, "runScript.js", `-script="someScript.js" -saveOptions=0 -savePosition=false`)
  48. //===================
  49.  
  50. function _localize(s) {
  51.     var strings = {
  52.         "&Arguments": {
  53.             ru: "&Аргументы"
  54.         },
  55.         "OK": {
  56.             ru: "ОК"
  57.         },
  58.         "Exec": {
  59.             ru: "Запустить"
  60.         },
  61.         "Edit": {
  62.             ru: "Изменить"
  63.         },
  64.         "Cancel": {
  65.             ru: "Отмена"
  66.         },
  67.         "File not found:\n%p\nUse F5 to reload list": {
  68.             ru: "Файл не найден:\n%p\nИспользуйте F5 для обновления списка"
  69.         }
  70.     };
  71.     var lng = "en";
  72.     switch(AkelPad.GetLangId(1 /*LANGID_PRIMARY*/)) {
  73.         case 0x19: lng = "ru";
  74.     }
  75.     _localize = function(s) {
  76.         return strings[s] && strings[s][lng] || s;
  77.     };
  78.     return _localize(s);
  79. }
  80.  
  81. var hMainWnd = AkelPad.GetMainWnd();
  82. if(!hMainWnd)
  83.     WScript.Quit();
  84.  
  85. var oSys = AkelPad.SystemFunction();
  86. var oSet = AkelPad.ScriptSettings();
  87. var fso = new ActiveXObject("Scripting.FileSystemObject");
  88. var scriptsDir = AkelPad.GetAkelDir(5 /*ADTYPE_SCRIPTS*/);
  89. var dialogTitle = WScript.ScriptName.replace(/^[!-\-_]+/, "");
  90. dialogTitle = dialogTitle.charAt(0).toUpperCase() + dialogTitle.substr(1);
  91.  
  92. function getPrefName(scriptName) {
  93.     return "/" + scriptName.replace(/=/g, "<equals>");
  94. }
  95.  
  96. // Read arguments:
  97. var selectScript  = AkelPad.GetArgValue("selectOpenedScript", 1|4);
  98. var scriptName    = AkelPad.GetArgValue("script", "") || selectScript & 1 && getCurScript();
  99. var saveOptions   = AkelPad.GetArgValue("saveOptions", 1);
  100. var savePosition  = AkelPad.GetArgValue("savePosition", true);
  101. var saveSize      = AkelPad.GetArgValue("saveSize", true);
  102. var selectContext = AkelPad.GetArgValue("selectContext", 3);
  103. var saveArgsLines = AkelPad.GetArgValue("saveArgsLines", true);
  104. var argsLines     = AkelPad.GetArgValue("argsLines", 1);
  105.  
  106. var ARGS_LINES_MAX = 15;
  107. function limitArgsLines(al) {
  108.     return Math.max(1, Math.min(ARGS_LINES_MAX, al || 1));
  109. }
  110. argsLines = limitArgsLines(argsLines);
  111. var argsMultiline = argsLines > 1;
  112.  
  113. selectScriptDialog();
  114.  
  115. function getCurScript() {
  116.     var filePath = AkelPad.GetEditFile(0);
  117.     if(isScript(filePath) && fso.GetParentFolderName(filePath).toLowerCase() == scriptsDir.toLowerCase())
  118.         return fso.GetFileName(filePath);
  119.     return "";
  120. }
  121. function isScript(path) {
  122.     return /\.(js|vbs)$/i.test(path);
  123. }
  124. function expandArgs(args) {
  125.     var wsh = new ActiveXObject("WScript.Shell");
  126.     expandArgs = function(args) {
  127.         var file = AkelPad.GetEditFile(0);
  128.         return wsh.ExpandEnvironmentStrings(args)
  129.             .replace(/%f/ig, file)
  130.             .replace(/%d/ig, file && fso.GetParentFolderName(file))
  131.             .replace(/%a/ig, AkelPad.GetAkelDir())
  132.             .replace(/%([^%]|$)/g, "$1")
  133.             .replace(/%%/g, "%")
  134.             .replace(/ ?\r\n?| ?\n\r?/g, " ");
  135.     };
  136.     return expandArgs(args);
  137. }
  138.  
  139. function selectScriptDialog(modal) {
  140.     var hInstanceDLL = AkelPad.GetInstanceDll();
  141.     var dialogClass = "AkelPad::Scripts::" + WScript.ScriptName + "::" + oSys.Call("kernel32::GetCurrentProcessId");
  142.     var hListBoxSubClass;
  143.  
  144.     var IDC_STATIC     = -1;
  145.     var IDC_LISTBOX    = 1000;
  146.     var IDC_ARGS       = 1001;
  147.     var IDC_OK         = 1002;
  148.     var IDC_EXEC       = 1003;
  149.     var IDC_EDIT       = 1004;
  150.     var IDC_CANCEL     = 1005;
  151.     var IDC_ARG_INC    = 1006;
  152.     var IDC_ARG_DEC    = 1007;
  153.     var IDC_CUR_SCRIPT = 1008;
  154.     var IDC_OK_DELAY   = 1009;
  155.     var IDC_EXEC_DELAY = 1010;
  156.  
  157.     var hWndDialog = oSys.Call("user32::FindWindowEx" + _TCHAR, 0, 0, dialogClass, 0);
  158.     if(hWndDialog) {
  159.         if(oSys.Call("user32::IsIconic", hWndDialog))
  160.             oSys.Call("user32::ShowWindow", hWndDialog, 9 /*SW_RESTORE*/);
  161.         AkelPad.SendMessage(hWndDialog, 7 /*WM_SETFOCUS*/, 0, 0);
  162.         if(selectScript & 4)
  163.             AkelPad.SendMessage(hWndDialog, 273 /*WM_COMMAND*/, IDC_CUR_SCRIPT, 0);
  164.         return;
  165.     }
  166.  
  167.     if(
  168.         !AkelPad.WindowRegisterClass(dialogClass)
  169.         && ( // Previous script instance crashed
  170.             !AkelPad.WindowUnregisterClass(dialogClass)
  171.             || !AkelPad.WindowRegisterClass(dialogClass)
  172.         )
  173.     )
  174.         return;
  175.  
  176.     var curName = scriptName || "";
  177.  
  178.     var dlgX, dlgY;
  179.     var lastW, lastH;
  180.     var save = saveOptions || savePosition || saveSize || saveArgsLines;
  181.     if(save && oSet.Begin(WScript.ScriptBaseName, 0x1 /*POB_READ*/)) {
  182.         if(saveOptions && !curName)
  183.             curName = oSet.Read("lastScript", 3 /*PO_STRING*/, "");
  184.         if(saveArgsLines && AkelPad.GetArgValue("argsLines", null) === null) {
  185.             argsLines = limitArgsLines(oSet.Read("argsLines", 1 /*PO_DWORD*/));
  186.             argsMultiline = argsLines > 1;
  187.         }
  188.         if(savePosition) {
  189.             dlgX = oSet.Read("windowLeft", 1 /*PO_DWORD*/);
  190.             dlgY = oSet.Read("windowTop",  1 /*PO_DWORD*/);
  191.         }
  192.         if(saveSize) {
  193.             lastW = oSet.Read("windowWidth",  1 /*PO_DWORD*/);
  194.             lastH = oSet.Read("windowHeight", 1 /*PO_DWORD*/);
  195.         }
  196.         oSet.End();
  197.     }
  198.     var _cleanup = {};
  199.     function saveSettings(rewrite) {
  200.         if(!save)
  201.             return;
  202.         if(!oSet.Begin(WScript.ScriptBaseName, 0x2 /*POB_SAVE*/ | (rewrite ? 0x4 /*POB_CLEAR*/ : 0)))
  203.             return;
  204.         if((savePosition || saveSize) && !oSys.Call("user32::IsIconic", hWndDialog)) {
  205.             var rcWnd = getWindowRect(hWndDialog);
  206.             if(rcWnd) {
  207.                 if(savePosition) {
  208.                     oSet.Write("windowLeft", 1 /*PO_DWORD*/, rcWnd.left);
  209.                     oSet.Write("windowTop",  1 /*PO_DWORD*/, rcWnd.top);
  210.                 }
  211.                 if(saveSize) {
  212.                     oSet.Write("windowWidth",  1 /*PO_DWORD*/, Math.round((rcWnd.right - rcWnd.left)/scale.x(10000)*10000) - sizeNonClientX);
  213.                     oSet.Write("windowHeight", 1 /*PO_DWORD*/, Math.round((rcWnd.bottom - rcWnd.top)/scale.y(10000)*10000) - sizeNonClientY);
  214.                 }
  215.             }
  216.         }
  217.         if(saveArgsLines)
  218.             oSet.Write("argsLines", 1 /*PO_DWORD*/, argsLines);
  219.         if(saveOptions) {
  220.             if(runned || saveOptions == 2)
  221.                 oSet.Write("lastScript", 3 /*PO_STRING*/, saveOptions == 2 ? curName : runnedName);
  222.             var names = saveOptions == 2 ? argsObj : runned || {};
  223.             for(var name in names)
  224.                 saveArgs(name, argsObj[name]);
  225.             for(var name in _cleanup) {
  226.                 oSet.Delete("lastArgs-" + encodeURIComponent(name));
  227.                 !names[name] && saveArgs(name, _cleanup[name]);
  228.             }
  229.         }
  230.         oSet.End();
  231.     }
  232.     function saveArgs(name, args) {
  233.         var prefName = getPrefName(name);
  234.         if(args)
  235.             oSet.Write(prefName, 3 /*PO_STRING*/, argsToStorage(args));
  236.         else
  237.             oSet.Delete(prefName);
  238.     }
  239.     function argsToStorage(args) {
  240.         return args.replace(/ ?\r\n?| ?\n\r?/g, " -<BR> ");
  241.     }
  242.     function argsFromStorage(str) {
  243.         return str.replace(/ -<BR> /g, argsMultiline ? "\r\n" : " \r\n");
  244.     }
  245.  
  246.     var selfRun = false;
  247.     var runned, runnedName;
  248.     var argsObj = {};
  249.     var startTime = new Date().getTime();
  250.  
  251.     var hWndListBox, hWndGroupArgs, hWndArgs;
  252.     var hWndOK, hWndExec, hWndEdit, hWndCancel;
  253.     var hWndArgsInc, hWndArgsDec;
  254.  
  255.     var lbW = 260;
  256.     var lbH = 320;
  257.  
  258.     var btnW = 82;
  259.     var btnH = 23;
  260.     var btnSep = 4;
  261.  
  262.     var mlStyle = 0x201044; // ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL|ES_AUTOVSCROLL
  263.     var hGuiFont = oSys.Call("gdi32::GetStockObject", 17 /*DEFAULT_GUI_FONT*/);
  264.     var ignoreResize = false;
  265.     var argsLineH = 14;
  266.     var argsH = 21 + (argsMultiline ? argsLineH*(argsLines - 1) : 0);
  267.     var gbH = 27 + argsH;
  268.     var gbW = lbW + 12 + btnW;
  269.  
  270.     var incDecX = gbW - 12;
  271.     var incDecW = 16;
  272.     var incDecH = 16;
  273.  
  274.     var dlgW = 12 + lbW + 12 + btnW + 12;
  275.     var dlgH = 12 + lbH + 12 + gbH + 12;
  276.  
  277.     var dlgMinW = dlgW - lbW + 120;
  278.     var dlgMinH = 12 + btnH*4 + btnSep*3 + 12 + gbH + 12;
  279.  
  280.     if(lastW != undefined)
  281.         lastW = Math.max(dlgMinW, lastW);
  282.     if(lastH != undefined)
  283.         lastH = Math.max(dlgMinH, lastH);
  284.  
  285.     var scale = new Scale(0, hMainWnd);
  286.     var sizeNonClientX = oSys.Call("user32::GetSystemMetrics", 32 /*SM_CXSIZEFRAME*/) * 2;
  287.     var sizeNonClientY = oSys.Call("user32::GetSystemMetrics", 33 /*SM_CYSIZEFRAME*/) * 2 + oSys.Call("user32::GetSystemMetrics", 4 /*SM_CYCAPTION*/);
  288.  
  289.     // Create dialog
  290.     hWndDialog = oSys.Call(
  291.         "user32::CreateWindowEx" + _TCHAR,
  292.         0,                                       //dwExStyle
  293.         dialogClass,                             //lpClassName
  294.         0,                                       //lpWindowName
  295.         0x90CE0000,                              //WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_THICKFRAME
  296.         scale.x(dlgX || 0),                      //x
  297.         scale.y(dlgY || 0),                      //y
  298.         scale.x(lastW || dlgW) + sizeNonClientX, //nWidth
  299.         scale.y(lastH || dlgH) + sizeNonClientY, //nHeight
  300.         hMainWnd,                                //hWndParent
  301.         0,                                       //ID
  302.         hInstanceDLL,                            //hInstance
  303.         dialogCallback                           //Script function callback. To use it class must be registered by WindowRegisterClass.
  304.     );
  305.     if(!hWndDialog)
  306.         return;
  307.  
  308.     function dialogCallback(hWnd, uMsg, wParam, lParam) {
  309.         switch(uMsg) {
  310.             case 1: //WM_CREATE
  311.                 dlgW = scale.x(dlgW) + sizeNonClientX;
  312.                 dlgH = scale.y(dlgH) + sizeNonClientY;
  313.                 dlgMinW = scale.x(dlgMinW) + sizeNonClientX;
  314.                 dlgMinH = scale.y(dlgMinH) + sizeNonClientY;
  315.  
  316.                 // Dialog caption
  317.                 oSys.Call("user32::SetWindowText" + _TCHAR, hWnd, dialogTitle);
  318.  
  319.                 //centerWindow(hWnd);
  320.                 //centerWindow(hWnd, hMainWnd);
  321.                 restoreWindowPosition(hWnd, hMainWnd);
  322.  
  323.                 hWndListBox = createWindowEx(
  324.                     0x204,        //WS_EX_CLIENTEDGE|WS_EX_NOPARENTNOTIFY
  325.                     "LISTBOX",    //lpClassName
  326.                     0,            //lpWindowName
  327.                     0x50210103,   //WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_TABSTOP|LBS_NOINTEGRALHEIGHT|LBS_SORT|LBS_NOTIFY
  328.                     12,           //x
  329.                     12,           //y
  330.                     lbW,          //nWidth
  331.                     lbH,          //nHeight
  332.                     hWnd,         //hWndParent
  333.                     IDC_LISTBOX,  //ID
  334.                     hInstanceDLL, //hInstance
  335.                     0             //lpParam
  336.                 );
  337.                 setWindowFont(hWndListBox, hGuiFont);
  338.                 hListBoxSubClass = AkelPad.WindowSubClass(hWndListBox, listBoxCallback, 258 /*WM_CHAR*/);
  339.  
  340.                 // GroupBox action
  341.                 hWndGroupArgs = createWindowEx(
  342.                     0,             //dwExStyle
  343.                     "BUTTON",      //lpClassName
  344.                     0,             //lpWindowName
  345.                     0x50000007,    //WS_VISIBLE|WS_CHILD|BS_GROUPBOX
  346.                     12,            //x
  347.                     12 + lbH + 12, //y
  348.                     gbW,           //nWidth
  349.                     gbH,           //nHeight
  350.                     hWnd,          //hWndParent
  351.                     IDC_STATIC,    //ID
  352.                     hInstanceDLL,  //hInstance
  353.                     0              //lpParam
  354.                 );
  355.                 setWindowFontAndText(hWndGroupArgs, hGuiFont, _localize("&Arguments"));
  356.  
  357.                 // Arguments lines increase button window
  358.                 hWndArgsInc = createWindowEx(
  359.                     0,                     //dwExStyle
  360.                     "BUTTON",              //lpClassName
  361.                     0,                     //lpWindowName
  362.                     0x50010000,            //WS_VISIBLE|WS_CHILD|WS_TABSTOP
  363.                     incDecX - incDecW - 4, //x
  364.                     12 + lbH + 10,         //y
  365.                     incDecW,               //nWidth
  366.                     incDecH,               //nHeight
  367.                     hWnd,                  //hWndParent
  368.                     IDC_ARG_INC,           //ID
  369.                     hInstanceDLL,          //hInstance
  370.                     0                      //lpParam
  371.                 );
  372.                 setWindowFontAndText(hWndArgsInc, hGuiFont, "+");
  373.                 argsLines >= ARGS_LINES_MAX && enabled(hWndArgsInc, false);
  374.  
  375.                 // Arguments lines decrease button window
  376.                 hWndArgsDec = createWindowEx(
  377.                     0,             //dwExStyle
  378.                     "BUTTON",      //lpClassName
  379.                     0,             //lpWindowName
  380.                     0x50010000,    //WS_VISIBLE|WS_CHILD|WS_TABSTOP
  381.                     incDecX,       //x
  382.                     12 + lbH + 10, //y
  383.                     incDecW,       //nWidth
  384.                     incDecH,       //nHeight
  385.                     hWnd,          //hWndParent
  386.                     IDC_ARG_DEC,   //ID
  387.                     hInstanceDLL,  //hInstance
  388.                     0              //lpParam
  389.                 );
  390.                 setWindowFontAndText(hWndArgsDec, hGuiFont, "−");
  391.                 !argsMultiline && enabled(hWndArgsDec, false);
  392.  
  393.                 // Edit: arguments
  394.                 var ml = argsMultiline ? mlStyle : 0;
  395.                 hWndArgs = createWindowEx(
  396.                     0x200,              //WS_EX_CLIENTEDGE
  397.                     "EDIT",             //lpClassName
  398.                     0,                  //lpWindowName
  399.                     0x50010080|ml,      //WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL
  400.                     12 + 8,             //x
  401.                     12 + lbH + 12 + 18, //y
  402.                     gbW - 8*2,          //nWidth
  403.                     argsH,              //nHeight
  404.                     hWnd,               //hWndParent
  405.                     IDC_ARGS,           //ID
  406.                     hInstanceDLL,       //hInstance
  407.                     0                   //lpParam
  408.                 );
  409.                 setWindowFont(hWndArgs, hGuiFont);
  410.                 setEditText(hWndArgs, "");
  411.  
  412.                 // OK button window
  413.                 hWndOK = createWindowEx(
  414.                     0,             //dwExStyle
  415.                     "BUTTON",      //lpClassName
  416.                     0,             //lpWindowName
  417.                     0x50010001,    //WS_VISIBLE|WS_CHILD|WS_TABSTOP|BS_DEFPUSHBUTTON
  418.                     12 + lbW + 12, //x
  419.                     12,            //y
  420.                     btnW,          //nWidth
  421.                     btnH,          //nHeight
  422.                     hWnd,          //hWndParent
  423.                     IDC_OK,        //ID
  424.                     hInstanceDLL,  //hInstance
  425.                     0              //lpParam
  426.                 );
  427.                 setWindowFontAndText(hWndOK, hGuiFont, _localize("OK"));
  428.  
  429.                 // Exec button window
  430.                 hWndExec = createWindowEx(
  431.                     0,                  //dwExStyle
  432.                     "BUTTON",           //lpClassName
  433.                     0,                  //lpWindowName
  434.                     0x50010000,         //WS_VISIBLE|WS_CHILD|WS_TABSTOP
  435.                     12 + lbW + 12,      //x
  436.                     12 + btnH + btnSep, //y
  437.                     btnW,               //nWidth
  438.                     btnH,               //nHeight
  439.                     hWnd,               //hWndParent
  440.                     IDC_EXEC,           //ID
  441.                     hInstanceDLL,       //hInstance
  442.                     0                   //lpParam
  443.                 );
  444.                 setWindowFontAndText(hWndExec, hGuiFont, _localize("Exec"));
  445.  
  446.                 // Edit button window
  447.                 hWndEdit = createWindowEx(
  448.                     0,                      //dwExStyle
  449.                     "BUTTON",               //lpClassName
  450.                     0,                      //lpWindowName
  451.                     0x50010000,             //WS_VISIBLE|WS_CHILD|WS_TABSTOP
  452.                     12 + lbW + 12,          //x
  453.                     12 + (btnH + btnSep)*2, //y
  454.                     btnW,                   //nWidth
  455.                     btnH,                   //nHeight
  456.                     hWnd,                   //hWndParent
  457.                     IDC_EDIT,               //ID
  458.                     hInstanceDLL,           //hInstance
  459.                     0                       //lpParam
  460.                 );
  461.                 setWindowFontAndText(hWndEdit, hGuiFont, _localize("Edit"));
  462.  
  463.                 // Cancel button window
  464.                 hWndCancel = createWindowEx(
  465.                     0,                      //dwExStyle
  466.                     "BUTTON",               //lpClassName
  467.                     0,                      //lpWindowName
  468.                     0x50010000,             //WS_VISIBLE|WS_CHILD|WS_TABSTOP
  469.                     12 + lbW + 12,          //x
  470.                     12 + (btnH + btnSep)*3, //y
  471.                     btnW,                   //nWidth
  472.                     btnH,                   //nHeight
  473.                     hWnd,                   //hWndParent
  474.                     IDC_CANCEL,             //ID
  475.                     hInstanceDLL,           //hInstance
  476.                     0                       //lpParam
  477.                 );
  478.                 setWindowFontAndText(hWndCancel, hGuiFont, _localize("Cancel"));
  479.  
  480.                 if(lastW != undefined || lastH != undefined)
  481.                     resizeDialog(hWnd, lastW || dlgW, lastH || dlgH);
  482.  
  483.                 fillListBox(hWnd);
  484.                 updArgs();
  485.             break;
  486.             case 7: //WM_SETFOCUS
  487.                 var alreadyOpened = new Date().getTime() - startTime > 250;
  488.                 if(alreadyOpened ? selectScript & 2 && !(selectScript & 4) : selectScript & 1)
  489.                     AkelPad.SendMessage(hWnd, 273 /*WM_COMMAND*/, IDC_CUR_SCRIPT, 0);
  490.                 oSys.Call("user32::SetFocus", curName ? hWndArgs : hWndListBox);
  491.             break;
  492.             case 256: //WM_KEYDOWN
  493.                 var ctrl = oSys.Call("user32::GetAsyncKeyState", 17 /*VK_CONTROL*/) & 0x8000;
  494.                 var shift = oSys.Call("user32::GetAsyncKeyState", 16 /*VK_SHIFT*/) & 0x8000;
  495.                 //var alt = oSys.Call("user32::GetAsyncKeyState", 18 /*VK_MENU*/) & 0x8000;
  496.                 if(wParam == 27) //VK_ESCAPE
  497.                     postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_CANCEL, 0);
  498.                 else if(wParam == 13) { //VK_RETURN
  499.                     if(ctrl || shift && !argsMultiline) { // Ctrl+Enter, Shift+Enter
  500.                         if(argsMultiline && oSys.Call("user32::GetFocus") == hWndArgs) {
  501.                             AkelPad.SendMessage(hWnd, 11 /*WM_SETREDRAW*/, false, 0);
  502.                             var lpKeyState = AkelPad.MemAlloc(256);
  503.                             if(lpKeyState) { // Reset to not send Ctrl+Backspace
  504.                                 oSys.Call("user32::SetKeyboardState", lpKeyState);
  505.                                 AkelPad.MemFree(lpKeyState);
  506.                             }
  507.                             postMessage(hWndArgs, 256 /*WM_KEYDOWN*/, 8 /*VK_BACK*/, 0);
  508.                         }
  509.                         postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_EXEC_DELAY, 0);
  510.                     }
  511.                     else if(!ctrl && !shift) { // Enter
  512.                         if(argsMultiline && oSys.Call("user32::GetFocus") == hWndArgs) {
  513.                             // Window will be closed, don't show just inserted newline
  514.                             AkelPad.SendMessage(hWnd, 11 /*WM_SETREDRAW*/, false, 0);
  515.                             postMessage(hWndArgs, 256 /*WM_KEYDOWN*/, 8 /*VK_BACK*/, 0);
  516.                         }
  517.                         postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_OK_DELAY, 0);
  518.                     }
  519.                 }
  520.                 else if(wParam == 114 /*VK_F3*/) // F3
  521.                     postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_EXEC, 0);
  522.                 else if(wParam == 112 /*VK_F1*/)
  523.                     navigate(ctrl || shift);
  524.                 else if(wParam == 113 /*VK_F2*/ || ctrl && wParam == 83 /*S*/) { // F2, Ctrl+S
  525.                     var so = saveOptions;
  526.                     saveOptions = 2;
  527.                     saveSettings(true);
  528.                     saveOptions = so;
  529.                 }
  530.                 else if(wParam == 115 /*VK_F4*/ || ctrl && wParam == 69 /*E*/) // F4, Ctrl+E
  531.                     postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_EDIT, 0);
  532.                 else if(wParam == 116 /*VK_F5*/)
  533.                     redrawListbox();
  534.                 else if(ctrl && (wParam == 107 /*VK_ADD*/ || wParam == 187 /*+/=*/)) // Ctrl++
  535.                     setArgsLines(shift ? -argsLines + ARGS_LINES_MAX : 1);
  536.                 else if(ctrl && (wParam == 109 /*VK_SUBTRACT*/ || wParam == 189 /*-/_*/)) // Ctrl+-
  537.                     setArgsLines(shift ? -argsLines + 1 : -1);
  538.             break;
  539.             case 273: //WM_COMMAND
  540.                 var idc = wParam & 0xffff;
  541.                 switch(idc) {
  542.                     case IDC_OK:
  543.                     case IDC_EXEC:
  544.                         var isSelf = curName == WScript.ScriptName;
  545.                         selfRun = false;
  546.                         if(!curName || isSelf && idc == IDC_EXEC)
  547.                             break;
  548.                         var scriptPath = scriptsDir + "\\" + curName;
  549.                         if(oSys.Call("kernel32::GetFileAttributes" + _TCHAR, scriptPath) == -1) {
  550.                             var msg = _localize("File not found:\n%p\nUse F5 to reload list")
  551.                                 .replace("%p", scriptPath);
  552.                             AkelPad.MessageBox(hWnd, msg, WScript.ScriptName, 48 /*MB_ICONEXCLAMATION*/);
  553.                             break;
  554.                         }
  555.                         if(!runned)
  556.                             runned = {};
  557.                         runned[runnedName = curName] = true;
  558.                         if(isSelf)
  559.                             selfRun = true;
  560.                         else
  561.                             AkelPad.Call("Scripts::Main", 1, curName, expandArgs(argsObj[curName] || ""));
  562.                         if(idc == IDC_OK)
  563.                             closeDialog();
  564.                         else {
  565.                             ensureVisibility();
  566.                             ensureTimers(notifyButton, hWndExec);
  567.                         }
  568.                     break;
  569.                     case IDC_EDIT:
  570.                         if(!curName)
  571.                             break;
  572.                         AkelPad.Call("Scripts::Main", 3, curName);
  573.                         oSys.Call("user32::SetFocus", hMainWnd);
  574.                         ensureTimers(notifyButton, hWndEdit);
  575.                     break;
  576.                     case IDC_CANCEL:
  577.                         closeDialog();
  578.                     break;
  579.                     case IDC_ARGS:
  580.                         argsObj[curName] = windowText(hWndArgs).replace(/^\s+|\s+$/g, "");
  581.                     break;
  582.                     case IDC_LISTBOX:
  583.                         updArgs();
  584.                         if((wParam >> 16 & 0xFFFF) == 2 /*LBN_DBLCLK*/)
  585.                             postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_EXEC, 0);
  586.                     break;
  587.                     case IDC_ARG_INC:
  588.                     case IDC_ARG_DEC:
  589.                         setArgsLines(idc == IDC_ARG_INC ? 1 : -1);
  590.                     break;
  591.                     case IDC_CUR_SCRIPT:
  592.                         var scriptName = getCurScript();
  593.                         if(!scriptName)
  594.                             break;
  595.                         var indx = getIndexFromString(scriptName);
  596.                         if(indx != undefined) {
  597.                             curName = scriptName;
  598.                             setListBoxSel(indx);
  599.                             AkelPad.SendMessage(hWnd, 273 /*WM_COMMAND*/, IDC_LISTBOX, 0);
  600.                         }
  601.                     break;
  602.                     // Tricks for WM_KEYDOWN with focused multiline arguments
  603.                     case IDC_OK_DELAY:
  604.                         postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_OK, 0);
  605.                     break;
  606.                     case IDC_EXEC_DELAY:
  607.                         postMessage(hWnd, 273 /*WM_COMMAND*/, IDC_EXEC, 0);
  608.                         AkelPad.SendMessage(hWnd, 11 /*WM_SETREDRAW*/, true, 0);
  609.                 }
  610.             break;
  611.             case 36: //WM_GETMINMAXINFO
  612.                 if(ignoreResize)
  613.                     break;
  614.                 AkelPad.MemCopy(_PtrAdd(lParam, 24), dlgMinW, 3 /*DT_DWORD*/); //ptMinTrackSize.x
  615.                 AkelPad.MemCopy(_PtrAdd(lParam, 28), dlgMinH, 3 /*DT_DWORD*/); //ptMinTrackSize.y
  616.             break;
  617.             case 5: //WM_SIZE
  618.                 if(ignoreResize || oSys.Call("user32::IsIconic", hWnd))
  619.                     break;
  620.                 var rcWnd = getWindowRect(hWnd);
  621.                 if(!rcWnd)
  622.                     break;
  623.                 var curW = rcWnd.right - rcWnd.left;
  624.                 var curH = rcWnd.bottom - rcWnd.top;
  625.                 resizeDialog(hWnd, curW, curH);
  626.             break;
  627.             case 15: //WM_PAINT
  628.                 // Based on code of SearchReplace.js script
  629.                 var ps;
  630.                 var hDC;
  631.                 var lpGrip;
  632.                 var rcGrip;
  633.                 if(ps = AkelPad.MemAlloc(_X64 ? 72 : 64 /*sizeof(PAINTSTRUCT)*/)) {
  634.                     if(hDC = oSys.Call("user32::BeginPaint", hWnd, ps)) {
  635.                         if(lpGrip = AkelPad.MemAlloc(16 /*sizeof(RECT)*/)) {
  636.                             if(oSys.Call("user32::GetClientRect", hWnd, lpGrip)) {
  637.                                 rcGrip = parseRect(lpGrip);
  638.                                 rcGrip.left = rcGrip.right  - oSys.Call("user32::GetSystemMetrics", 2 /*SM_CXVSCROLL*/);
  639.                                 rcGrip.top  = rcGrip.bottom - oSys.Call("user32::GetSystemMetrics", 20 /*SM_CYVSCROLL*/);
  640.  
  641.                                 AkelPad.MemCopy(_PtrAdd(lpGrip,  0), rcGrip.left,   3 /*DT_DWORD*/);
  642.                                 AkelPad.MemCopy(_PtrAdd(lpGrip,  4), rcGrip.top,    3 /*DT_DWORD*/);
  643.                                 AkelPad.MemCopy(_PtrAdd(lpGrip,  8), rcGrip.right,  3 /*DT_DWORD*/);
  644.                                 AkelPad.MemCopy(_PtrAdd(lpGrip, 12), rcGrip.bottom, 3 /*DT_DWORD*/);
  645.  
  646.                                 oSys.Call("user32::DrawFrameControl", hDC, lpGrip, 3 /*DFC_SCROLL*/, 0x8 /*DFCS_SCROLLSIZEGRIP*/);
  647.                             }
  648.                             AkelPad.MemFree(lpGrip);
  649.                         }
  650.                         oSys.Call("user32::EndPaint", hWnd, ps);
  651.                     }
  652.                     AkelPad.MemFree(ps);
  653.                 }
  654.             break;
  655.             case 123: //WM_CONTEXTMENU
  656.                 if(wParam == hWndArgsInc)
  657.                     setArgsLines(-argsLines + ARGS_LINES_MAX);
  658.                 else if(wParam == hWndArgsDec)
  659.                     setArgsLines(-argsLines + 1);
  660.                 return 1;
  661.             case 16: //WM_CLOSE
  662.                 saveSettings();
  663.                 modal && enabled(hMainWnd, true); // Enable main window
  664.                 oSys.Call("user32::DestroyWindow", hWnd); // Destroy dialog
  665.             break;
  666.             case 2: //WM_DESTROY
  667.                 oSys.Call("user32::PostQuitMessage", 0); // Exit message loop
  668.         }
  669.         return 0;
  670.     }
  671.    
  672.     function listBoxCallback(hWnd, uMsg, wParam, lParam) {
  673.         if (oSys.Call("user32::GetAsyncKeyState", 17 /*VK_CONTROL*/) & 0x8000)
  674.             AkelPad.WindowNoNextProc(hListBoxSubClass);
  675.     }
  676.  
  677.     function fillListBox(hWndDialog) {
  678.         //var t = new Date().getTime();
  679.         var files = [];
  680.         // Foollowing is very slow (especially on slow devices like USB flash):
  681.         //var filesEnum = new Enumerator(fso.GetFolder(scriptsDir).Files);
  682.         //for(; !filesEnum.atEnd(); filesEnum.moveNext()) {
  683.         //  var name = filesEnum.item().Name;
  684.         //  if(isScript(name))
  685.         //      files[files.length] = name;
  686.         //}
  687.  
  688.         // Based on Instructor's code: http://akelpad.sourceforge.net/forum/viewtopic.php?p=12548#12548
  689.         var lpFindData = AkelPad.MemAlloc(592 /*sizeof(WIN32_FIND_DATAW)*/);
  690.         if(!lpFindData)
  691.             return;
  692.         var hSearch = oSys.Call("kernel32::FindFirstFile" + _TCHAR, scriptsDir + "\\*", lpFindData)
  693.             || AkelPad.MemFree(lpFindData);
  694.         if(!hSearch)
  695.             return;
  696.         do {
  697.             var fName = AkelPad.MemRead(_PtrAdd(lpFindData, 44 /*offsetof(WIN32_FIND_DATAW, cFileName)*/), _TSTR);
  698.             if(fName == "." || fName == "..")
  699.                 continue;
  700.             var dwAttributes = AkelPad.MemRead(_PtrAdd(lpFindData, 0) /*offsetof(WIN32_FIND_DATAW, dwAttributes)*/, 3 /*DT_DWORD*/);
  701.             if(dwAttributes & 0x10 /*FILE_ATTRIBUTE_DIRECTORY*/)
  702.                 continue;
  703.             if(isScript(fName))
  704.                 files[files.length] = fName;
  705.         }
  706.         while(oSys.Call("kernel32::FindNextFile" + _TCHAR, hSearch, lpFindData));
  707.         oSys.Call("kernel32::FindClose", hSearch);
  708.         AkelPad.MemFree(lpFindData);
  709.         //var dt = new Date().getTime() - t;
  710.         //oSys.Call("user32::SetWindowText" + _TCHAR, hWndDialog, dialogTitle + " [" + dt + " ms]");
  711.         //files.sort();
  712.  
  713.         var lpStr = AkelPad.MemAlloc(256*_TSIZE);
  714.         if(!lpStr)
  715.             return;
  716.  
  717.         var read = oSet.Begin(WScript.ScriptBaseName, 0x1 /*POB_READ*/);
  718.  
  719.         var indx = 0;
  720.         for(var i = 0, l = files.length; i < l; ++i) {
  721.             var name = files[i];
  722.  
  723.             if(read) {
  724.                 var args = argsFromStorage(oSet.Read(getPrefName(name), 3 /*PO_STRING*/) || "");
  725.                 var oldArgs = oSet.Read("lastArgs-" + encodeURIComponent(name), 3 /*PO_STRING*/);
  726.                 if(oldArgs != undefined)
  727.                     _cleanup[name] = oldArgs;
  728.                 argsObj[name] = args || oldArgs || "";
  729.             }
  730.  
  731.             AkelPad.MemCopy(lpStr, name.substr(0, 255), _TSTR);
  732.             var pos = AkelPad.SendMessage(hWndListBox,  0x180 /*LB_ADDSTRING*/, 0, lpStr);
  733.             if(pos < 0) {
  734.                 AkelPad.MessageBox(
  735.                     hWndDialog,
  736.                     "LB_ADDSTRING failed! Error: " + (({"-1": "LB_ERR", "-2": "LB_ERRSPACE"})[pos] || pos),
  737.                     dialogTitle,
  738.                     16 /*MB_ICONERROR*/
  739.                 );
  740.                 break;
  741.             }
  742.         }
  743.         AkelPad.MemFree(lpStr);
  744.         read && oSet.End();
  745.  
  746.         var indx = getIndexFromString(curName);
  747.         if(indx != undefined)
  748.             setListBoxSel(indx);
  749.         else
  750.             curName = "";
  751.     }
  752.     function redrawListbox() {
  753.         for(var name in argsObj)
  754.             delete argsObj[name];
  755.  
  756.         AkelPad.SendMessage(hWndDialog, 11 /*WM_SETREDRAW*/, false, 0);
  757.  
  758.         AkelPad.SendMessage(hWndListBox,  0x184 /*LB_RESETCONTENT*/, 0, 0);
  759.         fillListBox(hWndDialog);
  760.  
  761.         AkelPad.SendMessage(hWndDialog, 11 /*WM_SETREDRAW*/, true, 0);
  762.         oSys.Call("user32::InvalidateRect", hWndListBox, 0, true);
  763.  
  764.         updArgs();
  765.     }
  766.     function setListBoxSel(i) {
  767.         var context = selectContext;
  768.         if(context > 0) { // Trick to show context (items before/after selected)
  769.             var cur = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/, 0, 0);
  770.             var max = AkelPad.SendMessage(hWndListBox, 0x18B /*LB_GETCOUNT*/, 0, 0) - 1;
  771.  
  772.             var lpRect = max > 0 && AkelPad.MemAlloc(16); //sizeof(RECT)
  773.             var rcLB;
  774.             if(
  775.                 lpRect
  776.                 && AkelPad.SendMessage(hWndListBox, 0x198 /*LB_GETITEMRECT*/, Math.max(0, cur), lpRect) != -1 /*LB_ERR*/
  777.                 && (rcLB = getWindowRect(hWndListBox))
  778.             ) {
  779.                 var rcItem = parseRect(lpRect);
  780.                 var itemH = rcItem.top - rcItem.bottom;
  781.                 var lbH = rcLB.top - rcLB.bottom;
  782.                 var maxContext = Math.round(lbH/itemH/2) - 1;
  783.                 if(context > maxContext)
  784.                     context = maxContext;
  785.             }
  786.             lpRect && AkelPad.MemFree(lpRect);
  787.  
  788.             var ni = Math.max(0, Math.min(max, i + (i > cur ? 1 : -1)*context));
  789.             if(ni != i)
  790.                 AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/, ni, 0);
  791.         }
  792.         AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/, i, 0);
  793.     }
  794.     function updArgs() {
  795.         var str = getStringFromIndex(AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/, 0, 0));
  796.         if(!str) {
  797.             enableControls({
  798.                 exec: false,
  799.                 edit: false,
  800.                 ok:   false
  801.             });
  802.             return;
  803.         }
  804.         curName = str;
  805.         var args = updMultilineArgs(argsObj[str] || "");
  806.         setEditText(hWndArgs, args);
  807.         enableControls({
  808.             exec: str != WScript.ScriptName,
  809.             edit: true,
  810.             ok:   true
  811.         });
  812.     }
  813.     function enableControls(enable) {
  814.         var hWndFocused = oSys.Call("user32::GetFocus");
  815.         enabled(hWndExec, enable.exec);
  816.         enabled(hWndEdit, enable.edit);
  817.         enabled(hWndOK,   enable.ok);
  818.         if(
  819.             !enable.exec && hWndFocused == hWndExec
  820.             || !enable.edit && hWndFocused == hWndEdit
  821.             || !enable.ok && hWndFocused == hWndOK
  822.         )
  823.             oSys.Call("user32::SetFocus", hWndDialog);
  824.     }
  825.     function ensureTimers(callback, arg) {
  826.         var lib = "timer.js";
  827.         (ensureTimers = fso.FileExists(AkelPad.GetAkelDir(6 /*ADTYPE_INCLUDE*/) + "\\" + lib)
  828.             && AkelPad.Include(lib)
  829.             ? function(callback, arg) { callback(arg); }
  830.             : function() {})(callback, arg);
  831.     }
  832.     function notifyButton(hWndBtn) {
  833.         var moveFocus = oSys.Call("user32::GetFocus") == hWndBtn;
  834.         moveFocus && oSys.Call("user32::SetFocus", hWndArgs);
  835.         enabled(hWndBtn, false);
  836.         setTimeout(function() {
  837.             enabled(hWndBtn, true);
  838.             if(moveFocus && oSys.Call("user32::GetFocus") == hWndArgs)
  839.                 oSys.Call("user32::SetFocus", hWndBtn);
  840.         }, 500);
  841.     }
  842.     function ensureVisibility() {
  843.         var indx = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/, 0, 0);
  844.         if(indx != -1)
  845.             setListBoxSel(indx);
  846.     }
  847.     function navigate(up) {
  848.         var i = AkelPad.SendMessage(hWndListBox,  0x188 /*LB_GETCURSEL*/, 0, 0);
  849.         var max = AkelPad.SendMessage(hWndListBox,  0x18B /*LB_GETCOUNT*/, 0, 0) - 1;
  850.         if(up) {
  851.             if(--i < 0)
  852.                 i = max;
  853.         }
  854.         else {
  855.             if(++i > max)
  856.                 i = 0;
  857.         }
  858.         setListBoxSel(i);
  859.         postMessage(hWndDialog, 273 /*WM_COMMAND*/, IDC_LISTBOX, 0);
  860.     }
  861.     function setArgsLines(dl) {
  862.         argsLines += dl;
  863.         if(argsLines > ARGS_LINES_MAX) {
  864.             dl -= argsLines - ARGS_LINES_MAX;
  865.             argsLines = ARGS_LINES_MAX;
  866.         }
  867.         else if(argsLines < 1) {
  868.             dl += 1 - argsLines;
  869.             argsLines = 1;
  870.         }
  871.         var wasMultiline = argsMultiline;
  872.         argsMultiline = argsLines > 1;
  873.  
  874.         var noInc = argsLines == ARGS_LINES_MAX;
  875.         var noDec = argsLines == 1;
  876.         enabled(hWndArgsInc, !noInc);
  877.         enabled(hWndArgsDec, !noDec);
  878.         noInc && oSys.Call("user32::SetFocus", hWndArgsDec);
  879.         noDec && oSys.Call("user32::SetFocus", hWndArgsInc);
  880.         if(!dl)
  881.             return;
  882.  
  883.         AkelPad.SendMessage(hWndDialog, 11 /*WM_SETREDRAW*/, false, 0);
  884.         var rc, rcr;
  885.         if(
  886.             wasMultiline ^ argsMultiline
  887.             && (rc = getWindowRect(hWndArgs, hWndDialog))
  888.             && (rcr = getWindowRect(hWndArgs))
  889.         ) {
  890.             // Will re-create EDIT control,
  891.             // see https://docs.microsoft.com/en-US/windows/win32/controls/edit-control-styles
  892.             var args = updMultilineArgs(windowText(hWndArgs));
  893.             var restoreFocus = oSys.Call("user32::GetFocus") == hWndArgs;
  894.             destroyWindow(hWndArgs);
  895.             var ml = argsMultiline ? mlStyle : 0;
  896.             hWndArgs = oSys.Call(
  897.                 "user32::CreateWindowEx" + _TCHAR,
  898.                 0x200,                //WS_EX_CLIENTEDGE
  899.                 "EDIT",               //lpClassName
  900.                 0,                    //lpWindowName
  901.                 0x50010080|ml,        //WS_VISIBLE|WS_CHILD|WS_TABSTOP|ES_AUTOHSCROLL
  902.                 rc.left,              //x
  903.                 rc.top,               //y
  904.                 rcr.right - rcr.left, //nWidth
  905.                 rcr.bottom - rcr.top, //nHeight
  906.                 hWndDialog,           //hWndParent
  907.                 IDC_ARGS,             //ID
  908.                 hInstanceDLL,         //hInstance
  909.                 0                     //lpParam
  910.             );
  911.             setWindowFont(hWndArgs, hGuiFont);
  912.             setEditText(hWndArgs, args);
  913.             restoreFocus && oSys.Call("user32::SetFocus", hWndArgs);
  914.         }
  915.  
  916.         var dh = dl*scale.y(argsLineH);
  917.         resizeWindow(hWndArgs, 0, dh);
  918.         resizeWindow(hWndGroupArgs, 0, dh);
  919.         ignoreResize = true;
  920.         resizeWindow(hWndDialog, 0, dh);
  921.         ignoreResize = false;
  922.         AkelPad.SendMessage(hWndDialog, 11 /*WM_SETREDRAW*/, true, 0);
  923.         oSys.Call("user32::InvalidateRect", hWndDialog, 0, true);
  924.  
  925.         dlgMinH += dh;
  926.         dlgH += dh;
  927.     }
  928.     function updMultilineArgs(args) {
  929.         return argsMultiline
  930.             ? args.replace(/ (\r|\n)/g, "$1")
  931.             : args.replace(/ ?\r\n?| ?\n\r?/g, " \r\n");
  932.     }
  933.  
  934.     function restoreWindowPosition(hWnd, hWndParent) {
  935.         if(dlgX == undefined || dlgY == undefined) {
  936.             centerWindow(hWnd, hWndParent);
  937.             return;
  938.         }
  939.  
  940.         var rcWnd = getWindowRect(hWnd);
  941.         if(!rcWnd)
  942.             return;
  943.  
  944.         var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
  945.         if(!lpRect)
  946.             return;
  947.         AkelPad.MemCopy(_PtrAdd(lpRect,  0), dlgX,                              3 /*DT_DWORD*/);
  948.         AkelPad.MemCopy(_PtrAdd(lpRect,  4), dlgY,                              3 /*DT_DWORD*/);
  949.         AkelPad.MemCopy(_PtrAdd(lpRect,  8), dlgX + (rcWnd.right - rcWnd.left), 3 /*DT_DWORD*/);
  950.         AkelPad.MemCopy(_PtrAdd(lpRect, 12), dlgY + (rcWnd.top - rcWnd.bottom), 3 /*DT_DWORD*/);
  951.         var hMonitor = oSys.Call("user32::MonitorFromRect", lpRect, 0x2 /*MONITOR_DEFAULTTONEAREST*/);
  952.  
  953.         if(hMonitor) {
  954.             //typedef struct tagMONITORINFO {
  955.             //  DWORD cbSize;
  956.             //  RECT  rcMonitor;
  957.             //  RECT  rcWork;
  958.             //  DWORD dwFlags;
  959.             //} MONITORINFO, *LPMONITORINFO;
  960.             var sizeofMonitorInfo = 4 + 16 + 16 + 4;
  961.             var lpMi = AkelPad.MemAlloc(sizeofMonitorInfo);
  962.             if(lpMi) {
  963.                 AkelPad.MemCopy(lpMi, sizeofMonitorInfo, 3 /*DT_DWORD*/);
  964.                 oSys.Call("user32::GetMonitorInfo" + _TCHAR, hMonitor, lpMi);
  965.                 var rcWork = parseRect(_PtrAdd(lpMi, 4 + 16));
  966.                 AkelPad.MemFree(lpMi);
  967.             }
  968.         }
  969.         else { //?
  970.             oSys.Call("user32::SystemParametersInfo" + _TCHAR, 48 /*SPI_GETWORKAREA*/, 0, lpRect, 0);
  971.             var rcWork = parseRect(lpRect);
  972.         }
  973.         AkelPad.MemFree(lpRect);
  974.  
  975.         if(rcWork) {
  976.             var edge = Math.max(
  977.                 16,
  978.                 oSys.Call("user32::GetSystemMetrics", 33 /*SM_CYSIZEFRAME*/)
  979.                     + oSys.Call("user32::GetSystemMetrics", 4 /*SM_CYCAPTION*/)
  980.             );
  981.  
  982.             var minX = rcWork.left - (rcWnd.right - rcWnd.left) + edge;
  983.             var minY = rcWork.top;
  984.             var maxX = rcWork.right - edge;
  985.             var maxY = rcWork.bottom - edge;
  986.  
  987.             dlgX = Math.max(minX, Math.min(maxX, dlgX));
  988.             dlgY = Math.max(minY, Math.min(maxY, dlgY));
  989.         }
  990.  
  991.         moveWindow(hWnd, dlgX, dlgY);
  992.     }
  993.     function centerWindow(hWnd, hWndParent) {
  994.         var rcWnd = getWindowRect(hWnd);
  995.         var rcWndParent = getWindowRect(hWndParent || oSys.Call("user32::GetDesktopWindow"));
  996.         if(!rcWndParent || !rcWnd)
  997.             return;
  998.         var x = rcWndParent.left + ((rcWndParent.right  - rcWndParent.left) / 2 - (rcWnd.right  - rcWnd.left) / 2);
  999.         var y = rcWndParent.top  + ((rcWndParent.bottom - rcWndParent.top)  / 2 - (rcWnd.bottom - rcWnd.top)  / 2);
  1000.         moveWindow(hWnd, x, y);
  1001.     }
  1002.     function moveWindow(hWnd, x, y, hWndParent) {
  1003.         if(hWndParent) {
  1004.             var rcWnd = getWindowRect(hWnd, hWndParent);
  1005.             if(rcWnd) {
  1006.                 x += rcWnd.left;
  1007.                 y += rcWnd.top;
  1008.             }
  1009.         }
  1010.         oSys.Call("user32::SetWindowPos", hWnd, 0, x, y, 0, 0, 0x15 /*SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE*/);
  1011.     }
  1012.     function resizeWindow(hWnd, dw, dh) {
  1013.         var rcWnd = getWindowRect(hWnd);
  1014.         if(!rcWnd)
  1015.             return;
  1016.         var w = rcWnd.right - rcWnd.left + dw;
  1017.         var h = rcWnd.bottom - rcWnd.top + dh;
  1018.         oSys.Call("user32::SetWindowPos", hWnd, 0, 0, 0, w, h, 0x16 /*SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE*/);
  1019.     }
  1020.     function resizeDialog(hWnd, curW, curH) {
  1021.         var dw = curW - dlgW;
  1022.         var dh = curH - dlgH;
  1023.  
  1024.         resizeWindow(hWndListBox, dw, dh);
  1025.  
  1026.         resizeWindow(hWndGroupArgs, dw, 0);
  1027.         resizeWindow(hWndArgs,      dw, 0);
  1028.         moveWindow(hWndGroupArgs, 0, dh, hWnd);
  1029.         moveWindow(hWndArgs,      0, dh, hWnd);
  1030.  
  1031.         moveWindow(hWndArgsInc, dw, dh, hWnd);
  1032.         moveWindow(hWndArgsDec, dw, dh, hWnd);
  1033.  
  1034.         moveWindow(hWndOK,     dw, 0, hWnd);
  1035.         moveWindow(hWndExec,   dw, 0, hWnd);
  1036.         moveWindow(hWndEdit,   dw, 0, hWnd);
  1037.         moveWindow(hWndCancel, dw, 0, hWnd);
  1038.  
  1039.         dlgW = curW;
  1040.         dlgH = curH;
  1041.  
  1042.         oSys.Call("user32::InvalidateRect", hWnd, 0, true);
  1043.     }
  1044.     function getWindowRect(hWnd, hWndParent) {
  1045.         var lpRect = AkelPad.MemAlloc(16); //sizeof(RECT)
  1046.         getRect: if(lpRect) {
  1047.             if(!oSys.Call("user32::GetWindowRect", hWnd, lpRect))
  1048.                 break getRect;
  1049.             if(hWndParent && !oSys.Call("user32::ScreenToClient", hWndParent, lpRect))
  1050.                 break getRect;
  1051.             var rcWnd = parseRect(lpRect);
  1052.         }
  1053.         lpRect && AkelPad.MemFree(lpRect);
  1054.         return rcWnd;
  1055.     }
  1056.     function parseRect(lpRect) {
  1057.         return {
  1058.             left:   AkelPad.MemRead(_PtrAdd(lpRect,  0), 3 /*DT_DWORD*/),
  1059.             top:    AkelPad.MemRead(_PtrAdd(lpRect,  4), 3 /*DT_DWORD*/),
  1060.             right:  AkelPad.MemRead(_PtrAdd(lpRect,  8), 3 /*DT_DWORD*/),
  1061.             bottom: AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/)
  1062.         };
  1063.     }
  1064.  
  1065.     function getStringFromIndex(i) {
  1066.         if(i == -1 || i == undefined)
  1067.             return "";
  1068.         var len = AkelPad.SendMessage(hWndListBox, 0x18A /*LB_GETTEXTLEN*/, i, 0);
  1069.         var lpString = AkelPad.MemAlloc((len + 1)*_TSIZE);
  1070.         if(!lpString)
  1071.             return "";
  1072.         AkelPad.SendMessage(hWndListBox, 0x189 /*LB_GETTEXT*/, i, lpString);
  1073.         var str = AkelPad.MemRead(lpString, _TSTR);
  1074.         AkelPad.MemFree(lpString);
  1075.         return str;
  1076.     }
  1077.     function getIndexFromString(str) {
  1078.         // Note: not case sensitive!
  1079.         return AkelPad.SendMessage(hWndListBox, 0x1A2 /*LB_FINDSTRINGEXACT*/, -1, str);
  1080.     }
  1081.  
  1082.     function windowText(hWnd, pText) {
  1083.         if(arguments.length > 1)
  1084.             return oSys.Call("user32::SetWindowText" + _TCHAR, hWnd, pText);
  1085.         var len = oSys.Call("user32::GetWindowTextLength" + _TCHAR, hWnd);
  1086.         var lpText = AkelPad.MemAlloc((len + 1)*_TSIZE);
  1087.         if(!lpText)
  1088.             return "";
  1089.         oSys.Call("user32::GetWindowText" + _TCHAR, hWnd, lpText, len + 1);
  1090.         pText = AkelPad.MemRead(lpText, _TSTR);
  1091.         AkelPad.MemFree(lpText);
  1092.         return pText;
  1093.     }
  1094.     function setWindowFont(hWnd, hFont) {
  1095.         AkelPad.SendMessage(hWnd, 48 /*WM_SETFONT*/, hFont, true);
  1096.     }
  1097.     function setWindowFontAndText(hWnd, hFont, pText) {
  1098.         setWindowFont(hWnd, hFont);
  1099.         windowText(hWnd, pText);
  1100.     }
  1101.     function setEditText(hWnd, pText, selectAll) {
  1102.         windowText(hWnd, pText);
  1103.         pText && AkelPad.SendMessage(hWnd, 177 /*EM_SETSEL*/, selectAll ? 0 : pText.length, -1);
  1104.     }
  1105.     function enabled(hWnd, val) {
  1106.         oSys.Call("user32::EnableWindow", hWnd, val);
  1107.     }
  1108.     function destroyWindow(hWnd) {
  1109.         oSys.Call("user32::DestroyWindow", hWnd);
  1110.     }
  1111.     function closeDialog() {
  1112.         postMessage(hWndDialog, 16 /*WM_CLOSE*/, 0, 0);
  1113.     }
  1114.     function postMessage(hWnd, msg, wParam, lParam) {
  1115.         oSys.Call("user32::PostMessage" + _TCHAR, hWnd, msg, wParam, lParam);
  1116.     }
  1117.     function Scale(hDC, hWnd) {
  1118.         var hNewDC = hDC || oSys.Call("user32::GetDC", hWnd);
  1119.         if(hNewDC) {
  1120.             this._x = oSys.Call("gdi32::GetDeviceCaps", hNewDC, 88 /*LOGPIXELSX*/);
  1121.             this._y = oSys.Call("gdi32::GetDeviceCaps", hNewDC, 90 /*LOGPIXELSY*/);
  1122.  
  1123.             //Align to 16 pixel
  1124.             this._x += (16 - this._x % 16) % 16;
  1125.             this._y += (16 - this._y % 16) % 16;
  1126.  
  1127.             !hDC && oSys.Call("user32::ReleaseDC", hWnd, hNewDC);
  1128.  
  1129.             this.x = function(x) {
  1130.                 return oSys.Call("kernel32::MulDiv", x, this._x, 96);
  1131.             };
  1132.             this.y = function(y) {
  1133.                 return oSys.Call("kernel32::MulDiv", y, this._y, 96);
  1134.             };
  1135.         }
  1136.         else {
  1137.             this.x = this.y = function(n) {
  1138.                 return n;
  1139.             };
  1140.         }
  1141.     }
  1142.     function createWindowEx(
  1143.         dwExStyle, lpClassName, lpWindowName, dwStyle,
  1144.         x, y, w, h,
  1145.         hWndParent, id, hInstance, callback
  1146.     ) {
  1147.         return oSys.Call(
  1148.             "user32::CreateWindowEx" + _TCHAR,
  1149.             dwExStyle, lpClassName, lpWindowName, dwStyle,
  1150.             scale.x(x), scale.y(y),
  1151.             scale.x(w), scale.y(h),
  1152.             hWndParent, id, hInstance, callback || 0
  1153.         );
  1154.     }
  1155.  
  1156.     modal && enabled(hMainWnd, false); // Disable main window, to make dialog modal
  1157.  
  1158.     AkelPad.ScriptNoMutex(); // Allow other scripts running
  1159.     AkelPad.WindowGetMessage(); // Message loop
  1160.  
  1161.     AkelPad.WindowUnregisterClass(dialogClass);
  1162.  
  1163.     selfRun && AkelPad.Call("Scripts::Main", 1, WScript.ScriptName, expandArgs(argsObj[curName] || ""));
  1164. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement