Tietojenkäsittelytiede                          Harjoitustehtäviä
Graafisten käyttöliittymien toteutus            31.1.2001


x1.  +-------------------------------------------------------+
     |            Tämä tehtävä on pakollinen.                |
     |                                                       |
     | Ratkaisu on lähetettävä sähköpostina osoitteella      |
     | gkt01@cs.joensuu.fi viimeistään 30.1.2001 klo 8.00.   |
     |                                                       |
     | ÄLÄ LÄHETÄ VASTAUSTA LIITETIEDOSTONA VAAN OSANA ITSE  |
     | KIRJEEN TEKSTIÄ !!!                                   |
     |                                                       |
     | Tuo harjoitustilaisuuteen ohjelmalistaus ja valmiiksi |
     | täyttämäsi x-tehtävän arviointilomake.                |
     +-------------------------------------------------------+

    Laadi C++:lla (n)curses-kirjastoa käyttävä merkkipohjainen (siis
    ei graafinen) ohjelma, joka antaa käyttäjän tehdä valintoja va-
    lintaruutujen ja valintanappien ryhmistä ja lopuksi tulostaa
    käyttäjän tekemät valinnat. Ohjelma on myös testattava.
    
    Valintaryhmien toiminnat ovat seuraavat:

    - Valintaruuturyhmä:        Joukko vaihtoehtoja, joista kukin voi
                                olla valittu (X) tai ei (_). Käyttäjä
                                voi liikkua vaihtoehdosta toiseen
                                näppäimillä NuoliYlös ja NuoliAlas ja
                                vaihtaa valintatilaa näppäimellä En-
                                ter.

    - Valintanappiryhmä:        Joukko vaihtoehtoja, joista yksi on
                                valittu (@) ja muut eivät ole (O).
                                Käyttäjä voi liikkua vaihtoehdosta
                                toiseen näppäimillä NuoliVasemmalle
                                ja NuoliOikealle (vaikka vaihtoehdot
                                ovatkin päällekkäin !) ja vaihtaa ny-
                                kyisen vaihtoehdon valituksi näppäi-
                                mellä Enter.

    Valintaryhmiä voi olla näytöllä mielivaltainen määrä ja käyttäjä
    pääsee ryhmästä seuraavaan näppäimellä Tab. Lisäksi numeroilla
    1..9 pääsee suoraan ko. ryhmään (ja "suurinumeroisiin" ei tällä
    tavalla pääse). Ryhmät voivat sijaita näytöllä osittain päällek-
    käin ja ohjelman velvollisuus on "nostaa" kulloinkin käsiteltävä
    ryhmä näkyviin. Käyttäjä voi käydä kussakin ryhmässä niin monta
    kertaa kuin hän haluaa. Näppäimellä 'q' toiminta loppuu ja ohjel-
    ma tulostaa voimassaolevat valinnat.

    Näytölle tulevat valintaryhmät kuvataan tiedostossa, jossa on ku-
    takin ryhmää kohden:

    - rivi, jossa on ryhmän laji (r: ruutu, n: nappi) ja sen sijain-
      tipaikan vasemman yläkulman rivi ja sarake
    - kutakin vaihtoehtoa varten rivi, jossa on vaihtoehdon teksti
    - rivi, jolla on merkki '#'

    Tämä ohjaustiedosto voisi olla esimerkiksi seuraavanlainen:

        r 5 20
        Musta
        Valkoinen
        Punainen
        Vaaleanvihreä
        #
        r 15 1
        Aamiainen
        Lounas
        Päivällinen
        Iltapala
        Kahvit (2 kpl)
        #
        n 13 7
        Puuvilla
        Pellava
        Villa
        Keinokuitu
        #
        r 15 50
        Maljakko
        Vati
        #
        n 10 40
        Kukka
        Vilja tms.
        #

    Edellisen ohjaustiedoston tapauksessa näyttö voisi olla käyttäjän
    tehtyä joitakin valintoja seuraavanlainen (reunoja leikattu pois):

  ===================================================================

                     _ Musta
                     X Valkoinen
                     X Punainen
                     _ Vaaleanvihreä

                                         @ Kukka
                                         O Vilja tms.

        O Puuvilla
        @ Pellava
  _ Aam O Villa                                    _ Maljakko
  X Lou O Keinokuitu                               _ Vati
  _ Päivällinen
  X Iltapala
  X Kahvit (2 kpl)

  ===================================================================

=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*

    Valintaryhmät on toteuttava olioina käyttäen seuraavaa liittymän
    määrittelyä:


#define maxTeksti 80
#define MaxValintoja 10

/* ------------- Yläluokka valintaryhmille ------------- */

class ValintaRyhma {

protected:
                        /* ... */

public:

  /* Valintaryhmä muodostetaan antamalla muodostajalle parametreina
     valintaryhmän vasemman yläkulman koordinaatit ja kutsumalla ope-
     raatioita valinta kerran kutakin kyseiseen ryhmään kuuluvaa va-
     lintaa kohti. (Muodostajana käytetään tietenkin aliryhmän
     muodostajaa.)

     Esim:      ryhma = new RuutuRyhma(5,15);
                virhe=ryhma->valinta("Vaihtoehto 1");
                virhe=ryhma->valinta("Vaihtoehto 2");
                virhe=ryhma->valinta("Vaihtoehto 3");
  */

  ValintaRyhma(int rivi, int sarake);
  virtual int valinta(char *teksti); // -1 jos virhe

  /* Valintaryhmää käytetään seuraavilla operaatioilla:


             piirry:      Valintaryhmä tulostaa itsensä ruudulle ny-
                          kyisillä valinnoilla.

             tuloRyhmään: Kursori on tulossa ryhmään. Operaatio si-
                          joittaa kursorin ensimmäisen vaihtoehdon
                          kohdalle.

             nappaily:    Käyttäjä on painanut jotain näppäintä, jon-
                          ka menetelmä saa parametrinaan. Operaation
                          on muutettava valintojen ulkoasu vastaavas-
                          ti ja sijoitettava kursori oikeaan kohtaan.

      Esim:     ryhma->piirry();
                ryhma->tuloRyhmaan();
                ryhma->nappaily(ALAS);
                ryhma->nappaily(ALAS);
                ryhma->nappaily(ENTER);
                ryhma->nappaily(YLOS);
                ryhma->nappaily('x');
                ryhma->nappaily(ENTER);
                ryhma->piirry();
                ryhma->tuloRyhmaan();
  */

  virtual void piirry();
  virtual void tuloRyhmaan();
  virtual void nappaily(char c);

  /* Ryhmän voimassaolevia valintoja voi pyytää operaatioilla
     ensValittu ja seurValittu, jotka palauttavat parametrissaan
     osoittimen vaihtoehdon tekstiin ja omana arvonaan vaihtoehdon
     numeron tai -1 jos valintoja ei enää ole.

     Esim:      ekaValinta = ryhma->ensValittu(valinnanTeksti1);
                if (ekaValinta >= 0)
                      tokaValinta = ryhma->seurValittu(valinnanTeksti2);
   */

   virtual int ensValittu(char *teksti);
   virtual int seurValittu(char *teksti);
};

/* ------------- Valintaruutujen ryhmä ----------------- */

class RuutuRyhma : public ValintaRyhma {

                        /* ... */
};

/* ------------- Valintanappien ryhmä ------------------ */

class NappiRyhma : public ValintaRyhma {

                        /* ... */
};

=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*

    Curses-kirjastosta tarvitaan tässä tehtävässä vain hyvin pientä
    osaa. Seuraava esimerkki havainnollistaa kirjaston käyttöä:

        /* curses-esimerkki (ohjelma.cc)

           Ohjelman kääntäminen:

           gcc -o ohjelma ohjelma.cc -lcurses

           tai (ympäristöstä riippuen)

           gcc -o ohjelma ohjelma.cc -lcurses -ltermcap

        */

        #include <curses.h>     // curses-kirjasto
        #define ENTER 10

        main ()
        { char c;

          initscr(); cbreak(); noecho();        // Alusta curses

          mvprintw(5,20,"Paina jotain: ");
          refresh();                            // Näytön päivitys
          if ((c=getch()) == ENTER) {
             move(10,0); printw("Painettu ENTER");
             refresh();
          } else {
             mvprintw(10,0,"Painettu %c",c);
             refresh();
          }

          c=getch(); // Jotta kerkiäisi näkemään tulostuksen
          move(LINES-1,0); refresh(); endwin(); // Lopeta curses
        }