ButtonBarTools

Название ButtonBarTools
Имя файла (*.txt) ButtonBarTools.txt
Описание См. комментарии
Автор Вахмурка
Параметры [Режим] [[панель-источник], [панель-приемник], [начальный_номер], [конечный_номер]]
(см. комментарии)
Вызываемые плагины vec, ini, file, clip, win, miscplugin, unicode
Иконка
Версия 2.3
Дата обновления 28.06.2022
args Param

static Mode = Param

if(arg(0) > 1) do
	.@Batch(arg(1), arg(2), arg(3), arg(4))
	quit all
endif

static BB = "Buttonbar"
static BC = "Buttoncount"
static hh = win.handle("c=TTOTAL_CMD")
static Path = file.folder(win.exepath(hh))
static ButtonCount = 0
static G = "General"
static Config = pprofolder ++ "scripts\ini\ButtonBarTools.ini"
static Height = ini.get(Config, G, "Height") - 2
local MainBar, Cur
static E = cl.Create("Bars", 1)
local Sex = ini.enum_sections(Config)
static FSS = "Format StartSubmenu"
static FES = "Format EndSubmenu"
static FNCL = "Format NewColumnLine"
static Mask = "*.bar"
static CR = esc(?+\r+, ?+\+)
static CR2 = esc(?+\r\r+, ?+\+)
static Tab = esc(?+\t+, ?+\+)
static BBTS = "ButtonBarTools Script"
static FCV = "Failure creating vector"
static Target = Path ++ "\BBT" ++ ifelse(ini.get(Config, G, "SameNameResult"), "", date ++ time) ++ ".bar"
static TTS = ini.get(Config, G, "Separator")
E.SetTooltipSeparator(TTS)

static w = vec.createfromwords("button cmd param path menu iconic")
if(not w) do
	messagebox("ok error", FCV, "VEC plugin Error #4")
	quit
endif

static KeyWords = w.length

static S = vec.create(6)
if(not S) do
	messagebox("ok error", FCV, "VEC plugin Error #2")
	quit
endif

S[1] = 0
S[3] = 0
S[5] = 0

E.Insert(0)
E.AddLeft(0, FSS)
E.SetLabel(0, "Main Bars")
.@Read()

Cur = E.length
E.Insert(Cur)
E.AddLeft(Cur, FES)

for each line MainBar in Sex
	if(MainBar != G) do
		Cur = E.length
		E.Insert(Cur)
		E.AddLeft(Cur, FSS)
		E.SetLabel(Cur, MainBar)
		.@Read(MainBar)
		Cur = E.length
		E.Insert(Cur)
		E.AddLeft(Cur, FES)
	endif
endfor

E.SetProperties("Format=samesize vertical iconsize: 16 tooltips")

if(Mode == "s" || Shift) do
	static Ba = "Bars"
	static Bu = "Buttons"
	Cur = S[1] + S[3] + S[5]
	MainBar = S[0] + S[2] + S[4]
	Sex = "Main:" ++ CR ++ Ba ++ Tab ++ S[0] ++ CR ++ Bu ++ Tab ++ S[1] ++ CR2
	Sex ++= "Local:" ++ CR ++ Ba ++ Tab ++ S[2] ++ CR ++ Bu ++ Tab ++ S[3] ++ CR2
	Sex ++= "Other:" ++ CR ++ Ba ++ Tab ++ S[4] ++ CR ++ Bu ++ Tab ++ S[5] ++ CR2
	Sex ++= "Total:" ++ CR ++ Ba ++ Tab ++ MainBar ++ CR ++ Bu ++ Tab ++ Cur
	messagebox("ok information", Sex, BBTS)
else
	E.ShowMenu("centerscreen")
endif

if(!ini.get(Config, G, "KeepResult") || Alt)
	file.delete(Target)

if(Mode == "b") do
	Cur = E.GetLastMenuSel()
	if(Cur)
		quit(E.GetId(Cur))

endif

quit all

;;************************************************
Function Read(Sec)

local Str, List, Elem, Counter, j, Cur, Pan, Temp
;;, Item
static i = "information"
static B1 = " bars"
static B2 = " buttons"
static T = "timeout=5"
static FolderIcon = env("WINDIR") ++ "\system32\shell32.dll"

switch (Sec)
	case "Local Bars"
		Str = ini.enum_keys(Config, Sec)
		Pan = line(Str, 0)
		miscplugin.BalloonTip(1, i, "Local: " ++ Pan ++ B1, T)
		S[2] = Pan

		for each line Temp in Str
			Elem = ini.get(Config, Sec, Temp)
			j = Elem ++ "_local.bar"
			Cur = E.length

			with E.Insert(Cur)
				.SetLabel(j)
				.SetIcon(FolderIcon, 4)
				.SetTooltip(ini.get(j, BB, BC) ++ B2)
				.SetId(j)
			endwith

			if(Mode != "b") do
				E.AddLeft(Cur, FSS)
				S[3] += .@Bur(j)
				Cur = E.length
				E.Insert(Cur)
				E.AddLeft(Cur, FES)
			endif

			if(Counter > Height) do
				E.Insert(Cur + 1)
				E.AddLeft(Cur + 1, FNCL)
				Counter = 0
			else
				Counter++
			endif

		endfor
		break

	case "Other Bars"
		Str = ini.enum_keys(Config, Sec)

		for each line Pan in Str
			Elem = ini.get(Config, Sec, Pan)
			List = file.listfiles(Elem ++ Mask)
			S[4] += line(List, 0)
			miscplugin.BalloonTip(1, i, "Other: " ++ S[4] ++ B1, T)

			for each line j in List
				Cur = E.length

				with E.Insert(Cur)
					.SetLabel(j)
					.SetIcon(FolderIcon, 4)
					.SetTooltip(ini.get(j, BB, BC) ++ B2)
					.SetId(j)
				endwith

				if(Mode != "b") do
					E.AddLeft(Cur, FSS)
					S[5] += .@Bur(j)
					Cur = E.length
					E.Insert(Cur)
					E.AddLeft(Cur, FES)
				endif

				if(Counter > Height) do
					E.Insert(Cur + 1)
					E.AddLeft(Cur + 1, FNCL)
					Counter = 0
				else
					Counter++
				endif
			endfor
		endfor
		break
	case else
		Temp = file.listfiles(Path ++ "\*.bar")
		Pan = line(Temp, 0)
		S[0] = Pan
		miscplugin.BalloonTip(1, i, " Main: " ++ Pan ++ B1, T)

		for each line j in Temp
			Elem = file.name(j)
			Cur = E.length

			with E.Insert(Cur)
				.SetLabel(Elem)
				.SetIcon(FolderIcon, 4)
				.SetTooltip(j ++ TTS ++ ini.get(j, BB, BC) ++ B2)
				.SetId(j)
			endwith

			if(Mode != "b") do
				E.AddLeft(Cur, FSS)
				S[1] += .@Bur(j)
				Cur = E.length
				E.Insert(Cur)
				E.AddLeft(Cur, FES)
			endif
			
			if(Counter > Height) do
				E.Insert(Cur + 1)
				E.AddLeft(Cur + 1, FNCL)
				Counter = 0
			else
				Counter++
			endif
		endfor
;;		quit
endswitch

quit

;;************************************************
Function Bur(Name)
local Name
local Buttons = ini.get(Name, BB, BC)
local BarNum = E.length - 1
local j, Temp, Cur, TT, Counter, Item, cmds, TTL

for(j = 1; j <= Buttons; j++)
	Temp = w[1] ++ j

	if(ini.check_exists(Name, BB, Temp) == 2) do
		Cur = E.length
		E.Insert(Cur)
		E.AddLeft(Cur, "Format Separator")
		continue
	endif

	if(ini.get(Name, BB, Temp) == -2) do
		Cur = E.length
		E.Insert(Cur)
		E.AddLeft(Cur, FNCL)
		continue
	endif

	Cur = E.length
	Item = E.Insert(Cur)
	cmds++

	with Item
		if(ini.check_exists(Name, BB, w[4] ++ j) == 3)
			.SetLabel(ini.get(Name, BB, w[4] ++ j))

		if(ini.check_exists(Name, BB, w[0] ++ j) == 3)
			.SetIcon(ini.get(Name, BB, w[0] ++ j))

		TT = "Command: " ++ ini.get(Name, BB, Temp)

		if(ini.check_exists(Name, BB, w[2] ++ j) == 3)
			TT ++= TTS ++ "Parameters: " ++ ini.get(Name, BB, w[2] ++ j)

		if(ini.check_exists(Name, BB, w[3] ++ j) == 3)
			TT ++= TTS ++ "Path: " ++ ini.get(Name, BB, w[3] ++ j)

		Temp = E.GetMaxtext
		TTL = length(TT)

		if(TTL > Temp)
			TT = remove(TT, Temp - TTL - 20) ++ "/...truncated"

		.SetTooltip(TT)

		.AddLeft(cb("@Mark", Cur, BarNum, j))
		.AddRight(cb("@BInsert", BarNum, j))
	endwith

	if(Counter > Height) do
		E.Insert(Cur + 1)
		E.AddLeft(Cur + 1, FNCL)
		Counter = 0
	else
		Counter++
	endif
endfor

quit(cmds)
;;************************************************
Function Mark(Num, BarNum, Button)

local k, Key, Value
local Source = E.GetId(BarNum)

static ButtonColor = ini.get(Config, G, "MarkButton")
static BurColor = ini.get(Config, G, "MarkBar")

E.SetBackColor(Num, ButtonColor)
E.SetBackColor(BarNum, BurColor)

ButtonCount++
ini.error_dialog_off()

for(k = 0; k < KeyWords; k++)
	Temp = w[k]
	Key = Temp ++ Button

	if(ini.check_exists(Source, BB, Key) == 3) do
		Value = ini.get(Source, BB, Key)
		ini.set(Target, BB, Temp ++ ButtonCount, Value)
		ini.set(Target, BB, BC, ButtonCount)
	endif
endfor

E.ShowMenu("centerscreen")

quit
;;************************************************
Function BInsert(BarNum, Button)

local Source = E.GetId(BarNum)

if(Ctrl || Mode == "c") do
	.@Buffer(Source, Button)
	quit all
endif

local Keys = ini.get(Source, BB, BC)
local k, m, Temp, Value, Key, Shift

for(k = Keys; k > Button; k--)
	Shift = k + ButtonCount

	for(m = 0; m < KeyWords; m++)
		Temp = w[m]
		Key = Temp ++ k
		if(ini.check_exists(Source, BB, Key) == 3) do
			Value = ini.get(Source, BB, Key)
			Temp = w[m] ++ Shift
			ini.set(Source, BB, Temp, Value)
			ini.delete_key(Source, BB, Key)
		endif
	endfor
endfor

for(k = 1; k <= ButtonCount; k++)
	Shift = k + Button

	for(m = 0; m < KeyWords; m++)
		Temp = w[m]
		Key = Temp ++ k
		if(ini.check_exists(Target, BB, Key) == 3) do
			Value = ini.get(Target, BB, Key)
			Temp = w[m] ++ Shift
			ini.set(Source, BB, Temp, Value)
		endif
	endfor
endfor

messagebox("ok information", ButtonCount ++ " buttons copied to " ++ Source, BBTS)
ini.set(Source, BB, BC, Keys + ButtonCount)

quit
;;************************************************
Function Batch(SourceBar, TargetBar, From, To)
local j, Str, Counter, Temp, Elem
local Buttons = ini.get(TargetBar, BB, BC)
local Next = Buttons

if(not validpath(TargetBar)) do
	Str = "Target bar file name " ++ TargetBar ++ " is wrong"
	messagebox ("ok", Str, BBTS)
	quit
endif

if(not validpath(SourceBar)) do
	Str = "Source bar file name " ++ SourceBar ++ " is wrong"
	messagebox ("ok", Str, BBTS)
	quit
endif

if(From > To) do
	Str = "Starting button number " ++ From ++ " is more than ending number " ++ To
	messagebox ("ok", Str, BBTS)
	quit
endif

Temp = ini.get(SourceBar, BB, BC)

if(Temp < To) do
	Str = "Button count in " ++ SourceBar ++ " is " ++ Temp ++ " and is less than ending number " ++ To
	messagebox ("ok", Str, BBTS)
	quit
endif

if(!From && !To) do
	From = 1
	To = Temp
endif

for(j = From; j <= To; j++)
	Counter++
	Next++

	for each Elem in w
		Temp = Elem ++ j
		if(ini.check_exists(SourceBar, BB, Temp) == 3) do
			Str = ini.get(SourceBar, BB, Temp)
			ini.set(TargetBar, BB, Elem ++ Next, Str)
		endif
	endfor
endfor

ini.set(TargetBar, BB, BC, Buttons + Counter)

Str = Counter ++ " buttons are successfully copied from " ++ SourceBar ++ " to " ++ TargetBar
messagebox ("ok", Str, BBTS)
quit
;;************************************************
Function Buffer(Source, Button)

local k, Value, Key
local x = vec.create(KeyWords)
local Temp = "TOTALCMD#BAR#DATA" ++ CR

if(not x) do
	messagebox("ok error", FCV, "VEC plugin Error #3")
	quit all
endif

for(k = 0; k < KeyWords; k++)
	Value = w[k]
	Key = Value ++ Button
	x[k] = ifelse(ini.check_exists(Source, BB, Key) == 3, ini.get(Source, BB, Key), "")

endfor

Temp ++=  x[1] ++ CR ++ x[2] ++ CR ++ x[0] ++ CR ++ x[4] ++ CR ++ x[3] ++ CR ++ x[5]

unicode.clip_set(Temp)
quit all

Комментарии:

Скрипт для различных видов работ с панелями кнопок существует в четырех видах.

  1. Button2Clip. Как ясно из названия, он позволяет копировать кнопку только в буфер и только одну;

  2. Версия 1.0, она же B-версия. Для представления панели кнопок (button bar) Total Commander используются как меню, так и панель (bar) PowerPro. По сравнению с последней версия 1.0 чем-то выигрывала в интерфейсе, но была несколько своеобразна и непривычна в представлении и использовании;

  3. Версия 2.0, она же М-версия. Теперь для представления панели кнопок используется только меню, что автору кажется более правильным.
    В файле настроек ButtonBarTools.ini, в разделе [General] есть ключ Separator. Для данной версии символ, являющийся значением ключа, будет использован для замены косой черты "/" во всплывающих подсказках (tooltips). Например, если задано

    Separator=\
    
    то подсказка "Первый/Второй/Третий" будет выглядеть так же.
    Если же задать
    Separator=/
    
    то есть не производить замену, то подсказка будет выглядеть так:

    Первый
    Второй
    Третий

  4. Наконец, версия 2.1, она же S-версия, то есть текущая. Имеет смысл только для версии PowerPro не ниже чем 5.3.35s, причем важна именно буква "s". Внимание: функция pproversion возвратит только цифры! Узнать текущую версию полностью можно, просмотрев свойства файла powerpro.exe.

    История появления версии 2.1 такова. В кнопках Total Commander часто содержится символ "/", особенно в поле Parameters, как часть ключей программ. В то же время символ "/" является разделителем всплывающих подсказок PowerPro. Этот конфликт легко разрешить в GUI-интерфейсе настроек меню и панелей PowerPro, задав любой другой символ в качестве разделителя. Но если меню/панель формируется в скрипте, управлять символом-разделителем нельзя. Поэтому автор этих строк предложил автору PowerPro, Bruce Switzer'у, ввести функции SetTooltipSeparator и GetTooltipSeparator, что автор и сделал в версии 5.3.35s.

    Соответственно, в версии 2.1 скрипта ключ Separator приобрел несколько иной смысл. Следует задать значение ключа равным тому символу, которого нет в строке всплывающей подсказки – и тогда переносы строк будут появляться там, где им и положено. В примере выше, если изначально эта строка имела вид "Первый`Второй`Третий", и мы хотим расположить каждое слово на отдельной строке, то следует задать

    Separator=`
    
    как это и сделано по умолчанию.
    Кроме смысла ключа Separator и представления подсказок, нет никакой разницы между версиями 2.0 и 2.1.

Итак, как перенести несколько кнопок с одной панели на другую? Во-первых, можно переносить по одной через буфер: открыл одну панель, скопировал первую кнопку, открыл другую, вставил, потом еще раз, и опять… Во-вторых, можно скопировать в буфер все кнопки подряд, а потом с помощью менеджера буфера обмена (если таковой есть) вставлять по одной. В-третьих, можно присоединить одну панель к другой (с помощью, например, этого скрипта), и удалить лишнее. В-четвертых, можно открыть обе панели в текстовом редакторе и, рискуя ошибиться, вручную править номера…

Иными словами, способы есть, но все они не отличаются удобством. А поскольку у меня 2064 кнопки на 137 панелях, разбросанных по дискам, то перенос кнопок с одной на другую становится настоящей проблемой. Чтобы решить ее, я и написал этот скрипт.

Прежде всего ознакомимся с файлом настроек ButtonBarTools.ini. Он должен иметь путь pprofolder\scripts\ini\ButtonBarTools.ini, где pprofolder – путь к исполняемому файлу PowerPro.exe. Файл имеет один обязательный раздел [General] и в нем ряд обязательных ключей, смысл которых будет раскрыт позже.

Например, чтобы длинный список умещался на экране, можно экспериментально подобрать значение ключа Height – он соответствует максимальному числу пунктов в колонке.

При использовании локальных панелей (локальных меню; с этим понятием можно ознакомиться здесь) раздел с обязательным именем "Local Bars" должен содержать любое число ключей вида

Произвольное_имя=путь_к_меню\

причем сами файлы должны иметь фиксированное имя _local.bar (впрочем, его легко изменить в тексте скрипта). Если локальные меню не используются, раздел следует удалить или закомментировать целиком.

Кроме того, в файле конфигурации может содержаться любое количество разделов с произвольными именами и ключами по тому же формату. Однако, в отличие от ключей раздела "Local Bars", остальные не накладывают ограничений ни на имена файлов панелей, ни на их количество: будут считаны все файлы с расширением bar, находящиеся по указанному пути. В данном файле конфигурации это раздел "Other Bars" с двумя ключами.

Скрипт имеет шесть функций-режимов, задаваемыми параметрами или нажатиями клавиш. Иногда при запуске возникает многоуровневое меню. На первом уровне будет как минимум один пункт "Main Bars", а для данного файла конфигурации – еще и пункты "Local Bars" и "Other Bars".

Второй уровень содержит панели, третий – кнопки. Информация о кнопке содержится во всплывающей подсказке, о которой была речь выше. Кнопки имеют иконки, если это возможно. В пункте меню "Main Bars" содержатся панели с путем %COMMANDER_PATH%.

Режим первый (основной) – копирование кнопок между панелями

В этом режиме скрипт параметров не имеет. Найдя кнопку, которую нужно скопировать на другую панель, нажимаем ее левой кнопкой мыши. Сама кнопка помечается одним цветом, а панель, где кнопка находится – другим. Два этих цвета задаются ключами MarkButton и MarkBar, соответственно. Если цвета по умолчанию пользователя не устраивают, их можно поменять. Как задать цвет фона, описано в документации к PowerPro. Поиск можно проводить по ключевому слову SetTextColor.

Итак, процедуру выбора разных кнопок на разных панелях можно повторять многократно. Убедившись, что все кнопки, предназначенные к копированию, отмечены, выбираем на любой панели кнопку, после которой их предполагается вставить, и нажимаем правую кнопку мыши. Скрипт выдаст сообщение об общем числе успешно скопированных кнопок и панели-приемнике.

Кнопки именно копируются, а не перемещаются! Во-первых, так безопаснее, а во-вторых, бывает полезно иметь дубликаты кнопки на разных панелях.

Одновременно с выбором кнопок они копируются во вновь созданную панель. Ее путь определяется переменной %COMMANDER_PATH%, а имя зависит от ключа SameNameResult конфигурации: если значение ключа равно 1, то панель имеет фиксированное имя BBT.bar, иначе - уникальное имя, в которое входят текущие дата и время.

Ключ KeepResult, равный 1, оставит полученную панель после окончания работы скрипта. Иначе она будет стерта.

Имеет смысл оставлять панель, если ее предполагается переименовать и использовать как новую, содержащую ранее созданные кнопки.

Удалить панель, безотносительно к значению ключа KeepResult, можно, удерживая клавишу Alt во время окончания работы скрипта.

Режим второй – помещение образа кнопки в буфер

Это можно сделать тремя способами. Во-первых, запустить скрипт с параметром "с". Во-вторых, запустить скрипт без параметров, как в первом режиме, но нажать Ctrl в момент левого щелчка по кнопке. В-третьих, в первом режиме нажать нужную кнопку, как и ранее, правой кнопкой мыши, но сделать это тогда, когда ни одной кнопки не выделено и цветом не отмечено.

В любом случае в буфере обмена окажется образ нажатой кнопки. Следует навести курсор мыши на свободное место панели, нажать правую кнопку мыши и выбрать "Paste...".

Режим третий – сбор сведений

Скрипт запускается с параметром "s" (от "summary" или "statistics"). Или без параметров, но с нажатой клавишей Shift. Диалоговое окно будет содержать самую общую информацию о панелях всех трех типов.

Режим четвертый – пакетный

Параметры скрипта имеют следующий смысл:

панель-источник, панель-приемник, начальный_номер, конечный_номер

Источник и приемник удобно задавать как "%P%N", "%T%M", но можно указать имена bar-файлов в явном виде.

Что подразумевается под "номером" кнопки? (такой вопрос может возникнуть у новичков). Следует открыть панель в программе просмотра и найти первую из тех команд, которые предполагается скопировать. Это будет выглядеть примерно так:

cmd14=c:\path\myprogram.exe
param14=%P
button14=c:\path\myprogram.exe,1
menu14=Моя программа
В данном примере 14 – это и есть номер команды. Следует ориентироваться именно на ключ "cmd.." – он один является обязательным.

Нетрудно видеть, что пакетный режим, в отличие от основного, позволяет копировать только подряд идущие кнопки.

Пример: скрипт с такими параметрами

.ButtonBarTools(?"%P%N", "c:\some\dir\any.bar", 7, 11)

скопирует из панели под курсором в панель c:\some\dir\any.bar кнопки с номерами с 7 до 11 включительно (всего 5 штук).

Режим пятый – объединение панелей

Ранее для этих целей использовался скрипт MergeBars. Пятый режим можно считать частным случаем четвертого. Если в примере выше параметров у скрипта не 4, а 2, то есть

.ButtonBarTools(?"%P%N", "c:\some\dir\any.bar")

то будут скопированы все кнопки панели под курсором в панель any.bar.

Режим шестой - вспомогательный (служебный)

Скрипт с параметром "b" вызывается из других скриптов. У меню всего два уровня, то есть уровень панели становится нижним. После выбора панели и нажатия пользователем левой кнопки мыши на одной из панелей скрипт возвращает полный путь панели


На главную Все о Total Commander PowerPro Все скрипты