# TUI user interface # # Copyright (C) 2015 Patrick "P. J." McDermott # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . tui_init_ui() { term_init term_raw term_noecho term_hide_cursor term_clear } tui_exit_ui() { term_attr_reset term_clear term_show_cursor term_echo term_cooked } _tui_box() { local w=${1} local h=${2} shift 2 local y= local x= local i= local line='' # Clear the screen and set the cursor position to center the box. term_clear y=$(expr \( $(term_lines) - ${h} \) / 2) x=$(expr \( $(term_columns) - ${w} \) / 2) term_cursor_position ${y} ${x} # Build the line. i=0 while [ ${i} -lt ${w} ]; do line="${line} " i=$(($i + 1)) done # Draw white box background lines. term_fg_color_set black term_bg_color_set white i=0 while [ ${i} -lt ${h} ]; do term_write "${line}" term_cursor_back ${w} term_cursor_down 1 i=$(($i + 1)) done # Reset the cursor to the top-left corner of the box. term_cursor_up ${h} printf '%d %d' ${y} ${x} return 0 } _tui_dialog() { local lvl="${1}" local fmt="${2}" shift 2 local msg='' # Format the message. msg="$(printf "${fmt}" "${@}")" # Draw the box. _tui_box $(expr ${#msg} + 8) 5 >/dev/null # Draw an icon. term_cursor_forward 2 case "${lvl}" in warn) term_fg_color_set yellow term_write ' .' term_cursor_back 2 term_cursor_down 1 term_attr_on underline term_write '/!\' term_attr_off underline term_fg_color_set black ;; err) term_cursor_forward 1 term_fg_color_set red term_attr_on underline term_write ' ' term_attr_off underline term_cursor_back 2 term_cursor_down 1 term_write '(' term_attr_on underline term_write 'x' term_attr_off underline term_write ')' term_fg_color_set black ;; esac # Write the message. term_cursor_forward 1 term_write "${msg}" # Draw a (selected) button. term_cursor_back 4 term_cursor_down 2 term_attr_on reverse term_write '[OK]' term_attr_off reverse while :; do case "$(term_getch)" in KEY_ENTER | KEY_SPACE) break;; esac done return 0 } tui_dbg() { : No output. } tui_info() { : No output. } tui_warn() { local fmt="${1}" shift 1 _tui_dialog warn "${fmt}" "${@}" } tui_err() { local fmt="${1}" shift 1 _tui_dialog err "${fmt}" "${@}" } tui_show_menu() { local title="${1}" shift 1 return 0 } tui_show_prompt() { local title="${1}" local len=${2} shift 2 local w= local y= local x= local i= local line='' local input='' local curpos=0 local focus=0 local key= # Calculate width and draw the box. w=$(expr ${#title} + 4) if [ $(expr ${len} + 7) -gt ${w} ]; then w=$(expr ${len} + 7) fi read -r y x <<-EOF $(_tui_box ${w} 7) EOF # Write the title. term_cursor_down 1 term_cursor_forward 2 term_write "${title}" # Build blank input line. i=0 while [ ${i} -le ${len} ]; do line="${line} " i=$(($i + 1)) done # Event loop. while :; do # Draw a button. term_cursor_position $(($y + 5)) $(($x + $w - 6)) if [ ${focus} -eq 1 ]; then term_attr_on reverse term_write '[OK]' term_attr_off reverse else term_write '[OK]' fi # Draw a textbox. term_cursor_position $(($y + 3)) $(($x + 2)) term_write '[' term_attr_on underline term_write "${line}" term_attr_off underline term_write ']' term_cursor_position $(($y + 3)) $(($x + 3)) term_attr_on underline term_write "${input}" term_attr_off underline # Put the cursor in the text box. if [ ${focus} -eq 0 ]; then term_show_cursor term_cursor_position $(($y + 3)) $(($x + 3 + $curpos)) else term_hide_cursor fi # Input. key="$(term_getch)" if [ "x${key}" = xKEY_INVALID ]; then continue elif [ "x${key}" = xKEY_TAB ]; then focus=$(expr \( ${focus} + 1 \) % 2) elif [ ${focus} -eq 0 ]; then case "${key}" in KEY_ENTER) break;; KEY_BACKSPACE) input="${input%?}" curpos=$(($curpos - 1)) ;; KEY_DEL) ;; # TODO: Line editing KEY_SPACE) input="${input} " curpos=$(($curpos + 1)) ;; *) input="${input}${key}" curpos=$(($curpos + 1)) ;; esac elif [ ${focus} -eq 1 ]; then case "${key}" in KEY_ENTER | KEY_SPACE) break;; esac fi done printf '%s' "${input}" return 0 }