From 0cc814838465dad46064eb26b3ea4d1c8b71be47 Mon Sep 17 00:00:00 2001 From: Bert Burgemeister Date: Fri, 27 May 2016 23:03:55 +0200 Subject: [PATCH] New example: RPN desk calculator --- README | 6 +- calc.sh | 282 +++++++++++++++++ calc.ui | 1053 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1340 insertions(+), 1 deletion(-) create mode 100755 calc.sh create mode 100644 calc.ui diff --git a/README b/README index 66f62a3..d8b7c8a 100644 --- a/README +++ b/README @@ -51,7 +51,11 @@ back into a text area of the same GUI. Another example, ./clock.sh, -uses the GtkBuilder file clock.ui and displays an analog clock. +uses the GtkBuilder file clock.ui to display an analog clock, and + + ./calc.sh + +harnesses dc(1) to provide an RPN desk calculator. There are three other example GtkBuilder files. To see how they look like, call diff --git a/calc.sh b/calc.sh new file mode 100755 index 0000000..7976d3a --- /dev/null +++ b/calc.sh @@ -0,0 +1,282 @@ +#! /usr/bin/env bash + +coproc dc 2>&1 +./pipeglade -i calc.in -o calc.out -b -u calc.ui -O calc.err -l calc.log >/dev/null + +NUMKEYS=(0 1 2 3 4 5 6 7 8 9 A B C D E F) +NUMPAD=("${NUMKEYS[@]}" neg point div mul minus plus squareroot power) +STORAGEKEYS=(recall store) +OTHERKEYS=(enter edit swap clear drop cancel) +VARKEYS=(var_2 var_3 var_a var_b var_c var_d var_e var_f var_g var_h var_i \ + var_j var_k var_l var_m var_n var_o var_p var_q var_r var_s \ + var_t var_u var_v var_w var_x var_y var_z) + +varkeys_set_visible() +# expose second keybord level +{ + for i in "${VARKEYS[@]}"; do + echo "$i:set_visible $1" >calc.in + done +} + +printstack() +{ + echo "entry:set_placeholder_text" >calc.in + # tell dc to print its stack + echo "f" + i=0 + unset DC_OUT + # read dc's response, which may include error messages + while read -t .1 DC_OUT[$i]; do (( i++ )); done + # check for specific errors + if [[ "${DC_OUT[0]}" =~ "stack" || "${DC_OUT[0]}" =~ "zero" ]]; then + echo "entry:set_placeholder_text ${DC_OUT[0]}" + echo "stack:grab_focus" # unfocussing entry + else + # display stack in a GtkTreeView + echo "stack:clear" + echo "stack:set 5 1" + ROW=4 + while [[ $i -gt 0 ]]; do + (( i-- )) + (( ROW++ )) + echo "stack:set $ROW 0 $i" + echo "stack:set $ROW 1 ${DC_OUT[$i]}" + done + echo "stack:scroll $ROW 1" + fi >calc.in +} + +edittop() +# put top of stack into GtkEntry +{ + echo "p s!" # talking to dc, + read -t .1 DC_OUT # reading dc's response, + # and sending it to pipeglade + echo "entry:set_text $DC_OUT" >calc.in +} + + +# initial window dressing +echo "precision:set_value 5" >calc.in +for i in "${NUMPAD[@]}"; do + echo "$i:style border-radius:20px; border-color:darkblue; font-weight:bold; font-size:16px" +done >calc.in +for i in "${OTHERKEYS[@]}"; do + echo "$i:style border-radius:20px; font-weight:bold" +done >calc.in +for i in "${STORAGEKEYS[@]}"; do + echo "$i:style border-radius:20px; border-color:darkgreen; font-weight:bold" +done >calc.in +for i in "${VARKEYS[@]}"; do + echo "$i:style border-radius:10px; border-color:darkgreen; font-style:italic; font-size:16px" +done >calc.in +echo "off:style color:darkred; border-radius:20px; border-color:darkred; font-weight:bold" >calc.in +echo "entry:style font:monospace 12" >calc.in +echo "main:style border-radius:20px" >calc.in + + +{ + # main loop; stdin and stdout are connected to the dc coprocess + printstack + while true; do + # receive feedback from GUI + read IN calc.in + elif [[ "$IN" =~ "entry:text " ]]; then + # feedback from our GtkEntry + CURRENT_ENTRY="${IN#entry:text }" + NUM="$CURRENT_ENTRY" + # dc uses '_' as a negative sign + CURRENT_ENTRY="${CURRENT_ENTRY//-/_}" + elif [[ "$IN" =~ "var_" ]]; then + # freedback from variable buttons + VAR="${IN#var_}" + VAR="${VAR%:clicked}" + if [[ "$VARMODE" == "recall" ]]; then + echo "L$VAR" + elif [[ "$VARMODE" == "store" ]]; then + echo "S$VAR" + fi + printstack + varkeys_set_visible 0 + elif [[ "$IN" =~ "radix:value " ]]; then + # feedback from the radix scale + RADIX="${IN#radix:value }" + RADIX="${RADIX/.[0-9]*}" + # telling dc what to do + echo "A i $RADIX o $RADIX i" + printstack + # graying out meaningless digit keys + for i in "${NUMKEYS[@]:2:(( $RADIX - 1 ))}"; do + echo "$i:set_sensitive 1" >calc.in + done + for i in "${NUMKEYS[@]:$RADIX}"; do + echo "$i:set_sensitive 0" >calc.in + done + elif [[ $IN =~ "precision:value " ]]; then + # feedback from the precision scale + PRECISION="${IN#precision:value }" + PRECISION="${PRECISION/.[0-9]*}" + echo "$PRECISION k" + elif [[ $IN == "main:closed" ]]; then + # exit gracefully when GUI gets killed by window manager + exit + elif [[ -n $C ]]; then + # here, $C is a multi-character button name that doesn't look like "var_x" + case "$C" in + point) + NUM="$NUM." + echo "entry:set_text $NUM" >calc.in + ;; + neg) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY _1 *" + edittop + else + echo "_1 *" + unset NUM + unset CURRENT_ENTRY + printstack + fi + ;; + edit) + edittop + printstack + ;; + enter) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + else + echo "d" + fi + unset NUM + unset CURRENT_ENTRY + printstack + ;; + div) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "/" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + mul) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "*" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + minus) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "-" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + plus) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "+" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + power) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "^" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + squareroot) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + echo "v" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + swap) + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + fi + # portability kludge. The parentheses are dc variable names + echo "s(s)L(L)" + unset NUM + unset CURRENT_ENTRY + printstack + ;; + drop) + if [[ -z "$CURRENT_ENTRY" ]]; then + # portabilty kludge (and memory leak) + echo "s!" + fi + echo "entry:set_text" >calc.in + unset NUM + unset CURRENT_ENTRY + printstack + ;; + clear) + echo "c" + echo "entry:set_text" >calc.in + unset NUM + unset CURRENT_ENTRY + printstack + ;; + cancel) + varkeys_set_visible 0 + echo "entry:set_text" >calc.in + unset NUM + unset CURRENT_ENTRY + printstack + ;; + recall) + VARMODE="recall" + varkeys_set_visible 1 + ;; + store) + VARMODE="store" + if [[ -n "$CURRENT_ENTRY" ]]; then + echo "LE: $CURRENT_ENTRY" >>ttt + echo "$CURRENT_ENTRY" + echo "entry:set_text" >calc.in + unset NUM + unset CURRENT_ENTRY + fi + varkeys_set_visible 1 + ;; + off) + echo "_:main_quit" >calc.in + exit + ;; + esac + fi + done +} <&"${COPROC[0]}" >&"${COPROC[1]}" diff --git a/calc.ui b/calc.ui new file mode 100644 index 0000000..4b05aeb --- /dev/null +++ b/calc.ui @@ -0,0 +1,1053 @@ + + + + + + 30 + 1 + 10 + + + 2 + 16 + 10 + 1 + 2 + + + + + + + + + + + False + pipeglade RPN + False + + + True + False + 13 + 7 + 5 + 3 + 3 + True + True + + + CNCL + True + True + True + + + 0 + 11 + + + + + True + True + stack + always + in + False + + + True + True + treestore1 + False + False + False + 0 + False + horizontal + + + none + + + + + fixed + 3 + + + 1 + monospace + gray + 12 + + + 0 + + + + + 0 + monospace + gray + 12 + : + + + + + + + autosize + True + + + 1 + monospace 12 + 12 + + + 1 + + + + + + + + + 0 + 0 + 5 + 3 + + + + + True + True + radix + adjustment2 + 0 + 0 + + + 0 + 4 + 3 + + + + + True + True + precision + adjustment1 + 0 + 0 + + + 3 + 4 + 2 + + + + + OFF + True + True + True + + + 0 + 10 + + + + + STO + True + True + True + + + 0 + 8 + + + + + True + False + + + D + True + False + True + True + + + + -1 + + + + + c + True + True + + + + + 1 + 6 + + + + + True + False + + + E + True + False + True + True + + + + -1 + + + + + d + True + True + + + + + 2 + 6 + + + + + True + False + + + F + True + False + True + True + + + + -1 + + + + + e + True + True + + + + + 3 + 6 + + + + + True + False + + + 9 + True + True + True + + + + + -1 + + + + + m + True + True + + + + + 3 + 8 + + + + + True + False + + + 6 + True + True + True + + + + + -1 + + + + + q + True + True + + + + + 3 + 9 + + + + + True + False + + + 3 + True + True + True + + + + + -1 + + + + + u + True + True + + + + + 3 + 10 + + + + + True + False + + + EDIT + True + True + True + + + -1 + + + + + y + True + True + + + + + 3 + 11 + + + + + True + False + + + 8 + True + True + True + + + + + -1 + + + + + l + True + True + + + + + 2 + 8 + + + + + True + False + + + 5 + True + True + True + + + + + -1 + + + + + p + True + True + + + + + 2 + 9 + + + + + True + False + + + 2 + True + True + True + + + + + -1 + + + + + t + True + True + + + + + 2 + 10 + + + + + True + False + + + . + True + True + True + + + + + -1 + + + + + x + True + True + + + + + 2 + 11 + + + + + True + False + + + 7 + True + True + True + + + + + -1 + + + + + k + True + True + + + + + 1 + 8 + + + + + True + False + + + 4 + True + True + True + + + + + -1 + + + + + o + True + True + + + + + 1 + 9 + + + + + True + False + + + 1 + True + True + True + + + + + -1 + + + + + s + True + True + + + + + 1 + 10 + + + + + True + False + + + 0 + True + True + True + + + + + -1 + + + + + w + True + True + + + + + 1 + 11 + + + + + True + False + + + ^ + True + True + True + + + -1 + + + + + b + True + True + + + + + 4 + 5 + + + + + True + False + + + SWAP + True + True + True + + + -1 + + + + + f + True + True + + + + + 4 + 6 + + + + + True + False + + + ÷ + True + True + True + + + + + -1 + + + + + n + True + True + + + + + 4 + 8 + + + + + True + False + + + × + True + True + True + + + + + -1 + + + + + r + True + True + + + + + 4 + 9 + + + + + True + False + + + + True + True + True + + + + + -1 + + + + + v + True + True + + + + + 4 + 10 + + + + + True + False + + + + + True + True + True + + + + + -1 + + + + + z + True + True + + + + + 4 + 11 + + + + + True + False + + + + True + True + True + + + -1 + + + + + a + True + True + + + + + 3 + 5 + + + + + True + False + + + ENTER + True + True + True + + + + + -1 + + + + + 2 + True + True + + + + + 0 + 5 + 2 + + + + + True + False + + + +/− + True + True + True + + + -1 + + + + + 3 + True + True + + + + + 2 + 5 + + + + + RCL + True + True + True + + + 0 + 7 + + + + + True + False + + + A + True + False + True + True + + + + -1 + + + + + g + True + True + + + + + 1 + 7 + + + + + True + False + + + B + True + False + True + True + + + + -1 + + + + + h + True + True + + + + + 2 + 7 + + + + + True + False + + + C + True + False + True + True + + + + -1 + + + + + i + True + True + + + + + 3 + 7 + + + + + True + False + + + DROP + True + True + True + + + -1 + + + + + j + True + True + + + + + 4 + 7 + + + + + CLR + True + True + True + + + 0 + 6 + + + + + True + True + number + + + 0 + 3 + 5 + + + + + + + + + -- 2.11.4.GIT