152 lines
4.1 KiB
Bash
Executable File
152 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# TUI timer setter — vim keys, unicode frames, labeled fields
|
||
# Usage: timer.sh [-v|--verbose]
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$(realpath "$0")")" && pwd)"
|
||
|
||
VERBOSE=0
|
||
for arg in "$@"; do
|
||
[[ "$arg" == "-v" || "$arg" == "--verbose" ]] && VERBOSE=1
|
||
done
|
||
|
||
cleanup() { tput cnorm; tput rmcup; }
|
||
trap cleanup EXIT INT TERM
|
||
|
||
tput smcup
|
||
tput civis
|
||
|
||
R="$(tput sgr0)"
|
||
NORMAL="$(tput setaf 7)"
|
||
SELECT="$(tput bold)$(tput setaf 6)"
|
||
TITLE="$(tput bold)$(tput setaf 5)"
|
||
DIM="$(tput dim)$(tput setaf 7)"
|
||
ERR="$(tput bold)$(tput setaf 1)"
|
||
|
||
VALUES=(0 0 0)
|
||
LIMITS=(23 59 59)
|
||
LABELS=("HOURS" "MINUTES" "SECONDS")
|
||
FIELD=0
|
||
SHOW_ERR=0
|
||
KEY=""
|
||
|
||
# draw_box row col val label active
|
||
# Box inner width = 10, total = 12, height = 6
|
||
draw_box() {
|
||
local y=$1 x=$2 val=$3 label=$4 active=$5
|
||
local num; printf -v num '%02d' "$val"
|
||
local inner=10
|
||
|
||
local tl tr bl br bh bv color
|
||
if [[ $active -eq 1 ]]; then
|
||
tl='╔' tr='╗' bl='╚' br='╝' bh='═' bv='║' color=$SELECT
|
||
else
|
||
tl='┌' tr='┐' bl='└' br='┘' bh='─' bv='│' color=$NORMAL
|
||
fi
|
||
|
||
local hline; printf -v hline '%*s' $inner ''; hline="${hline// /$bh}"
|
||
|
||
local lpad=$(( (inner - ${#label}) / 2 ))
|
||
local lrpad=$(( inner - lpad - ${#label} ))
|
||
local npad=$(( (inner - ${#num}) / 2 ))
|
||
local nrpad=$(( inner - npad - ${#num} ))
|
||
|
||
tput cup $y $x; printf '%s%s%s%s%s' "$color" "$tl" "$hline" "$tr" "$R"
|
||
tput cup $((y+1)) $x; printf '%s%s%*s%s%*s%s%s' "$color" "$bv" $lpad '' "$label" $lrpad '' "$bv" "$R"
|
||
tput cup $((y+2)) $x; printf '%s%s%*s%s%s' "$color" "$bv" $inner '' "$bv" "$R"
|
||
tput cup $((y+3)) $x; printf '%s%s%*s%s%*s%s%s' "$color" "$bv" $npad '' "$num" $nrpad '' "$bv" "$R"
|
||
tput cup $((y+4)) $x; printf '%s%s%*s%s%s' "$color" "$bv" $inner '' "$bv" "$R"
|
||
tput cup $((y+5)) $x; printf '%s%s%s%s%s' "$color" "$bl" "$hline" "$br" "$R"
|
||
}
|
||
|
||
draw_colon() {
|
||
local y=$1 x=$2
|
||
tput cup $((y+3)) $x
|
||
printf '%s ∶ %s' "$DIM" "$R"
|
||
}
|
||
|
||
draw() {
|
||
local W H
|
||
W=$(tput cols); H=$(tput lines)
|
||
printf '\033[2J\033[H'
|
||
|
||
local title="─── T I M E R ───"
|
||
tput cup 2 $(( (W - ${#title}) / 2 ))
|
||
printf '%s%s%s' "$TITLE" "$title" "$R"
|
||
|
||
# 3 boxes × 12 wide + 2 colons × 3 wide = 42 total
|
||
local total=42
|
||
local sx=$(( (W - total) / 2 ))
|
||
local dy=$(( (H - 6) / 2 ))
|
||
(( dy < 4 )) && dy=4
|
||
|
||
local -a bx=( $sx $((sx + 15)) $((sx + 30)) )
|
||
|
||
for i in 0 1 2; do
|
||
local active=0; [[ $i -eq $FIELD ]] && active=1
|
||
draw_box $dy "${bx[$i]}" "${VALUES[$i]}" "${LABELS[$i]}" $active
|
||
done
|
||
|
||
draw_colon $dy $((sx + 12))
|
||
draw_colon $dy $((sx + 27))
|
||
|
||
if [[ $SHOW_ERR -eq 1 ]]; then
|
||
local msg="set a non-zero time first"
|
||
tput cup $((dy + 7)) $(( (W - ${#msg}) / 2 ))
|
||
printf '%s%s%s' "$ERR" "$msg" "$R"
|
||
fi
|
||
|
||
local verbose_tag=""; [[ $VERBOSE -eq 1 ]] && verbose_tag=" [verbose]"
|
||
local hint="h/l field j/k adjust Enter start q cancel${verbose_tag}"
|
||
tput cup $((H - 2)) $(( (W - ${#hint}) / 2 ))
|
||
printf '%s%s%s' "$DIM" "$hint" "$R"
|
||
}
|
||
|
||
read_key() {
|
||
local seq
|
||
IFS= read -rsn1 KEY
|
||
if [[ "$KEY" == $'\033' ]]; then
|
||
IFS= read -rsn2 -t 0.05 seq 2>/dev/null || true
|
||
KEY="$KEY$seq"
|
||
fi
|
||
}
|
||
|
||
while true; do
|
||
draw
|
||
SHOW_ERR=0
|
||
read_key
|
||
|
||
case "$KEY" in
|
||
q|$'\033')
|
||
exit 0
|
||
;;
|
||
h|$'\033[D')
|
||
FIELD=$(( (FIELD + 2) % 3 ))
|
||
;;
|
||
l|$'\033[C')
|
||
FIELD=$(( (FIELD + 1) % 3 ))
|
||
;;
|
||
k|$'\033[A')
|
||
VALUES[$FIELD]=$(( (VALUES[$FIELD] + 1) % (LIMITS[$FIELD] + 1) ))
|
||
;;
|
||
j|$'\033[B')
|
||
VALUES[$FIELD]=$(( (VALUES[$FIELD] - 1 + LIMITS[$FIELD] + 1) % (LIMITS[$FIELD] + 1) ))
|
||
;;
|
||
$'\n'|$'\r')
|
||
total=$(( VALUES[0] * 3600 + VALUES[1] * 60 + VALUES[2] ))
|
||
if (( total == 0 )); then
|
||
SHOW_ERR=1
|
||
else
|
||
label=$(printf '%02d:%02d:%02d' "${VALUES[0]}" "${VALUES[1]}" "${VALUES[2]}")
|
||
if [[ $VERBOSE -eq 1 ]]; then
|
||
kitty --title "Timer: $label" bash "$SCRIPT_DIR/timer-notify.sh" "$total" "$label" --verbose &
|
||
disown
|
||
else
|
||
setsid bash "$SCRIPT_DIR/timer-notify.sh" "$total" "$label" &>/dev/null &
|
||
disown
|
||
fi
|
||
exit 0
|
||
fi
|
||
;;
|
||
esac
|
||
done
|