Что нового

Контекстное меню для пунктов меню трея

Webarion

Осваивающий
Сообщения
143
Репутация
24
Привет! Подскажите, как, или возможно ли вообще сделать контекстное меню, открывающееся кликом правой кнопки мыши, по пунктам меню в трее. Нужно, чтобы клик ПКМ по [Пункт1,Пункт2] открывал контекстное меню [Действие1,Действие2,Действие3]:

Код:
#Include <ModernMenuRaw.au3>
#NoTrayIcon

Opt("TrayMenuMode", 1 + 2)
_TrayIconSetClick(-1, 2 + 16)

_TrayIconCreate("", @AutoItExe, -1)
_TrayCreateContextMenu()
_TrayIconSetState()

$i1 =_TrayCreateItem('Пункт1')
$i2 =_TrayCreateItem('Пункт2')
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Пример из справки:
Код:
$iSettings = TrayCreateMenu("Настройки") ; Создаёт меню трея и подменю с двумя пунктами.
$iDisplay = TrayCreateItem("Монитор", $iSettings)
$iPrinter = TrayCreateItem("Принтер", $iSettings)
А если обойтись обычными подменю?


Добавлено:
Сообщение автоматически объединено:

Я никогда и не видел таких меню, в которых еще одно по правому клику открывается. Разве что меню Пуск.
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Я тоже не видел подобной реализации, но вдруг) У меня в меню трея, висят файлы для быстрого доступа, и вот понадобилось сделать выбор из нескольких действий по отношению к файлу. Самое идеальное для меня, это дополнительное меню через ПКМ. А обычное подменю не использую, так как прикручены иконки от файлов. В общем это похоже на меню Open Server своей реализации.
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Немного приблизился к решению, но есть загвоздка. В следующем примере при клике правой в любом месте, меню появляется, а в меню трея нет, блокирует. Вот как бы это обойти?

Код:
#include <WindowsConstants.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>

#include <UserInput.au3>

Opt('TrayMenuMode', 3)

$m1 = TrayCreateMenu("M1")
$m1i1 = TrayCreateItem('M1I1', $m1)
$m1i2 = TrayCreateItem('M1I2', $m1)
$m1i3 = TrayCreateItem('M1I3', $m1)
$m2 = TrayCreateMenu("M2")
$m2i1 = TrayCreateItem('M2I1', $m2)
$m2i2 = TrayCreateItem('M2I2', $m2)
$m2i3 = TrayCreateItem('M2I3', $m2)

$i1 = TrayCreateItem('I1')
$i2 = TrayCreateItem('I2')

TrayCreateItem('')
$Exit = TrayCreateItem('Exit')

TraySetState()

While 1
	$aRead = _UserInput_Read('[:ALLMOUSE:]')
	If $aRead[0] Then
		If $aRead[1] = '02' Then
			ConsoleWrite('Клик правой'&@CRLF)
			_ShowPopupMenu_Proc()
		EndIf
	EndIf
	Sleep(10)
WEnd


Func _ShowPopupMenu_Proc()
	Local $hDlg, $cDummy, $nContextMenu, $hContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
	$hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
	$cDummy = GUICtrlCreateDummy()
	$nContextMenu = GUICtrlCreateContextMenu($cDummy)
	$hContextMenu = GUICtrlGetHandle($nContextMenu)
	$nHide_MItem = GUICtrlCreateMenuItem('Пункт1', $nContextMenu)
	$nShowMsg_MItem = GUICtrlCreateMenuItem('Пункт2', $nContextMenu)
	GUICtrlCreateMenuItem('', $nContextMenu)
	$nExit_MItem = GUICtrlCreateMenuItem('Выход', $nContextMenu)
	GUISetState(@SW_SHOW, $hDlg)
	$aMousePos = MouseGetPos()
	$nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1, 2)
	Switch $nResult
		Case $nShowMsg_MItem
			MsgBox(64, 'Заголовок', 'Сообщение')
		Case $nExit_MItem
			Exit
	EndSwitch
	GUIDelete($hDlg)
EndFunc   ;==>_ShowPopupMenu_Proc
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
Vanguger
Для AutoIt отображение всплывающего меню такая же блокирующая операция, как вывод MsgBox.
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
InnI сказал(а):
Для AutoIt отображение всплывающего меню такая же блокирующая операция, как вывод MsgBox.

Хорошо, тогда, как в данном примере, программно закрыть меню трея, чтобы после закрытия отобразилось контекстное? Я что-то не нашел способ, должен же он быть.
Мне для этой структуры нужен доп. функционал по правой:
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
Как вариант
Код:
#include <WindowsConstants.au3>
#include <TrayConstants.au3>
#include <SendMessage.au3>
#include <WinAPISys.au3>
#include <GuiMenu.au3>
#include <Timers.au3>
#include <Misc.au3>

Opt("TrayMenuMode", 3)
Opt("WinWaitDelay", 11)

$MainItemName = ""
$ShowPopup = False

$GUI = GUICreate("", 0, 0, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
GUISetState()

$MainDummy = GUICtrlCreateDummy()
$MainPopup = GUICtrlCreateContextMenu($MainDummy)
$M1 = GUICtrlCreateMenu("M1", $MainPopup)
$M11 = GUICtrlCreateMenuItem("M11", $M1)
$M12 = GUICtrlCreateMenuItem("M12", $M1)
$M2 = GUICtrlCreateMenu("M2", $MainPopup)
$M21 = GUICtrlCreateMenuItem("M21", $M2)
$M22 = GUICtrlCreateMenuItem("M22", $M2)
$M3 = GUICtrlCreateMenuItem("M3", $MainPopup)
$M4 = GUICtrlCreateMenuItem("M4", $MainPopup)

$cDummy = GUICtrlCreateDummy()
$nContextMenu = GUICtrlCreateContextMenu($cDummy)
$nHide_MItem = GUICtrlCreateMenuItem("Пункт1", $nContextMenu)
$nShowMsg_MItem = GUICtrlCreateMenuItem("Пункт2", $nContextMenu)
GUICtrlCreateMenuItem("", $nContextMenu)
$nExit_MItem = GUICtrlCreateMenuItem("Выход", $nContextMenu)

While 1
  Switch TrayGetMsg()
    Case $TRAY_EVENT_SECONDARYUP
      $Timer = _Timer_SetTimer($GUI, 33, "Timer")
      _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($MainPopup), $GUI)
  EndSwitch
  Switch GUIGetMsg()
    Case $M11
      MsgBox(0, "", "Выбран пункт M11")
    Case $M12
      MsgBox(0, "", "Выбран пункт M12")
    Case $M21
      MsgBox(0, "", "Выбран пункт M21")
    Case $M22
      MsgBox(0, "", "Выбран пункт M22")
    Case $M3
      MsgBox(0, "", "Выбран пункт M3")
    Case $M4
      MsgBox(0, "", "Выбран пункт M4")
    Case $nHide_MItem
      MsgBox(0, "", "Пункт1 вызван для " & $MainItemName)
    Case $nShowMsg_MItem
      MsgBox(0, "", "Пункт2 вызван для " & $MainItemName)
    Case $nExit_MItem
      Exit
  EndSwitch
  If $ShowPopup Then
    $ShowPopup = False
    _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($nContextMenu), $GUI)
  EndIf
WEnd

Func Timer($hWnd, $iMsg, $iIDTimer, $iTime)
  If _IsPressed("02") Then
    _Timer_KillTimer($GUI, $Timer)
    While _IsPressed("02")
      Sleep(11)
    WEnd
    $MainItemName = ""
    Local $tPoint = _WinAPI_GetMousePos()
    Local $PopUp = _WinAPI_WindowFromPoint($tPoint)
    If _WinAPI_GetClassName($PopUp) = "#32768" Then
      Local $hMenu = _SendMessage($PopUp, $MN_GETHMENU)
      $MainItemName = _GUICtrlMenu_GetItemText($hMenu, _GUICtrlMenu_MenuItemFromPoint($PopUp, $hMenu))
      $ShowPopup = True
    EndIf
    WinActivate("[class:#32768]")
  EndIf
EndFunc
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
InnI сказал(а):

Благодарю InnI! Внимательно изучу этот вариант. Я то уже начал подумывать в сторону имитации контекстного меню, с нужным функционалом, без блокировки. Тоже уже набросал немного сырой, но работающий. С костылями, ну блин :stars:, хоть как-то уже, для себя пойдёт.

Код:
#include <MouseOnEvent.au3>
#include <GuiMenu.au3>
Opt('TrayMenuMode', 3)

$m1 = TrayCreateMenu("M1")
$m1i1 = TrayCreateItem('M1I1', $m1)
$m1i2 = TrayCreateItem('M1I2', $m1)
$m1i3 = TrayCreateItem('M1I3', $m1)
$m2 = TrayCreateMenu("M2")
$m2i1 = TrayCreateItem('M2I1', $m2)
$m2i2 = TrayCreateItem('M2I2', $m2)
$m2i3 = TrayCreateItem('M2I3', $m2)
$i1 = TrayCreateItem('I1')
$i2 = TrayCreateItem('I2')
TrayCreateItem('')
$Exit = TrayCreateItem('Exit')

TraySetState()

$hMenu = TrayItemGetHandle(0)

_MouseSetOnEvent($MOUSE_SECONDARYUP_EVENT, "__ClickMouseR")

While 1
  Switch TrayGetMsg()
		Case $Exit
			Exit
	EndSwitch
	Sleep(10)
WEnd

Func __ClickMouseR()

Local $sPMLine = "" & @CRLF
	$sPMLine &= "#include <WindowsConstants.au3>" & @CRLF
	$sPMLine &= "#include <GuiMenu.au3>" & @CRLF
	$sPMLine &= "Local $hDlg, $cDummy, $nContextMenu, $hContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult" & @CRLF
	$sPMLine &= "$hDlg = GUICreate('', 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)" & @CRLF
	$sPMLine &= "$cDummy = GUICtrlCreateDummy()" & @CRLF
	$sPMLine &= "$nContextMenu = GUICtrlCreateContextMenu($cDummy)" & @CRLF
	$sPMLine &= "$hContextMenu = GUICtrlGetHandle($nContextMenu)" & @CRLF
	$sPMLine &= "$nHide_MItem = GUICtrlCreateMenuItem('Пункт1', $nContextMenu)" & @CRLF
	$sPMLine &= "$nShowMsg_MItem = GUICtrlCreateMenuItem('Пункт2', $nContextMenu)" & @CRLF
	$sPMLine &= "GUISetState(@SW_SHOW, $hDlg)" & @CRLF
	$sPMLine &= "$aMousePos = MouseGetPos()" & @CRLF
	$sPMLine &= "$nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0]-50, $aMousePos[1]-10, 1, 1, 2)" & @CRLF
	$sPMLine &= "Switch $nResult" & @CRLF
	$sPMLine &= "	Case $nShowMsg_MItem" & @CRLF
	$sPMLine &= "		MsgBox(64, 'Заголовок', 'Сообщение')" & @CRLF
	$sPMLine &= "EndSwitch" & @CRLF
	$sPMLine &= "GUIDelete($hDlg)" & @CRLF
	$sPMLine &= "FileDelete(@ScriptFullPath)" & @CRLF
	$sPMLine &= "Exit" & @CRLF

	Local $hFile = FileOpen(@ScriptDir & '\consoleMenu.tmp', 2)
	FileWrite($hFile, $sPMLine)
	FileClose($hFile)

	Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptDir & '\consoleMenu.tmp"')

EndFunc   ;==>_ShowPopupMenu_Proc



Добавлено:
Сообщение автоматически объединено:

В общем, всё у меня получилось. Так как список приложений для меню у меня отдаёт модуль(отдельный скрипт) и он же обрабатывает клики, то ему я и поручил создавать дополнительное контекстное меню. Ядро в этом случае просто говорит модулю, что клик правой кнопкой и отдаёт ему параметры клика. Получилось так как нужно и даже менюха не закрывается :ok:

InnI, спасибо за подсказки!
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Протестировал пару недель то, что у меня здесь ранее получилось. Должен сказать, что без глюков не обошлось. Контекстное меню, которое вызывается из стороннего скрипта, хоть и накладывается на основное, но вызывает некоторые аномалии и неудобства в работе, иногда это приводит к зависанию. Поэтому мне пришлось создать имитацию контекстного меню без блокировки, и с теми возможностями, которые мне были нужны. Результат на скриншоте. Пример ниже, под спойлером, можно скачать сразу архивом. Возможно кому-то и пригодится. Версия AutoIt 3.3.14.5, другие не проверял. Конечно есть ещё тут над чем поработать, но в целом такое поведение КМ меня устраивает:

ContextLM.au3
Код:
#include-once

#include <GDIPlus.au3>
#include <WinAPI.au3>

; =======================================================================================================================
; Название ........: ContextLM
; Дата обновления .: 15.09.2018г, 14:40
; AutoIt Версия ...: 3.3.14.5
; Описание ........: Имитация контекстного меню без блокировки.
;                  	 		Создаёт контекстное меню из элементов Label
;										 		Имеет возможность добавить вложенное контекстное меню внутри себя
; Доп.инфо ........: Используемые UDF:
;                  	 		WinAPI.au3
;										 		GDIPlus.au3
;                    		Icons.au3 - http://autoit-script.ru/index.php?topic=49.0
; Автор ...........: Vanguger
; =======================================================================================================================

#Region ПОЛЬЗОВАТЕЛЬСКИЕ ПАРАМЕТРЫ
Global $ICON_SIZE_CONTEXTLM = 16 ;По умолчанию размер иконок

Global $ITEM_HEIGHT_CONTEXTLM = 22 ;По умолчанию высота пункта

Global $BORDER_COLOR_CONTEXTLM = 0x99A2A9 ;Цвет рамки

Global $SHOW_DEFAULT_ICON_MENU_CONTEXTLM = 1 ;0-нет,1-показать иконку по умолчанию для меню
Global $SHOW_DEFAULT_ICON_ITEM_CONTEXTLM = 1 ;0-нет,1-показать иконку по умолчанию для пункта
Global $DEFAULT_ICON_MENU_CONTEXTLM = @SystemDir & '\shell32.dll;212' ;Иконка по умолчанию для меню
Global $DEFAULT_ICON_ITEM_CONTEXTLM = @SystemDir & '\shell32.dll;1' ;Иконка по умолчанию для пункта

Global $BG_ICONS_COLOR_CONTEXTLM = -2 ; 0xBFCDDB ; -2 - прозрачный ; фоновый цвет области иконок

Global $BG_HOVER_CONTEXTLM = 0xBFCDDB ;Цвет элемента наведения
Global $LEFT_HOVER_CONTEXTLM = -1 ;Отступ элемента наведения слева

Global $VERTICAL_SEPARATOR_CONTEXTLM = 1 ;0-нет,1-показать вертикальный разделитель между иконками и текстом элементов
Global $VERT_SEPARATOR_COLOR1_CONTEXTLM = 0xE3E3E3 ;Первый цвет вертикального разделителя(Основной)
Global $VERT_SEPARATOR_COLOR2_CONTEXTLM = 0xFFFFFF ;Второй цвет вертикального разделителя(Используется как тень)

Global $HOR_SEPARATOR_COLOR1_CONTEXTLM = 0xE3E3E3 ;Первый цвет горизонтального разделителя(Основной)
Global $HOR_SEPARATOR_COLOR2_CONTEXTLM = 0xFFFFFF ;Второй цвет горизонтального разделителя(Используется как тень)
#EndRegion ПОЛЬЗОВАТЕЛЬСКИЕ ПАРАМЕТРЫ

#Region СИСТЕМНЫЕ ПАРАМЕТРЫ
Global $aMatrixContextLM[1][4][0] ; Основная матрица
Global $sIndGlob_ContextLM, $sLabels_ContextLM = '', $sHoverBG_ContextLM = ''
Global $AddMenuIndex1D_ContextLM
Global $iGlobIndex_ContextLM = 1
Global $hFormLM[0]
Global $INIT_ConlextLM = 0
; Иконка стрелки меню
Local $binArrowIcon_ContextLM = '0x00000100010010100000010020006804000016000000280000001000000020000000010020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000FF000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000FF000000FF000000FF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000FF000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF000000FF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFAC41FFFFAC41FFFFAC41FFFFAC41FFFFAC41FDFFAC41FCFFAC41FC7FAC41FC3FAC41FC7FAC41FCFFAC41FDFFAC41FFFFAC41FFFFAC41FFFFAC41FFFFAC41'
Global $sArrowIcon_ContextLM = @ScriptDir & '\ArrowIcon_ContextLM.jpg'
If Not FileExists($sArrowIcon_ContextLM) Then
	$hFile = FileOpen($sArrowIcon_ContextLM, 16 + 2)
	FileWrite($hFile, $binArrowIcon_ContextLM)
	FileClose($hFile)
EndIf

Opt("TrayMenuMode", 3)
Opt("MouseCoordMode", 1)
AutoItSetOption('MouseCoordMode', 2)
#EndRegion СИСТЕМНЫЕ ПАРАМЕТРЫ

#Region ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ

;	Создаёт новое меню
Func _NewMenu_ContextLM($Ident = -1)

	Local $numMenu = UBound($aMatrixContextLM, 3)
	ReDim $aMatrixContextLM[UBound($aMatrixContextLM)][4][$numMenu + 1]

	If $Ident <> -1 And Not HWnd($Ident) Then
		Local $ret = GUICtrlGetHandle($Ident)
		If $ret Then $Ident = $ret
	EndIf

	$aMatrixContextLM[0][0][$numMenu] = $Ident
	$AddMenuIndex1D_ContextLM = 1
	Return $numMenu
EndFunc   ;==>_NewMenu_ContextLM

;	Добавляет элемент (меню, пункт или разделитель)
Func _CreateElem_ContextLM($sText = '-', $iSubLevel = -1, $sIcon = '')
	If Not $sText Then $sText = '-'
	Local $numMenu = UBound($aMatrixContextLM, 3)
	If $iSubLevel < 0 Then ; При уровне -1 и менее, запись в корневой уровень
		Local $sSp = ($aMatrixContextLM[0][1][$numMenu - 1]) ? '|' : ''
		$aMatrixContextLM[0][1][$numMenu - 1] &= $sSp & $AddMenuIndex1D_ContextLM
	Else ; При вложенности уровня отмечаем его
		Local $iSubIndex = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iSubLevel)
		Local $sSp = ($aMatrixContextLM[$iSubIndex][1][$numMenu - 1]) ? '|' : ''
		$aMatrixContextLM[$iSubIndex][1][$numMenu - 1] &= $sSp & $AddMenuIndex1D_ContextLM
	EndIf

	Local $iCount1D = UBound($aMatrixContextLM)
	Local $iRow = $AddMenuIndex1D_ContextLM

	If $AddMenuIndex1D_ContextLM >= $iCount1D Then $iCount1D += 1
	ReDim $aMatrixContextLM[$iCount1D][4][$numMenu]
	$aMatrixContextLM[$iRow][0][$numMenu - 1] = $sText

	_isDefParam_ContextLM($sIcon, '')
	If $sIcon Then $aMatrixContextLM[$iRow][2][$numMenu - 1] = $sIcon

	Local $sSp = ($sIndGlob_ContextLM) ? '|' : ''
	$sIndGlob_ContextLM &= $sSp & $iGlobIndex_ContextLM & '=' & $AddMenuIndex1D_ContextLM & ';' & $numMenu - 1

	$AddMenuIndex1D_ContextLM += 1
	$iGlobIndex_ContextLM += 1

	Return $iGlobIndex_ContextLM - 1
EndFunc   ;==>_CreateElem_ContextLM

;	Выгружает и удаляет все меню
Func _DeleteAll_ContextLM()
	_CloseAllMenu_ContextLM()
	Global $sIndGlob_ContextLM, $iGlobIndex_ContextLM = 1
	Global $aMatrixContextLM[1][4][0]
EndFunc   ;==>_DeleteAll_ContextLM

;	Закрывает все меню
Func _CloseAllMenu_ContextLM()
	If UBound($hFormLM) > 0 Then
		For $i = 0 To UBound($hFormLM) - 1
			GUIDelete($hFormLM[$i])
		Next
		Global $hFormLM[0], $sLabels_ContextLM = '', $sHoverBG_ContextLM = ''
	EndIf
EndFunc   ;==>_CloseAllMenu_ContextLM

;	Удаляет элемент в меню
Func _DeleteElem_ContextLM($iControlID = -1)
	Local $iRow
	If $iControlID < 0 Then
		$iRow = $AddMenuIndex1D_ContextLM - 1
		$iControlID = $iGlobIndex_ContextLM - 1
	Else
		$iRow = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 0)
	EndIf
	Local $iRootMenuID = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 1)
	$aMatrixContextLM[$iRow][0][$iRootMenuID] = ''
	$aMatrixContextLM[$iRow][1][$iRootMenuID] = ''
	$aMatrixContextLM[$iRow][2][$iRootMenuID] = ''
	$aMatrixContextLM[$iRow][3][$iRootMenuID] = ''
EndFunc   ;==>_DeleteElem_ContextLM

;	Устанавливает текст элементу
Func _SetText_ContextLM($sText, $iControlID = -1)
	Local $iRow
	If $iControlID < 0 Then
		$iRow = $AddMenuIndex1D_ContextLM - 1
		$iControlID = $iGlobIndex_ContextLM - 1
	Else
		$iRow = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 0)
	EndIf
	Local $iRootMenuID = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 1)
	$aMatrixContextLM[$iRow][0][$iRootMenuID] = $sText
EndFunc   ;==>_SetText_ContextLM

;	Получает текст элемента
Func _GetText_ContextLM($iControlID = -1)
	Local $iRow, $sText
	If $iControlID < 0 Then
		$iRow = $AddMenuIndex1D_ContextLM - 1
		$iControlID = $iGlobIndex_ContextLM - 1
	Else
		$iRow = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 0)
	EndIf
	Local $iRootMenuID = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 1)
	Local $sText = $aMatrixContextLM[$iRow][0][$iRootMenuID]
	Return $sText
EndFunc   ;==>_GetText_ContextLM

;	Добавляет иконку элементу
Func _SetIcon_ContextLM($sPathIcon = '', $iIndexIcon = -1, $iControlID = -1)
	Local $iRow, $sIcon
	If $iControlID < 0 Then
		$iRow = $AddMenuIndex1D_ContextLM - 1
		$iControlID = $iGlobIndex_ContextLM - 1
	Else
		$iRow = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 0)
	EndIf
	Local $iRootMenuID = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 1)
	$sIcon = ($sPathIcon And FileExists($sPathIcon)) ? $sPathIcon & ';' & $iIndexIcon : ''
	$aMatrixContextLM[$iRow][2][$iRootMenuID] = $sIcon
EndFunc   ;==>_SetIcon_ContextLM

;	Получает путь и индекс установленной иконки элемента
Func _GetIcon_ContextLM($iControlID = -1)
	Local $sIcon, $iRow
	If $iControlID < 0 Then
		$iRow = $AddMenuIndex1D_ContextLM - 1
		$iControlID = $iGlobIndex_ContextLM - 1
	Else
		$iRow = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 0)
	EndIf
	Local $iRootMenuID = _getOfStartParam_ContextLM($sIndGlob_ContextLM, $iControlID, 1)
	$sIcon = $aMatrixContextLM[$iRow][2][$iRootMenuID]
	If $sIcon Then Return $sIcon

	Return 0
EndFunc   ;==>_GetIcon_ContextLM

;	Запускает основной обработчик
Func _InitContextLM()
	AdlibRegister('_ControlHover_ContextLM', 10)
	If @error Then Return SetError(1, 0, 0)
	$INIT_ConlextLM = 1
EndFunc   ;==>_InitContextLM

;	Останавливает основной обработчик
Func _DeinitContextLM()
	AdlibUnRegister('_ControlHover_ContextLM')
	If @error Then Return SetError(1, 0, 0)
	$INIT_ConlextLM = 0
EndFunc   ;==>_DeinitContextLM

;	Показывает меню
Func _Show_ContextLM($iRootMenuID = UBound($aMatrixContextLM, 3) - 1, $iPosX = -1, $iPosY = -1)
	If Not $INIT_ConlextLM Then Return SetError(1, 0, 0)
	_Draw_ContextLM(0, $iRootMenuID, 'def', 'def', $iPosX, $iPosY)
EndFunc   ;==>_Show_ContextLM

;	Возвращает события контекстного меню ContextLM
Func GetMsg_ContextLM($iType = 0)
	If Not $INIT_ConlextLM Then Return SetError(1, 0, 0)
	Local $click = _IsClickMouse_ContextLM(); проверяем клик мышью
	Local $nMsg = TrayGetMsg()

	Local $tPoint, $hControl, $iGlobInd, $numMenu, $countMenus
	$tPoint = _WinAPI_GetMousePos()
	$hControl = _WinAPI_WindowFromPoint($tPoint)
	$iGlobInd = _hWndToGlobalIndex_ContextLM($hControl)
	$numMenu = _hWndToNumMenu_ContextLM($hControl)

	$countMenus = UBound($aMatrixContextLM, 3)

	If $nMsg = -8 Or $nMsg = -10 Then ; $TRAY_EVENT_PRIMARYUP,$TRAY_EVENT_SECONDARYU
		Local $trayInd = -1
		For $i = 0 To $countMenus - 1
			If $aMatrixContextLM[0][0][$i] == 0 Then $trayInd = $i
		Next
		If $trayInd > -1 Then _Draw_ContextLM(0, $trayInd, 1)
	EndIf

	; для клика левой
	Local $retL = 0, $retR = 0
	If Not _RepeatTrigger_ContextLM($click[0], 'LMOUSE') And $click[0] = 0 Then ; если нажатие по циклу не повторяется
		If _RepeatTrigger_ContextLM($click[0], 'LMOUSE_UP') Then ; Отжата левая
			$retL = (_Hovered_ContextLM()) ? $iGlobInd : -1
		EndIf
	EndIf

	; для клика правой
	If Not _RepeatTrigger_ContextLM($click[1], 'RMOUSE') And $click[1] = 0 Then ; если нажатие по циклу не повторяется
		If _RepeatTrigger_ContextLM($click[1], 'RMOUSE_UP') Then ; Отжата правая

			For $i = 0 To $countMenus - 1
				If $aMatrixContextLM[0][0][$i] = $hControl Then
					_Draw_ContextLM(0, $i)
					ExitLoop
				EndIf
			Next
			$retR = (_Hovered_ContextLM()) ? $iGlobInd : -1
		EndIf
	EndIf

	Local $num1D = _hWndToIndex1D_ContextLM($hControl)
	If Not $aMatrixContextLM[$num1D][1][$numMenu] And $retL Then _CloseAllMenu_ContextLM()

	If $iType = 0 And $retL Then Return $retL
	If $iType = 1 And $retR Then Return $retR
	If $iType = 2 Then
		If $retL Or $retR Then
			Local $aRet[2] = [$retL, $retR]
			Return $aRet
		EndIf
	EndIf

	Return 0
EndFunc   ;==>GetMsg_ContextLM
#EndRegion ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ

; ===============================================================================================================================

#Region СИСТЕМНЫЕ ФУНКЦИИ
;**********************************************************************
; ОТРИСОВКА КОНТЕКСТНОГО МЕНЮ
;**********************************************************************
Func _Draw_ContextLM($iIndex1D = 0, $numMenu = UBound($aMatrixContextLM, 3) - 1, $PositionTray = 0, $posTop = 0, $iPosX = -1, $iPosY = -1)
	If Not $INIT_ConlextLM Then Return SetError(1, 0, 0)
	Local $icSize = $ICON_SIZE_CONTEXTLM
	Local $padding = 3, $itX = $padding, $itY = $padding
	Local $paddingRight_Arrow = 20

	Local $itW = 150, $itH = $ITEM_HEIGHT_CONTEXTLM
	If $itH < $icSize Then $itH = $icSize + 6

	; Создаём окно для меню
	ReDim $hFormLM[UBound($hFormLM) + 1]
	$hFormLM[UBound($hFormLM) - 1] = GUICreate("ContextLM", $itW + $padding + 3, 100, 200, 150, 0x80000000, 0x00000080) ; $WS_POPUP,$WS_EX_TOOLWINDOW
	Local $hForm = $hFormLM[UBound($hFormLM) - 1]
	WinSetOnTop($hForm, '', 1)
	;
	Local $a_thisLevel = StringSplit($aMatrixContextLM[$iIndex1D][1][$numMenu], '|', 2) ; Текущий уровень вложенности

	;находим максимальную длину текста в меню
	Local $iLenText, $sMaxText, $sText
	For $i = 0 To UBound($a_thisLevel) - 1
		$sText = $aMatrixContextLM[Number($a_thisLevel[$i])][0][$numMenu]
		$iLenText = StringLen($sText)
		If $iLenText > StringLen($sMaxText) Then $sMaxText = $sText
	Next
	;

	; Получаем размер текста в пикселях и определяем размер пробела
	Local $labTmp, $sizeText, $a, $b
	$labTmp = GUICtrlCreateLabel('', 0, 0, 0, 0)
	$sizeText = GetStringDimensions(GUICtrlGetHandle($labTmp), $sMaxText)
	$a = GetStringDimensions(GUICtrlGetHandle($labTmp), 'a a')
	$b = GetStringDimensions(GUICtrlGetHandle($labTmp), 'aa')
	GUICtrlDelete($labTmp)
	;

	Local $SpaceLen = Ceiling($icSize / ($a[0] - $b[0])) + 5 ; Отступ текста слева, в зависимости от размера иконки
	$itW = $icSize + $SpaceLen + $sizeText[0] + $paddingRight_Arrow + 10 ; Ширина Label
	Local $sPaddingLeftText = StringReplace(StringFormat('%' & $SpaceLen & 's', ''), ' ', ' '); Превращаем количество пробелов в реальные пробелы

	; Цикл отрисовки
	For $i = 0 To UBound($a_thisLevel) - 1
		Local $iIndexMM = Number($a_thisLevel[$i])
		Local $text = $aMatrixContextLM[$iIndexMM][0][$numMenu]
		If Not $text Then ContinueLoop
		If $text And StringStripWS($text, 8) <> '-' Then ; Если не сепаратор
			Local $label = GUICtrlCreateLabel($sPaddingLeftText & $text, $itX, $itY, $itW - $itX + 3, $itH, BitOR(0x0, 0x0200))

			GUICtrlSetBkColor(-1, -2); сделать Label прозрачным

			Local $sSp = ($sLabels_ContextLM) ? '|' : ''
			$sLabels_ContextLM &= $sSp & ControlGetHandle($hForm, '', $label) & '=' & $iIndexMM & ';' & $numMenu; Записываем, какой hwnd принадлежит порядковому индексу элемента в матрице

			Local $sIcon = $aMatrixContextLM[$iIndexMM][2][$numMenu] ; Получаем запись об основной иконке

			; Иконка стрелки, указывающей на вложенность(которая справа)
			If $aMatrixContextLM[Number($a_thisLevel[$i])][1][$numMenu] Then ; Если текущий элемент является меню
				Local $Pic2 = ''
				$Pic2 = GUICtrlCreatePic('', $itX + $itW - $paddingRight_Arrow, $itY + Int(($itH / 2) - ($icSize / 2)), 16, 16)
				Local $hIcon2 = _Icons_Icon_Extract($sArrowIcon_ContextLM, -1, 16, 16)
				Local $hBitmap2 = _Icons_Bitmap_CreateFromIcon($hIcon2)
				_SetHImage($Pic2, $hBitmap2)
				_WinAPI_DeleteObject($hBitmap2)
				_WinAPI_DestroyIcon($hIcon2)
				; Если нет иконки и по умолчанию включена иконка МЕНЮ, то показать её
				If Not $sIcon And $SHOW_DEFAULT_ICON_MENU_CONTEXTLM Then $sIcon = $DEFAULT_ICON_MENU_CONTEXTLM
			Else
				; Если нет иконки и по умолчанию включена иконка ПУНКТА, то показать её
				If Not $sIcon And $SHOW_DEFAULT_ICON_ITEM_CONTEXTLM Then $sIcon = $DEFAULT_ICON_ITEM_CONTEXTLM
			EndIf
			;

			Local $aIcon = StringRegExp($sIcon, '(.*);(-{0,1}\d+)$', 1) ; Парсим из строки файл иконки и её индекс
			If Not IsArray($aIcon) Then Dim $aIcon[2] = [$sIcon, 0]; Если не получилось, то создадим стандарт
			;

			; Отрисовка основной иконки
			If $aIcon[0] Then
				If $aIcon[1] = -1 Then $aIcon[1] = 0 ; Если нет индекса, или индекс равен -1

				Local $Pic1 = GUICtrlCreatePic('', $itX + 3, $itY - Int(($icSize / 2) - ($itH / 2)), $icSize, $icSize)
				Local $hIcon1 = _Icons_Icon_Extract($aIcon[0], $aIcon[1], $icSize, $icSize)
				Local $hBitmap1 = _Icons_Bitmap_CreateFromIcon($hIcon1)

				If Not $hBitmap1 Then ; костылёк - обход глюка, с исчезновением некоторых иконок 16x16
					Local $hIcon1 = _Icons_Icon_Extract($aIcon[0], $aIcon[1], $icSize + 1, $icSize + 1)
					Local $hBitmap1 = _Icons_Bitmap_CreateFromIcon($hIcon1)
				EndIf

				_SetHImage($Pic1, $hBitmap1)
				_WinAPI_DeleteObject($hBitmap1)
				_WinAPI_DestroyIcon($hIcon1)

			EndIf

			$itY += $itH
		Else ; Если сепаратор
			Local $xCorr = 0, $h_HorSep
			If $VERTICAL_SEPARATOR_CONTEXTLM Then $xCorr = $icSize + 12
			$h_HorSep = GUICtrlCreateGraphic($itX + $xCorr, $itY, $itW - $xCorr, 10)
			GUICtrlSetGraphic(-1, 8, $HOR_SEPARATOR_COLOR1_CONTEXTLM)
			GUICtrlSetGraphic(-1, 6, 0, 4)
			GUICtrlSetGraphic(-1, 2, $itW - $xCorr, 4)
			GUICtrlSetGraphic(-1, 8, $HOR_SEPARATOR_COLOR2_CONTEXTLM)
			GUICtrlSetGraphic(-1, 6, 0, 5)
			GUICtrlSetGraphic(-1, 2, $itW - $xCorr, 5)

			$itY += $itH - $icSize + 4
		EndIf

	Next

	; Работаем над координатами и размерами текущего меню
	Local $Pos = __MouseGetPos()
	If $iPosX >= 0 Then $Pos[0] = $iPosX
	If $iPosY >= 0 Then $Pos[1] = $iPosY
	Local $hForm_Height = $itY + 3
	Local $widhtForm = $itW + $padding + 3
	Local $top = 0
	If Not $iIndex1D Then
		_isDefParam_ContextLM($PositionTray, 0)
		$top = (Not $PositionTray) ? $Pos[1] : $Pos[1] - $hForm_Height
		If $Pos[0] < 0 Then $Pos[0] = 0
		If $Pos[0] + $itW + $padding + 3 > @DesktopWidth Then $Pos[0] = @DesktopWidth - $itW - $padding - 3
	Else
		Local $prPos = WinGetPos($hFormLM[UBound($hFormLM) - 2])
		_isDefParam_ContextLM($posTop, 0)
		$top = ($posTop) ? $prPos[1] + $posTop : $Pos[1]

		Local $prC = $prPos[0] + Int($prPos[2] / 2)
		Local $posLeft = $prPos[0] - $itW - 3
		Local $posRight = $prPos[0] + $prPos[2] - 3
		Local $left = ($Pos[0] - $prC <= 0 And $prPos[2] > 200) ? $posLeft : $posRight
		If $left + $itW - 3 > @DesktopWidth Then $left = $posLeft
		If $left < 0 Then $left = $posRight
		$Pos[0] = $left

	EndIf

	If $top < 0 Then $top = 0
	If $top + $hForm_Height > @DesktopHeight Then $top = @DesktopHeight - $hForm_Height

	WinMove($hForm, '', $Pos[0], $top, $itW + $padding + 3, $hForm_Height); Устанавливаем нужное расположение и размер

	; Вертикальный сепаратор. Будет показан при явном указании и если нет длинного горизонтального разделителя(только при коротком) ??? (длинный сепаратор не реализован)
	If $VERTICAL_SEPARATOR_CONTEXTLM Then
		Local $h_VertSep = GUICtrlCreateGraphic($icSize + 8, 0, 10, $hForm_Height)
		GUICtrlSetGraphic(-1, 8, $VERT_SEPARATOR_COLOR1_CONTEXTLM)
		GUICtrlSetGraphic(-1, 6, 4, 0)
		GUICtrlSetGraphic(-1, 2, 4, $hForm_Height)
		GUICtrlSetGraphic(-1, 8, $VERT_SEPARATOR_COLOR2_CONTEXTLM)
		GUICtrlSetGraphic(-1, 6, 5, 0)
		GUICtrlSetGraphic(-1, 2, 5, $hForm_Height)
	EndIf

	; Рамка и её цвет
	Local $h_BorderForm = GUICtrlCreateGraphic(0, 0, $itW + $padding + 3, $hForm_Height)
	GUICtrlSetColor(-1, $BORDER_COLOR_CONTEXTLM)

	; фон под иконками
	Local $h_BGIcons = GUICtrlCreateGraphic(1, 1, $icSize + 12, $hForm_Height - 2)
	GUICtrlSetBkColor(-1, $BG_ICONS_COLOR_CONTEXTLM)
	;
	; Создаём графику наведения курсора, оставляем невидимой
	If Not IsDeclared('nHoverBG') Then
		Local $nHoverBG = GUICtrlCreateGraphic(0, 0, 1, 1)
		GUICtrlSetState($nHoverBG, 32) ; Скрыть
		GUICtrlSetBkColor($nHoverBG, $BG_HOVER_CONTEXTLM)
		$sSp = ($sHoverBG_ContextLM) ? '|' : ''
		$sHoverBG_ContextLM &= $sSp & $hForm & '=' & $nHoverBG
	EndIf

	GUISetState(@SW_SHOW); Показываем меню

EndFunc   ;==>_Draw_ContextLM

Func _isDefParam_ContextLM(ByRef $vVar, $vDef)
	If StringLower($vVar) = 'default' Or StringLower($vVar) = 'def' Then $vVar = $vDef
	Return $vVar
EndFunc   ;==>_isDefParam_ContextLM

Func _getParam_ContextLM($sParams, $sGet = 'name', $sParam = '')
	Local $aKey
	$aKey = StringRegExp($sParams, '(?:^|\|)\s*(?i:' & $sGet & ')\s*=\s*([^\|]*?)\s*(?:\||\z)', 1)
	If IsArray($aKey) And $aKey[0] Then
		If $sParam Then
			If StringLower($aKey[0]) = StringLower($sParam) Then Return 1
			Return 0
		EndIf
		Return $aKey[0]
	EndIf
	If $sGet = 'name' Then $aKey = StringRegExp($sParams, '(?:^|\|)\s*([^|\s][^=]*?)\s*(?:\||\z)', 1)
	If IsArray($aKey) And $aKey[0] Then Return $aKey[0]
	$aKey = StringRegExp($sParams, '(?:^|\|)\s*(' & $sGet & ')\s*(?:\||\z)', 0)
	If $aKey And Not $sParam Then Return 1
	Return 0
EndFunc   ;==>_getParam_ContextLM

Func _getOfStartParam_ContextLM($sParams, $sGet, $ind = 0)
	Local $aParam = StringRegExp($sParams, '(?:^|\|)(?:' & $sGet & ')=(.*?)(?:\||$)', 1)

	If IsArray($aParam) And $aParam[0] Then
		Local $split = StringSplit($aParam[0], ';', 2)
		If $ind < 0 Then $ind = 0
		If $ind > UBound($split) Then $ind = UBound($split) - 1
		Return $split[$ind]
	EndIf
	Return 0
EndFunc   ;==>_getOfStartParam_ContextLM

Func __MouseGetPos()
	Local $t_Point, $aRet, $aPos[2]
	$t_Point = DllStructCreate('struct;long X;long Y;endstruct')
	$aRet = DllCall('user32.dll', 'bool', 'GetCursorPos', 'ptr', DllStructGetPtr($t_Point))
	If (@error) Or (Not $aRet[0]) Then Return SetError(1, 0, 0)
	$aPos[0] = DllStructGetData($t_Point, 'X')
	$aPos[1] = DllStructGetData($t_Point, 'Y')
	Return $aPos
EndFunc   ;==>__MouseGetPos

;**********************************************************************
; Получить размер строки в пикселях
;**********************************************************************
Func GetStringDimensions($hWnd, $sText)
	Local $hDC = _WinAPI_GetDC($hWnd) ; Возвращает дескриптор контекста устройства указанного окна.
	Local $hFont = _SendMessage($hWnd, 0x0031) ; Возвращает дескриптор шрифта, используемого для создания текста.
	Local $hSelectObject = _WinAPI_SelectObject($hDC, $hFont) ; Выбирает объект в указанном контекст устройстве.
	Local $tSIZE = _WinAPI_GetTextExtentPoint32($hDC, $sText) ; Вычисляет ширину и высоту указанной строки.
	_WinAPI_SelectObject($hDC, $hSelectObject)
	_WinAPI_ReleaseDC($hWnd, $hDC) ; Освобождает контекст устройства
	Local $aReturn[2] = [DllStructGetData($tSIZE, 1), DllStructGetData($tSIZE, 2)] ; Объявляет массив с шириной и высотой строки.
	Return $aReturn
EndFunc   ;==>GetStringDimensions

;**********************************************************************
; Отслеживание нажатий в меню
;**********************************************************************
Func _IsPressed_ContextLM($sHexKey, $vDLL = 'user32.dll')
	Local $aReturn = DllCall($vDLL, 'short', 'GetAsyncKeyState', 'int', '0x' & $sHexKey)
	If @error Then Return SetError(@error, @extended, False)
	Return BitAND($aReturn[0], 0x8000) <> 0
EndFunc   ;==>_IsPressed_ContextLM

Func _IsClickMouse_ContextLM()
	Local $hDLL = DllOpen("user32.dll")
	Local $LMOUSE = (_IsPressed_ContextLM('01')) ? 1 : 0
	Local $RMOUSE = (_IsPressed_ContextLM('02')) ? 1 : 0
	DllClose($hDLL)
	Local $mouse = [$LMOUSE, $RMOUSE]
	Return $mouse
EndFunc   ;==>_IsClickMouse_ContextLM

; Получить глобальный индекс по hWnd
Func _hWndToGlobalIndex_ContextLM($hControl)
	Local $count1DMatrix, $iIndex_Matrix, $numMenu
	$count1DMatrix = UBound($aMatrixContextLM)
	$iIndex_Matrix = _getOfStartParam_ContextLM($sLabels_ContextLM, $hControl) ; Определяем матричный индекс лэйбла, под которым курсор
	$numMenu = _getOfStartParam_ContextLM($sLabels_ContextLM, $hControl, 1) ;
	Return ($count1DMatrix * $numMenu) + $iIndex_Matrix
EndFunc   ;==>_hWndToGlobalIndex_ContextLM

; Получить матричный индекс первого измерения по hWnd
Func _hWndToIndex1D_ContextLM($hControl)
	Return Number(_getOfStartParam_ContextLM($sLabels_ContextLM, $hControl))
EndFunc   ;==>_hWndToIndex1D_ContextLM

; Получить порядковый номер меню по hWnd
Func _hWndToNumMenu_ContextLM($hControl)
	Return Number(_getOfStartParam_ContextLM($sLabels_ContextLM, $hControl, 1))
EndFunc   ;==>_hWndToNumMenu_ContextLM

Func _ControlHover_ContextLM()

	If Not IsArray($hFormLM) And UBound($hFormLM) < 1 Then Return 0 ; выход если нет форм

	Local $tPoint, $hControl, $hGUI
	$tPoint = _WinAPI_GetMousePos()
	$hControl = _WinAPI_WindowFromPoint($tPoint)
	$hGUI = _WinAPI_GetAncestor($hControl, 2)

	; Если курсор не над контекстным меню, то
	If Not _Hovered_ContextLM() Then
		Local $click = _IsClickMouse_ContextLM(); проверяем клик мышью
		If $click[0] Or $click[1] And _WinAPI_GetWindowText($hGUI) <> 'ContextLM' Then _CloseAllMenu_ContextLM(); закрываем все формы меню, если клик вне их
		Return 0
	EndIf
	; End ****************************************************************************************

	; Если контрол повторяется, то выходим, так как курсор находится на элементе, по которому отрисовка наведения уже отработана
	If _RepeatTrigger_ContextLM($hControl, 'hControl') Then Return 0
	; End ****************************************************************************************

	; **********************************************************************************************
	;	ОТРИСОВКА НАВЕДЕНИЯ
	; **********************************************************************************************
	Local $nControlID = __GetDlgCtrlID_ContextLM($hControl)
	Local $iIndex_MM = _getOfStartParam_ContextLM($sLabels_ContextLM, $hControl) ; Определяем матричный индекс лэйбла, под которым курсор
	Local $nHoverBG = _getOfStartParam_ContextLM($sHoverBG_ContextLM, $hGUI) ; Определяем ID блока наведения, связанного с формой, под которой курсор

	If $iIndex_MM Then
		Local $aPosControl = ControlGetPos($hGUI, '', $nControlID)

		Local $leftHov = $aPosControl[0]
		Local $widthHov = $aPosControl[2]

		If $BG_ICONS_COLOR_CONTEXTLM <> -2 Then ; $GUI_BKCOLOR_TRANSPARENT=-2
			Local $leftHov = $aPosControl[0] + $ICON_SIZE_CONTEXTLM + 10
			Local $widthHov = $aPosControl[2] - $ICON_SIZE_CONTEXTLM - 10
		EndIf

		If $LEFT_HOVER_CONTEXTLM > -1 Then
			$leftHov = $LEFT_HOVER_CONTEXTLM + 3
			Local $widthHov = WinGetPos($hGUI)[2] - $leftHov - 3
		EndIf

		; Перемещение элемента наведения
		GUICtrlSetState($nHoverBG, 32) ; Скрыть - такой подход сглаживает перемещение элемента наведения
		GUICtrlSetPos($nHoverBG, $leftHov, $aPosControl[1], $widthHov, $aPosControl[3]) ; Переместить
		GUICtrlSetState($nHoverBG, 16) ; Показать

	Else
		GUICtrlSetState($nHoverBG, 32)
	EndIf
	;

	Global $Sub_Timer_Params_ContextLM[2] = [$hGUI, $hControl]
	AdlibRegister('_ShowSub_Timer_ContextLM', 500)

EndFunc   ;==>_ControlHover_ContextLM

Func _RepeatTrigger_ContextLM($sVAR, $trigName)
	Local $sNewTrig = 'StopTrigger_' & $trigName & '_ContextLM'
	If Not IsDeclared($sNewTrig) Then Assign($sNewTrig, 0, 2)
	If Eval($sNewTrig) = $sVAR Then Return 1
	Local $a = Eval($sNewTrig)
	Assign($sNewTrig, $sVAR, 2)
	Return 0
EndFunc   ;==>_RepeatTrigger_ContextLM


Func _ShowSub_Timer_ContextLM()
	AdlibUnRegister('_ShowSub_Timer_ContextLM')

	If Not IsArray($Sub_Timer_Params_ContextLM) Or Not $Sub_Timer_Params_ContextLM[0] Or Not $Sub_Timer_Params_ContextLM[0] Then Return 0
	Local $hGUI = $Sub_Timer_Params_ContextLM[0]
	Local $hControl = $Sub_Timer_Params_ContextLM[1]
	Local $iIndex_MM = _getOfStartParam_ContextLM($sLabels_ContextLM, $hControl)

	Local $iGlobInd = _hWndToGlobalIndex_ContextLM($hControl)

	Local $isTAG = 0
	For $i = 0 To UBound($hFormLM) - 1
		If $isTAG > 0 Then GUIDelete($hFormLM[$i]) ; закрыть все окна кроме кликнутого и предыдущих ему
		If $hFormLM[$i] = $hGUI Then $isTAG = $i + 1
	Next
	If $isTAG > 0 Then ReDim $hFormLM[$isTAG]

	Local $numMenu = _getOfStartParam_ContextLM($sLabels_ContextLM, $hControl, 1)

	If $aMatrixContextLM[$iIndex_MM][1][$numMenu] And $iIndex_MM Then
		Local $posTop = ControlGetPos($hGUI, '', _WinAPI_GetDlgCtrlID($hControl)), $topPos = 0
		If IsArray($posTop) And $posTop[1] Then $topPos = $posTop[1]
		_Draw_ContextLM($iIndex_MM, $numMenu, 0, $topPos)
	EndIf

	$Sub_Timer_Params_ContextLM[0] = 0
	$Sub_Timer_Params_ContextLM[1] = 0
EndFunc   ;==>_ShowSub_Timer_ContextLM

; Находится ли курсор над GUI меню
Func _Hovered_ContextLM()
	If Not IsArray($hFormLM) And UBound($hFormLM) < 1 Then Return SetError(1, 0, 0) ; выход если нет форм
	Local $tPoint, $hControl, $hGUI
	$tPoint = _WinAPI_GetMousePos()
	$hControl = _WinAPI_WindowFromPoint($tPoint)
	$hGUI = _WinAPI_GetAncestor($hControl, 2)
	For $i = 0 To UBound($hFormLM) - 1
		If $hGUI = $hFormLM[$i] Then Return 1
	Next
	Return 0
EndFunc   ;==>_Hovered_ContextLM

; Возвращает идентификатор указанного элемента управления
Func __GetDlgCtrlID_ContextLM($hWnd)
	Return DllCall("user32.dll", "int", "GetDlgCtrlID", "hwnd", $hWnd)[0]
EndFunc   ;==>__GetDlgCtrlID_ContextLM

Func _BinToIcon_ContextLM($bData, $X = 0, $Y = 0, $W = -1, $H = -1)
	Local $Lenght = BinaryLen($bData)
	Local $hData = DllCall("kernel32.dll", "handle", "GlobalAlloc", "uint", 2, "ulong_ptr", $Lenght)[0]
	If @error Then Return SetError(@error, @extended, 0)
	Local $pData = DllCall("kernel32.dll", "ptr", "GlobalLock", "handle", $hData)[0]
	If @error Then Return SetError(@error, @extended, 0)
	$tData = DllStructCreate('byte[' & $Lenght & ']', $pData)
	DllStructSetData($tData, 1, $bData)
	DllCall("kernel32.dll", "bool", "GlobalUnlock", "handle", $hData)
	If @error Then Return SetError(@error, @extended, 0)
	$hStream = _WinAPI_CreateStreamOnHGlobal($hData)
	_GDIPlus_Startup()
	$hImage = _GDIPlus_BitmapCreateFromStream($hStream)
	$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
	$Width = _GDIPlus_ImageGetWidth($hImage)
	$Height = _GDIPlus_ImageGetHeight($hImage)
	_GDIPlus_ImageDispose($hImage)
	_GDIPlus_Shutdown()
	If $W = -1 Then $W = $Width
	If $H = -1 Then $H = $Height
	$Pic = GUICtrlCreatePic('', $X, $Y, $Width, $Height, BitOR(0x0100, 0x00800000))
	$hPic = GUICtrlGetHandle($Pic)
	_SendMessage($hPic, $STM_SETIMAGE, 0, $hBitmap)
	$hObj = _SendMessage($hPic, $STM_GETIMAGE)
	If $hObj <> $hBitmap Then
		_WinAPI_DeleteObject($hBitmap)
	EndIf
	Return $Pic
EndFunc   ;==>_BinToIcon_ContextLM
#EndRegion СИСТЕМНЫЕ ФУНКЦИИ

#Region Несколько необходимых функций из UDF Icons.au3
; Ссылка на UDF: http://autoit-script.ru/index.php?topic=49.0
Func _Icons_Icon_Extract($sIcon, $iIndex, $iWidth, $iHeight)
	Local $ret = DllCall('shell32.dll', 'int', 'SHExtractIconsW', 'wstr', $sIcon, 'int', $iIndex, 'int', $iWidth, 'int', $iHeight, 'ptr*', 0, 'ptr*', 0, 'int', 1, 'int', 0)
	If (@error) Or ($ret[0] = 0) Then Return SetError(1, 0, 0)
	Return $ret[5]
EndFunc   ;==>_Icons_Icon_Extract
;---
Func _Icons_Bitmap_CreateFromIcon($hIcon)
	Local $tICONINFO = DllStructCreate($tagICONINFO)
	Local $ret, $hBitmap
	$ret = DllCall('user32.dll', 'int', 'GetIconInfo', 'ptr', $hIcon, 'ptr', DllStructGetPtr($tICONINFO))
	If (@error) Or ($ret[0] = 0) Then
		Return 0
	EndIf
	$hBitmap = _Icons_Bitmap_Duplicate(DllStructGetData($tICONINFO, 5), 1)
	If Not _Icons_Bitmap_IsAlpha($hBitmap) Then
		_GDIPlus_Startup()
		_WinAPI_DeleteObject($hBitmap)
		If Not IsDeclared('ghGDIPDll') Then Global $ghGDIPDll
		$ret = DllCall($ghGDIPDll, 'int', 'GdipCreateBitmapFromHICON', 'ptr', $hIcon, 'ptr*', 0)
		If (Not @error) And ($ret[0] = 0) Then
			$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($ret[2])
			_GDIPlus_ImageDispose($ret[2])
		Else
			$hBitmap = 0
		EndIf
		_GDIPlus_Shutdown()
	EndIf
	Return $hBitmap
EndFunc   ;==>_Icons_Bitmap_CreateFromIcon
;---
Func _Icons_Bitmap_Duplicate($hBitmap, $fDelete = 0)
	If $fDelete Then
		$fDelete = $LR_COPYDELETEORG
	EndIf
	Local $ret = DllCall('user32.dll', 'hwnd', 'CopyImage', 'ptr', $hBitmap, 'int', 0, 'int', 0, 'int', 0, 'int', BitOR(0x2000, $fDelete))
	If (@error) Or ($ret[0] = 0) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $ret[0]
EndFunc   ;==>_Icons_Bitmap_Duplicate
;---
Func _Icons_Bitmap_IsAlpha($hBitmap)
	Local $ret, $tBits, $Lenght
	$ret = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBitmap, 'long', 0, 'ptr', 0)
	If (@error) Or ($ret[0] = 0) Then
		Return SetError(1, 0, 0)
	EndIf
	$Lenght = $ret[0] / 4
	$tBits = DllStructCreate('dword[' & $Lenght & ']')
	$ret = DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $hBitmap, 'long', $ret[0], 'ptr', DllStructGetPtr($tBits))
	If (@error) Or ($ret[0] = 0) Then
		Return SetError(1, 0, 0)
	EndIf
	For $i = 1 To $Lenght
		If BitAND(DllStructGetData($tBits, 1, $i), 0xFF000000) Then
			Return 1
		EndIf
	Next
	Return 0
EndFunc   ;==>_Icons_Bitmap_IsAlpha
;---
Func _SetHImage($hWnd, $hBitmap, $hOverlap = 0)
	$hWnd = _Icons_Control_CheckHandle($hWnd)
	If $hWnd = 0 Then
		Return SetError(1, 0, 0)
	EndIf
	Local $Result, $hImage
	If Not ($hOverlap < 0) Then
		$hOverlap = _Icons_Control_CheckHandle($hOverlap)
	EndIf
	$hBitmap = _Icons_Bitmap_Duplicate($hBitmap)
	$Result = _Icons_Control_SetImage($hWnd, $hBitmap, 0, $hOverlap)
	If $Result Then
		$hImage = _SendMessage($hWnd, 0x0173, 0, 0)
		If (@error) Or ($hBitmap = $hImage) Then
			$hBitmap = 0
		EndIf
	EndIf
	If $hBitmap Then
		_WinAPI_DeleteObject($hBitmap)
	EndIf
	Return SetError(1 - $Result, 0, $Result)
EndFunc   ;==>_SetHImage
;---
Func _Icons_Control_CheckHandle($hWnd)
	If Not IsHWnd($hWnd) Then
		$hWnd = GUICtrlGetHandle($hWnd)
		If $hWnd = 0 Then
			Return 0
		EndIf
	EndIf
	Return $hWnd
EndFunc   ;==>_Icons_Control_CheckHandle
;---
Func _Icons_Control_SetImage($hWnd, $hImage, $iType, $hOverlap)
	Local $Static, $Style, $Update, $tRect, $hPrev
	Switch $iType
		Case 0
			$Static = 0x0E
		Case 1
			$Static = 0x03
		Case Else
			Return 0
	EndSwitch
	$Style = _WinAPI_GetWindowLong($hWnd, $GWL_STYLE)
	If @error Then
		Return 0
	EndIf
	_WinAPI_SetWindowLong($hWnd, $GWL_STYLE, BitOR($Style, $Static))
	If @error Then
		Return 0
	EndIf
	$tRect = _Icons_Control_GetRect($hWnd)
	$hPrev = _SendMessage($hWnd, 0x0172, $iType, $hImage)
	If @error Then
		Return 0
	EndIf
	If $hPrev Then
		If $iType = 0 Then
			_WinAPI_DeleteObject($hPrev)
		Else
			_WinAPI_DestroyIcon($hPrev)
		EndIf
	EndIf
	If (Not $hImage) And (IsDllStruct($tRect)) Then
		_WinAPI_MoveWindow($hWnd, DllStructGetData($tRect, 1), DllStructGetData($tRect, 2), DllStructGetData($tRect, 3) - DllStructGetData($tRect, 1), DllStructGetData($tRect, 4) - DllStructGetData($tRect, 2), 0)
	EndIf
	If $hOverlap Then
		If Not IsHWnd($hOverlap) Then
			$hOverlap = 0
		EndIf
		_Icons_Control_Update($hWnd, $hOverlap)
	Else
		_Icons_Control_Invalidate($hWnd)
	EndIf
	Return 1
EndFunc   ;==>_Icons_Control_SetImage
;---
Func _Icons_Control_GetRect($hWnd)
	Local $Pos = ControlGetPos($hWnd, '', '')
	If (@error) Or ($Pos[2] = 0) Or ($Pos[3] = 0) Then
		Return 0
	EndIf
	Local $tRect = DllStructCreate($tagRECT)
	DllStructSetData($tRect, 1, $Pos[0])
	DllStructSetData($tRect, 2, $Pos[1])
	DllStructSetData($tRect, 3, $Pos[0] + $Pos[2])
	DllStructSetData($tRect, 4, $Pos[1] + $Pos[3])
	Return $tRect
EndFunc   ;==>_Icons_Control_GetRect
;---
Func _Icons_Control_Update($hWnd, $hOverlap)
	Local $tBack, $tFront = _Icons_Control_GetRect($hWnd)
	If $tFront = 0 Then
		Return
	EndIf
	Local $aNext = _Icons_Control_Enum($hWnd, 1)
	Local $aPrev = _Icons_Control_Enum($hWnd, 0)
	If UBound($aPrev) = 1 Then
		_WinAPI_InvalidateRect(_WinAPI_GetParent($hWnd), $tFront)
		Return
	EndIf
	Local $aWnd[UBound($aNext) + UBound($aPrev - 1)]
	Local $tIntersect = DllStructCreate($tagRECT), $pIntersect = DllStructGetPtr($tIntersect)
	Local $iWnd, $ret, $XOffset, $YOffset, $Count = 0, $Update = 0

	For $i = UBound($aPrev) - 1 To 1 Step -1
		$aWnd[$Count] = $aPrev[$i]
		$Count += 1
	Next
	For $i = 0 To UBound($aNext) - 1
		$aWnd[$Count] = $aNext[$i]
		$Count += 1
	Next
	For $i = 0 To $Count - 1
		If $aWnd[$i] = $hWnd Then
			_WinAPI_InvalidateRect($hWnd)
		Else
			If (Not $hOverlap) Or ($aWnd[$i] = $hOverlap) Then
				$tBack = _Icons_Control_GetRect($aWnd[$i])
				$ret = DllCall('user32.dll', 'int', 'IntersectRect', 'ptr', $pIntersect, 'ptr', DllStructGetPtr($tFront), 'ptr', DllStructGetPtr($tBack))
				If (Not @error) And ($ret[0]) Then
					$ret = DllCall('user32.dll', 'int', 'IsRectEmpty', 'ptr', $pIntersect)
					If (Not @error) And (Not $ret[0]) Then
						$XOffset = DllStructGetData($tBack, 1)
						$YOffset = DllStructGetData($tBack, 2)
						$ret = DllCall('user32.dll', 'int', 'OffsetRect', 'ptr', $pIntersect, 'int', -$XOffset, 'int', -$YOffset)
						If (Not @error) And ($ret[0]) Then
							_WinAPI_InvalidateRect($aWnd[$i], $tIntersect)
							$Update += 1
						EndIf
					EndIf
				EndIf
			EndIf
		EndIf
	Next
	If Not $Update Then
		_WinAPI_InvalidateRect(_WinAPI_GetParent($hWnd), $tFront)
	EndIf
EndFunc   ;==>_Icons_Control_Update
;---
Func _Icons_Control_Invalidate($hWnd)
	Local $tRect = _Icons_Control_GetRect($hWnd)
	If IsDllStruct($tRect) Then
		_WinAPI_InvalidateRect(_WinAPI_GetParent($hWnd), $tRect)
	EndIf
EndFunc   ;==>_Icons_Control_Invalidate
;---
Func _Icons_Control_Enum($hWnd, $iDirection)
	Local $iWnd, $Count = 0, $aWnd[50] = [$hWnd]
	If $iDirection Then
		$iDirection = $GW_HWNDNEXT
	Else
		$iDirection = $GW_HWNDPREV
	EndIf
	While 1
		$iWnd = _WinAPI_GetWindow($aWnd[$Count], $iDirection)
		If Not $iWnd Then
			ExitLoop
		EndIf
		$Count += 1
		If $Count = UBound($aWnd) Then
			ReDim $aWnd[$Count + 50]
		EndIf
		$aWnd[$Count] = $iWnd
	WEnd
	ReDim $aWnd[$Count + 1]
	Return $aWnd
EndFunc   ;==>_Icons_Control_Enum
#EndRegion Несколько необходимых функций из UDF Icons.au3

Пример.au3
Код:
#include <GUIConstantsEx.au3>
#include "ContextLM.au3"

Local $hGUI, $Button, $Button1, $newMenu1, $newMenu2, $newMenu3, $newMenu4
Local $m1,$m2, $m3, $m4, $m5, $m6, $i1, $i2, $i3, $mm1, $mm2, $mmm1, $mmmm1

local $sIconPath = @SystemDir & '\shell32.dll'

$hGUI = GUICreate("Имитация контекстного меню без блокировки",310, 310)
GUICtrlCreateLabel('Кликните в этом окне в любом месте под кнопками', 10, 10, 300, 25)
GUICtrlCreateLabel('Кликните по иконке скрипта в трее', 10, 30, 250, 25)
$Button = GUICtrlCreateButton('Кликните по этой кнопке правой кнопкой мыши', 10, 50, 290, 25)
$Button1 = GUICtrlCreateButton('Показать меню в произвольном месте', 10, 80, 290, 25)

GUISetState(@SW_SHOW)

TraySetIcon(@AutoItExe)

; Можно установить нестандартный размер иконок. Высота пунктов меню будет пропорциональна этому значению, если иконка больше стандартной высоты пункта.
;$ICON_SIZE_CONTEXTLM = 32

; Высоту пунктов меню, можно изменить в большую сторону относительно высоты иконок. Значения меньше, будут автоматически подстроены под размер иконки
;$ITEM_HEIGHT_CONTEXTLM = 40

;Меню для GUI
$newMenu1 = _NewMenu_ContextLM($hGUI)
$m1 = _CreateElem_ContextLM('Меню 1')
_CreateElem_ContextLM('Пункт 1 М1', $m1)
$m2 = _CreateElem_ContextLM('Меню 2')
$i1 = _CreateElem_ContextLM('Пункт 1 (Кликните здесь левой)')
_SetIcon_ContextLM($sIconPath, 43)
_CreateElem_ContextLM('Пункт 1 М2', $m2)
_CreateElem_ContextLM('Пункт 2 М2', $m2)
_CreateElem_ContextLM('Пункт 3 М2', $m2)
_CreateElem_ContextLM('',$m2) ; разделитель
_CreateElem_ContextLM('Пункт 4 М2', $m2)
_CreateElem_ContextLM('Пункт 5 М2', $m2)
$i2 = _CreateElem_ContextLM('Пункт 2 (Кликните здесь правой)')
_SetIcon_ContextLM($sIconPath, 57, -1)
_CreateElem_ContextLM() ; разделитель
$i3 = _CreateElem_ContextLM('Пункт 3')
_SetIcon_ContextLM($sIconPath, 130, $i3)
$m3 = _CreateElem_ContextLM('Меню 3', -1, $sIconPath & ';24')
_CreateElem_ContextLM('Пункт 1 М3', $m3)
_CreateElem_ContextLM('Пункт 2 М3', $m3)
_CreateElem_ContextLM('Пункт 3 М3', $m3)
_CreateElem_ContextLM()
$m4 = _CreateElem_ContextLM('Меню 4')
$m5 = _CreateElem_ContextLM('Меню 1 М4', $m4)
$m6 = _CreateElem_ContextLM('Пункт 1 М4M1', $m5)

; Меню для кнопки
$newMenu2 = _NewMenu_ContextLM($Button)
$mm1 = _CreateElem_ContextLM('+Меню 1')
$mm2 = _CreateElem_ContextLM('+Меню 2')
_CreateElem_ContextLM('Пункт 1 +М1', $mm1)
_CreateElem_ContextLM('Пункт 1 +М2', $mm2)
_CreateElem_ContextLM('+Пункт 1')

; Меню для трея
$newMenu3 = _NewMenu_ContextLM(0) ; 0 - привязка к трею
$mmm1 = _CreateElem_ContextLM('++ Меню 1')
_CreateElem_ContextLM('Пункт 1 ++М1', $mmm1)
_CreateElem_ContextLM('++ Пункт 1')

; Вложенное контекстное меню внутри контекстного меню
$newMenu4 = _NewMenu_ContextLM()
$mmmm1 = _CreateElem_ContextLM('+++ Меню 1')
_CreateElem_ContextLM('Пункт 1 +++ М1', $mmmm1)
_CreateElem_ContextLM('+++ Пункт 1')

_InitContextLM()

Local $Msg, $nMsg, $nClickL, $nClickR, $iRandX, $iRandY
While 1
	$Msg = GUIGetMsg()
	; Для GetMsg_ContextLM(Type)
	; Если Type = 0 - исключительно для ЛКМ
	; Если Type = 1 - исключительно для ПКМ
	; Если Type = 2 - вернётся результат в виде массива состояния клика [ЛКМ, ПКМ]
	$nMsg = GetMsg_ContextLM(2)
	$nClickL = (IsArray($nMsg)) ? $nMsg[0] : 0
	$nClickR = (IsArray($nMsg)) ? $nMsg[1] : 0

	Switch $nClickL
		Case $i1
			MsgBox(0,'','Нажат Пункт 1')
	EndSwitch

	Switch $nClickR
		Case $i2
			_Show_ContextLM($newMenu4)
	EndSwitch

	Switch $Msg
		Case $Button1
			$iRandX = Random( 0, @DesktopWidth, 1)
			$iRandY = Random( 0, @DesktopHeight, 1)
			_Show_ContextLM($newMenu1, $iRandX, $iRandY)
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch

	Sleep(10)

WEnd

Архив с подробным описанием:
https://yadi.sk/d/0ZrPOdL4fKiKRg

Скриншот:
 

yuraiva

Новичок
Сообщения
3
Репутация
0
Хорошая работа, но не запускается.
\AutoIt3\Include\Icons.au3"(625,28) : warning: $ghGDIPDll: possibly used before declaration.
Windows 7 x64 AutoIt 3.3.14.5
Сообщение автоматически объединено:

А вот и ответ.
Добавил в глобальные переменные библиотеки
Global Const $STM_SETIMAGE = 0x0172
Global Const $STM_GETIMAGE = 0x0173

и заменил $ghGDIPDll на $__g_hGDIPDll
 
Последнее редактирование:
Верх