De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.

Calculadora programada com YAD (Yet Another Dialoging shell programming)

Colaboração: Julio Cezar Neves

Data de Publicação: 25 de fevereiro de 2021

Acho que nunca foi feita uma linguagem de programação tão sucinta quanto o Shell. Apesar disso, em tempos de mouse e telas coloridas, realmente ele deixava um pouco a desejar porque lhe faltavam essas habilidades, apesar de terem sido várias as tentativas, como (só para citar algumas): Zenity, Dialog, Kdialog, Xdialog, Gdialog, ...

Surge agora, um novo projeto que é um fork do Zenity e chama-se YAD (Yet Another Dialoging shell programing). Em seu pouco tempo de vida ele já tem mais do dobro das facilidades oferecidas pelo Zenity, seu predecessor, e é capaz de montar praticamente todas as interfaces com os usuários em um único formulário, definido pela opção --form.

A intenção desse artigo não é ensinar a instalar o YAD, ou como usá-lo. O que quero deixar muito claro, é a sua qualidade da apresentação, como é fácil e sucinto usá-lo e a sua abrangência de uso. Assim sendo, vamos logo a um exemplo que usa somente um de seus 19 diálogos possíveis.

O diálogo que usaremos é o --form que, somente ele, aceita 19 tipos de opções de caixas distintas isto é, dentro de um formulário, podemos definir ComboBoxes, CheckBoxes, campo escondido (senha), SpinBoxes, caixas para seleção de arquivos, para seleção de fontes, para seleção de cores, caixas de texto multilinha, ...

Vejamos um exemplo de um formulário que é formado somente por botões, e um mostrador, já que nossa intenção é fazer uma calculadora. O exemplo é formado por 2 programas. O primeiro, calc.yad, faz a camada de apresentação e o segundo, calc.sh, põe o bash para trabalhar, para fazer a camada de negócio, ou seja, a lógica da calculadora.

Veja o produto final:

UAUUU! Com um acabamento desses isso não pode ser Shell! Mas é sim. Shell + YAD + bc. O trio trilha troços trufados! ;)

Pela figura, você pode ver que montamos uma apresentação plana, mas que ganha relevo quando o mouse se superpõe a um botão (mouse over). Pode-se notar também que é possível introduzir dicas (tips) na definição de cada botão. Vejamos o código:

$ cat calc.yad
#!/bin/bash
#  Calculadora usando Bash, bc e yad

> ~/.mem   # Será usado como memória
trap 'rm ~/.mem; exit' 0 2 3 15
yad --form --columns 8 --width 500 --no-buttons \
    --title "Calculadora YAD + Bash + bc"       \
    --field='' ''  --field :LBL ''              \
    --field :RO 'Casas decimais'                \
    --field 'Decimais!Ajusta a precisão         \
do cálculo':BTN "@calc.s h '' PR"               \
    --field=7:BTN "@echo 1:%1\7"                \
    --field=4:BTN "@echo 1:%1\4"                \
    --field=1:BTN "@echo 1:%1\1"                \
    --field=,:BTN "@echo 1:%1\,"                \
    --field=8:BTN "@echo 1:%1\8"                \
    --field=5:BTN "@echo 1:%1\5"                \
    --field=2:BTN "@echo 1:%1\2"                \
    --field=0:BTN "@echo 1:%1\0"                \
    --field=9:BTN "@echo 1:%1\9"                \
    --field=6:BTN "@echo 1:%1\6"                \
    --field=3:BTN "@echo 1:%1\3"                \
    --field '!Enche linguiça':BTN ''            \
    --field=+:BTN "@echo 1:%1\+"                \
    --field=:BTN "@echo 1:%1\x"                 \
    --field='??!Raiz Quadrada':BTN              \
        '@./calc.sh '%1' RQ %3'                 \
    --field='±!Troca sinal':BTN                 \
        "@./calc.sh '%1' +-"                    \
    --field=-:BTN "@echo 1:%1\-"                \
    --field=÷:BTN "@echo 1:%1\/"                \
    --field='x?!Potenciação':BTN "@echo 1:%1\^" \
    --field='1/x!Inverte':BTN                   \
        '@./calc.sh '%1' 1X %3'                 \
    --field==:BTN '@./calc.sh '%1' = %3'        \
    --field=\(:BTN "@echo 1:%1\("               \
    --field='CL!Limpa':BTN "@echo 1:"           \
    --field='MC!Limpa memória':BTN              \
        "@./calc.sh '' MC"                      \
    --field=\?:BTN "@./calc.sh %1 AP"           \
    --field=\):BTN "@echo 1:%1\)"               \
    --field='M+!Adiciona à memória':BTN "       \
        @./calc.sh '%1' M+ %3"                  \
    --field='MR!Trás conteúdo da memória':BTN   \
        "@./calc.sh '%1' MR"

Como vocês viram o formulário é somente um composto de um diálogo --form com diversos campos do tipo botão (:BTN). As contrabarras no fim da cada linha são para informar ao Shell que a linha não terminou e o texto continua na linha seguinte. Se não as tivesse usado, teria de escrever todo o comando em uma única linha e aí ficaria muito difícil de explicá-lo, de lê-lo e principalmente de depurá-lo.

No início do script, criei um arquivo chamado .mem no diretório home, em seguida montei uma trap para removê-lo quando o programa terminasse ou fosse (ex)terminado. ;) e a partir de então foi somente mais um comando yad, onde destaco:

Diretiva Função
--form que define que o diálogo com o operador será via um formulário;
--columns que especifica a quantidade de colunas do formulário;
--width para determinar a largura mínima;
--no-button Para que o yad não adicione os botões padrão (Default) ao diálogo (OK e Cancelar)
--field que define o nome, o tipo, as dicas e a ação de cada campo do formulário.

Como todos os demais campos são do tipo botão (:BTN), vamos entender como se comportam começando pela sua sintaxe:

--field ROTULO[!DICA]:BTN CMD

Onde:

ROTULO é o que vem escrito no botão;
DICA é uma ajuda que aparece em uma etiqueta popup;
:BTN isso que o define como um campo botão;
CMD comando que será executado quando o botão for clicado.

Se CMD começar com um arroba (@), é sinal que vou usar outros campos do formulário. Se nessa linha houver um %N, onde N é um numérico, ele será trocado pelo conteúdo do campo N (enésimo campo). Para mandar um valor para o campo M, onde M também é um número, ele deve ser mencionado com M:. Resumindo: %N recebe valor do enésimo campo e M: coloca o valor no emésimo campo.

Para entender melhor, veja esses exemplos:

$ yad --form --field _Botão:BTN 'ls -l'

Nesse caso quando Botão for clicado, mandará a saída do "ls -l" para a tela. O sublinha (_) antes do B, faz com que ele apareça sublinhado no formulário e <ALT>+<B> passa a ser a sua tecla de atalho.

$ yad --form --field '':TXT '' \
    --field Botão:BTN "@echo 1:$(ls)"

Desta vez, foi criado mais um campo no formulário, este do tipo :TXT. Esse tipo de campo é para receber textos multilinhas. Nesse caso, como CMD começava com arroba (@), o 1:$(ls), diz para a saída do ls ser feita no primeiro campo (1:).

$ yad --form --field "Arquivo:FL" '' \
    --field '1ª Linha:TXT' ''        \
    --field 'Mostre 1ª linha:BTN' "@./aux '%1'"

Neste último caso, temos um campo para seleção de arquivo (:FL), um do tipo texto multilinha (:TXT) e outro do tipo botão (:BTN). Esse último, quando clicado, chama o programa aux, (@./aux) passando o arquivo selecionado no primeiro campo (%1). Veja que aux também é um script e que ele verifica se o arquivo passado existe e, caso afirmativo, lista sua primeira linha. Veja só o aux; é um scriptizinho xexelento:

$ cat aux
[ -f $1 ] && 
    echo 2:$(head -1 $1) || 
    echo 2:$1 não é arquivo

Bem já vimos as diversas formas de trabalhar com botões, mas há algum tempo mandei para a Dicas-L um artigo que explicava o uso de botões no YAD. Se você se interessou pelo tema, pode vê-lo aqui. Então vamos voltar ao código da nossa calculadora: repare que existem somente dois tipos de ação com os campos do tipo botão:

1º tipo de ação:

 --field=7:BTN "@echo 1:%1\7"

Especifica um botão cujo rótulo é 7 e que vai enviar para o campo 1 (1:), que é o mostrador, o valor do próprio campo 1 (%1) concatenado com 7. A contrabarra (\) antes do 7 é inócua pois é para o Shell e usei-a para separar o 1 do 7 de modo a não ser interpretado como o 17º campo (%17).

2º tipo de ação:

--field='M+!Adiciona à memória':BTN "       \
        @./calc.sh '%1' M+ %3"

Agora o rótulo do botão é M+. !Adiciona à memória será a dica que aparecerá em um diálogo popup quando o mouse estiver sobre este botão e executa o programa calc.sh passando 3 parâmetros:

%1 O conteúdo do primeiro campo (mostrador);
M+ O programa calc.sh executa diversas ações diferentes, de acordo com o ponto do qual ele foi chamado. Esse parâmetro (que é um literal) serve para que calc.sh saiba que tem que incrementar o conteúdo da memória;
%3 O conteúdo do 3º campo, que é um somente leitura (Read Only - :RO) que guarda a precisão em decimais arbitrada pelo usuário.

Vejamos agora o programa calc.sh:

$ cat calc.sh
#!/bin/bash 

Prec=$(expr $3 + 0 2> /dev/null) || Prec=0 
case $2 in 
    =)  Conta=$(tr 'x,' '*.' <<< "$1") 
        echo 1:$(echo "scale=$Prec; $Conta" | 
            bc | tr . ,) ;; 
    RQ) Conta=$(tr 'x,' '*.' <<< "$1") 
        echo 1:$(echo "scale=$Prec; sqrt ($Conta)" | 
            bc | tr . ,) ;; 
    1X) Conta=$(tr 'x,' '*.' <<< "$1") 
        echo 1:$(echo "scale=$Prec; 1/($Conta)" | \
            bc | tr . ,) ;; 
    M+) Num=$([ -s ~/.mem ] && cat ~/.mem || echo 0) 
        Conta=$(tr , . <<< "$1") 
        bc <<< "$Conta + $Num" > ~/.mem ;; 
    MR) echo 1:$(cat ~/.mem) ;; 
    MC) > ~/.mem ;; 
    AP) echo 1:${1%?} ;; 
    PR) IFS='|' read lx lx Dec lx <<< \
        "$(yad --form --columns 4 \
            --title "Decimais" \ 
            --field "\tInforme precisão":LBL '' \
            --field "\tentre 0 e 9 decimais":LBL '' \
            --field '' '' --field :LBL '' \ 
            --field 1:BTN '@echo 3:1' 
            --field 4:BTN '@echo 3:4' \
            --field 7:BTN '@echo 3:7' \
            --field :BTN '' \ 
            --field 2:BTN '@echo 3:2' \
            --field 5:BTN '@echo 3:5' \
            --field 8:BTN '@echo 3:8' \
            --field 0:BTN '@echo 3:0' \ 
            --field 3:BTN '@echo 3:3' \
            --field 6:BTN '@echo 3:6' \
            --field 9:BTN '@echo 3:9' \
            --field :BTN '' --button OK)" 
        echo 3:$Dec ;; 
    +-) Conta=$(tr , . <<< "$1") 
        echo 1:$(echo "-1 * $Conta" | bc | tr . ,) ;; 
    *)  echo 1:$1 
esac

Se você não se assustar e prestar atenção, verá que este é um programa bastante simples, já que é basicamente um só case. Vou porém fazer alguns destaques:

O comando tr aparece com grande frequência isso se dá basicamente porque o mostrador da calculadora exibe virgula (,), sinal de dividir (÷), entre outros, que é necessário trocá-los antes para o bc entender e após, para que o resultado seja exibido de forma com vírgula decimal.

A linha de comando yad que se encontra neste programa, monta outro teclado para que o usuário possa escolher a precisão dos cálculos (quantidade de decimais)

Todos os itens do case que mandam a saída para o mostrador, terminam fazendo um echo 1:..., ou seja quando o calcula.yad recebe este valor, manda-o para o campo 1 que é o mostrador. A exceção é o comando yad que captura a precisão. Ela termina com um echo 3:$Dec, para que a quantidade de decimais ($Dec) escolhida pelo usuário seja enviada para o campo 3 da calculadora, que é um campo somente de leitura e foi criado para exibir este valor.

Espero que tenha sido claro na minha explicação, de forma a permitir que você compreenda que belíssima ferramenta é o YAD.

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários (1)

Avatar
Novo

linha 11 calc.s h => ./calc.sh

assim vai funcionar



Veja a relação completa dos artigos de Julio Cezar Neves