Orion9

|
Posted: Wed Nov 12, 2025 13:27 Post subject: |
|
|
Только не сбивайте мне вайб, у меня маза пошла, иду на рекорд
Титаник и Леон лежат ровно, чего не скажешь о бэкапах ТС - их словно пробили на перфокарте )
 Hidden text
Шутки шутками, а я нашёл серьёзный косяк. Не учёл, что панель может изменяться не только при перетаскивании кнопок, но и при обычных операциях копирования и вставки. Соответственно, индекс нарушался. Внёс небольшие изменения, а также добавил ключ "/R", который забыл в прошлый раз добавить.
 Bars.aucfg | Code: | Pragma IncludeOnce
# наведение на главную панель
ControlSetHint /F /D:50 28 "HBarShowHint"
# правый клик с удержанием Ctrl
ControlSetMouseAction /R /K:C 28 "HBarShowMenu"
Global gDragIndex, gDropIndex
Global gHBarButtons = 0, gHBarDivs = 0
Global gHBarName, gHBarFile, gHBarFileTs,
Global gHBarTxt, gHBarCP = "ANSI", gHBarWincmd = 0
Global gHBarHint = 0, gHBarVerb, gHBarCancel, gHBarCancelLoad, gHBarLoadError = 0
Global gHBarList = List(), gHBarMap = List(), gHBarUndo, gHBarUndoTs, gHBarUndoLoad
Global gHBarWndProc, hBarWnd = 0
Global gHBarWP = Callback("HBarWndProc", "hwnd;uint;wparam;lparam")
Func HBarWndProc(hWnd, uMsg, wParam, lParam)
Static IsDrag = 0, _
hTotal = DllCall("GetModuleHandleW", "Ptr", 0, "handle"), _
MK_SHIFT = 0x0004, _
MK_CONTROL = 0x0008, _
MK_LBUTTON = 0x0001, _
WM_MOUSEMOVE = 0x0200, _
WM_LBUTTONDOWN = 0x0201, _
WM_LBUTTONUP = 0x0202
Static drag_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32646), _
stop_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32648), _
drag_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 22), _
stop_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 21)
Static SM_CXDRAG = 68, SM_CYDRAG = 69, _
dragX = GetSystemMetrics(SM_CXDRAG), dragY = GetSystemMetrics(SM_CYDRAG), _
startX, startY
Local x, y, pos
If gHBarLoadError Then
Return DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndIf
Switch uMsg
Case WM_LBUTTONDOWN
If IsDrag = 0 And BitAND(wParam, MK_CONTROL) Then
#MouseGetPos("x","y")
Static buf = Buffer(8) # POINT
buf.Zero()
x = BitAND(lParam, 0xFFFF)
y = BitAND(BitShift(lParam,16), 0xFFFF)
startX = x
startY = y
buf.SetNum(0, "int", x, "int", y)
DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
pos = buf.GetNum(0, "int64")
#x = buf.GetNum(0)
#y = buf.GetNum(4)
#If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
If DllCall("DragDetect", "hwnd", hWnd, "int64", pos) Then
IsDrag = 1
WinSetStyle(0x80000, 3, hWnd)
DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
gDragIndex = HBarGetIdx()
Else
IsDrag = 0
DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", WM_LBUTTONUP, "wparam", wParam, "lparam", lParam)
Return 0
EndIf
EndIf
Case WM_LBUTTONUP
If IsDrag = 1 Then
DllCall("ReleaseCapture")
IsDrag = 0
If WinFromPoint() = hWnd Then
gDropIndex = HBarGetIdx()
If gDragIndex <> gDropIndex Then
If gHBarHint Then ShowDragHint("Index " & gDragIndex & " To Index: " & gDropIndex)
HBarDragnDrop(gDragIndex, gDropIndex)
EndIf
EndIf
WinSetStyle(0x80000, 5, hWnd)
#Return 0
#MouseGetPos("x","y")
#lParam = MakeInt(y, x + 200, 2)
lParam = 0
EndIf
Case WM_MOUSEMOVE
If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
If WinFromPoint() = hWnd Then
DllCall("SetCursor", "Ptr", drag_cursor)
Else
DllCall("SetCursor", "Ptr", stop_cursor)
EndIf
EndIf
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func HBarShowHint()
If WinHasStyle(0x80000, 1, hBarWnd) Then Return
# состояние Ctrl
Local bMap = IsPressed(0x11)
# состояние CapsLock и Shift
If Not bMap Then
If BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1) = 0 Then
If Not IsPressed(0x10) Then Return
EndIf
EndIf
# дескриптор горизонтальной панели
Local hWnd = RequestInfo(28)
If hWnd = 0 Then
Return "Окно панели не найдено " & hWnd
EndIf
# глобальные переменные дескриптора и оконной процедуры
If hBarWnd <> hWnd Then
hBarWnd = hWnd
gHBarWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
"hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWP.Ptr, "ptr")
EndIf
# поиск файла панели
If gHBarName <> WinGetText(hBarWnd) Then
gHBarUndo = false
gHBarUndoLoad = ""
gHBarCancel = false
gHBarCancelLoad = ""
gHBarFile = HBarGetFile()
If Not FileExist(gHBarFile) Then
gHBarName = ""
Return "Файл панели не найден " & gHBarFile
EndIf
# метка времени
gHBarFileTs = FileGetTime(gHBarFile)
# загрузка панели
HBarLoad()
If gHBarLoadError Then Return HBarGetHint(bMap)
ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
gHBarUndo = false
gHBarUndoLoad = ""
If Not FileExist(gHBarFile) Then
gHBarName = ""
Return "Файл панели не найден " & gHBarFile
EndIf
gHBarFileTs = FileGetTime(gHBarFile)
HBarLoad()
If gHBarLoadError Then Return HBarGetHint(bMap)
EndIf
# индекс кнопки под курсором
gDragIndex = HBarGetIdx()
If Not gDragIndex Then Return "Не удалось определить индекс кнопки"
Return HBarGetHint(bMap)
EndFunc
Func HBarGetFile()
Local bar, txt
# информация о файле панели в wincmd.ini
IniRead /R bar %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\DEFAULT.BAR"
# раскрытие переменной окружения
bar = Set(bar)
# в конфигурации указано только имя файла
If FileGetDir(bar) = "" Then bar = COMMANDER_PATH & "\" & bar
gHBarWincmd = bar
# чтение текста окна панели
txt = WinGetText(hBarWnd)
gHBarName = txt
# на панель загружен временный .bar файл
If Not StrPos(bar, txt) Then
bar = COMMANDER_PATH & "\Bars\" & txt
EndIf
If Not FileExist(bar) Then
bar = GetCurrentPath() & "\" & txt
EndIf
# проверка существования файла панели
If Not FileExist(bar) Then
bar = COMMANDER_PATH & "\" & txt
EndIf
Return bar
EndFunc
Func HBarLoad()
gHBarLoadError = 0
Local bar = FileRead(gHBarFile, 128, "RAW")
Local bom = "FFFE"
Local utf = "5B0042007500740074006F006E006200610072005D000D000A00"
If ERROR = 1 Then
gHBarLoadError = 1
gHBarCP = "Unknown"
Return
EndIf
If StrLeft(bar, 4) = "FFFE" Then
gHBarCP = "UTF-16 BOM"
Else
IF StrPos(bar, utf) Then
gHBarCP = "UTF-16 без BOM"
Else
gHBarCP = "ANSI"
EndIf
EndIf
# загрузка файла в массив
gHBarList.Count = 0
gHBarList.LoadFromFile(gHBarFile, gHBarCP)
# количество кнопок в файле
Local nCount = 0
IniRead /R nCount %gHBarFile% "Buttonbar" "Buttoncount" 0
# обнуление счетчиков
gHBarDivs = 0
gHBarButtons = 0
# локальные переменные
Local j, key, val, found, oButton = Map(), oCmd = Map()
# поиск кнопок и команд
For j = 0 To gHBarList.Count - 1
found = 0
If StrLeft(gHBarList[j], 6) = "button" Then
found = 1
ElseIf StrLeft(gHBarList[j], 3) = "cmd" Then
found = 2
EndIf
If found > 0 Then
key = StrLower(StrPart(gHBarList[j], "=", 1))
val = StrLen(StrPart(gHBarList[j], "=", 2))
If found = 1 Then
oButton.Set(key, val)
Else
oCmd.Set(key, val)
EndIf
EndIf
Next
gHBarMap.Count = 0
# подсчет кнопок и разделителей
For j = 1 To nCount
key = "button" & j
val = oButton.Get(key, 0)
If val > 0 Then
# количество кнопок
gHBarButtons += 1
gHBarMap.Add(1)
Else
# количество разделителей
gHBarDivs += 1
gHBarMap.Add(0)
EndIf
Next
Free(oButton, oCmd)
If gHBarButtons = 0 Then gHBarLoadError = 1
# карта панели
gHBarTxt = auCRLF & auCRLF & "Loaded" & ": " & gHBarFile & " > " & gHBarCP & " "
If gHBarLoadError Then gHBarTxt &= " -- ERROR LOADING"
gHBarTxt &= auCRLF
For j = 0 To gHBarMap.Count - 1
gHBarTxt &= gHBarMap[j] & " "
If j > 0 and Mod(j, 50) = 0 Then gHBarTxt &= auCRLF
Next
gHBarTxt &= auCRLF & "Wincmd.ini: " & gHBarWincmd
EndFunc
Func HBarGetIdx()
# дескриптор монитора окна ТС
Local hMon = DllCall("MonitorFromWindow", "hwnd", AUTORUN_TCHANDLE, "dword", 2)
# буфер для структуры MONITORINFOEX
Local buf = Buffer(104)
buf.Zero()
buf.SetNum(0, "dword", 104)
DllCall("GetMonitorInfoW", "ptr", hMon, "ptr", buf.ptr)
# имя монитора
Local sMon = buf.GetStr(40)
# информация о масштабировании экрана
Local DC = DllCall("GetDC", "int", 0)
Local nDPI = DllCall("GetDeviceCaps", "handle", DC, "int", 88) # LOGPIXELSX
Local nScale = DllCall("MulDiv", "int", 100, "int", nDPI, "int", 96)
DllCall("ReleaseDC", "int", 0, "handle", DC)
# локальные переменные
Local x, y, w, h, mx, my, idx, row, rows, rowh, dpi, b, extra
# координаты и размеры окна панели
WinGetPos("x", "y", "w", "h", hBarWnd)
# координаты указателя мыши
MouseGetPos("mx", "my")
# чтение информации о высоте кнопок
IniRead /R b %COMMANDER_INI% "Buttonbar" "Buttonheight"
IniRead /R dpi %COMMANDER_INI% "Buttonbar" "DefaultDpi" %'nDPI'
Local b_ini = b, b_calc
# масштабирование экрана
If dpi <> nDPI Then
IniRead /R d %COMMANDER_INI% "Buttonbar" %'"Buttonheight" & nDPI' 0
If d <> 0 Then
b = d
Else
b = Round(b / (dpi / nDPI), 0)
b_calc = "*"
EndIf
EndIf
# количество рядов кнопок на панели
rows = Floor(h/b)
If rows = 0 Then Return HBarShowHint("Error number of rows can't be zero")
# количество дополнительных пикселей
extra = Mod(h,b)
# ширина разделителя
Local div = Floor(b/3)
# высота одного ряда
rowh = b + 3
# номер ряда под указателем
row = Ceil((my - y)/rowh)
# абстрактные координаты по оси х
Local tx = (mx - x + 1) + ((row - 1) * w), cx = 0
# индекс кнопки в ряду
If gHBarDivs = 0 Then
idx = (Floor((mx - x)/b) + 1) + (row-1)*(Floor(w/b))
Else
j = 1
idx = 0
For i = 0 To gHBarMap.Count - 1
cx += (gHBarMap[i] = 0 ? div : b)
ex = j*w - cx
If i + 1 <= gHBarMap.Count - 1 Then
If ex < (gHBarMap[i+1] = 0 ? div : b) Then
cx += ex
j += 1
EndIf
Else
cx += ex
EndIf
If cx >= tx Then
idx = i + 1
Break
EndIf
Next
EndIf
# дополнительная информация
gHBarVerb = "mouse=" & mx & ", " & my & auCRLF & _
"bar=" & x & ", " & y & ", " & w & ", " & h & auCRLF & _
"map=" & tx & ", " & cx & auCRLF & _
"row=" & row & " of " & rows & auCRLF & _
"height=" & rowh & " (" & extra & ")" & " b=" & b & b_calc & " (" & b_ini & ")" & auCRLF & _
"buttons=" & gHBarButtons & " + " & gHBarDivs & " divs" & auCRLF & _
"width=" & b & ", " & div & auCRLF & _
"mon=" & HMon & " dpi=" & nDPI & " scale=" & nScale & "%"
Return idx
EndFunc
Func HBarGetHint(bMap)
# чтение информации о кнопке из .bar фйла
Local sMenu, sButton, sCmd, sParam, sPath, sIcon
IniRead sMenu %gHBarFile% "Buttonbar" %'"menu" & gDragIndex' ""
IniRead sButton %gHBarFile% "Buttonbar" %'"button" & gDragIndex' ""
IniRead sCmd %gHBarFile% "Buttonbar" %'"cmd" & gDragIndex' ""
IniRead sParam %gHBarFile% "Buttonbar" %'"param" & gDragIndex' ""
IniRead sPath %gHBarFile% "Buttonbar" %'"path" & gDragIndex' ""
IniRead sIcon %gHBarFile% "Buttonbar" %'"iconic" & gDragIndex' ""
# удаление подсказки тотала
Local hTip = WinFind(0, "TToolTip")
If hTip > 0 Then DllCall("DestroyWindow", "handle", hTip)
# возврат текста
Return gHBarVerb & auCRLF & _
"" & auCRLF & _
"index=" & gDragIndex & " of " & gHBarButtons+gHBarDivs & auCRLF & _
"menu=" & sMenu & auCRLF & _
"button=" & sButton & auCRLF & _
"cmd=" & sCmd & auCRLF & _
"param=" & sParam & auCRLF & _
"path=" & sPath & auCRLF & _
"iconic=" & sIcon & (bMap ? gHBarTxt : "")
EndFunc
Func HBarDragnDrop(DragIdx, DropIdx)
Static aItems = List("button","cmd","param","path","menu","iconic")
Local T1, T2, bTL = 0
If bTL Then T1 = GetUptime()
Local i, j, k, txt, key, new
txt = gHBarList.Text
gHBarUndoLoad = txt
If Not gHBarCancel Then
gHBarCancel = true
gHBarCancelLoad = txt
EndIf
# временная замена индекса
For j = 0 To aItems.Count - 1
key = aItems[j] & DragIdx & "="
new = aItems[j] & 9999 & "="
txt = StrReplace(txt, key, new)
Next
If bTL Then
T2 = Round(GetUptime() - T1, 0) / 1000
OutputDebugString("Время операции 1: " & StrFormat("%.3f", T2) & " sec")
EndIf
If DragIdx < DropIdx Then
For i = DragIdx + 1 To DropIdx
For k = 0 To aItems.Count - 1
key = aItems[k] & i & "="
new = aItems[k] & i - 1 & "="
txt = StrReplace(txt, key, new)
If bTL Then OutputDebugString("DragIdx < " & key & " -> " & new)
Next
Next
Else
For i = DragIdx - 1 TO DropIdx Step -1
For k = 0 To aItems.Count - 1
key = aItems[k] & i & "="
new = aItems[k] & i + 1 & "="
txt = StrReplace(txt, key, new)
If bTL Then OutputDebugString("DragIdx > " & key & " -> " & new)
Next
Next
EndIf
If bTL Then
T2 = Round(GetUptime() - T1, 0) / 1000
OutputDebugString("Время операции 2: " & StrFormat("%.3f", T2) & " sec")
EndIf
For j = 0 To aItems.Count - 1
key = aItems[j] & 9999 & "="
new = aItems[j] & DropIdx & "="
txt = StrReplace(txt, key, new)
Next
gHBarList.Text = txt
gHBarList.SaveToFile(gHBarFile, gHBarCP)
gHBarUndoTs = FileGetTime(gHBarFile)
gHBarFileTs = FileGetTime(gHBarFile)
If gHBarUndoTs Then
gHBarUndo = true
Else
gHBarUndo = false
gHBarUndoLoad = ""
EndIf
HBarLoad()
If bTL Then
T2 = Round(GetUptime() - T1, 0) / 1000
OutputDebugString("Время операции 3: " & StrFormat("%.3f", T2) & " sec")
EndIf
SendCommand(2945) # cm_ReloadBarIcons
EndFunc
Func ShowDragHint(DragHint)
SetHintParam("ShowHint", "Font", 14, "Arial")
SetHintParam("ShowHint", "BackColor", 0x000000)
SetHintParam("ShowHint", "Text", 0xFFFFFF)
SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
SetHintParam("ShowHint", "DarkText", 0xFFFFFF)
ShowHint(DragHint, "", "", 3000, 1)
WinAlign(LAST_HINT_WINDOW)
Sleep(10)
SetHintParam("ShowHint", "Reload")
EndFunc
Func HBarShowMenu()
Local hWnd = RequestInfo(28)
If hWnd = 0 Then
ShowDragHint("Окно панели не найдено")
Return
EndIf
If gHBarName <> WinGetText(hWnd) Then
ShowDragHint("Нет сведений о файле панели")
Return
EndIf
ShowPopupMenu /D /F /I:0 "HBarMenu"
EndFunc
Func HBarMenu()
Local txt
Local bak1 = FileChangeExt(gHBarFile, "bak1")
Local bak2 = FileChangeExt(gHBarFile, "bak2")
txt &= 'MENUITEM "' & gHBarName & '", em_aucmd /D' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Загружена как ANSI", em_aucmd ' & (gHBarCP = "ANSI" ? "/C" : "") & ' -1' & auCRLF
txt &= 'MENUITEM "Загружена как UTF-16", em_aucmd ' & (StrPos(gHBarCP, "UTF-16") ? "/C" : "") & ' -1' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Отменить действие", em_aucmd ' & (gHBarUndo ? "" : "/D") & ' -1 HBarUndo' & auCRLF
txt &= 'MENUITEM "Отменить последние действия", em_aucmd ' & (gHBarCancel ? "" : "/D") & ' -1 HBarCancel' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Резервная копия 1", em_aucmd ' & (FileExist(bak1) ? "" : "/D") & ' -1 HBarLoadBak 1' & auCRLF
txt &= 'MENUITEM "Резервная копия 2", em_aucmd ' & (FileExist(bak2) ? "" : "/D") & ' -1 HBarLoadBak 2' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Сделать резервную копию 1", em_aucmd -1 HBarSaveBak 1' & auCRLF
txt &= 'MENUITEM "Сделать резервную копию 2", em_aucmd -1 HBarSaveBak 2' & auCRLF
Return txt
EndFunc
Func HBarSetCodePage(nCodePage)
Local sCP = (nCodePage = 1 ? "ANSI" : "UTF-16")
Local bLoadQ = gHBarCP <> sCP
gHBarCP = sCP
If bLoadQ Then
MsgBox("Открыть панель в кодировке " & gHBarCP & "?", "Autorun", 3+64+0)
If EXTENDED = 6 Then
HBarLoad()
ShowDragHint("Панель открыта как " & gHBarCP)
SendCommand(2945)
EndIf
EndIf
EndFunc
Func HBarSaveBak(nBak)
Local bak = FileChangeExt(gHBarFile, "bak" & nBak)
If FileExist(bak) Then
MsgBox("Файл существует" & auCRLF & auCRLF & _
bak & auCRLF & auCRLF & "Перезаписать?", "Autorun", 3+32+0)
If EXTENDED <> 6 Then Return
EndIf
FileCopy(gHBarFile, bak, 1)
ShowDragHint("Файл сохранен " & bak)
EndFunc
Func HBarLoadBak(nBak)
Local bak = FileChangeExt(gHBarFile, "bak" & nBak)
If Not FileExist(bak) Then
MsgBox("Файл не существует " & bak, "Autorun")
Return
EndIf
If Not FileExist(gHBarFile) Then
MsgBox("Файл не существует " & gHBarFile, "Autorun")
Return
EndIf
MsgBox("Файл " & gHBarFile & " будет перезаписан файлом " & _
bak & auCRLF & auCRLF & "Продолжить?", "Autorun", 3+32+0)
If EXTENDED <> 6 Then Return
FileCopy(bak, gHBarFile, 1)
HBarLoad()
ShowDragHint("Файл загружен " & bak)
SendCommand(2945)
EndFunc
Func HBarUndo()
If Not gHBarUndo Then Return
If FileGetTime(gHBarFile) <> gHBarUndoTs Then
MsgBox("Файл " & gHBarFile & " изменился на диске" & auCRLF & auCRLF & _
"Отмена действия невозможна", "Autorun", 64)
Return
EndIf
FileWrite(gHBarFile, gHBarUndoLoad, gHBarCP)
If ERROR = 1 Then
MsgBox("Ошибка записи " & gHBarFile, "Autorun", 64)
Else
gHBarUndo = false
gHBarUndoLoad = ""
#gHBarFileTs = FileGetTime(gHBarFile)
HBarLoad()
ShowDragHint("Действие отменено")
SendCommand(2945)
EndIf
EndFunc
Func HBarCancel()
If Not gHBarCancel Then Return
If gHBarCancelLoad = "" Then Return MsgBox("Пустое значение CancelLoad")
MsgBox("Файл будет перезаписан" & auCRLF & auCRLF & _
gHBarFile & auCRLF & auCRLF & "Продолжить?", "Autorun", 3+32+0)
If EXTENDED <> 6 Then Return
FileWrite(gHBarFile, gHBarCancelLoad, gHBarCP)
If ERROR = 1 Then
MsgBox("Ошибка записи " & gHBarFile, "Autorun", 64)
Else
gHBarCancel = false
gHBarCancelLoad = ""
#gHBarFileTs = FileGetTime(gHBarFile)
HBarLoad()
ShowDragHint("Первоначальная панель загружена")
SendCommand(2945)
EndIf
EndFunc |
И хотя всё работает, от глюков по-прежнему гарантий нет. Так что делайте резервные копии, если будете пользоваться. А мы тем временем еще раз продемонстрируем Гислеру как происходит "случайное" перетаскивание кнопок на главной панели инструментов:
 Hidden text
Ладно, пора заканчивать этот кордебалет. Осталось только бандл завернуть, и в общем-то для этого всё уже почти готово. |
|