Если 5 параметром указать 1, то при выборе пункта мышь сначала вернётся в координаты на момент вызова меню, если 2 то вернётся и кликнет.
Можно задать пункту свои цвета указав 3 параметром массив:
B - фон, H - подсветка, T - текст. См. пример ниже, второе меню.
Если какой то из них не указан, берётся из общего для меню.
Можно в последствии изменить текст пункта указав его индекс, ширина меню при этом не изменится.
Можно запретить колёсико мыши, если например меню вызывается по средней кнопке или колёсику.
#SingleInstance Force
#NoEnv
List1 := [["Мой компьютер","g1"],["Программы","g2"],["Рабочий стол","g3"],["Мои документы","g4"]]
List2 := [["Папка скрипта","OpenDir"],["Редактировать","Edit"],["Как определить имя пункта","Check_name",{B:"FFDE8A",H:"E66C4F",T:"000000"}]]
Menu1 := New Menu(List1, "FFFFFF", "DBDBDB", "2842A0", 210, 10)
Menu2 := New Menu(List2, "5976C5", "2EC001", "FFFFFF", , 22)
Escape:: ExitApp
1::
Menu1.Show()
KeyWait, 1
Menu1.Hide(1)
Return
2::Menu2.Show("Center", 100, "S",, 1)
OpenDir:
Run %A_ScriptDir%
Return
Edit:
Run, Edit %A_ScriptFullPath%
Return
Check_name:
MsgBox % Menu.Name
Return
g1:
Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d}
Return
g2:
Run, %A_ProgramFiles%
Return
g3:
Run, %A_Desktop%
Return
g4:
Run, %A_MyDocuments%
Return
Class Menu {
Static View, Selection, AllReady, Obj, PrCtrl, WaitX, WaitY, Name, Label
__New(List, bcgColor, hiColor, textColor, Transparent = 255, FontSize = 0, XMargin = 1, YMargin = 1) {
If !Menu.AllReady
Menu.SetHotkeys(), OnMessage(0x202, this["WM_LBUTTONUP"].Bind(this)), Menu.AllReady := 1
Gui, New
Gui, +AlwaysOnTop -DPIScale +hwndhGui +LabelMenuOn -Caption +Border +Owner +E0x08000000
this.hwnd := hGui, this.List := List
Gui, Font, % "q1" . (FontSize ? " s" FontSize : "")
Gui, Margin, 0, 0
Gui, Color, %bcgColor%
S_AutoTrim := A_AutoTrim
AutoTrim, Off
Loop % XMargin
XMarginStr .= " "
this.XMarginStr := XMarginStr
AutoTrim, %S_AutoTrim%
this.GetMaxSize(List, maxW, maxH)
Gui, Show, Hide w0 h0
For k, v in List
{
_bcgColor := v[3].B != "" ? v[3].B : bcgColor, _textColor := v[3].T != "" ? v[3].T : textColor, _hiColor := v[3].H != "" ? v[3].H : hiColor
Gui, Add, Progress, % (k = 1 ? "x0 y0" : "y+0") " hwndhBack w" maxW " h" maxH + (maxH / 100 * YMargin) " Background" _bcgColor, 0
Gui, Add, Text, % "xp yp wp hp hwndhText +0x200 BackgroundTrans c" _textColor, % XMarginStr v[1] XMarginStr
this.Items[hText] := {back:hBack,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
this.Items[hBack] := {text:hText,key:k,Label:v[2],name:v[1],bcgColor:_bcgColor,hiColor:_hiColor,textColor:_textColor}
this.ItemPos[k] := {text:hText,back:hBack}
}
Gui, Show, Hide AutoSize, #32768
S_DetectHiddenWindows := A_DetectHiddenWindows
DetectHiddenWindows, On
If (Transparent < 255)
WinSet, Transparent, %Transparent%, ahk_id %hGui%
WinGetPos, , , Width, Height, ahk_id %hGui%
this.Width := Width, this.Height := Height
DetectHiddenWindows, %S_DetectHiddenWindows%
Return this
}
Show(x = 0, y = 0, Relative = "M", hWin = 0, SaveMouse = 0) {
Menu.Close()
Hwnd := Menu.View := this.hwnd
If SaveMouse
DllCall("GetCursorPos", "int64P", pt), this.SaveMouseX := pt << 32 >> 32, this.SaveMouseY := pt >> 32
this.SaveMouse := SaveMouse
Menu.Name := Menu.Label := Menu.PrCtrl := ""
If Relative = S
sx := x, sy := y
Else
{
If Relative = W
{
WinGetPos, wx, wy, ww, wh, % (hWin ? "ahk_id" hWin : "A")
ix := wx + (x = "Center" ? ((ww // 2) - (this.Width // 2)) : x)
iy := wy + (y = "Center" ? ((wh // 2) - (this.Height // 2)) : y)
}
Else If Relative = M
{
DllCall("GetCursorPos", "int64P", pt), ix := pt << 32 >> 32, iy := pt >> 32
ix += (x = "Center" ? -(this.Width // 2) : x)
iy += (y = "Center" ? -(this.Height // 2) : y)
}
Menu.GetClientSize(Hwnd, w, h)
Menu.CalculatePopupWindowPosition(sx, sy, w, h, ix, iy)
}
Gui, %Hwnd%:Show, NA AutoSize x%sx% y%sy%
hFunc := ObjBindMethod(this, "MouseGet")
SetTimer, % hFunc, 10
Menu.Obj := this
}
Hide(Select = 0) {
hFunc := ObjBindMethod(this, "MouseGet")
SetTimer, % hFunc, Off
Hwnd := Menu.View
this := Menu.Obj
item := this.Items[Menu.Selection]
Menu.Color(item.bcgColor, item.back)
If this.SaveMouse
DllCall("SetCursorPos", "Uint", this.SaveMouseX, "Uint", this.SaveMouseY)
If this.SaveMouse = 2
Click
Menu.View := Menu.Selection := 0, Menu.WaitX := Menu.WaitY := Menu.Obj := ""
Try Gui, %Hwnd%:Show, Hide
If Select
Try GoSub, % Menu.Label
}
GetMaxSize(Items, ByRef maxW, ByRef maxH) {
For k, v in Items
{
Gui, Add, Text, hwndhDummy hidden, % this.XMarginStr v[1] this.XMarginStr
GuiControlGet, Pos, Pos, %hDummy%
maxW := !maxW || PosW > maxW ? PosW : maxW
maxH := !maxH || PosH > maxH ? PosH : maxH
DllCall("DestroyWindow", "Ptr", hDummy)
}
}
NewText(Index, Text) {
hText := this.ItemPos[Index].text
GuiControl, , %hText%, % this.XMarginStr Text this.XMarginStr
this.Items[hText].name := Text
this.Items[this.ItemPos[Index].back].name := Text
}
Select() {
Menu.Hide(1)
}
Close() {
this := Menu.Obj, this.SaveMouse := 0
Menu.Label := Menu.Name := "", Menu.Hide()
}
MouseGet() {
MouseGetPos, , , win, ctrl, 2
If (Menu.WaitX != "")
{
If (win != Menu.View)
Return
DllCall("GetCursorPos", "int64P", pt), X := pt << 32 >> 32, Y := pt >> 32
If (Abs(X - Menu.WaitX) > 1 || Abs(Y - Menu.WaitY) > 1)
Menu.WaitX := Menu.WaitY := ""
Else
Return
}
If (win = Menu.View)
{
If (ctrl && ctrl != Menu.PrCtrl)
{
this := Menu.Obj
item := this.Items[Menu.Selection]
Menu.Color(item.bcgColor, item.back)
Menu.Selection := ctrl
item := this.Items[Menu.Selection]
Menu.Color(item.hiColor, item.back)
Menu.Label := item.Label
Menu.Name := item.Name
Menu.PrCtrl := ctrl
}
}
Else If Menu.Selection
{
this := Menu.Obj
item := this.Items[Menu.Selection]
Menu.Color(item.bcgColor, item.back)
Menu.Name := Menu.Label := Menu.PrCtrl := Menu.Selection := ""
}
Hwnd := Menu.View
Try Gui, %Hwnd%:+AlwaysOnTop
}
Up_Down() {
this := Menu.Obj
mi := this.List.MaxIndex()
sel := this.Items[Menu.Selection].key
new := InStr(A_ThisHotkey, "Up")
? (!sel || sel = 1 ? mi : sel - 1)
: (!sel || sel = mi ? 1 : sel + 1)
item := this.Items[Menu.Selection]
Menu.Color(item.bcgColor, item.back)
Menu.Selection := this.ItemPos[new].text
item := this.Items[Menu.Selection]
Menu.Color(item.hiColor, item.back)
Menu.Label := item.Label
Menu.Name := item.Name
Menu.PrCtrl := 0
DllCall("GetCursorPos", "int64P", pt), Menu.WaitX := pt << 32 >> 32, Menu.WaitY := pt >> 32
}
SetHotkeys() {
#If Menu.View
#If Menu.View && Menu.Selection
#If
Hotkey, IF, Menu.View
hFunc := ObjBindMethod(this, "Up_Down")
If !Menu.NotWheel
{
Hotkey, *$WheelUp, % hFunc
Hotkey, *$WheelDown, % hFunc
}
Hotkey, *$Up, % hFunc
Hotkey, *$Down, % hFunc
hFunc := ObjBindMethod(this, "MenuIsUnderMouse")
Hotkey, ~*$LButton, % hFunc
Hotkey, ~*$RButton, % hFunc
Hotkey, ~*$MButton, % hFunc
hFunc := ObjBindMethod(this, "Close")
Hotkey, *$Escape, % hFunc
Hotkey, $Escape, % hFunc
Hotkey, *$LAlt, % hFunc
Hotkey, *$LWin, % hFunc
Hotkey, IF, Menu.View && Menu.Selection
hFunc := ObjBindMethod(this, "Select")
Hotkey, *$Space, % hFunc
Hotkey, *$Enter, % hFunc
Hotkey, IF
}
MenuIsUnderMouse() {
MouseGetPos, , , win
If (win != Menu.View)
Menu.Close()
}
Color(color, hwndback) {
GuiControl, +Background%color%, %hwndback%
GuiControl, +Redraw, %hwndback%
GuiControl, +Redraw, % Menu.Selection
}
WM_LBUTTONUP(w, l, m, h) {
If (A_Gui = Menu.View)
Menu.Select()
}
GetClientSize(hwnd, ByRef W, ByRef H) {
VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
W := NumGet(pwi, 28, "Int") - NumGet(pwi, 20, "Int")
H := NumGet(pwi, 32, "Int") - NumGet(pwi, 24, "Int")
}
CalculatePopupWindowPosition(byref left, byref top, w, h, x, y, offsetx = 0, offsety = 0) {
VarSetCapacity(point, 8, 0), VarSetCapacity(structs, 24, 0)
NumPut(x, point, 0, "int"), NumPut(y, point, 4, "int")
NumPut(w + offsetx, structs, 0, "int"), NumPut(h + offsety, structs, 4, "int")
If !DllCall("CalculatePopupWindowPosition"
, "ptr", &point
, "ptr", &structs
, "int", 0
, "ptr", 0
, "ptr", &structs + 8)
Return 0
left := NumGet(structs, 8, "int") + offsetx
top := NumGet(structs, 12, "int") + offsety
Return 1
}
}