ButtonBarTools

Title ButtonBarTools
File Name ButtonBarTools.txt
Description See comments
Author Vochomurka
Parameters [Mode] [[SourceBar, TargetBar], From, To]
(see comments)
Plugins Called vec, ini, file, clip, win, miscplugin, unicode
Icon
Version 2.3
Updated on 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

Comments:

Script to work with button bars has four implementations.

  1. Button2Clip. As the name says, it allows to put only one button only to the clipboard;

  2. Version 1.0, or B-version. Both PowerPro bars and menus are used;

  3. Version 2.0, or M-version. Only PowerPro menu is used.
    The [General] section of the configuration file ButtonBarTools.ini contains key Separator. Its value is a character to replace the slash "/" in PowerPro tooltips. For example, if

    Separator=\
    
    then tooltip "First/Second/Third" looks as is. But if
    Separator=/
    
    what means no slash replacement, then the tooltip gets

    First
    Second
    Third

  4. Finally, the 2.1 version, or S-version – the actual one. It should be run under PowerPro version not older than 5.3.35s while the "s" letter matters.

    In the Total Commander buttons there are many slashes, especially in the Parameters field. Meanwhile in PowerPro bars slashes are tooltip separators. In the GUI bar/menu setup the separating character can be easily changed, but not in scripts. So, satisfying my request, Bruce Switzer introduced two new functions: SetTooltipSeparator and GetTooltipSeparator in the 5.3.35s version of PowerPro.

    Therefore, in the 2.1 script version the Separator gets another meaning: its value should be some character not containing in the tooltip text. In the above example, if we want each word to be on a separate line, we should set "First`Second`Third"

    Separator=`
    
    which is the default.
    The Separator key meaning is the only difference between versions 2.0 and 2.1.

So, how to transfer buttons from one button bar to another? First, we can use the clipboard: open source bar, copy one button to the clipboard, open target bar, paste button, open source bar again, etc. Second, we can copy all buttons to the clipboard and then paste them one by one using a clipboard manager, if any. Third, we can merge bars (using, for example, this script), and then delete excessive buttons. Fourth, we can open both bars in text editor and carefully change numbers...

So, existing ways are not handy. On my computer there are 2064 buttons on 137 bars in various directories, so the button transition from one bar to another is a problem. This script is used to solve it. Its early edition was called Button2Clip and allowed to copy only one button and only to the clipboard. The present edition has more functions.

First of all let's have a look at the configuration file ButtonBarTools.ini. Its path has to be pprofolder\scripts\inis\ButtonBarTools.ini, where pprofolder is the path PowerPro is installed in. ButtonBarTools.ini has one obligatory section [General] with some obligatory keys.

For example, the Height key value is a maximum number of rows of all menus, and is taken experimentally.

To use local bars (or local menus; they are described here) section with obligatory name [Local Bars] must contain strings like

Any_name=path_to_local_menu\

Local menus must have names _local.bar. If local menus are not used, the [Local Bars] section must be completely deleted or commented.

Further, the configuration file can contain other sections with any names each with any numbers of keys with the same format. Unlike the [Local Bars] section, other ones have no restrictions to both button bar file names and their quantity: all *.bar files with indicated path will be considered.

The script has six modes whose execution is provided by parameters or button presses. But anyway the multi-level menu is displayed. First level contains at least one item "Main Bars" and, for the present configuration, "Local Bars" and "Other Bars" items. "Main Bars" submenu contains all *.bar files with path %COMMANDER_PATH%. Second level of menu concerns button bars, the third one – buttons. Useful information is containing in tooltips discussed above. Buttons have icons if available.

First (main) mode – copying buttons from one bar to another

Script has no parameters. Button to be copied to another bar is pressed by left mouse button. The background colors of both button and its bar are changed to colors described by values of MarkButton and MarkBar keys, respectively. The color is set according to PowerPro rules – see manual about the SetTextColor keyword.

Picking different buttons can be done as many times as necessary. After all buttons are marked, the place to copy all these buttons to is indicated by right mouse button click. Finally, the script informs user about total number of buttons and the target bar.

Note that buttons are copied rather than moved! First, it is safely, second, it is sometimes useful to have the same buttons on different bars.

Along with marking buttons they are copied to new button bar file. Its path is %COMMANDER_PATH%, its name is set by the SameNameResult key value: if it is 1, then the file has name BBT.bar, otherwise – a unique name with current date and time.

The KeepResult key with the 1 value keeps the button bar after script terminates. It could be useful if to rename and use this button bar with buttons created before.

The button bar file irrespective of the above key value is deleted if to keep the Alt button pressed at the script termination.

Second mode – copying button image to the clipboard

It can be done by three ways. First, run the script with the "c" parameter. Second, run the script without parameters, but press the Ctrl key while left-clicking the button to be copied. Third, in the parameter-free mode the button is right-clicked, but no other button is marked.

Anyway, after the second mode execution, the button image is put to the clipboard. Then the user can point an empty place on any button bar, press right mouse button, and pick "Paste...".

Third mode – button bar summary

Script is run with the "s" parameter, or without any, but with Shift pressed. Dialog window is displayed with common information about button bars of all three types.

Fourth mode - batch

Script parameters are

source_bar, target_bar, starting_button_number, ending_button_number

Both bars can be Total Commander parameters like %P%N, or explicit full paths.

Unlike the main mode, the batch one allows to copy only sequential buttons.

Example: script call

.ButtonBarTools(?"%P%N", "c:\some\dir\any.bar", 7, 11)
copies 5 buttons with numbers 7-11 from bar under cursor to bar c:\some\dir\any.bar.

Fifth mode – merging bars

MergeBars script has the similar function. Fifth mode is a specific instance of the fourth one. If in the above example script has 2 parameters rather than 4, that is

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

then all buttons from the button bar file under cursor will be copied to any.bar.

Sixth mode – subscript

If this script is called from another script with the "b" parameter, then only two menu levels are shown. After clicking a bar name script returns this bar full path


All Scripts Total Commander TotalCmd.net PowerPro