Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a series of toggle switches in a scrollable menu with Batch?

I have spent hours doing this.

@echo off
set list = 0 0 1 1
:loop
cls
echo Program Select
echo --------------
set "el=0"
for %%a in (%list%) do ( 
    set /a "el+=1"
    if %%a equ 0 echo "[ ] Program %el%"
    if %%a equ 1 echo "[X] Program %el%"
)
echo ----------------------------------------------------
echo W = Up  /  S = Down  /  L  = Toggle  /  H  = Confirm
choice /C WSLH /N >nul
if %ERRORLEVEL% equ 1 set key=UP
if %ERRORLEVEL% equ 2 set key=DN
if %ERRORLEVEL% equ 3 set key=SL
if %ERRORLEVEL% equ 4 set key=CN
echo %key%
pause >nul
goto loop

Now the key variable works fine, and I have yet to implement scrolling, because I can't seem to get it to even render the text.

The goal is to get output like this

Program Select
--------------
[ ] Program 1
[ ] Program 2
[X] Program 3
[X] Program 4
----------------------------------------------------
W = Up  /  S = Down  /  L  = Toggle  /  H  = Confirm

But instead, I just get the Program Select and the controls. What am I missing?

like image 914
Gabriel Keess Avatar asked Nov 27 '25 11:11

Gabriel Keess


1 Answers

Here's a more "meated-out" version of your code:

@echo off
SETLOCAL enabledelayedexpansion


:: Program names used

set "program[1]=Program one"
set "program[2]=Program two"
set "program[3]=Program three"
set "program[4]=Program four"
set /a maxprogs=4

:: symbols used for statuses

set "symbols= X"
set "symbolsc=-+"

:restart
:: Set original list status. 0=not selected, 1=selected;

set "list=0 0 1 1"
set /a cursor=1

:loop
cls
echo Program Select
echo --------------
set /a el=0
for %%a in (%list%) do ( 
    set /a el+=1
    if !el!==%cursor% (set "ds=!symbolsc:~%%a,1!") else (set "ds=!symbols:~%%a,1!")
    call set "progname=%%program[!el!]%%"
    echo [!ds!] !progname!
)
echo ----------------------------------------------------
choice /C WSLHQ /N /M "W = Up  /  S = Down  /  L  = Toggle  /  H  = Confirm / Q = Quit "
set /a key=%errorlevel%
if %key%==5 goto :eof
if %key%==4 goto confirm
if %key%==3 goto toggle
if %key%==2 if %cursor%==%maxprogs% (set /a cursor=1) else set /a cursor+=1
if %key%==1 if %cursor%==1 (set /a cursor=%maxprogs%) else set /a cursor-=1

goto loop

:confirm
echo Confirmed!
set "runany="
set /a el=0
for %%a in (%list%) do ( 
    set /a el+=1
    if %%a==1 (
     set /a runany+=1
     call set "progname=%%program[!el!]%%"
     echo Run !progname!
    )
)
if not defined runany echo None selected :(

timeout /t 5 /nobreak
goto restart

:toggle
set "newlist="
set /a el=0
for %%a in (%list%) do ( 
    set /a el+=1
    if !el!==%cursor% (
     if %%a==0 (set "newlist=!newlist! 1") else (set "newlist=!newlist! 0")
    ) else set "newlist=!newlist! %%a"
)
set "list=%newlist%"
goto loop

Comments:

SETLOCAL enabledelayedexpansion allows !var! to access the changed value of var within a loop (%var% accesses the original value, before the loop started executing).

I used maxprogs so that expansion of the list is intuitive - just follow the bouncing ball...

Since the cursor is static, I used symbols to represent the non-selected/selected states and symbolsc for when the "cursor" is on the state, so + is cursor-is-here-it's-selected and - is cursor-is-here-it's-not-selected

The list usage is similar to your version - cursor is for the current cursor-line.

In the display-selections-and-prognames section, note the use of !el! to access the modified value of el within the loop

The tricky bit here is the call set "progname=%%program[!el!]%%" statement. This uses a parsing trick to get the value of the program name el. Assuming the current value of el is 2 for instance, this executes the command set "progname=%program[2]%" in a sub-shell by interpreting %% as an escaped-% and substituting for the current value of el. The subshell inherits the environment of its caller, so the destination variable is assigned from the calculated value.

I've modified the choice command to prompt with the legend, and added Q for Quit as good measure. I'd have used UDTRQ myself, for Up/Down/Toggle/Run/Quit, but something tells me you may not necessarily be using English.

I set errorlevel into key to avoid having to be particularly careful about maintaining its value, then tested key for the only 5 values of interest; on others just beep (from choice and present-again.

Quit is obvious; cursor-move simply increments or decrements cursor and checks boundary conditions for roll-around.

The other two routines are simply modifications of the display-list routine; the run displays the prognames as I have no idea whether you want to run the programs serially or in parallel.

The toggle routine uses the same technique to rebuild list whilst toggling the cursor'th element.

like image 160
Magoo Avatar answered Nov 30 '25 05:11

Magoo