### 6.3 Exemplo 2: Módulo Externo Simples Usando o Painel de Controle FORMS

Nota de tradução: Este exemplo é muito antigo e não compila nas máquinas atuais. Até o momento de digitação destas linhas de tradução ele não tinha sido atualizado permanecendo portanto inoperante.

Essa seção fornece uma nova versão do módulo acima — uma versão que inclue uma interface de usuário para controlar a velocidade da oscilação. Usamos a biblioteca FORMS criada por Mark Overmars para o painel de controle. A biblioteca FORMS é uma coleção de ferramentas para interface de usuário de domínio público para IRISes.

Para experimentar esse exemplo, faça uma cópia do arquivo `example2.c` (distribuído com Geomview no subdiretório `doc`) no seu diretório e compile-o com o comando

         cc -I/u/gcg/ngrap/include -o example2 example2.c \
           -L/u/gcg/ngrap/lib/sgi -lforms -lfm_s -lgl_s -lm

Você pode substituir a sequência de caracteres `/u/gcg/ngrap` acima com o nome do caminho do diretório de distribuição do Geomview em seu sistema. (A biblioteca forms é distribuída com Geomview e as opções `-I` e `-L` acima dizem ao compilador onde encontrá-las.)

Então coloque a linha

         (emodule-define "Example 2" "./example2")

em um arquivo chamado `.geomview` no diretório e chame Geomview do mesmo diretório. Clique sobre a entrada "Example 2" no navegador de módulos (Modules) para chamar o módulo. Um pequeno painel de controle deverá aparecer. Você pode então controlar a velocidade da oscilação da malha movendo o botão deslizante.

         /*
          * example2.c: oscillating mesh with FORMS control panel
          *
          * This example module is distributed with the Geomview manual.
          * If you are not reading this in the manual, see the "External
          * Modules" chapter of the manual for an explanation.
          *
          * This module creates an oscillating mesh and has a FORMS control
          * panel that lets you change the speed of the oscillation with a
          * slider.
          */

         #include <math.h>
         #include <stdio.h>
         #include <sys/time.h>           /* for struct timeval below */

         #include "forms.h"              /* for FORMS library */

         FL_FORM *OurForm;
         FL_OBJECT *VelocitySlider;
         float dt;

         /* F is the function that we plot
          */
         float F(x,y,t)
              float x,y,t;
         {
           float r = sqrt(x*x+y*y);
           return(sin(r + t)*sqrt(r));
         }

         /* SetVelocity is the slider callback procedure; FORMS calls this
          * when the user moves the slider bar.
          */
         void SetVelocity(FL_OBJECT *obj, long val)
         {
           dt = fl_get_slider_value(VelocitySlider);
         }

         /* Quit is the "Quit" botão callback procedure; FORMS calls this
          * when the user cliques the "Quit" botão.
          */
         void Quit(FL_OBJECT *obj, long val)
         {
           exit(0);
         }

         /* create_form_OurForm() creates the FORMS panel by calling a bunch of
          * procedures in the FORMS library.  This code was generated
          * automatically by the FORMS designer program; normally this code
          * would be in a separate file which you would not edit by hand.  For
          * simplicity of this example, however, we include this code here.
          */
         create_form_OurForm()
         {
           FL_OBJECT *obj;
           FL_FORM *form;
           OurForm = form = fl_bgn_form(FL_NO_BOX,380.0,120.0);
           obj = fl_add_box(FL_UP_BOX,0.0,0.0,380.0,120.0,"");
           VelocitySlider = obj = fl_add_valslider(FL_HOR_SLIDER,20.0,30.0,
                                                   340.0,40.0,"Velocity");
             fl_set_object_lsize(obj,FL_LARGE_FONT);
             fl_set_object_align(obj,FL_ALIGN_TOP);
             fl_set_call_back(obj,SetVelocity,0);
           obj = fl_add_button(FL_NORMAL_BUTTON,290.0,75.0,70.0,35.0,"Quit");
             fl_set_object_lsize(obj,FL_LARGE_FONT);
             fl_set_call_back(obj,Quit,0);
           fl_end_form();
         }

         main(argc, argv)
              char **argv;
         {
           int xdim, ydim;
           float xmin, xmax, ymin, ymax, dx, dy, t;
           int fdmask;
           static struct timeval timeout = {0, 200000};

           xmin = ymin = -5;             /* Set x and y            */
           xmax = ymax = 5;              /*    plot ranges         */
           xdim = ydim = 24;             /* Set x and y resolution */
           dt = 0.1;                     /* Time increment is 0.1  */

           /* Forms panel setup.
            */
           foreground();
           create_form_OurForm();
           fl_set_slider_bounds(VelocitySlider, 0.0, 1.0);
           fl_set_slider_value(VelocitySlider, dt);
           fl_show_form(OurForm, FL_PLACE_SIZE, TRUE, "Example 2");

           /* Geomview setup.
            */
           printf("(geometry example { : foo })\n");
           fflush(stdout);

           /* Loop until killed.
            */
           for (t=0; ; t+=dt) {
             fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
             select(qgetfd()+1, &fdmask, NULL, NULL, &timeout);
             fl_check_forms();
             UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
           }
         }

         /* UpdateMesh sends one mesh iteration to Geomview
          */
         UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
              float xmin, xmax, ymin, ymax, t;
              int xdim, ydim;
         {
           int i,j;
           float x,y, dx,dy;

           dx = (xmax-xmin)/(xdim-1);
           dy = (ymax-ymin)/(ydim-1);

           printf("(read geometry { define foo \n");
           printf("MESH\n");
           printf("%1d %1d\n", xdim, ydim);
           for (j=0, y = ymin; j<ydim; ++j, y += dy) {
             for (i=0, x = xmin; i<xdim; ++i, x += dx) {
               printf("%f %f %f\t", x, y, F(x,y,t));
             }
             printf("\n");
           }
           printf("})\n");
           fflush(stdout);
         }

O Código inicia-se pela inclusão de alguns arquivos de cabeçalho necassários para o evento cíclico e para a biblioteca FORMS. O código então declara variáveis globais para manter um ponteiro para o objeto FORMS do tipo botão deslizante e a velocidade `dt`. Essas duas variáveis são do tipo global porque elas são necessárias no procedimento de retorno do botão deslizante chamado `SetVelocity`, que faz todas as chamadas a cada vez que o usuário move a barra do botão deslizante. `SetVelocity` atualiza o valor da variável `dt` com o novo valor do botão deslizante.

`Quit` é o procedimento de chamada de retorno para o botão Quit; esse botão fornece um caminho elegante para o usuário encerrar o programa.

O procedimento `create_panel` chama um conjunto de procedimentos da biblioteca FORMS para ajustar o painel de controle com o botão deslizante e o botão simples. Para mais informação sobre o uso de FORMS para criar painéis de interface veja a documentação de FORMS. Em particular, FORMS vem com um desenhista de painel gráfico que conduz você a desenhar seus painéis de forma interativa e a gerar códigos como o código em `create_panel`.

Esse programa principal exemplo é similar ao exemplo anterior, mas inclui codificação extra para lidar com ajustes e gerenciamento o painel FORMS.

Para ajustar o painel chamamos o procedimento GL `foreground` para fazer com que o processo execute em primeiro plano. Por padrão programas GL executam em segundo plano, e por várias razões módulos externos que usam FORMS (que é baseado em GL) precisa executar em primeiro plano. Chamamos então `create_panel` para criar o painel e `fl_set_slider_value` para ajustar o valor inicial do botão deslizante. A chamada a `fl_show_form` faz com que o painel apareça na tela.

As primeiras três linhas do ciclo principal, iniciam-se com

         fdmask = (1 << fileno(stdin)) | (1 << qgetfd());

monitora e conduz os eventos no painel. A chamada a `select` impõe uma espera a cada passagem pelo ciclo principal. Essa chamada retorna ou após uma espera de 1/5 de segundo ou quando o evento GL seguinte ocorrer, ou quando dados aparecerem na entrada padrão, o que acontecer primeiro. A variável `timeout` especifica a quantidade de tempo a esperar nessa chamada; o primeiro número (0 nesse exemplo) fornece o número de segundos, e o segundo número (200000 nesse exemplo) fornece o número de microsegundos. Finalmente, `fl_check_forms()` procura e executa quaisquer eventos FORMS que tenham ocorridos; nesse caso isso significa uma chamada a `SetVelocity` se o usuário iver movido o botão deslizante ou uma chamada a `Quit` se o usuário tiver clicado no botão Quit.

O propósito da espera no ciclo é para prevenir que o programa use excessivamente o tempo da CPU executando seu ciclo pincipal quando não hoverem eventos a serem processados. Isso não é tão crucial nesse exemplo, e de fato pode tornar a animação mais lenta até certo ponto, mas em geral com módulos extrnos que possuirem eventos cíclicos essa espera é importante para do something like this because otherwise the module will needlessly take que os ciplos da CPU sigam adiante para outros programamas que estejam sendo executados (tais como Geomview!) mesmo quando estes não estiverem fazendo nada.

A última linha do ciclo principal ensse exemplo, a chamada a `UpdateMesh`, é a mesma que no exemplo anterior.