How to create a menu from a ListBox

Just starting out? Need help? Post your questions and find answers here.
AZJIO
Addict
Addict
Posts: 2183
Joined: Sun May 14, 2017 1:48 am

How to create a menu from a ListBox

Post by AZJIO »

There is a JavaScript code for AkelPad that simulates a pop-up menu. I'm trying to convert it to PureBasic, but some functions, such as AkelPad.ThreadHook, AkelPad.WindowSubClass, AkelPad.ScriptNoMutex, etc., require intuition to create their counterparts.

JavaScript

Code: Select all

// https://akelpad.sourceforge.net/forum/viewtopic.php?p=35182#p35182
// Author: The script remade Azjio from the Tabswitch.js script from Instructor
//
//
// Description(1033): Closes tabs of the specified type, for example, all htm files
// Description(1049): Закрывает вкладки определённого типа, например все htm-файлы
//
// Arguments:
// -CtrlTab=false       -No Ctrl+Tab hotkey is assigned to TabSwitch.js (default is true).
// -MinTabs=2           -Minimum number of tabs before switch window appeared (default is 2).
// -FontName="Arial"    -Font name. Unchanged, if "".
// -FontStyle=3         -Font style (one of the following):
//                         0  ignored (default).
//                         1  normal.
//                         2  bold.
//                         3  italic.
//                         4  bold italic.
// -FontSize=10         -Font size. Unchanged, if 0 (default).
// -LineGap=10          -Space between items (default is 1).
// -SingleClick=false   -Single mouse click chooses item (default is true).
// -ShowModify=2        -Show modification sign (one of the following):
//                         0  hidden.
//                         1  display asterisk * at the end (default).
//                         2  display asterisk * at the beginning.
// -WindowLeft=100      -Left window position. Special values:
//                        -1 centered (default).
//                        -2 cursor position.
// -WindowTop=100       -Top window position. Special values:
//                        -1 centered (default).
//                        -2 cursor position.
// -WindowMaxHeight=500 -Maximum window height. Special values:
//                        -1 unlimited (default).
// -WindowMaxWidth=500  -Maximum window width. Special values:
//                        -1 unlimited (default).
//
// Usage:
// Toolbar button example:
//   -"Close tabs by extension" Call("Scripts::Main", 1, "CloseTabByExt.js", `-CtrlTab=false -MinTabs=1 -WindowLeft=%bl -WindowTop=%bb`)
// ContextMenu item example:
//   -"Close tabs by extension" Call("Scripts::Main", 1, "CloseTabByExt.js", `-CtrlTab=false -MinTabs=1 -WindowLeft=-2 -WindowTop=-2`)

//Arguments
var bCtrlTab = AkelPad.GetArgValue("CtrlTab", true);
var nMinTabs = AkelPad.GetArgValue("MinTabs", 2);
var pFontName = AkelPad.GetArgValue("FontName", "");
var nFontStyle = AkelPad.GetArgValue("FontStyle", 0);
var nFontSize = AkelPad.GetArgValue("FontSize", 0);
var nLineGap = AkelPad.GetArgValue("LineGap", 1);
var bSingleClick = AkelPad.GetArgValue("SingleClick", true);
var nWindowLeft = AkelPad.GetArgValue("WindowLeft", -1);
var nWindowTop = AkelPad.GetArgValue("WindowTop", -1);
var nWindowMaxHeight = AkelPad.GetArgValue("WindowMaxHeight", -1);
var nWindowMaxWidth = AkelPad.GetArgValue("WindowMaxWidth", -1);
var bAsk = AkelPad.GetArgValue("Ask", false);

//Variables
var hMainWnd = AkelPad.GetMainWnd();
var hWndEdit = AkelPad.GetEditWnd();
var oSys = AkelPad.SystemFunction();
var hInstanceDLL = AkelPad.GetInstanceDll();
var pClassName = "AkelPad::Scripts::" + WScript.ScriptName + "::" + oSys.Call("kernel32::GetCurrentProcessId");
var hWndContainer = 0;
var hWndListBox = 0;
var hHookPost;
var hHookSend;
var dwMainThreadID = oSys.Call("user32::GetWindowThreadProcessId", hMainWnd, 0);
var hSubClass;
var hDC;
var hBrushHollow;
var hFontEdit;
var lpFrameList = [];
var lpAllList = [];
var rcMain = [];
var ptPoint = [];
var nItemHeight;
var nScreenWidth;
var nControlWidth;
var nControlHeight;
var nMaxControlHeight;
var nCharWidth;
var nCharHeight;
var nMaxCharWidth = 0;
var nMaxCharHeight = 0;
var nIconSize = 16;
var nIconGap = 2;
var bNoSwitch = false;
var i;



//Get list of documents
nCurSel = GetFrameList(lpFrameList, lpAllList);
// WScript.Echo(lpFrameList.length);
if (lpFrameList.length > 0)
// if (lpFrameList.length >= nMinTabs && lpFrameList.length > 0)
{

	//Get font
	if (pFontName || nFontStyle || nFontSize)
		hFontEdit = CreateFont(pFontName, nFontStyle, nFontSize);
	else
		hFontEdit = AkelPad.SendMessage(hWndEdit, 0x31 /*WM_GETFONT*/ , 0, 0);
	if (!hFontEdit) WScript.Quit();

	//Get maximum character size
	if (lpSize = AkelPad.MemAlloc(8 /*sizeof(SIZE)*/ )) {
		if (hDC = oSys.Call("user32::GetDC", hWndEdit)) {
			oSys.Call("gdi32::SelectObject", hDC, hFontEdit);

			for (i = 0; i < lpFrameList.length; ++i) {
				if (oSys.Call("gdi32::GetTextExtentPoint32" + _TCHAR, hDC, lpFrameList[i][0], lpFrameList[i][0].length, lpSize)) {
					nCharWidth = AkelPad.MemRead(_PtrAdd(lpSize, 0) /*offsetof(SIZE, cx)*/ , 3 /*DT_DWORD*/ );
					nCharHeight = AkelPad.MemRead(_PtrAdd(lpSize, 4) /*offsetof(SIZE, cy)*/ , 3 /*DT_DWORD*/ );
					if (nCharWidth > nMaxCharWidth) nMaxCharWidth = nCharWidth;
					if (nCharHeight > nMaxCharHeight) nMaxCharHeight = nCharHeight;
				}
			}
			oSys.Call("user32::ReleaseDC", hWndEdit, hDC);
		}
		nMaxCharWidth += nIconSize + nIconGap + 16;

		AkelPad.MemFree(lpSize);
	}

	//Create dialog
	if (AkelPad.WindowRegisterClass(pClassName, 0x21 /*WM_MOUSEACTIVATE*/ ,
			0x2B /*WM_DRAWITEM*/ )) {
		if (hWndContainer = oSys.Call("user32::CreateWindowEx" + _TCHAR, 0, pClassName, 0, 0x80000000 /*WS_POPUP*/ , 0, 0, 0, 0, hMainWnd, 0, hInstanceDLL, DialogCallback)) {
			if (hWndListBox = oSys.Call("user32::CreateWindowEx" + _TCHAR, 0, "LISTBOX", 0, 0x50700010 /*WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL|WS_DLGFRAME|LBS_OWNERDRAWFIXED*/ , 0, 0, 0, 0, hWndContainer, 0, hInstanceDLL, 0)) {
				//Make hWndContainer invisible
				hBrushHollow = oSys.Call("gdi32::GetStockObject", 5 /*HOLLOW_BRUSH*/ );
				oSys.Call("user32::SetClassLong" + _TCHAR, hWndContainer, -10 /*GCL_HBRBACKGROUND*/ , hBrushHollow);

				AkelPad.SendMessage(hWndListBox, 48 /*WM_SETFONT*/ , hFontEdit, 1);
				nItemHeight = nMaxCharHeight + nLineGap;
				i = AkelPad.SendMessage(hWndListBox, 0x1A1 /*LB_GETITEMHEIGHT*/ , 0, 0);
				if (nItemHeight < i)
					nItemHeight = i;
				else
					AkelPad.SendMessage(hWndListBox, 0x1A0 /*LB_SETITEMHEIGHT*/ , 0, nItemHeight);
				nMaxControlHeight = lpFrameList.length * nItemHeight + oSys.Call("user32::GetSystemMetrics", 8 /*SM_CYDLGFRAME*/ ) * 2;
				if (nWindowMaxHeight > 0)
					nControlHeight = Math.min(nWindowMaxHeight, nMaxControlHeight);
				else
					nControlHeight = nMaxControlHeight;
				nControlHeight = Math.min(oSys.Call("user32::GetSystemMetrics", 62 /*SM_CYMAXIMIZED*/ ) - 8, nControlHeight);
				if (nWindowMaxWidth > 0)
					nControlWidth = Math.min(nWindowMaxWidth, nMaxCharWidth);
				else
					nControlWidth = nMaxCharWidth;
				nControlWidth = Math.min(oSys.Call("user32::GetSystemMetrics", 61 /*SM_CXMAXIMIZED*/ ) - 8, nControlWidth);

				if (nMaxCharWidth > nControlWidth) {
					AkelPad.SendMessage(hWndListBox, 0x194 /*LB_SETHORIZONTALEXTENT*/ , nMaxCharWidth, 0);
					if (nMaxControlHeight == nControlHeight)
						nControlHeight += oSys.Call("user32::GetSystemMetrics", 21 /*SM_CXHSCROLL*/ );
				}

				//Fill listbox
				for (i = 0; i < lpFrameList.length; ++i)
					oSys.Call("user32::SendMessage" + _TCHAR, hWndListBox, 0x180 /*LB_ADDSTRING*/ , 0, lpFrameList[i][0]);

				GetWindowSize(hMainWnd, 0, rcMain);
				if (nWindowLeft >= 0)
					rcMain.left = nWindowLeft;
				else if (nWindowLeft == -2) {
					GetCursorPos(ptPoint);
					rcMain.left = ptPoint.x;
				} else
					rcMain.left += rcMain.right / 2 - nControlWidth / 2;
				if (!(nScreenWidth = oSys.Call("user32::GetSystemMetrics", 78 /*SM_CXVIRTUALSCREEN*/ )))
					nScreenWidth = oSys.Call("user32::GetSystemMetrics", 61 /*SM_CXMAXIMIZED*/ );
				rcMain.left = Math.min(rcMain.left, Math.max((nScreenWidth - 8) - nControlWidth, 0));
				if (rcMain.left < 0) rcMain.left = 0;

				if (nWindowTop >= 0)
					rcMain.top = nWindowTop;
				else if (nWindowTop == -2) {
					GetCursorPos(ptPoint);
					rcMain.top = ptPoint.y;
				} else
					rcMain.top += rcMain.bottom / 2 - nControlHeight / 2;
				rcMain.top = Math.min(rcMain.top, Math.max((oSys.Call("user32::GetSystemMetrics", 62 /*SM_CYMAXIMIZED*/ ) - 8) - nControlHeight, 0));
				if (rcMain.top < 0) rcMain.top = 0;

				oSys.Call("user32::SetWindowPos", hWndContainer, 0, rcMain.left, rcMain.top, nControlWidth, nControlHeight, 0x14 /*SWP_NOZORDER|SWP_NOACTIVATE*/ );
				oSys.Call("user32::SetWindowPos", hWndListBox, 0, 0, 0, nControlWidth, nControlHeight, 0x16 /*SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE*/ );
				AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , nCurSel, 0);
				oSys.Call("user32::ShowWindow", hWndContainer, 4 /*SW_SHOWNOACTIVATE*/ );
				//oSys.Call("user32::SetFocus", hWndListBox);
				//oSys.Call("user32::ShowWindow", hWndContainer, 5 /*SW_SHOW*/);
				//oSys.Call("user32::UpdateWindow", hMainWnd);

				//Cause listbox is non-active, hook and send to listbox keyboard and mouse actions.
				if (hHookPost = AkelPad.ThreadHook(3 /*WH_GETMESSAGE*/ , HookPostCallback, dwMainThreadID, 0x201 /*WM_LBUTTONDOWN*/ ,
						0x0A1 /*WM_NCLBUTTONDOWN*/ ,
						0x204 /*WM_RBUTTONDOWN*/ ,
						0x0A4 /*WM_NCRBUTTONDOWN*/ ,
						0x207 /*WM_MBUTTONDOWN*/ ,
						0x0A7 /*WM_NCMBUTTONDOWN*/ ,
						0x100 /*WM_KEYDOWN*/ ,
						0x101 /*WM_KEYUP*/ ,
						0x104 /*WM_SYSKEYDOWN*/ ,
						0x105 /*WM_SYSKEYUP*/ ,
						0x20A /*WM_MOUSEWHEEL*/ )) {
					if (hHookSend = AkelPad.ThreadHook(4 /*WH_CALLWNDPROC*/ , HookSendCallback, dwMainThreadID, 0x6 /*WM_SETFOCUS*/ )) {
						if (hSubClass = AkelPad.WindowSubClass(hWndListBox, ListBoxCallback, 0x021 /*WM_MOUSEACTIVATE*/ ,
								0x087 /*WM_GETDLGCODE*/ ,
								0x100 /*WM_KEYDOWN*/ ,
								0x101 /*WM_KEYUP*/ ,
								0x201 /*WM_LBUTTONDOWN*/ ,
								0x202 /*WM_LBUTTONUP*/ ,
								0x203 /*WM_LBUTTONDBLCLK*/ )) {
							//Allow other scripts running
							AkelPad.ScriptNoMutex();

							//Message loop
							AkelPad.WindowGetMessage();

							AkelPad.WindowUnsubClass(hWndListBox);
						}
						AkelPad.ThreadUnhook(hHookSend);
					}
					AkelPad.ThreadUnhook(hHookPost);
				}

				if (!bNoSwitch) {
					i = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0);
					// oSys.Call("user32::PostMessage" + _TCHAR, hMainWnd, 1285 /*AKD_FRAMEACTIVATE*/ , 0, lpFrameList[i][1]);
					// Редактируемый участок 1
					var Pos;
					var Ext;
					Pos = lpFrameList[i][0].indexOf(" - ")
					Ext = lpFrameList[i][0].substr(Pos + 3)
					if (bAsk)
					{
						var mess = "";
						for (i = 0; i < lpAllList.length; ++i) {
							if (Ext === lpAllList[i][0])
							{
								mess += AkelPad.GetFilePath(lpAllList[i][2], 2) + "\n";
							}
						}
						if (AkelPad.MessageBox(hMainWnd, mess, "Закрыть эти вкладки?", 32, 0, 1 , "&OK", 0x1 , 2 , "&Cancel", 0) == 1)
						{
							for (i = 0; i < lpAllList.length; ++i) {
								if (Ext === lpAllList[i][0])
								{
									oSys.Call("user32::PostMessage" + _TCHAR, hMainWnd, 1287 /*AKD_FRAMEDESTROY*/ , 0, lpAllList[i][1]);
								}
							}
						}
					} else {
						for (i = 0; i < lpAllList.length; ++i) {
							if (Ext === lpAllList[i][0])
							{
								oSys.Call("user32::PostMessage" + _TCHAR, hMainWnd, 1287 /*AKD_FRAMEDESTROY*/ , 0, lpAllList[i][1]);
							}
						}
					}
					// Конец Редактируемый участок 1
				}
				//oSys.Call("user32::DestroyWindow", hWndListBox);
			}
			oSys.Call("user32::DestroyWindow", hWndContainer);
		}
		AkelPad.WindowUnregisterClass(pClassName);
	}

	//Release font
	if (pFontName || nFontStyle || nFontSize) {
		if (hFontEdit)
			oSys.Call("gdi32::DeleteObject", hFontEdit);
	}
} else {
	if (lpFrameList.length >= 2)
		oSys.Call("user32::PostMessage" + _TCHAR, hMainWnd, 1285 /*AKD_FRAMEACTIVATE*/ , 0, lpFrameList[nCurSel][1]);
}

function DialogCallback(hWnd, uMsg, wParam, lParam) {
	if (uMsg == 0x021 /*WM_MOUSEACTIVATE*/ ) {
		return 3 /*MA_NOACTIVATE*/ ;
	} else if (uMsg == 0x2B /*WM_DRAWITEM*/ ) {
		var hDC;
		var hIcon;
		var nItemID;
		var nItemState;
		var lpItem;
		var rcItem = [];
		var crText;
		var crBk;
		var hBrushBk;
		var nModeBkOld;

		hDC = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 32 : 24) /*offsetof(DRAWITEMSTRUCT, hDC)*/ , 2 /*DT_QWORD*/ );
		nItemID = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 8 : 8) /*offsetof(DRAWITEMSTRUCT, itemID)*/ , 3 /*DT_DWORD*/ );
		nItemState = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 16) /*offsetof(DRAWITEMSTRUCT, itemState)*/ , 3 /*DT_DWORD*/ );
		lpItem = _PtrAdd(lParam, _X64 ? 40 : 28) /*offsetof(DRAWITEMSTRUCT, rcItem)*/ ;
		RectToArray(lpItem, rcItem);

		//Set background
		if (nItemState & 0x1 /*ODS_SELECTED*/ ) {
			crText = oSys.Call("user32::GetSysColor", 14 /*COLOR_HIGHLIGHTTEXT*/ );
			crBk = oSys.Call("user32::GetSysColor", 13 /*COLOR_HIGHLIGHT*/ );
			hBrushBk = oSys.Call("user32::GetSysColorBrush", 13 /*COLOR_HIGHLIGHT*/ );
		} else {
			crText = oSys.Call("user32::GetSysColor", 8 /*COLOR_WINDOWTEXT*/ );
			crBk = oSys.Call("user32::GetSysColor", 5 /*COLOR_WINDOW*/ );
			hBrushBk = oSys.Call("user32::GetSysColorBrush", 5 /*COLOR_WINDOW*/ );
		}
		oSys.Call("user32::FillRect", hDC, lpItem, hBrushBk);
		nModeBkOld = oSys.Call("gdi32::SetBkMode", hDC, 1 /*TRANSPARENT*/ );

		//Draw icon
		hIcon = AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/ , 38 /*FI_ICONHANDLE*/ , lpFrameList[nItemID][1]);
		oSys.Call("user32::DrawIconEx", hDC, rcItem.left, rcItem.top + (rcItem.bottom - rcItem.top) / 2 - nIconSize / 2, hIcon, nIconSize, nIconSize, 0, 0, 0x3 /*DI_NORMAL*/ );

		//Draw text
		oSys.Call("gdi32::SetTextColor", hDC, crText);
		oSys.Call("gdi32::SetBkColor", hDC, crBk);
		oSys.Call("gdi32::TextOut" + _TCHAR, hDC, rcItem.left + nIconSize + nIconGap, rcItem.top + (rcItem.bottom - rcItem.top) / 2 - nMaxCharHeight / 2, lpFrameList[nItemID][0], lpFrameList[nItemID][0].length);

		oSys.Call("gdi32::SetBkMode", hDC, nModeBkOld);
	}
	return 0;
}

function HookPostCallback(nCode, wParam, lParam) {
	var uMsg = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 8 : 4) /*offsetof(MSG, message)*/ , 3 /*DT_DWORD*/ );
	var nParamW;
	var nParamL;

	if (uMsg == 0x201 /*WM_LBUTTONDOWN*/ ||
		uMsg == 0x0A1 /*WM_NCLBUTTONDOWN*/ ||
		uMsg == 0x204 /*WM_RBUTTONDOWN*/ ||
		uMsg == 0x0A4 /*WM_NCRBUTTONDOWN*/ ||
		uMsg == 0x207 /*WM_MBUTTONDOWN*/ ||
		uMsg == 0x0A7 /*WM_NCMBUTTONDOWN*/ ) {
		var hWnd = AkelPad.MemRead(_PtrAdd(lParam, 0) /*offsetof(MSG, hwnd)*/ , 2 /*DT_QWORD*/ );

		if (hWnd != hWndListBox) {
			//Not in rect
			bNoSwitch = true;

			//Exit message loop
			oSys.Call("user32::PostQuitMessage", 0);
		}
	} else if (uMsg == 0x100 /*WM_KEYDOWN*/ ||
		uMsg == 0x101 /*WM_KEYUP*/ ||
		uMsg == 0x104 /*WM_SYSKEYDOWN*/ ||
		uMsg == 0x105 /*WM_SYSKEYUP*/ ||
		uMsg == 0x20A /*WM_MOUSEWHEEL*/ ) {
		nParamW = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8) /*offsetof(MSG, nParamW)*/ , 2 /*DT_QWORD*/ );
		nParamL = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 24 : 12) /*offsetof(MSG, lParam)*/ , 2 /*DT_QWORD*/ );
		AkelPad.SendMessage(hWndListBox, uMsg, nParamW, nParamL);
		AkelPad.MemCopy(_PtrAdd(lParam, _X64 ? 8 : 4) /*offsetof(MSG, message)*/ , 0 /*WM_NULL*/ , 3 /*DT_DWORD*/ );
	}
}

function HookSendCallback(nCode, wParam, lParam) {
	var uMsg = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8) /*offsetof(CWPSTRUCT, message)*/ , 3 /*DT_DWORD*/ );
	var nParamW;
	var nParamL;

	if (uMsg == 0x6 /*WM_SETFOCUS*/ ) {
		bNoSwitch = true;

		//Exit message loop
		oSys.Call("user32::PostQuitMessage", 0);
	}
}

function ListBoxCallback(hWnd, uMsg, wParam, lParam) {
	if (uMsg == 0x021 /*WM_MOUSEACTIVATE*/ ) {
		return 3 /*MA_NOACTIVATE*/ ;
	} else if (uMsg == 0x087 /*WM_GETDLGCODE*/ ) {
		AkelPad.WindowNoNextProc(hSubClass);
		return 0x4 /*DLGC_WANTALLKEYS*/ ;
	} else if (uMsg == 0x100 /*WM_KEYDOWN*/ ) {
		if (wParam == 0x43 /*c*/ ) {
			if (bCtrlTab || (oSys.Call("user32::GetKeyState", 0x11 /*VK_CONTROL*/ ) & 0x8000)) {
				i = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0);
				AkelPad.SetClipboardText(lpFrameList[i][0]);
			}
		} else if (wParam == 0x9 /*VK_TAB*/ ) {
			var nCount;

			nCount = AkelPad.SendMessage(hWndListBox, 0x18B /*LB_GETCOUNT*/ , 0, 0);
			i = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0);

			if (!(oSys.Call("user32::GetKeyState", 0x10 /*VK_SHIFT*/ ) & 0x8000)) {
				if (++i >= nCount)
					i = 0;
			} else {
				if (--i < 0)
					i = nCount - 1;
			}
			AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , i, 0);
		} else if (wParam == 0xD /*VK_RETURN*/ ) {
			//Exit message loop
			oSys.Call("user32::PostQuitMessage", 0);
		} else if (wParam == 0x1B /*VK_ESCAPE*/ ) {
			bNoSwitch = true;

			//Exit message loop
			oSys.Call("user32::PostQuitMessage", 0);
		}
	} else if (uMsg == 0x101 /*WM_KEYUP*/ ) {
		if (wParam == 0x11 /*VK_CONTROL*/ ) {
			if (bCtrlTab) {
				//Exit message loop
				oSys.Call("user32::PostQuitMessage", 0);
			}
		}
	} else if (uMsg == 0x201 /*WM_LBUTTONDOWN*/ ) {
		var lResult = AkelPad.SendMessage(hWndListBox, 0x01A9 /*LB_ITEMFROMPOINT*/ , 0, lParam);

		if (HIWORD(lResult) == 0)
			AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , LOWORD(lResult), 0);
		AkelPad.WindowNoNextProc(hSubClass);
	} else if (uMsg == 0x202 /*WM_LBUTTONUP*/ ||
		uMsg == 0x203 /*WM_LBUTTONDBLCLK*/ ) {
		if (uMsg == 0x203 /*WM_LBUTTONDBLCLK*/ || bSingleClick) {
			//Exit message loop
			oSys.Call("user32::PostQuitMessage", 0);
		}
	}
}

function GetFrameList(lpFrameList, lpAllList) {
	// var lpCurFrame=AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/, 1 /*FWF_CURRENT*/, 0);
	var lpInitFrame;
	var lpFrame;
	var pNumFind;
	var pStrFind = ":";
	var i;
	var j;
	var n;

	// Редактируемый участок 2
	lpInitFrame = AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/ , 8 /*FWF_BYTABINDEX*/ , 0);
	lpFrame = lpInitFrame;

	j = -1
	for (i = 0; lpFrame; ++i) {

		lpAllList[i] = [0, 0];
		lpAllList[i][0] = AkelPad.GetFilePath(AkelPad.MemRead(AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/ , 32 /*FI_FILEW*/ , lpFrame), 1 /*DT_UNICODE*/ ), 4 /*расширение*/ );
		lpAllList[i][1] = lpFrame;
		lpAllList[i][2] = AkelPad.MemRead(AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/ , 32 /*FI_FILEW*/ , lpFrame), 1 /*DT_UNICODE*/ );

// Если не найден то добавляем, иначе добавляем +1 к количеству, делая подсчёт однотипных
		if (pStrFind.indexOf(":" + lpAllList[i][0] + ":") === -1) {
			pStrFind += lpAllList[i][0] + ":"
			j += 1
			lpFrameList[j] = [0, 0];
			lpFrameList[j][0] = lpAllList[i][0];
			lpFrameList[j][1] = lpFrame;
// 			if (typeof(lpFrameList[j][2]) == "undefined") {
// 				lpFrameList[j][2] = 0
// 			}
			lpFrameList[j][2] = 1;
		} else {
			for (n = 0; n < lpFrameList.length; ++n) {
				if (lpAllList[i][0] === lpFrameList[n][0])
					lpFrameList[n][2] += 1;
			}
		}
		lpFrame = AkelPad.SendMessage(hMainWnd, 1288 /*AKD_FRAMEFIND*/ , 8 /*FWF_BYTABINDEX*/ , i + 1);
		if (lpFrame == lpInitFrame) break;
	}
	lpFrameList.sort(SortNum) // но сортируется по первой колонке, не то что требуется
	
	if (lpAllList.length < nMinTabs)
	{
		WScript.Quit();
	}

// делаем ширину пунктов одинаковой, для пунктов от 1 до 9 добавляем пробел слева
	for (i = 0; i < lpFrameList.length; ++i) {
		if (10 > lpFrameList[i][2])
		{
			lpFrameList[i][0] = "  " + lpFrameList[i][2] +" - " + lpFrameList[i][0];
		} else {
			lpFrameList[i][0] = lpFrameList[i][2] +" - " + lpFrameList[i][0];
		}
	}
	// Конец Редактируемый участок 2
	return 0;
}

function SortNum(a, b){
	return b[2] - a[2];
//     if(a < b)
//         return -1
//     if(a > b)
//         return 1
//     return 0
}

function CreateFont(pFaceName, nFontStyle, nPointSize) {
	//Release it with: oSys.Call("gdi32::DeleteObject", hFont);
	var lpLogFontSrc;
	var lpLogFontDst;
	var hDC;
	var hFont = 0;
	var nHeight;
	var nWeight;
	var nItalic;

	if (lpLogFontDst = AkelPad.MemAlloc(92 /*sizeof(LOGFONTW)*/ )) {
		lpLogFontSrc = AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/ , 48 /*FI_EDITFONTW*/ , 0);
		oSys.Call("kernel32::RtlMoveMemory", lpLogFontDst, lpLogFontSrc, 92 /*sizeof(LOGFONTW)*/ );

		if (nPointSize) {
			if (hDC = oSys.Call("user32::GetDC", hMainWnd)) {
				nHeight = -oSys.Call("kernel32::MulDiv", nPointSize, oSys.Call("gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/ ), 72);
				AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 0) /*offsetof(LOGFONTW, lfHeight)*/ , nHeight, 3 /*DT_DWORD*/ );
				oSys.Call("user32::ReleaseDC", hMainWnd, hDC);
			}
		}
		if (nFontStyle != 0 /*FS_NONE*/ ) {
			nWeight = (nFontStyle == 2 /*FS_FONTBOLD*/ || nFontStyle == 4 /*FS_FONTBOLDITALIC*/ ) ? 700 /*FW_BOLD*/ : 400 /*FW_NORMAL*/ ;
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 16) /*offsetof(LOGFONTW, lfWeight)*/ , nWeight, 3 /*DT_DWORD*/ );
			nItalic = (nFontStyle == 3 /*FS_FONTITALIC*/ || nFontStyle == 4 /*FS_FONTBOLDITALIC*/ ) ? 1 : 0;
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 20) /*offsetof(LOGFONTW, lfItalic)*/ , nItalic, 5 /*DT_BYTE*/ );
		}
		if (_TSTR == 0 /*DT_ANSI*/ && !pFaceName)
			pFaceName = AkelPad.MemRead(_PtrAdd(lpLogFontDst, 28) /*offsetof(LOGFONTW, lfFaceName)*/ , 1 /*DT_UNICODE*/ );
		if (pFaceName)
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 28) /*offsetof(LOGFONTW, lfFaceName)*/ , pFaceName.substr(0, 32 /*LF_FACESIZE*/ ), _TSTR);

		hFont = oSys.Call("gdi32::CreateFontIndirect" + _TCHAR, lpLogFontDst);
		AkelPad.MemFree(lpLogFontDst);
	}
	return hFont;
}

function GetCursorPos(ptPoint) {
	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 RectToArray(lpRect, rcRect) {
	rcRect.left = AkelPad.MemRead(_PtrAdd(lpRect, 0) /*offsetof(RECT, left)*/ , 3 /*DT_DWORD*/ );
	rcRect.top = AkelPad.MemRead(_PtrAdd(lpRect, 4) /*offsetof(RECT, top)*/ , 3 /*DT_DWORD*/ );
	rcRect.right = AkelPad.MemRead(_PtrAdd(lpRect, 8) /*offsetof(RECT, right)*/ , 3 /*DT_DWORD*/ );
	rcRect.bottom = AkelPad.MemRead(_PtrAdd(lpRect, 12) /*offsetof(RECT, bottom)*/ , 3 /*DT_DWORD*/ );
	return rcRect;
}

function GetWindowSize(hWnd, hWndOwner, rcRect) {
	var lpRect;
	var bResult = false;

	if (lpRect = AkelPad.MemAlloc(16 /*sizeof(RECT)*/ )) {
		if (oSys.Call("user32::GetWindowRect", hWnd, lpRect)) {
			RectToArray(lpRect, rcRect);
			rcRect.right -= rcRect.left;
			rcRect.bottom -= rcRect.top;

			if (hWndOwner)
				bResult = oSys.Call("user32::ScreenToClient", hWndOwner, lpRect);
			else
				bResult = true;
			rcRect.left = AkelPad.MemRead(_PtrAdd(lpRect, 0) /*offsetof(RECT, left)*/ , 3 /*DT_DWORD*/ );
			rcRect.top = AkelPad.MemRead(_PtrAdd(lpRect, 4) /*offsetof(RECT, top)*/ , 3 /*DT_DWORD*/ );
		}
		AkelPad.MemFree(lpRect);
	}
	return bResult;
}

function LOWORD(dwNumber) {
	return (dwNumber & 0xffff);
}

function HIWORD(dwNumber) {
	return (dwNumber >> 16);
}

function MAKELONG(a, b) {
	return (a & 0xffff) | ((b & 0xffff) << 16);
}
PureBasic

Code: Select all

;- TOP
EnableExplicit

;- ● Global
Global bCtrlTab = #True
Global nMinTabs = 2
Global pFontName$ = "Arial"
Global nFontStyle = 0 ; ignored
Global nFontSize = 0
Global nLineGap = 1
Global bSingleClick = #False
Global ShowModify = 2
Global nWindowLeft = -1
Global nWindowTop = -1
Global nWindowMaxHeight = -1
Global nWindowMaxWidth = -1
Global bAsk = #False

Global hMainWnd ; AkelPad.Windows
Global hWndEdit ; AkelPad.Edit
Global oSys ; AkelPad.SystemFunction
Global hInstanceDLL ; AkelPad.GetInstanceDll
Global pClassName
Global hWndContainer
Global hWndListBox
Global hHookPost
Global hHookSend
Global hSubClass
Global hDC
Global hBrushHollow
Global hFontEdit
Global Dim lpFrameList.s(5, 2)
Global rcMain.RECT
Global ptPoint.POINT
Global nItemHeight
Global nScreenWidth
Global nControlWidth
Global nControlHeight
Global nMaxControlHeight
Global nCharWidth
Global nCharHeight
Global nMaxCharWidth
Global nMaxCharHeight
Global nIconSize = 16
Global nIconGap = 2
Global bNoSwitch = #False


; Structure SIZE
; 	cx.l
; 	cy.l
; EndStructure

Define nCurSel, *lpSize.SIZE, i

;- ● Declare
Declare Min(*v1.Integer, *v2.Integer)
Declare Max(*v1.Integer, *v2.Integer)
Declare ListBoxCallback(hWnd, uMsg, wParam, lParam)
Declare GetFrameList(Array lpFrameList.s(2))
Declare DialogCallback(hWnd, uMsg, wParam, lParam)
Declare GetWindowSize(hWnd, hWndOwner, *rcRect.RECT)



;-┌──GUI──┐
If OpenWindow(0, 0, 0, 320, 300, "Main", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	hMainWnd = WindowID(0)
	EditorGadget(0, 8, 8, 306, 233)
	hWndEdit = GadgetID(0)
EndIf


; Get list of documents
nCurSel = GetFrameList(lpFrameList())
If ArraySize(lpFrameList()) > 0
	; Get font
	If Asc(pFontName$) Or nFontStyle Or nFontSize
; 		hFontEdit = CreateFont(pFontName$, nFontStyle, nFontSize)
		LoadFont(0, pFontName$, nFontSize, nFontStyle)
		hFontEdit = FontID(0)
	Else
		hFontEdit = SendMessage_(hWndEdit, #WM_GETFONT, 0, 0)
	EndIf
	If Not hFontEdit
		End
	EndIf

	; Get maximum character size
; 	If *lpSize = AllocateMemory(8)
	If 1
		If hDC = GetDC_(hWndEdit)
			SelectObject_(hDC, hFontEdit)
			For i = 0 To ArraySize(lpFrameList())
				If GetTextExtentPoint32_(hDC, lpFrameList(i, 0), Len(lpFrameList(i, 0)), *lpSize)
; 					nCharWidth = PeekI(*lpSize)
					nCharWidth = *lpSize\cx
; 					nCharHeight = PeekI(*lpSize + 4)
					nCharHeight = *lpSize\cy
					If nCharWidth > nMaxCharWidth
						nMaxCharWidth = nCharWidth
					EndIf
					If nCharHeight > nMaxCharHeight
						nMaxCharHeight = nCharHeight
					EndIf
				EndIf
			Next
			ReleaseDC_(hWndEdit, hDC)
		EndIf
		nMaxCharWidth + nIconSize + nIconGap + 16
		FreeMemory(*lpSize)
	EndIf

	; Create dialog
	; RegisterClass_(pClassName, #WM_MOUSEACTIVATE, #WM_DRAWITEM)
;-┌──GUI──┐
	If OpenWindow(0, 0, 0, 220, 100, "", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
		SetWindowCallback(@DialogCallback())
		If ListViewGadget(0, 10, 10, 250, 120, #WS_VISIBLE | #WS_CHILD | #WS_HSCROLL | #WS_VSCROLL | #WS_DLGFRAME | #LBS_OWNERDRAWFIXED)
			hWndListBox = GadgetID(0) ; #LVG
									  ; Make hWndContainer invisible
			hBrushHollow = GetStockObject_(#HOLLOW_BRUSH)
			SetClassLong_(hWndContainer, #GCL_HBRBACKGROUND, hBrushHollow)
			SendMessage_(hWndListBox, #WM_SETFONT, hFontEdit, 1)
			nItemHeight = nMaxCharHeight + nLineGap
			i = SendMessage_(hWndListBox, #LB_GETITEMHEIGHT, 0, 0)

			If nItemHeight < i
				nItemHeight = i
			Else
				SendMessage_(hWndListBox, #LB_SETITEMHEIGHT, 0, nItemHeight)
			EndIf

			nMaxControlHeight = ArraySize(lpFrameList()) * nItemHeight + GetSystemMetrics_(#SM_CYDLGFRAME) * 2

			If nWindowMaxHeight > 0
				nControlHeight = Min(@nWindowMaxHeight, @nMaxControlHeight)
; 				If nWindowMaxHeight < nMaxControlHeight
; 					nControlHeight = nWindowMaxHeight
; 				Else
; 					nControlHeight = nMaxControlHeight
; 				EndIf
			Else
				nControlHeight = nMaxControlHeight
			EndIf


			If nControlHeight > GetSystemMetrics_(#SM_CYMAXIMIZED) - 8
				nControlHeight = GetSystemMetrics_(#SM_CYMAXIMIZED) - 8
			EndIf

			If nWindowMaxWidth > 0
				nControlWidth = Min(@nWindowMaxWidth, @nMaxCharWidth)
; 				If nWindowMaxWidth < nMaxCharWidth
; 					nControlWidth = nWindowMaxWidth
; 				Else
; 					nControlWidth = nMaxCharWidth
; 				EndIf
			Else
				nControlWidth = nMaxCharWidth
			EndIf

			If GetSystemMetrics_(#SM_CXMAXIMIZED) - 8 < nControlWidth
				nControlWidth = GetSystemMetrics_(#SM_CXMAXIMIZED)
			EndIf

			If nMaxCharWidth > nControlWidth
				SendMessage_(hWndListBox, #LB_SETHORIZONTALEXTENT, nMaxCharWidth, 0)
				If nMaxControlHeight = nControlHeight
					nControlHeight + GetSystemMetrics_(#SM_CXHSCROLL)
				EndIf
			EndIf
			; Fill listbox
			For i = 0 To ArraySize(lpFrameList())
				SendMessage_(hWndListBox, #LB_ADDSTRING, 0, lpFrameList(i, 0))
			Next

			GetWindowSize(hMainWnd, 0, rcMain)
			If nWindowLeft >= 0
				rcMain\left = nWindowLeft;
			ElseIf nWindowLeft = -2
				GetCursorPos_(ptPoint)
				rcMain\left = ptPoint\x
			Else
				rcMain\left + rcMain\right / 2 - nControlWidth / 2
			EndIf
			If Not nScreenWidth = GetSystemMetrics_(#SM_CXVIRTUALSCREEN)
				nScreenWidth = GetSystemMetrics_(#SM_CXMAXIMIZED)
			EndIf
			rcMain\left = Min(@rcMain\left, Max((nScreenWidth - 8) - nControlWidth, 0))
			If rcMain\left < 0
				rcMain\left = 0
			EndIf

			If nWindowTop >= 0
				rcMain\top = nWindowTop
			ElseIf nWindowTop = -2
				GetCursorPos_(ptPoint)
				rcMain\top = ptPoint\y
			Else
				rcMain\top + rcMain\bottom / 2 - nControlHeight / 2
			EndIf
			rcMain\top = Min(rcMain\top, Max(GetSystemMetrics_(#SM_CYMAXIMIZED) - 8 - nControlHeight, 0))
			If rcMain\top < 0
				rcMain\top = 0
			EndIf

			SetWindowPos_(hWndContainer, 0, rcMain\left, rcMain\top, nControlWidth, nControlHeight, #SWP_NOZORDER | #SWP_NOACTIVATE)
			SetWindowPos_(hWndListBox, 0, 0, 0, nControlWidth, nControlHeight, #SWP_NOMOVE | #SWP_NOZORDER | #SWP_NOACTIVATE)
			SendMessage_(hWndListBox, #LB_SETCURSEL, nCurSel, 0)
			ShowWindow_(hWndContainer, #SW_SHOWNOACTIVATE)

			; Cause listbox is non-active, hook and send to listbox keyboard and mouse actions.
			If hHookPost = AkelPad.ThreadHook(#WH_GETMESSAGE, HookPostCallback, dwMainThreadID, #WM_LBUTTONDOWN,
			                                  #WM_NCLBUTTONDOWN,
			                                  #WM_RBUTTONDOWN,
			                                  #WM_NCRBUTTONDOWN,
			                                  #WM_MBUTTONDOWN,
			                                  #WM_NCMBUTTONDOWN,
			                                  #WM_KEYDOWN,
			                                  #WM_KEYUP,
			                                  #WM_SYSKEYDOWN,
			                                  #WM_SYSKEYUP,
			                                  #WM_MOUSEWHEEL)
				If hHookSend = AkelPad.ThreadHook(#WH_CALLWNDPROC, HookSendCallback, dwMainThreadID, #WM_SETFOCUS)
					If hSubClass = AkelPad.WindowSubClass(hWndListBox, ListBoxCallback, #WM_MOUSEACTIVATE,
					                                      #WM_GETDLGCODE,
					                                      #WM_KEYDOWN,
					                                      #WM_KEYUP,
					                                      #WM_LBUTTONDOWN,
					                                      #WM_LBUTTONUP,
					                                      #WM_LBUTTONDBLCLK)
						; Allow other scripts running
						AkelPad.ScriptNoMutex()
						; Message loop
						AkelPad.WindowGetMessage()
						AkelPad.WindowUnsubClass(hWndListBox)
					EndIf
					AkelPad.ThreadUnhook(hHookSend)
				EndIf
				AkelPad.ThreadUnhook(hHookPost)
			EndIf

			If Not bNoSwitch
				SendMessage_(hWndListBox, #LB_GETCURSEL, 0, 0)
; 				Здесь ваш код обработки
			EndIf
		EndIf
; 		DestroyWindow_(hWndContainer)
		CloseWindow(0)
; 	UnregisterClass(pClassName)
	EndIf

; 	Release font
	If pFontName$ Or nFontStyle Or nFontSize
		If hFontEdit
			DeleteObject_(hFontEdit)
		EndIf
	EndIf
Else
	If ArraySize(lpFrameList()) >= 2
		PostMessage_(hMainWnd, #AKD_FRAMEACTIVATE, 0, lpFrameList(nCurSel, 1))
	EndIf
EndIf


Procedure Min(*v1.Integer, *v2.Integer)
	If *v1\i > *v2\i
		ProcedureReturn *v2\i
	Else
		ProcedureReturn *v1\i
	EndIf
EndProcedure

Procedure Max(*v1.Integer, *v2.Integer)
	If *v1\i > *v2\i
		ProcedureReturn *v1\i
	Else
		ProcedureReturn *v2\i
	EndIf
EndProcedure




Procedure DialogCallback(hWnd, uMsg, wParam, lParam)
	Protected hDC, hIcon, nItemID, nItemState, *lpItem.rcItem, crText, crBk, hBrushBk, nModeBkOld
	Protected item.DRAWITEMSTRUCT
	; 	Dim rcItem(0)

	Select uMsg
		Case #WM_MOUSEACTIVATE
			ProcedureReturn #MA_NOACTIVATE
		Case #WM_DRAWITEM
			hDC = item\hDC
			nItemID = item\itemID
			nItemState = item\itemState
			*lpItem = item\rcItem
			; Set background
			If nItemState & #ODS_SELECTED
				crText = GetSysColor_(#COLOR_HIGHLIGHTTEXT)
				crBk = GetSysColor_(#COLOR_HIGHLIGHT)
				hBrushBk = GetSysColorBrush_(#COLOR_HIGHLIGHT)
			Else
				crText = GetSysColor_(#COLOR_WINDOWTEXT)
				crBk = GetSysColor_(#COLOR_WINDOW)
				hBrushBk = GetSysColorBrush_(#COLOR_WINDOW)
			EndIf
			FillRect_(hDC, *lpItem, hBrushBk)
			nModeBkOld = SetBkMode_(hDC, #TRANSPARENT)
			; Draw icon
			hIcon = SendMessage_(hMainWnd, #AKD_GETFRAMEINFO, #FI_ICONHANDLE, lpFrameList(nItemID, 1)) ; AKD - AkelPad
			DrawIconEx_(hDC, rcItem\left, rcItem.top + (rcItem.bottom - rcItem.top) / 2 - nIconSize / 2, hIcon, nIconSize, nIconSize, 0, 0, #DI_NORMAL)

			; Draw text
			SetTextColor_(hDC, crText)
			SetBkColor_(hDC, crBk)
			TextOut_(hDC, rcItem\left + nIconSize + nIconGap, rcItem\top + (rcItem\bottom - rcItem\top) / 2 - nMaxCharHeight / 2, lpFrameList(nItemID, 0), Len(lpFrameList(nItemID, 0)))
			SetBkMode_(hDC, nModeBkOld)
	EndSelect
	ProcedureReturn 0
EndProcedure

CompilerIf #PB_Compiler_Processor  = #PB_Processor_x86
	Macro x64(x64, x86)
		x86
	EndMacro
CompilerElse
	Macro x64(x64, x86)
		x64
	EndMacro
CompilerEndIf

Procedure HookPostCallback(nCode, wParam, lParam)
	Protected nParamW, nParamL, uMsg.l
; 	Protected MSG.MSG
; 	uMsg = MSG\message
	
	uMsg = PeekL(lParam + x64(8, 4))
	
	Select uMsg
		Case #WM_LBUTTONDOWN, #WM_NCLBUTTONDOWN, #WM_RBUTTONDOWN, #WM_NCRBUTTONDOWN, #WM_MBUTTONDOWN, #WM_NCMBUTTONDOWN	
			hWnd = PeekL(lParam)
			If hWnd <> hWndListBox
				; Not in rect
				bNoSwitch = #True
				; Exit message loop
				PostQuitMessage_(0)
			EndIf
		Case #WM_KEYDOWN, #WM_KEYUP, #WM_SYSKEYDOWN, #WM_SYSKEYUP, #WM_MOUSEWHEEL
			nParamW = PeekL(lParam+ x64(16, 8))
			nParamL = PeekL(lParam+ x64(24, 12))
			SendMessage_(hWndListBox, uMsg, nParamW, nParamL)
			PokeL(lParam + x64(8, 4), 0)
	EndSelect
EndProcedure

Procedure HookSendCallback(nCode, wParam, lParam)
	Protected nParamW, nParamL, uMsg.l
; 	Protected CWP.CWPSTRUCT
; 	uMsg = CWP\message
	
	uMsg = PeekL(lParam + x64(16, 8))
	
	Select uMsg
		Case #WM_SETFOCUS	
			bNoSwitch = #True
			; Exit message loop
			PostQuitMessage_(0)
	EndSelect
EndProcedure


Procedure ListBoxCallback(hWnd, uMsg, wParam, lParam)
	Protected nCount, i, bCtrlTab, hWndListBox

	Select uMsg
		Case #WM_MOUSEACTIVATE
			ProcedureReturn #MA_NOACTIVATE
		Case #WM_GETDLGCODE
			; AkelPad.WindowNoNextProc(hSubClass);
			ProcedureReturn #DLGC_WANTALLKEYS
		Case #WM_KEYDOWN
			If wParam = $43
				If bCtrlTab Or GetKeyState_(#VK_CONTROL) & $8000
					i = SendMessage_(hWndListBox, #LB_GETCURSEL, 0, 0)
					SetClipboardText(lpFrameList(i, 0))
				EndIf
			ElseIf wParam = #VK_TAB
				nCount = SendMessage_(hWndListBox, #LB_GETCOUNT, 0, 0)
				i = SendMessage_(hWndListBox, #LB_GETCURSEL, 0, 0)
				If Not GetKeyState_(#VK_SHIFT) & $8000
					If(i + 1) >= nCount
						i = 0
					EndIf
				Else
					If(i - 1) < 0
						i = nCount - 1
					EndIf
				EndIf
				SendMessage_(hWndListBox, #LB_SETCURSEL, i, 0)
			ElseIf wParam = #VK_RETURN
				; Exit message loop
				PostQuitMessage_(0)
			ElseIf wParam = #VK_ESCAPE
				bNoSwitch = #True
				; Exit message loop
				PostQuitMessage_(0)
			EndIf
		Case #WM_KEYUP
			If wParam = #VK_CONTROL
				If bCtrlTab
					; Exit message loop
					PostQuitMessage_(0)
				EndIf
			EndIf
		Case #WM_LBUTTONDOWN
			lResult = SendMessage_(hWndListBox, #LB_ITEMFROMPOINT, 0, lParam)
			HiWord = lResult >> 16
			LoWord = lResult & $FFFF
			If HiWord = 0
				SendMessage_(hWndListBox, #LB_SETCURSEL, LoWord, 0)
			EndIf
			; AkelPad.WindowNoNextProc(hSubClass)
		Case #WM_LBUTTONUP
			uMsg = #WM_LBUTTONDBLCLK
			If uMsg = #WM_LBUTTONDBLCLK Or bSingleClick
				; Exit message loop
				PostQuitMessage_(0)
			EndIf
	EndSelect
EndProcedure

Procedure GetFrameList(Array lpFrameList.s(2))
	Protected lpInitFrame, lpFrame, pNumFind, pStrFind = ":", i, j, n
	ReDim lpFrameList(5, 2)
	For i = 0 To 5
		lpFrameList(i, 0) = "item " + Str(i)
		lpFrameList(i, 1) = lpFrame
	Next
	ProcedureReturn 0
EndProcedure

Procedure GetWindowSize(hWnd, hWndOwner, *rcRect.RECT)
	Protected *lpRect.RECT, bResult = #False
	GetWindowRect_(hWnd, *lpRect)
	*rcRect.right - *lpRect.left
	*rcRect.bottom - *lpRect.top
	
	If hWndOwner
		bResult = ScreenToClient_(hWndOwner, *lpRect)
	Else
		bResult = #True
	EndIf
	*rcRect\left = *lpRect.left
	*rcRect\top = *lpRect.top
	
	ProcedureReturn bResult
EndProcedure

Procedure GetCursorPos(*ptPoint.POINT)
	Protected lpPoint.POINT
	GetCursorPos_(lpPoint)
	*ptPoint\x = lpPoint\x
	*ptPoint\y = lpPoint\y
EndProcedure
User avatar
Piero
Addict
Addict
Posts: 914
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: How to create a menu from a ListBox

Post by Piero »

How I wish I could help!
My JS is rusty and this PB noob today is already tired of making weird debugger and macro tests… :lol:
User avatar
mk-soft
Always Here
Always Here
Posts: 6242
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to create a menu from a ListBox

Post by mk-soft »

AkelPad.[Function] is an object. So an interface.
With your description of JavaScript I do not see where the object is fetched, created.
Either with COMate or with Module ActiveScript get the running instance
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
AZJIO
Addict
Addict
Posts: 2183
Joined: Sun May 14, 2017 1:48 am

Re: How to create a menu from a ListBox

Post by AZJIO »

mk-soft wrote: Sun Aug 31, 2025 12:15 pm AkelPad.[Function] is an object. So an interface.
With your description of JavaScript I do not see where the object is fetched, created.
Either with COMate or with Module ActiveScript get the running instance
I think it could be written from scratch without any source code. But I added the source code as a hint, because there are many events in the Callback. II used this example module and made 2 AkelPad sources from it for different cases. The essence of the module is a pop-up menu, and where to use it is a second question. I used it for deleting tabs, for the tab menu, and for actions related to the file extension. This menu works perfectly, never fails, and looks good. I would like to have an analogue of it, as it can be useful in any program, such as this one.

Video
Post Reply