gui: Use trap to make sure temporary files are removed.
[gsu.git] / gui
1 #!/bin/bash
2
3 if [[ "$(type -t _gsu_setup)" != "function" ]]; then
4 gsu_dir=${gsu_dir:-${BASH_SOURCE[0]%/*}}
5 . $gsu_dir/common || exit 1
6 _gsu_setup
7 fi
8
9 _gsu_node_name_pattern='[a-zA-Z_]'
10
11 _get_geometry()
12 {
13 local x y
14 result="$(stty size)"
15 if (($? != 0)); then
16 gsu_msg "fatal: could not get terminal geometry"
17 exit 1
18 fi
19 x="${result#* }"
20 y="${result%% *}"
21 (($x > 190)) && x=190
22 result="$y $x"
23 }
24
25 _set_dialog_ret()
26 {
27 local ec="$1"
28
29 case "$ec" in
30 0) ret=$GSU_SUCCESS;;
31 1) ret=1;; # cancelled
32 *)
33 result="dialog exit code $ec"
34 ret=-$E_GSU_DIALOG
35 esac
36 }
37
38 # Open a dialog box which asks the user to input a text
39 #
40 # Usage: gsu_input_box <text> <init>
41 #
42 # <text> is displayed above of the input field, which is is preset to <init>.
43 # The entered text is returned in $result. On success (user pressed OK)
44 # the function returns zero. If the user selected Cancel, the return value is
45 # one. On dialog errors, a negative error code is returned.
46 gsu_inputbox()
47 {
48 local g text="$1" init="$2"
49
50 _get_geometry
51 g="$result"
52 result="$(dialog --inputbox "$text" $g "$init" 3>&1 1>&2 2>&3 3>&-)"
53 _set_dialog_ret $?
54 }
55
56 # Show the given file in a text box
57 #
58 # Usage: gsu_textbox <path>
59 #
60 # The box has an OK button which closes the box when activated.
61 gsu_textbox()
62 {
63 local g file="$1"
64
65 _get_geometry
66 g="$result"
67
68 ret=-$E_GSU_DIALOG
69 result='textbox'
70 dialog --textbox "$file" $g
71 _set_dialog_ret $?
72 }
73
74 # Show a message in a text box
75 #
76 # Usage: gsu_msgbox <text>
77 #
78 # This is like gsu_textbox() but the text is passed as a string.
79 gsu_msgbox()
80 {
81 # Some versions of dialog segfault if the text is too long. Hence we
82 # always use a temporary file.
83 local tmp="$(mktemp gsu_msgbox.XXXXXXXXXX)"
84
85 if (($? != 0)); then
86 ret=-$E_GSU_MKTEMP
87 result='temp file for textbox'
88 return
89 fi
90 trap "rm -f $tmp" EXIT
91 echo "$1" > "$tmp"
92 gsu_textbox "$tmp"
93 rm -f "$tmp" # ignore errors
94 }
95
96 _gsu_menu()
97 {
98 local header="${1:-root}"
99 local items="$2"
100 local i state opts num=0
101
102 _get_geometry
103 opts="$result 16"
104 for i in $items; do
105 let num++
106 opts+=" $i $num"
107 done
108 result="$(dialog --menu "$gsu_banner_txt ($header)" $opts 3>&1 1>&2 2>&3 3>&-)"
109 _set_dialog_ret $?
110 }
111
112 _get_level()
113 {
114 local tmp="${1%%$_gsu_node_name_pattern*}"
115 result="${#tmp}"
116 }
117
118 _get_subtree()
119 {
120 local tree="$1" root="${2%/}"
121 local first TAB=' '
122
123 ret=-$E_GSU_MENU_TREE
124 result="subtree grep failed"
125 first="$(grep -n "$TAB\{1,\}$root/" <<< "$tree")" || return
126 [[ -z "$first" ]] && return
127
128 line_num="${first%%:*}"
129 _get_level "${first#*:}"
130 level="$result"
131
132 #echo "line: $line_num, root: $root, indent level: $level"
133 result="$(sed -e "1,${line_num}d;" <<< "$tree" \
134 | sed -e "/^$TAB\{1,$level\}$_gsu_node_name_pattern/,\$d" \
135 | sed -e "/^$TAB\{$(($level + 2))\}/d")"
136 if (($? != 0)); then
137 ret=-$E_GSU_MENU_TREE
138 result="sed command for subtree $root failed"
139 return
140 fi
141 ret=$GSU_SUCCESS
142 }
143
144 _get_root_nodes()
145 {
146 local tree="$1" TAB=' '
147
148 result="$(grep "^${TAB}${_gsu_node_name_pattern}" <<< "$tree")"
149 if (($? != 0)); then
150 ret=-$E_GSU_MENU_TREE
151 result="root node grep failed"
152 return
153 fi
154 ret=$GSU_SUCCESS
155 }
156
157 _browse()
158 {
159 local header="$1" old_header
160 local tree="$2" subtree="$3"
161
162 while :; do
163 _gsu_menu "$header" "$subtree"
164 (($ret < 0)) && return
165 [[ -z "$result" ]] && return # menu was cancelled
166 if [[ "${result%/}" != "$result" ]]; then
167 old_header="$header"
168 header="$result"
169 _get_subtree "$tree" "$header"
170 (($ret < 0)) && return
171 _browse "$header" "$tree" "$result"
172 (($ret < 0)) && return
173 header="$old_header"
174 continue
175 fi
176 eval ${gsu_name}_$result
177 done
178 }
179
180 gsu_gui()
181 {
182 local tree="$1" subtree
183
184 type -t dialog &> /dev/null
185 if (($? != 0)); then
186 gsu_msg "dialog executable not found"
187 exit 1
188 fi
189 _get_root_nodes "$tree"
190 subtree="$result"
191 _browse "main menu" "$tree" "$subtree"
192 }