#!/usr/bin/env bash # Dialog interface wrapper for audiogame-manager # Automatically switches between dialog (console) and yad (GUI) based on DISPLAY environment # This provides better accessibility for GUI environments while maintaining console functionality # Note: dialogType is now detected in the main script before DISPLAY is modified # This ensures console detection works correctly when AGM sets DISPLAY=":0" # If dialogType is not set (e.g., when called from standalone scripts), detect it if [[ -z "$dialogType" ]]; then if [[ -z "$DISPLAY" ]]; then dialogType="dialog" else dialogType="yad" fi fi # Wrapper function for menu selection # Usage: agm_menu "title" "backtitle" "text" option1 "description1" option2 "description2" ... agm_menu() { local title="$1" local backTitle="$2" local text="$3" shift 3 if [[ "$dialogType" == "yad" ]]; then # Build yad list format: Display only, then map back to value local yadList="" declare -A valueMap while [[ $# -gt 0 ]]; do local option="$1" local description="$2" valueMap["$description"]="$option" if [[ -n "$yadList" ]]; then yadList="$yadList\n" fi yadList="${yadList}${description}" shift 2 done local selectedDescription selectedDescription=$(echo -e "$yadList" | yad --list \ --title="$title" \ --text="$text" \ --column="Option" \ --no-headers \ --selectable-labels \ --search-column=1 \ --height=400 \ --width=600) # Strip trailing pipes and return the mapped value if [[ -n "$selectedDescription" ]]; then selectedDescription="${selectedDescription%|}" echo "${valueMap["$selectedDescription"]}" fi else # Build dialog menu format with mapping (same approach as yad) local dialogArgs=() declare -A valueMap while [[ $# -gt 0 ]]; do local option="$1" local description="$2" valueMap["$description"]="$option" dialogArgs+=("$description" "$description") shift 2 done local selectedDescription selectedDescription=$(dialog --backtitle "$backTitle" \ --title "$title" \ --no-tags \ --menu "$text" 0 0 0 \ "${dialogArgs[@]}" \ --stdout) # Return the mapped value if [[ -n "$selectedDescription" ]]; then echo "${valueMap["$selectedDescription"]}" fi fi } # Wrapper function for checklist selection # Usage: agm_checklist "title" "backtitle" "text" option1 "description1" "status1" option2 "description2" "status2" ... agm_checklist() { local title="$1" local backTitle="$2" local text="$3" shift 3 if [[ "$dialogType" == "yad" ]]; then local yadList="" while [[ $# -gt 0 ]]; do local option="$1" local description="$2" local status="$3" local checked="FALSE" [[ "$status" == "on" ]] && checked="TRUE" if [[ -n "$yadList" ]]; then yadList="$yadList\n" fi yadList="${yadList}${checked}|${description}|${option}" shift 3 done echo -e "$yadList" | yad --list \ --title="$title" \ --text="$text" \ --checklist \ --column="Select:CHK" \ --column="Option" \ --column="Value:HD" \ --hide-column=3 \ --print-column=3 \ --no-headers \ --selectable-labels \ --height=400 \ --width=600 \ --separator=" " else local dialogArgs=() while [[ $# -gt 0 ]]; do dialogArgs+=("$1" "$2" "$3") shift 3 done dialog --backtitle "$backTitle" \ --title "$title" \ --checklist "$text" 0 0 0 \ "${dialogArgs[@]}" \ --stdout fi } # Wrapper function for input dialog # Usage: agm_inputbox "title" "backtitle" "text" "default_value" agm_inputbox() { local title="$1" local backTitle="$2" local text="$3" local defaultValue="$4" if [[ "$dialogType" == "yad" ]]; then yad --entry \ --title="$title" \ --text="$text" \ --entry-text="$defaultValue" \ --selectable-labels \ --width=400 else dialog --backtitle "$backTitle" \ --title "$title" \ --inputbox "$text" 0 0 "$defaultValue" \ --stdout fi } # Wrapper function for message box # Usage: agm_msgbox "title" "backtitle" "text" agm_msgbox() { local title="$1" local backTitle="$2" local text="$3" if [[ "$dialogType" == "yad" ]]; then echo -e "$text" | yad --text-info \ --title="$title" \ --show-cursor \ --button="OK:0" \ --width=600 \ --height=400 else dialog --backtitle "$backTitle" \ --title "$title" \ --msgbox "$text" 0 0 fi } # Wrapper function for yes/no dialog # Usage: agm_yesno "title" "backtitle" "text" agm_yesno() { local title="$1" local backTitle="$2" local text="$3" if [[ "$dialogType" == "yad" ]]; then echo -e "$text" | yad --text-info \ --title="$title" \ --show-cursor \ --button="Yes:0" \ --button="No:1" \ --width=600 \ --height=400 else dialog --backtitle "$backTitle" \ --title "$title" \ --yesno "$text" 0 0 fi } # Wrapper function for info box (non-blocking message) # Usage: agm_infobox "title" "backtitle" "text" agm_infobox() { local title="$1" local backTitle="$2" local text="$3" if [[ "$dialogType" == "yad" ]]; then # For yad, we'll use a notification since infobox is non-blocking yad --notification \ --text="$text" \ --timeout=3 else dialog --backtitle "$backTitle" \ --title "$title" \ --infobox "$text" 0 0 fi } # Wrapper function for progress box # Usage: command | agm_progressbox "title" "text" agm_progressbox() { local title="$1" local text="$2" if [[ "$dialogType" == "yad" ]]; then # Start audio feedback for accessibility local beepPid local yadPid # Cleanup function for traps cleanup_progress() { [[ -n "$beepPid" ]] && kill "$beepPid" 2>/dev/null [[ -n "$yadPid" ]] && kill "$yadPid" 2>/dev/null } # Set trap to ensure cleanup on interruption trap cleanup_progress EXIT INT TERM if command -v sox >/dev/null 2>&1; then { while true; do # Generate a short, pleasant progress beep (440Hz for 0.1s) sox -q -n -d synth 0.1 sine 440 vol 0.3 2>/dev/null sleep 2 # Beep every 2 seconds done } & beepPid=$! fi # Start visual progress dialog with auto-close, redirect stdin to prevent conflicts yad --progress \ --title="$title" \ --text="$text" \ --auto-close \ --pulsate \ --width=400 \ --height=100 /dev/null [[ -n "$yadPid" ]] && kill "$yadPid" 2>/dev/null } # Set trap to ensure cleanup on interruption trap cleanup_simple_progress EXIT INT TERM if command -v sox >/dev/null 2>&1; then { while true; do # Generate a short, pleasant progress beep (440Hz for 0.1s) sox -q -n -d synth 0.1 sine 440 vol 0.3 2>/dev/null sleep 2 # Beep every 2 seconds done } & beepPid=$! fi # Show progress dialog with pulsating yad --progress \ --title="$title" \ --text="$text" \ --auto-close \ --pulsate \ --width=400 \ --height=100 & yadPid=$! # Read from stdin and discard, but keep dialogs open until command finishes cat > /dev/null # Clean up background processes cleanup_simple_progress trap - EXIT INT TERM # Remove traps else dialog --title "$title" \ --progressbox "$text" 20 70 fi } # Alternative status box for simple operations without meaningful progress # Usage: agm_statusbox "title" "text" & statusPid=$!; command; kill $statusPid 2>/dev/null agm_statusbox() { local title="$1" local text="$2" if [[ "$dialogType" == "yad" ]]; then # Show a simple status message that screen readers can access yad --form \ --title="$title" \ --field="$text:LBL" \ --selectable-labels \ --no-buttons \ --timeout=0 \ --width=400 \ --height=100 else # Use infobox for console dialog --title "$title" \ --infobox "$text" 5 50 fi } # Real progress bar with percentage updates (for operations that can report progress) # Usage: agm_progress_with_percent "title" "text" # Then send "percentage" or "#status text" to the returned file descriptor agm_progress_with_percent() { local title="$1" local text="$2" if [[ "$dialogType" == "yad" ]]; then # Start audio feedback for accessibility local beepPid local yadPid # Cleanup function for traps cleanup_percent_progress() { [[ -n "$beepPid" ]] && kill "$beepPid" 2>/dev/null [[ -n "$yadPid" ]] && kill "$yadPid" 2>/dev/null } # Set trap to ensure cleanup on interruption trap cleanup_percent_progress EXIT INT TERM if command -v sox >/dev/null 2>&1; then { while true; do # Generate a short, pleasant progress beep (440Hz for 0.1s) sox -q -n -d synth 0.1 sine 440 vol 0.3 2>/dev/null sleep 2 # Beep every 2 seconds done } & beepPid=$! fi # Create a true progress dialog that accepts percentage updates with tee for cleanup { cat cleanup_percent_progress trap - EXIT INT TERM } | yad --progress \ --title="$title" \ --text="$text" \ --auto-close \ --width=400 \ --height=150 else # For dialog, we'll simulate with a gauge dialog --title "$title" \ --gauge "$text" 6 50 0 fi } # Wrapper function for file selection # Usage: agm_fselect "title" "backtitle" "default_path" agm_fselect() { local title="$1" local backTitle="$2" local defaultPath="$3" if [[ "$dialogType" == "yad" ]]; then yad --file \ --title="$title" \ --filename="$defaultPath" \ --width=600 \ --height=400 else dialog --backtitle "$backTitle" \ --title "$title" \ --fselect "$defaultPath" 0 0 \ --stdout fi } # Wrapper function for directory selection # Usage: agm_dselect "title" "backtitle" "default_path" agm_dselect() { local title="$1" local backTitle="$2" local defaultPath="$3" if [[ "$dialogType" == "yad" ]]; then yad --file \ --directory \ --title="$title" \ --filename="$defaultPath" \ --width=600 \ --height=400 else dialog --backtitle "$backTitle" \ --title "$title" \ --dselect "$defaultPath" 0 0 \ --stdout fi }