| View previous topic :: View next topic |
| Author |
Message |
sa
Joined: 29 Apr 2009 Posts: 2754
|
(Separately) Posted: Thu Jul 16, 2026 11:28 Post subject: |
|
|
| Orion9 wrote: | | Попробовал как с включеннной кнопкой истории, так и выключенной. | Я ещё и без заголовка файловой панели пробовал.
Можно использовать и 2926 (Цепочки навигации: вкл/выкл) и 2910 (Командная строка: вкл/выкл) и т.п.
| Orion9 wrote: | | В usercmd.ini нужна команда | У меня команда заработала, когда вместо %A0 записал просто %A.
| Orion9 wrote: | | Вроде удобно. | Да, хорошо! |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1208
|
(Separately) Posted: Thu Jul 16, 2026 14:14 Post subject: |
|
|
| sa wrote: | | Можно использовать и 2926 (Цепочки навигации: вкл/выкл) и 2910 (Командная строка: вкл/выкл) и т.п. |
Ну, пока и так работает Целый час вчера гонял. Нельзя назвать это стресс-тестом панели, конечно, но уже что-то.
И кстати, ошибок никаких не словил, это радует! Думаю, сейчас ошибки могут быть только на стадии поиска и загрузки панели (первые три функции - HBarShowHint, HBarGetFile, HBarLoad). Плохо, что окно панели не хранит путь к панели, это создает трудности. Т.ч. придется пересматривать эти функции и делать проверку на конфликт имен, что-то вроде
| Code: | Func HBarConflict()
Local bars = List(), text, num = 0
bars.Text = FileFind(COMMANDER_PATH, "*.bar", -1, 1)
For i = 0 To bars.Count - 1
If StrPos(bars[i], gHBarName, -1) > 0 Then
num += 1
text &= bars[i] & auCRLF
Endif
Next
If num < 2 Then text = ""
Return text
EndFunc |
Но здесь не учитывается путь к панели из wincmd.ini и путь активной панели. От последнего, думаю, надо избавляться, чтобы он не создавал путаницу. Но это всё-равно не поможет, если OPENBAR будет вызван из самого ТС с произвольным путем к панели.
Самое неприятное, что когда OPENBAR открывает файл, дескриптор панели не меняется. Т.е. если я открою DEFAULT.BAR из каталога D:\Temp и если у меня открыта главная панель как %COMMANDER_PATH%\DEFAULT.BAR, то нет никакой возможности узнать, какая из этих двух панелей открыта в данный момент только по имени файла.
Ладно, подумаю над этим чуть позже. Сейчас, видимо, придется взять небольшую паузу, но если будут какие-то ошибки, постараюсь потихоньку исправлять. Главное иметь в виду, что открытие панели сейчас самое уязвимое место, и что остальной функционал еще недостаточно тестирован, т.ч. могут быть ошибки и косяки.
| sa wrote: | | У меня команда заработала, когда вместо %A0 записал просто %A. |
Спасибо, подправил. Убрал заодно снятие оконной процедуры при открытии через OPENBAR. Видимо, в нем была проблема. Еще Loopback писал, что вешается-то она легко, а вот снимается с ошибками. У меня она, похоже, вообше не снималась или снималась через раз
| Code: | DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
"hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWndProc, "ptr") |
Добавил еще пункт "Индекс удаления 1", чтобы можно было сразу очистить панель и проверку в HBarSaveAs, хотя там лучше сделать через копипование файла, но это потом.
Последний тестовый модуль.
 Bars.aucfg | Code: | Pragma IncludeOnce
# наведение на главную панель
ControlSetHint /F /D:50 28 "HBarShowHint"
# правый клик с удержанием Ctrl
ControlSetMouseAction /R /K:C 28 "HBarShowMenu"
# правый клик с удержанием Shift
ControlSetMouseAction /R /K:S 28 "HBarShowOpenMenu"
# Win + Backspace
# отмена последнего действия
SetHotkeyAction /K:W /H:BS "HBarUndo"
Global gDragIndex, gDropIndex, gSmartIndex
Global gHBarButtons = 0, gHBarDivs = 0, gHBarSmart = 1
Global gHBarName, gHBarFile, gHBarFileTs, gHBarReady = 0
Global gHBarTxt, gHBarCP = "ANSI", gHBarWincmd = 0, gHBarDbg = 0
Global gHBarHint = 0, gHBarVerb, gHBarCancel, gHBarCancelLoad, gHBarLoadError = 1
Global gHBarList = List(), gHBarMap = List(), gHBarBars = 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, _
MoveButton = MK_CONTROL, _
CopyButton = MK_SHIFT
Static drag_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32646), _
stop_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32648), _
icon_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 13), _
kick_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 26), _
copy_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 25), _
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
Switch uMsg
Case WM_LBUTTONDOWN
If IsDrag = 0 And (BitAND(wParam, MoveButton) Or BitAND(wParam, CopyButton)) Then
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
Local InfoMsg
If gHBarLoadError Or gHBarList.Count = 0 Then
InfoMsg = "Панель не загружена"
ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
InfoMsg = "Файл панели изменился"
Endif
If InfoMsg <> "" Then
ShowDragHint(InfoMsg)
lParam = -1000
Return DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndIf
If BitAND(wParam, MoveButton) And BitAND(wParam, CopyButton) Then
IsDrag = MoveButton
Else
IsDrag = wParam
EndIf
WinSetStyle(0x80000, 3, hWnd)
If BitAND(wParam, MoveButton) Then
DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
Else
DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 216, "dword", 2)
EndIf
x = buf.GetNum(0)
y = buf.GetNum(4)
gDragIndex = HBarGetIdx(1, x, y)
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
Local nDragMode = IsDrag
DllCall("ReleaseCapture")
IsDrag = 0
If WinFromPoint() = hWnd Then
MouseGetPos("x","y")
gSmartIndex = 0
gDropIndex = HBarGetIdx(2, x, y)
If gDragIndex <> gDropIndex Then
If gHBarHint Then ShowDragHint("Index " & gDragIndex & " To Index: " & gDropIndex)
If BitAND(nDragMode, MoveButton) Then
HBarDragDrop(gDragIndex, gDropIndex)
Else
If BitAND(wParam, MoveButton) Then
HBarDragIcon(gDragIndex, gDropIndex)
Else
HBarDragCopy(gDragIndex, gDropIndex)
EndIf
EndIf
EndIf
Else
y = BitAND(BitShift(lParam,16), 0xFFFF)
If BitAND(wParam, MoveButton) And lParam > 0 And y > 200 Then HBarDragDelete(gDragIndex)
EndIf
WinSetStyle(0x80000, 5, hWnd)
#Return 0
#lParam = MakeInt(y, x + 200, 2)
lParam = -1000
EndIf
Case WM_MOUSEMOVE
If IsDrag > 1 And BitAND(wParam, MK_LBUTTON) Then
If WinFromPoint() = hWnd Then
If BitAND(IsDrag, CopyButton) Then
DllCall("SetCursor", "Ptr", BitAND(wParam, MoveButton) ? icon_cursor : copy_cursor)
Else
DllCall("SetCursor", "Ptr", drag_cursor)
EndIf
#DllCall("SetCursor", "Ptr", BitAND(IsDrag, MoveButton) ? drag_cursor : copy_cursor)
Else
y = BitAND(BitShift(lParam,16), 0xFFFF)
#WinSetText(lParam & " y=" & y)
If BitAND(wParam, MoveButton) And lParam > 0 And y > 200 Then
DllCall("SetCursor", "Ptr", kick_cursor)
Else
DllCall("SetCursor", "Ptr", stop_cursor)
EndIf
EndIf
EndIf
EndSwitch
Return DllCall("CallWindowProcW", _
"ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc
Func HBarShowHint()
# панель в режиме drag'n'drop
If WinHasStyle(0x80000, 1, hBarWnd) Then Return
# состояние CapsLock и Shift
If BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1) = 0 Then
If Not IsPressed(0x10) Then Return
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")
Return
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()
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()
EndIf
# индекс кнопки под курсором
gDragIndex = HBarGetIdx()
If Not gDragIndex And Not gHBarDbg Then Return "Не удалось определить индекс кнопки"
Return HBarGetHint()
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 HBarConflict()
Local bars = List(), text, num = 0
bars.Text = FileFind(COMMANDER_PATH, "*.bar", -1, 1)
For i = 0 To bars.Count - 1
If StrPos(bars[i], gHBarName, -1) > 0 Then
num += 1
text &= bars[i] & auCRLF
Endif
Next
If num < 2 Then text = ""
Return text
EndFunc
Func HBarLoad()
gHBarLoadError = 1
Local bar = FileRead(gHBarFile, 128, "RAW")
Local bom = "FFFE"
Local utf = "5B0042007500740074006F006E006200610072005D000D000A00"
If ERROR = 1 Then
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
If oCmd.Get("cmd" & j, 0) = 2 Then
gHBarMap.Add(-2)
Else
gHBarMap.Add(0)
EndIf
EndIf
Next
Free(oButton, oCmd)
gHBarLoadError = gHBarMap.Count > 0 ? 0 : 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
#OutputDebugString("HBarLoad=" & gHBarMap.Count)
EndFunc
Func HBarGetIdx(MousePos = false, PosX = 0, PosY = 0)
# дескриптор монитора окна ТС
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)
# координаты указателя мыши
If MousePos Then
mx = PosX
my = PosY
Else
MouseGetPos("mx", "my")
EndIf
# чтение информации о высоте кнопок
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 ShowDragHint("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, ex = 0, idx_padding = 0
# индекс кнопки в ряду
If gHBarDivs = 0 Then
idx = (Floor((mx - x)/b) + 1) + (row-1)*(Floor(w/b))
If idx > gHBarButtons Then idx = gHBarButtons
Else
j = 1
idx = 0
For i = 0 To gHBarMap.Count - 1
idx_padding = 0
If gHBarMap[i] = -2 Then
If i = 0 Then cx += w # первая кнопка разрыв
j += 1
cx += ex
If i > 0 And gHBarMap[i-1] = -2 Then
cx += w - ex
EndIf
If i = gHBarMap.Count - 1 Then cx += w # последняя кнопка разрыв
If cx >= tx Then
idx = i + 1
Break
EndIf
Continue
EndIf
cx += (gHBarMap[i] = 0 ? div : b)
ex = j*w - cx
If i + 1 <= gHBarMap.Count - 1 Then
next_button = gHBarMap[i+1]
next_width = (next_button = -2 ? 0 : (next_button = 0 ? div : b))
If ex < next_width Then
cx += ex
idx_padding += ex
j += 1
EndIf
Else
cx += ex
idx_padding = ex
EndIf
If cx >= tx Then
idx = i + 1
Break
EndIf
Next
EndIf
If idx = 0 Then Return idx
Local SysDbg = 0
If SysDbg Then
OutputDebugString("idx=" & idx & " gHBarMap=" & gHBarMap.Count)
EndIf
idx_button = gHBarMap[idx-1]
idx_width = (idx_button = -2 ? 0 : (idx_button = 0 ? div : b))
idx_pixel = tx - (cx - idx_padding - idx_width)
idx_float = idx_width > 0 ? idx_pixel / idx_width : 0
# дробный индекс
gSmartIndex = idx + Round(idx_float, 3)
If Floor(gSmartIndex) > idx Then gSmartIndex = idx + 0.999
# дополнительная информация
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 & "%" & auCRLF & auCRLF & _
"smart=" & gSmartIndex & auCRLF & _
"button=" & idx_button & " width=" & idx_width & " pixel=" & idx_pixel
If SysDbg Then
OutputDebugString("" & auCRLF & (Not MousePos ? "Hint" : "Proc " & MousePos) & auCRLF & gHBarVerb & auCRLF & "idx=" & idx)
EndIf
If MousePos <> 2 Then gSmartIndex = 0
Return idx
EndFunc
Func HBarGetHint()
# чтение информации о кнопке из .bar фйла
Local sMenu, sButton, sCmd, sParam, sPath, sIcon, text
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, auX64 ? "HintWindow" : "TToolTip")
If hTip > 0 Then DllCall("DestroyWindow", "handle", hTip)
# возврат текста
text = "index=" & gDragIndex & " of " & gHBarButtons+gHBarDivs & auCRLF & _
"menu=" & sMenu & auCRLF & _
"button=" & sButton & auCRLF & _
"cmd=" & sCmd & auCRLF & _
"param=" & sParam & auCRLF & _
"path=" & sPath & auCRLF & _
"iconic=" & sIcon & (gHBarDbg ? auCRLF & auCRLF & gHBarVerb & gHBarTxt : "")
Return text
EndFunc
Func HBarDragDrop(DragIdx, DropIdx)
Static aItems = List("button","cmd","param","path","menu","iconic")
Local T1, T2, bTL = 0
Local i, j, k, txt, key, new
# режим отладки
If bTL Then T1 = GetUptime()
# сохранение файла панели
HBarSaveState(txt)
# временная замена индекса DragIdx = 9999
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")
OutputDebugString("Drag & Drop: " & DragIdx & " -> " & DropIdx)
EndIf
# умный сброс по границам кнопки
If gHBarSmart Then
If gSmartIndex > DropIdx + 0.499 Then
If DragIdx >= DropIdx Then
DropIdx += 1
EndIf
Else
If DragIdx < DropIdx Then
DropIdx -= 1
EndIf
EndIf
EndIf
# сдвиг индексов
If DragIdx < DropIdx Then
If gHBarMap[DropIdx-1] = -2 Then DropIdx -= 1
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
# обратная замена индекса DragIdx -> DropIdx
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)
# обновление панели
HBarUpdateReload()
If bTL Then
T2 = Round(GetUptime() - T1, 0) / 1000
OutputDebugString("Время операции 3: " & StrFormat("%.3f", T2) & " sec")
EndIf
EndFunc
Func HBarReadIndex(Index)
Local key, val, txt
Static aItems = List("button","cmd","param","path","menu","iconic")
# сохранение индекса
For j = 0 To aItems.Count - 1
key = aItems[j] & Index
val = IniRead(gHBarFile, "Buttonbar", key)
If val <> '' Then
If StrLeft(val, 1) ='"' And StrRight(val, 1) ='"' Then val = '"' & val & '"'
txt &= key & '=' & val & auCRLF
EndIf
Next
Return StrTrim(txt)
EndFunc
Func HBarDragCopy(DragIdx, DropIdx)
Local key, val, ini, new, txt
Static aItems = List("button","cmd","param","path","menu","iconic")
# сохранение кнопки
For j = 0 To aItems.Count - 1
key = aItems[j] & DragIdx
val = IniRead(gHBarFile, "Buttonbar", key)
If val <> '' Then
If StrLeft(val, 1) ='"' And StrRight(val, 1) ='"' Then val = '"' & val & '"'
ini &= key & '=' & val & auCRLF
EndIf
Next
ini = StrTrim(ini)
If ini = '' Then Return ShowDragHint("Нет данных о кнопке " & DragIdx)
# сохранение файла панели
HBarSaveState(txt)
# умный сброс по границам кнопки
If gHBarSmart Then
If gSmartIndex > DropIdx + 0.499 Then
DropIdx += 1
EndIf
EndIf
# сдвиг индексов
If DropIdx <= gHBarMap.Count Then
# замена ключей со сдвигом +1
For i = gHBarMap.Count To DropIdx Step -1
For j = 0 To aItems.Count - 1
key = aItems[j] & i & "="
new = aItems[j] & i + 1 & "="
txt = StrReplace(txt, key, new)
Next
Next
EndIf
# добавление сохраненной кнопки
For j = 0 To aItems.Count - 1
key = aItems[j] & DragIdx & "="
new = aItems[j] & DropIdx & "="
ini = StrReplace(ini, key, new)
Next
txt &= auCRLF & ini
# сохранение панели
gHBarList.Text = txt
gHBarList.SaveToFile(gHBarFile, gHBarCP)
IniWrite(gHBarFile, "Buttonbar", "Buttoncount", gHBarMap.Count+1)
# обновление панели
HBarUpdateReload()
EndFunc
Func HBarSaveState(ByRef Text)
Text = gHBarList.Text
gHBarUndoLoad = Text
If Not gHBarCancel Then
gHBarCancel = true
gHBarCancelLoad = Text
EndIf
EndFunc
Func HBarUpdateReload(Reopen = 0)
# временя последнего изменения
gHBarUndoTs = FileGetTime(gHBarFile)
gHBarFileTs = FileGetTime(gHBarFile)
If gHBarUndoTs Then
gHBarUndo = true
Else
gHBarUndo = false
gHBarUndoLoad = ""
EndIf
# загрузка файла панели
HBarLoad()
# обновление панели
If Reopen Then
SendMessage(AUTORUN_TCHANDLE, 11, 0, 0)
SendCommand(2901, 0, 1)
SendCommand(2901, 0, 1) # cm_VisButtonBar
Sleep(10)
SendMessage(AUTORUN_TCHANDLE, 11, 1, 0)
Else
SendCommand(2945) # cm_ReloadBarIcons
SendCommand(2919)
SendCommand(2919)
EndIf
#WinRedraw(1)
#WinRedraw(0)
EndFunc
Func ShowDragHint(DragHint)
Local dark = IniRead(COMMANDER_INI, "Configuration", "DarkMode", 0)
SetHintParam("ShowHint", "Font", 13, "Tahoma")
SetHintParam("ShowHint", "BackColor", 0x0F0F0F)
SetHintParam("ShowHint", "Text", 0xFFFFFF)
SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
SetHintParam("ShowHint", "DarkText", 0xFFFFFF)
ShowHint(auCRLF & " " & DragHint & " " & auCRLF, 0, 0, 1000, 1)
WinAlign(LAST_HINT_WINDOW)
If Not dark Then
WinSetStyle(0x80000, 3, LAST_HINT_WINDOW)
DllCall("SetLayeredWindowAttributes", _
"hwnd", LAST_HINT_WINDOW, "ptr", 0, "byte", 192, "dword", 2)
EndIf
Sleep(100)
SetHintParam("ShowHint", "Reload")
EndFunc
Func HBarShowMenu()
Local hWnd = RequestInfo(28)
If hWnd = 0 Then
ShowDragHint("Окно панели не найдено")
Return
EndIf
If gHBarName <> WinGetText(hWnd) Then
ShowDragHint("Shift + наведение загрузка панели")
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 /D ' & (gHBarCP = "ANSI" ? "/C" : "") & ' -1' & auCRLF
txt &= 'MENUITEM "Загружена как UTF-16", em_aucmd /D ' & (StrPos(gHBarCP, "UTF-16") ? "/C" : "") & ' -1' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Smart Drag&&Drop", em_aucmd ' & (gHBarSmart ? "/C" : "") & ' -1 HBarSmart' & auCRLF
txt &= 'MENUITEM "Отладочная информация", em_aucmd ' & (gHBarDbg ? "/C" : "") & ' -1 HBarDebugInfo' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Сохранить...", em_aucmd -1 HBarSaveAs' & auCRLF
txt &= 'POPUP "Загрузить панель"' & auCRLF
txt &= HBarAddBarMenu() & auCRLF
txt &= 'END_POPUP' & auCRLF
txt &= 'MENUITEM SEPARATOR' & auCRLF
txt &= 'MENUITEM "Добавить разрыв", em_aucmd -1 HBarAddButton -2' & auCRLF
txt &= 'MENUITEM "Добавить разделитель", em_aucmd -1 HBarAddButton 1' & auCRLF
txt &= 'POPUP "Удалить кнопки за разрывом"' & auCRLF
txt &= HBarBreakMenu() & auCRLF
txt &= 'END_POPUP' & 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 HBarDebugInfo()
gHBarDbg = Not gHBarDbg
If gHBarDbg Then
ShowDragHint("Отладочная информация включена")
Else
ShowDragHint("Отладочная информация отключена")
EndIf
EndFunc
Func HBarSmart()
gHBarSmart = Not gHBarSmart
If gHBarSmart Then
ShowDragHint("Smart Drag&Drop включен")
Else
ShowDragHint("Smart Drag&Drop отключен")
EndIf
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)
HBarUpdateReload()
ShowDragHint("Файл загружен " & bak)
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)
SendCommand(2919)
SendCommand(2919)
#WinRedraw(0)
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)
SendCommand(2919)
SendCommand(2919)
#WinRedraw(0)
EndIf
EndFunc
Func HBarShowOpenMenu()
ShowPopupMenu /D /F /I:0 "HBarOpenBarMenu"
EndFunc
Func HBarOpenBarMenu()
Local sBars = FileFind(COMMANDER_PATH, "*.bar", -1, 1)
Local text
gHBarBars.Count = 0
gHBarBars.Text = sBars
For i = 0 To gHBarBars.Count - 1
text = text & 'MENUITEM "' & gHBarBars[i] & '", em_aucmd -1 HBarOpenBar ' & i & auCRLF
Next
Return text
EndFunc
Func HBarOpenBar(FileIndex)
Local bar = gHBarBars[FileIndex]
c = IniRead(bar, "Buttonbar", "Buttoncount", 0)
If c = 0 Then
MsgBox("Файл не содержит данных о кнопках" & auCRLF & auCRLF & bar, "Autorun", 0+48)
Return
EndIf
If gHBarWndProc > 0 Then
gHBarLoadError = 1
#hBarWnd = 0
EndIf
CommandExec("em_open_bar_path", bar)
EndFunc
Func HBarAddBarMenu()
Local sBars = FileFind(COMMANDER_PATH, "*.bar", -1, 1)
#sBars = StrTrim(sBars)
Local text
gHBarBars.Count = 0
gHBarBars.Text = sBars
For i = 0 To gHBarBars.Count - 1
text = text & 'MENUITEM "' & gHBarBars[i] & '", em_aucmd -1 HBarMergeOne ' & i & auCRLF
Next
Return text
EndFunc
Func HBarMergeOne(FileIndex)
Local bar = gHBarBars[FileIndex]
c = IniRead(bar, "Buttonbar", "Buttoncount", 0)
If c = 0 Then
MsgBox("Файл не содержит данных о кнопках" & auCRLF & auCRLF & bar, "Autorun", 0+48)
Return
EndIf
If IsPressed(0x11) Then
CommandExec("em_open_bar_path", bar)
Return
Endif
If FileGetTime(gHBarFile) <> gHBarFileTs Then
MsgBox("Операция невозможна. Файл на диске изменился." & auCRLF & FileGetTime(gHBarFile) & "<>" & gHBarFileTs)
Return
Endif
Local text = FileRead(bar), count = gHBarMap.Count + 1
Local rext = 'button' & count & '=' & auCRLF & _
'cmd' & count & '=-2' & auCRLF & 'iconic' & count & '=0' & auCRLF
Local i = 0
Local rex = RegExp('(?i)(button|cmd|param|path|menu|iconic)(\d+?)=(.*?)(\R|\Z)', text)
If rex.Exec() Then
Do
#If StrLower(rex.Match[1]) = 'button' Then i += 1
If StrCompare(rex.Match[1], 'button') = 0 Then i += 1
rext &= rex.Match[1] & rex.Match[2]+count & '=' & rex.Match[3] & auCRLF
Until not rex.ExecNext()
EndIf
Free(rex)
If i < 1 Then
Return MsgBox("Не удалось найти ни одной кнопки" & auCRLF & auCRLF & _
"Buttoncount=" & c & " RegExp=" & i & auCRLF & & bar, "Autorun", 16)
ElseIf c <> i Then
MsgBox("Количество кнопок не совпадает" & auCRLF & auCRLF & _
"Buttoncount=" & c & " RegExp=" & i & auCRLF & & bar, "Autorun", 48)
EndIf
# сохранение панели
Local txt
HBarSaveState(txt)
txt &= auCRLF & rext
# обновление данных
gHBarList.Text = txt
gHBarList.SaveToFile(gHBarFile, gHBarCP)
IniWrite(gHBarFile, "Buttonbar", "Buttoncount", count+c)
# обновление панели
HBarUpdateReload()
ShowDragHint("Добавлено " & i+1 & " кнопок")
EndFunc
Func HBarBreakMenu()
Local text, br = List()
For i = 0 To gHBarMap.Count - 1
If gHBarMap[i] = -2 Then
br.Add(i+1)
text &= 'MENUITEM "Индекс разрыва: ' & i+1 & '", em_aucmd -1 HBarBreakErase ' & i+1 & ' ' & i+1 & auCRLF
EndIf
Next
If text = "" Then Return 'MENUITEM "Нет разрывов", em_aucmd /D -1'
If br.Count > 1 Then
Local r1 = br[0], r2 = 0
text &= 'MENUITEM SEPARATOR' & auCRLF
For i = 1 To br.Count - 1
r2 = br[i]
If r2 > 0 Then
text &= 'MENUITEM "Удалить кнопки между ' & r1 & ' - ' & r2 & '", em_aucmd -1 HBarBreakErase ' & r1 & ' ' & r2 & auCRLF
EndIf
r1 = r2
r2 = 0
Next
EndIf
If gHBarMap.Count > 1 Then
text &= 'MENUITEM SEPARATOR' & auCRLF
text &= 'MENUITEM "Индекс удаления 1", em_aucmd -1 HBarBreakErase ' & 2 & ' ' & 2 & auCRLF
EndIf
Return text
EndFunc
Func HBarBreakErase(BreakIndex, StopIndex)
Local Count = 0, txt, _
Range = StopIndex - BreakIndex
If FileGetTime(gHBarFile) <> gHBarFileTs Then
MsgBox("Операция невозможна. Файл на диске изменился." & auCRLF & FileGetTime(gHBarFile) & "<>" & gHBarFileTs)
Return
Endif
If BreakIndex < 2 Then
MsgBox("Индекс разрыва не может быть меньше 2")
Return
Endif
Local text = gHBarList.Text, rext = ""
Local rex = RegExp('(?i)(button|cmd|param|path|menu|iconic)(\d+?)=(.*?)(\R|\Z)', text)
If rex.Exec() Then
Do
If BreakIndex = StopIndex Then
If rex.Match[2] < BreakIndex Then
Count += 1
rext &= rex.Match[1] & rex.Match[2] & '=' & rex.Match[3] & auCRLF
EndIf
Else
If rex.Match[2] < BreakIndex Then
Count += 1
rext &= rex.Match[1] & rex.Match[2] & '=' & rex.Match[3] & auCRLF
ElseIf rex.Match[2] >= StopIndex Then
Count += 1
rext &= rex.Match[1] & rex.Match[2]-Range & '=' & rex.Match[3] & auCRLF
EndIf
EndIf
Until not rex.ExecNext()
EndIf
Free(rex)
If rext = "" Then Return MsgBox("Ошибка удаления. Buttoncount=0, BreakIndex=" & BreakIndex)
# сохранение панели
HBarSaveState(txt)
# обновление файла
Local NewCount = 0
If BreakIndex = StopIndex Then
NewCount = BreakIndex - 1
Else
NewCount = gHBarMap.Count - Range
EndIf
ShowDragHint("Удалено " & gHBarMap.Count - NewCount & " кнопок")
gHBarList.Text = "[Buttonbar]" & auCRLF & "Buttoncount=" & NewCount & auCRLF & rext
gHBarList.SaveToFile(gHBarFile, gHBarCP)
# обновление панели
HBarUpdateReload()
EndFunc
#{
поиск индекса по ключу и значению:
bar = COMMANDER_PATH & "\Bars\Main.bar"
idx = FindButtonIdx(bar, "cmd", "61007")
idx = FindButtonIdx(bar, "menu", "Auto_bars")
idx = FindButtonIdx(bar, "button", "WCMICONS.dll,72")
MsgBox(FindButtonIdx(bar, "param", '/ef "tcm(60011,1)"'))
#}
Func FindButtonIdx(ButtonBar, ButtonKey, ButtonVal)
Local txt, pos, len, sub, idx = 0
If Not FileExist(ButtonBar) Then
ShowDragHint("Панель не найдена " & ButtonBar)
Return 0
EndIf
len = StrLen(ButtonKey)
ProcessExecGetOutput txt %COMSPEC% '/c type "%ButtonBar%"'
pos = StrPos(txt, "=" & ButtonVal)
If pos = 0 Then Return 0
For i = 0 To 3
sub = StrMid(txt, pos-len-i, len)
If sub = ButtonKey Then
idx = StrMid(txt, pos-i, i)
If IsInt(idx) Then Break
Endif
Next
# перепроверка индекса
If idx > 0 Then
IniRead txt %ButtonBar% "Buttonbar" %"ButtonKey & idx"
If StrPos(txt, ButtonVal) > 0 Then Return idx
EndIf
Return 0
EndFunc
Func HBarSaveAs()
If FileGetTime(gHBarFile) <> gHBarFileTs Then
MsgBox("Операция невозможна. Файл на диске изменился." & auCRLF & FileGetTime(gHBarFile) & "<>" & gHBarFileTs)
Return
Endif
# буфер для имени файла
Local file = Buffer(1024)
file.Zero()
file.SetStr(gHBarFile)
# буфер для фильтра расширений
Local fstr = "Bar files (*.bar)" & Chr(0) & "*.bar" & Chr(0) & Chr(0)
Local flen = StrLen(fstr) * 2
Local filt = Buffer(flen)
filt.Zero()
filt.SetStr(fstr)
# буфер для структуры OPENFILENAMEW
Local ofn = Buffer(auX64 ? 152 : 76)
ofn.Zero()
ofn.SetNum(0, "UInt", ofn.size) # lStructSize
If auX64 Then
ofn.SetNum(8, "Ptr", AUTORUN_TCHANDLE) # hwndOwner
ofn.SetNum(24, "Ptr", filt.ptr) # lpstrFilter
ofn.SetNum(48, "Ptr", file.ptr) # lpstrFile
ofn.SetNum(56, "Dword", file.size) # nMaxFile
ofn.SetNum(96, "Dword", 0x00000802) # 0x00000002 | 0x00000800
Else
ofn.SetNum(4, "Ptr", AUTORUN_TCHANDLE) # hwndOwner
ofn.SetNum(12, "Ptr", filt.ptr) # lpstrFilter
ofn.SetNum(28, "Ptr", file.ptr) # lpstrFile
ofn.SetNum(32, "Dword", file.size) # nMaxFile
ofn.SetNum(52, "Dword", 0x00000802) # 0x00000002 | 0x00000800
EndIf
If DllCall("comdlg32\GetSaveFileNameW", "Ptr", ofn.ptr) Then
Local new = file.GetStr()
If new <> gHBarFile Then
gHBarList.SaveToFile(new, gHBarCP)
Else
MsgBox("Файл не может быть сохранен сам в себя","Autorun", 48)
EndIf
EndIf
Free(file, filt, ofn)
EndFunc
Func HBarDragIcon(DragIdx, DropIdx)
Local txt
# проверка индекса получателя
If gHBarMap[DropIdx-1] <> 1 Then Return ShowDragHint("Получатель не может быть разделителем")
# сохранение значка
Local val = IniRead(gHBarFile, "Buttonbar", "button" & DragIdx)
If val = '' Then
Return ShowDragHint("Нет данных о значке button" & DragIdx)
Else
If StrLeft(val, 1) ='"' And StrRight(val, 1) ='"' Then val = '"' & val & '"'
EndIf
# сохранение панели
HBarSaveState(txt)
# обновление значка
IniWrite(gHBarFile, "Buttonbar", "button" & DropIdx, val)
# обновление панели
HBarUpdateReload()
EndFunc
Func HBarDragDelete(DragIdx)
Local txt
Static aItems = List("button","cmd","param","path","menu","iconic")
# сохранение панели
HBarSaveState(txt)
# замена индекса удаляемой кнопки
Local key, new
For j = 0 To aItems.Count - 1
key = aItems[j] & DragIdx & "="
new = aItems[j] & 8888 & "="
txt = StrReplace(txt, key, new)
Next
# замена ключей со сдвигом -1
For i = DragIdx + 1 To gHBarMap.Count
For k = 0 To aItems.Count - 1
key = aItems[k] & i & "="
new = aItems[k] & i - 1 & "="
txt = StrReplace(txt, key, new)
Next
Next
# сохранение панели
gHBarList.Text = txt
gHBarList.SaveToFile(gHBarFile, gHBarCP)
# удаление ключей кнопки из файла
For j = 0 To aItems.Count - 1
key = aItems[j] & 8888
IniDelete(gHBarFile, "Buttonbar", key)
Next
# обновление общего количества кнопок
IniWrite(gHBarFile, "Buttonbar", "Buttoncount", gHBarMap.Count-1)
# обновление панели
HBarUpdateReload()
EndFunc
Func HBarAddButton(IndexType)
Local txt
If FileGetTime(gHBarFile) <> gHBarFileTs Then
MsgBox("Операция невозможна. Файл на диске изменился." & auCRLF & FileGetTime(gHBarFile) & "<>" & gHBarFileTs)
Return
Endif
# сохранение панели
HBarSaveState(txt)
# добавление новых ключей
IniWrite(gHBarFile, "Buttonbar", "button" & gHBarMap.Count+1)
IniWrite(gHBarFile, "Buttonbar", "iconic" & gHBarMap.Count+1, 0)
If IndexType = -2 Then
IniWrite(gHBarFile, "Buttonbar", "cmd" & gHBarMap.Count+1, -2)
EndIf
# обновление общего количества кнопок
IniWrite(gHBarFile, "Buttonbar", "Buttoncount", gHBarMap.Count+1)
# обновление панели
HBarUpdateReload()
ShowDragHint("Новый индекс " & gHBarMap.Count)
EndFunc |
Если кто-то хочет попробовать не подключая к своему ТС, можно взять готовую сборку и заменить модуль Bars.aucfg в каталоге Scripts
Ссылка 1
Ссылка 1 |
|
| Back to top |
|
 |
sa
Joined: 29 Apr 2009 Posts: 2754
|
(Separately) Posted: Thu Jul 16, 2026 15:59 Post subject: |
|
|
Orion9
Хотел всё-таки разобраться, в чём проблема удаления группы кнопок путём последовательного указания мышью (наведением, пусть с тем же модификатором Shift) двух крайних кнопок диапазона: ведь индексы этих кнопок определяются надёжно, а остальное кажется уже делом техники… |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1208
|
(Separately) Posted: Thu Jul 16, 2026 20:27 Post subject: |
|
|
| sa wrote: | | в чём проблема удаления группы кнопок путём последовательного указания мышью |
Да вроде нет больших проблем. Я просто подумал, что надо как-то визуально или графически делать выбор или через поля ввода, а с этим в Autorun сложности. Через DllCall многое можно порешать: и окна можно создать, и функции gdi вызывать, только зачем так заморачиваться
Благодаря вашей идее с копированием, поставленную задачу можно решить буквально за несколько секунд. Если на панели уже есть разрывы, достаточно просто скопировать один разрыв в начало диапазона, а второй разрыв в конец. После этого удалить кнопки между этими разрывами через меню. Если на панели нет разрывов, то нужно добавить один разрыв через меню и повторить описанные действия. Даже последний пункт меню, который я добавил для удаления всех кнопок после индекса 1, можно было не делать, т.к. задача тоже решается через копирование разрыва (за первый индекс) с последующим удлением всего за разрывом
Но если делать последовательное указание диапазона через запоминание индекса, то сделать можно, и это не должно быть сложно. Например:
 Hidden text | Code: | Global gHBarMark1 = 0, gHBarMark2 = 0
Func HBarMarkToDelete()
Local InfoMsg
If gHBarLoadError Or gHBarList.Count = 0 Then
InfoMsg = "Панель не загружена"
ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
InfoMsg = "Файл панели изменился"
Endif
If InfoMsg <> "" Then
ShowDragHint(InfoMsg)
Return
Endif
If Not gHBarMark1 Then
gHBarMark1 = HBarGetIdx()
If gHBarMark1 < 1 Then Return
MsgBox("Индекс: " & gHBarMark1 & auCRLF & auCRLF & _
"Задать начало диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then gHBarMark1 = 0
Return
Endif
If Not gHBarMark2 Then
gHBarMark2 = HBarGetIdx()
If gHBarMark2 <= gHBarMark1 Then
gHBarMark2 = 0
Return
EndIf
MsgBox("Индекс: " & gHBarMark2 & auCRLF & auCRLF & _
"Задать конец диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
gHBarMark2 = 0
Return
EndIf
Endif
MsgBox("Диапазон: " & gHBarMark1 & "-"& gHBarMark2 & auCRLF & auCRLF & _
"Удалить группу кнопок?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
ShowDragHint("Диапазон сброшен")
Else
# удаление
HBarBreakErase(gHBarMark1, gHBarMark2)
EndIf
gHBarMark1 = 0
gHBarMark2 = 0
EndFunc |
В самый конец функции HBarLoad нужно добавить сброс маркеров диапазона, чтобы при смене панели или состояния панели указанный наполовину диапазон сбрасывался.
| Code: | gHBarMark1 = 0
gHBarMark2 = 0 |
Функцию можно повесить и на среднюю кнопку мыши, но сейчас она у меня вызывается через Alt
| Code: | # правый клик с удержанием Alt
ControlSetMouseAction /R /K:A 28 "HBarMarkToDelete" |
Навскидку всё работает, но могут быть, конечно, неучтенные моменты. Если вам понравится, можно добавить к функционалу  |
|
| Back to top |
|
 |
sa
Joined: 29 Apr 2009 Posts: 2754
|
(Separately) Posted: Fri Jul 17, 2026 10:41 Post subject: |
|
|
| Orion9 wrote: | | неучтенные моменты |
Удобнее не ограничивать задание диапазона началом и концом, чтобы можно было, к примеру, начать с большего индекса, а закончить меньшим. Если оба раза указана одна кнопка, то её и удалять. Сейчас, например, при указании диапазона 67-68, удаляется только 67.
P.S.
Ну и сам интерфейс удаления сейчас такой, как будто пользователь сам помогает скрипту удалять кнопки (почти как с установкой разрывов), а не наоборот.
В идеале хотелось, чтобы была одна операция, а не две, не связанные друг с другом. Что-то нажать, получить запрос на указание первой граничной кнопки, зависнуть над ней мышью (если надо, то ещё что-то нажать дополнительно), следом получить запрос на указание второй граничной кнопки, зависнуть над ней мышью (если надо, то ещё что-то нажать дополнительно) и, наконец, подтвердить/отменить удаление. |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1208
|
(Separately) Posted: Fri Jul 17, 2026 13:15 Post subject: |
|
|
| sa wrote: | | начать с большего индекса, а закончить меньшим |
Это можно сделать через функции Min и Max. Вроде работает.
| sa wrote: | | Если оба раза указана одна кнопка, то её и удалять |
А зачем? Одну кнопку можно удалить и так.
Вообще, функция HBarBreakErase задумывалась для удаления между разделителями, одну кнопку она удалить не может, поэтому пришлось ввести это ограничение при выборе диапазона, т.к. если указать один и тот же индекс, то удалятся все кнопки за этим индексом, как при
| Code: | text &= 'MENUITEM "Индекс удаления 1", em_aucmd -1 HBarBreakErase ' & 2 & ' ' & 2 & auCRLF |
где передается диапазон 2-2. Поэтому для удаления одной кнопки придется делать дополнительную функцию.
Но можно ведь и не делать. Одну кнопку можно удалить простым дропом за панель, поэтому пока оставил как было, т.е. нельзя задать диапазон равный одной кнопке.
| sa wrote: | | Сейчас, например, при указании диапазона 67-68, удаляется только 67. |
Исправил. Там просто +1 нужно было добавить к параметру.
| sa wrote: | | Ну и сам интерфейс удаления сейчас такой, как будто пользователь сам помогает скрипту удалять кнопки (почти как с установкой разрывов), а не наоборот. |
Да нормальный интерфейс, мне даже нравится Конечно, было бы лучше, если бы первая кнопка как-то отмечалась, чтобы не держать ее в уме, но и так, вроде бы, удобно: навёл на кнопку, получил подсказку, убедился, что это нужный индекс, нажал следом Alt+ПКЛ для выбора диапазона, и всё.
В справке к Autohotkey есть пример на DllCall для закрашивания области экрана.
 Hidden text | Code: | Rect := Buffer(16) ; Set capacity to hold four 4-byte integers.
NumPut( "Int", 0 ; left
, "Int", 0 ; top
, "Int", A_ScreenWidth//2 ; right
, "Int", A_ScreenHeight//2 ; bottom
, Rect)
hDC := DllCall("GetDC", "Ptr", 0, "Ptr") ; Pass zero to get the desktop's device context.
hBrush := DllCall("CreateSolidBrush", "UInt", 0x0000FF, "Ptr") ; Create a red brush (0x0000FF is in BGR format).
DllCall("FillRect", "Ptr", hDC, "Ptr", Rect, "Ptr", hBrush) ; Fill the specified rectangle using the brush above.
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC) ; Clean-up.
DllCall("DeleteObject", "Ptr", hBrush) ; Clean-up. |
Я перевел его в Autorun с небольшой особенностью и добавил к функции.
 Hidden text | Code: | Global gHBarMark1 = 0, gHBarMark2 = 0
Func HBarMarkToDelete()
Local InfoMsg, sMenu
If gHBarLoadError Or gHBarList.Count = 0 Then
InfoMsg = "Панель не загружена"
ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
InfoMsg = "Файл панели изменился"
Endif
If InfoMsg <> "" Then
ShowDragHint(InfoMsg)
Return
Endif
HBarCreateColor()
If Not gHBarMark1 Then
gHBarMark1 = HBarGetIdx()
If gHBarMark1 < 1 Then
gHBarMark1 = 0
Return
EndIf
IniRead sMenu %gHBarFile% "Buttonbar" %'"menu" & gHBarMark1' "<>"
MsgBox("Индекс: " & gHBarMark1 & auCRLF & sMenu & auCRLF & auCRLF & _
"Задать начало диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then gHBarMark1 = 0
Return
Endif
If Not gHBarMark2 Then
gHBarMark2 = HBarGetIdx()
If gHBarMark2 = gHBarMark1 Then
gHBarMark2 = 0
Return
EndIf
IniRead sMenu %gHBarFile% "Buttonbar" %'"menu" & gHBarMark2' "<>"
MsgBox("Индекс: " & gHBarMark2 & auCRLF & sMenu & auCRLF & auCRLF & _
"Задать конец диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
gHBarMark2 = 0
Return
EndIf
Endif
Local nHBarMark1 = Min(gHBarMark1, gHBarMark2)
Local nHBarMark2 = Max(gHBarMark1, gHBarMark2)
MsgBox("Диапазон: " & nHBarMark1 & "-"& nHBarMark2 & auCRLF & auCRLF & _
"Удалить группу кнопок?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
ShowDragHint("Диапазон сброшен")
Else
# удаление
HBarBreakErase(nHBarMark1, nHBarMark2+1)
EndIf
gHBarMark1 = 0
gHBarMark2 = 0
EndFunc
Func HBarCreateColor()
MouseGetPos("x","y")
Local buf = Buffer(16) # RECT
buf.Zero()
buf.SetNum(0, "Int", x-5, _
"Int", y-5, _
"Int", x+5, _
"Int", y+5)
Local hDC = DllCall("GetDC", "ptr", 0, "ptr")
#Local hDC = DllCall("GetWindowDC", "ptr", hBarWnd, "ptr")
Local hBrush = DllCall("CreateSolidBrush", "UInt", 0x0000FF, "Ptr")
DllCall("FillRect", "Ptr", hDC, "Ptr", buf.ptr, "Ptr", hBrush)
DllCall("DeleteObject", "Ptr", hBrush)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Free(buf)
Sleep(100)
EndFunc |
Сейчас намного лучше стало. Если бы маркер держался на экране, то было бы еще лучше, но заморачиваться не хочется. Ведь размер панели может измениться в любой момент, а это значит, что придется пересчитывать координаты маркера. Как по мне, оно не стоит того. И сейчас вполне удобно
| sa wrote: | | В идеале хотелось, чтобы была одна операция, а не две, не связанные друг с другом. |
Надо подумать над этим. Но вы попробуйте обновленный вариант: он удобен по-своему, к нему просто привыкнуть надо. |
|
| Back to top |
|
 |
sa
Joined: 29 Apr 2009 Posts: 2754
|
(Separately) Posted: Fri Jul 17, 2026 15:00 Post subject: |
|
|
| Orion9 wrote: | | нельзя задать диапазон равный одной кнопке | Ничего страшного! А то получится, что при удалении можно обойтись и без Drag&Drop .
| Orion9 wrote: | Да нормальный интерфейс, мне даже нравится
...
Сейчас намного лучше стало. | Я ещё и подтверждения убрал (сначала все три, потом на удаление всё-таки зачем-то вернул - хотя и так имеется отмена последнего действия). Вместо первых двух стало достаточно красных квадратиков. Теперь можно при нажатом Alt щёлкнуть правой клавишей мыши по двум произвольным кнопкам панели и получить запрос на удаление – чем не одна операция?!
В окошке подтверждения удаления дополнительно указал количество кнопок в группе (Удалить группу кнопок: 12шт?)
Спасибо! |
|
| Back to top |
|
 |
Orion9

Joined: 01 Jan 2024 Posts: 1208
|
(Separately) Posted: Sat Jul 18, 2026 00:36 Post subject: |
|
|
| sa wrote: | | В окошке подтверждения удаления дополнительно указал количество кнопок в группе (Удалить группу кнопок: 12шт?) |
Хорошая идея. Тоже добавил. Только сообщение немножко другое.
| sa wrote: | | Я ещё и подтверждения убрал |
Да, теперь я понял задумку — сверхскоростное удаление! Удобно получилось Но, имхо, последнее сообщение я бы все же оставил, а то мало ли. К тому же, так можно сбросить диапазон, если вдруг понял, что граница неправильно выбрана. Хотя и откаты есть.
Я добавил параметр AskFor, для скрытия/показа диалога. В будущем можно будет опцию сделать, если понадобится. Но по-моему, без двух лишних сообщений работает прекрасно
| sa wrote: | | чем не одна операция?! |
Согласен. Прикольно получилось и удобно.
 Hidden text | Code: | Global gHBarMark1 = 0, gHBarMark2 = 0
Func HBarMarkToDelete()
Local InfoMsg, sMenu, AskFor = 0
If gHBarLoadError Or gHBarList.Count = 0 Then
InfoMsg = "Панель не загружена"
ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
InfoMsg = "Файл панели изменился"
Endif
If InfoMsg <> "" Then
ShowDragHint(InfoMsg)
Return
Endif
HBarCreateColor()
If Not gHBarMark1 Then
gHBarMark1 = HBarGetIdx()
If gHBarMark1 < 1 Then
gHBarMark1 = 0
Return
EndIf
If AskFor Then
IniRead sMenu %gHBarFile% "Buttonbar" %'"menu" & gHBarMark1' "<>"
MsgBox("Индекс: " & gHBarMark1 & auCRLF & sMenu & auCRLF & auCRLF & _
"Задать начало диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then gHBarMark1 = 0
EndIf
Return
Endif
If Not gHBarMark2 Then
gHBarMark2 = HBarGetIdx()
If gHBarMark2 = gHBarMark1 Then
gHBarMark2 = 0
Return
EndIf
If AskFor Then
IniRead sMenu %gHBarFile% "Buttonbar" %'"menu" & gHBarMark2' "<>"
MsgBox("Индекс: " & gHBarMark2 & auCRLF & sMenu & auCRLF & auCRLF & _
"Задать конец диапазона?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
gHBarMark2 = 0
Return
EndIf
EndIf
Endif
Local nHBarMark1 = Min(gHBarMark1, gHBarMark2)
Local nHBarMark2 = Max(gHBarMark1, gHBarMark2)
MsgBox("Диапазон: " & nHBarMark1 & "-"& nHBarMark2 & auCRLF & auCRLF & _
"Удалить группу из " & nHBarMark2 - nHBarMark1 + 1 & " кнопок?", "Autorun", 3+64+0)
If EXTENDED <> 6 Then
ShowDragHint("Диапазон сброшен")
Else
# удаление
HBarBreakErase(nHBarMark1, nHBarMark2+1)
EndIf
gHBarMark1 = 0
gHBarMark2 = 0
EndFunc |
 Hidden text |
|
| Back to top |
|
 |
sa
Joined: 29 Apr 2009 Posts: 2754
|
(Separately) Posted: Sat Jul 18, 2026 00:55 Post subject: |
|
|
| Orion9 wrote: | | Только сообщение немножко другое. | Удалить группу из 21 кнопок?
Не очень звучит… |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|