home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / qc25 / beispiel / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-25  |  14.4 KB  |  420 lines

  1. /* MENU - Module mit Funktionen zur Anzeige von Menüs auf dem Bildschirm und
  2.  * zur Handhabung von Tastatureingaben. Um dieses Modul anzuwenden, müssen
  3.  * Sie die Einfügdatei MENU.H in Ihr Programm einschließen. Folgende
  4.  * Funktionen sind global:
  5.  *
  6.  * Menue     - Bringt ein Menü auf den Bildschirm, liest Eingaben dafür ein
  7.  * Box       - Zeichnet Kästchen auf dem Bildschirm (nach Wunsch füllen)
  8.  * GetKey    - Holt ASCII- oder Funktionstaste
  9.  * _outchar  - Gibt Zeichen an gegenwärtiger Textposition und mit aktueller
  10.  *             Farbe aus
  11.  *
  12.  * Folgende Strukturen sind definiert:
  13.  *
  14.  *   MENU       -   Definiert Menüfarben, Kästchen, ob mittig
  15.  *   ITEM       -   Definiert Text der Menü-Wahlmöglichkeit und Index der
  16.  *                  hervorgehobenen Zeichen
  17.  *
  18.  * Die Globalvariable "mnuAtrib" ist Typ MENU. Um das Aussehen des Menüs zu
  19.  * ändern, müssen Sie diese Variable ändern.
  20.  */
  21.  
  22. #include <string.h>
  23. #include <stddef.h>
  24. #include <ctype.h>
  25. #include <graph.h>
  26. #include <bios.h>
  27. #include "menu.h"
  28. #include "mouse.h"
  29.  
  30. /* Prototyp für interne Funktion */
  31. static void Itemize( int Reihe, int Spalte, int fCur, ITEM itm, int cBlank );
  32.  
  33. /* Vorgegebenes Menüattribut. Die Vorgabe ist für Farbe und S/W brauchbar.
  34.  * Man kann die Vorgabe außer Kraft setzen, indem man seine eigene MENU-
  35.  * Variable definiert und sie mnuAtrib zuweist bzw. zur Laufzeit bestimmte
  36.  * Felder ändert. So könnte man beispielsweise für Farbbildschirme andere
  37.  * Attribute verwenden als für Schwarz/Weißmonitore.
  38.  */
  39. MENU mnuAtrib =
  40. {
  41.     _TBLACK, _TBLACK, _TWHITE, _TBRIGHTWHITE, _TBRIGHTWHITE,
  42.     _TWHITE, _TWHITE, _TBLACK, _TWHITE, _TBLACK,
  43.     WAHR,
  44.     '┌', '┐', '┘', '└', '│', '─'
  45. };
  46.  
  47. /* Menue - Bringt Menü zum Bildschirm und liest Menüeingabe von der Tastatur
  48.  * ein. Wurde die Taste für einen hervorgehobenen Buchstaben gedrückt oder
  49.  * EINGABE, ist das Ergebnis der Index der gewählten Menüauswahl.
  50.  *
  51.  * Parameter:
  52.  * row und col - Ist "fMittig" als Attribut von "mnuAtrib" wahr, Reihe und
  53.  *               Spalte des Menüs mittigstellen, sonst links oben im Menü.
  54.  * aItem       - Datenfeld aus Strukturen mit dem Text einer jeden Wahlmög-
  55.  *               lichkeit und Index des betreffenden erhellten Buchstabens
  56.  * iCur        - Index der gegenwärtigen Auswahl -- für erste Möglichkeit 0
  57.  *               übergeben oder statischen Wert beibehalten
  58.  *
  59.  * Ergibt:       Den Index der gewählten Möglichkeit
  60.  *
  61.  * Verwendet:    mnuAtrib
  62.  */
  63. int Menue( int row, int col, ITEM aItem[], int iCur )
  64. {
  65.     int cItem, cchItem = 2; /* Anzahl von Möglichkeiten und Zeichen je
  66.                              * Möglichkeit
  67.                              */
  68.     int i;                  /* Indizes - vorläufig und vorheriger         */
  69.     int acchItem[MAXITEM];  /* Datenfeld mit Zeichenanzahl/Möglichkeiten  */
  70.     char achErhellt[36];    /* Datenfeld für hervorgehobene Zeichen       */
  71.     long bgColor;           /* Bildschirmfarbe, Position und Cursor       */
  72.     short fgColor;
  73.     struct rccoord rc;
  74.     unsigned fCursor;
  75.  
  76.     /* Bildschirminformation speichern. */
  77.     fCursor = _displaycursor( _GCURSOROFF );
  78.     bgColor = _getbkcolor();
  79.     fgColor = _gettextcolor();
  80.     rc = _gettextposition();
  81.  
  82.     /* Wahlmöglichkeiten zählen, die längste finden und Zeichenanzahl einer
  83.      * jeden in Datenfeld speichern. Auch die jeweils hervorgehobenen
  84.      * Zeichen in ein Datenfeld speichern.
  85.      */
  86.     for( cItem = 0; aItem[cItem].achItem[0]; cItem++ )
  87.     {
  88.         acchItem[cItem] = strlen( aItem[cItem].achItem );
  89.         cchItem = (acchItem[cItem] > cchItem) ? acchItem[cItem] : cchItem;
  90.         i = aItem[cItem].iErhellt;
  91.         achErhellt[cItem] = aItem[cItem].achItem[i];
  92.     }
  93.     cchItem += 2;
  94.     achErhellt[cItem] = 0;  /* Null-beendete und Kleinbuchst-Zeichenfolge */
  95.     strlwr( achErhellt );
  96.  
  97.     /* Falls mittig, anpassen und Menükästchewn zeichnen. */
  98.     if( mnuAtrib.fMittig )
  99.     {
  100.         row -= cItem / 2;
  101.         col -= cchItem / 2;
  102.     }
  103.     Box( row++, col++, cItem, cchItem );
  104.  
  105.     /* Wahlmöglichkeiten in Menü plazieren. */
  106.     for( i = 0; i < cItem; i++ )
  107.     {
  108.         if( i == iCur )
  109.         Itemize( row + i, col, WAHR, aItem[i], cchItem - acchItem[i] );
  110.         else
  111.         Itemize( row + i, col, FALSCH, aItem[i], cchItem - acchItem[i] );
  112.     }
  113.  
  114. iCur = EventSchleife ( row, col, aItem, iCur, cItem, cchItem,
  115.               acchItem, achErhellt);
  116.                 _setbkcolor( bgColor );
  117.                 _settextcolor( fgColor );
  118.                 _settextposition( rc.row, rc.col );
  119.                 _displaycursor( fCursor );
  120.                 return iCur;
  121. }
  122.  
  123.  
  124. int EventSchleife ( int row, int col, ITEM aItem[], int iCur, int cItem,
  125.                int cchItem, int acchItem[], char achErhellt[] )
  126. {
  127.   unsigned    uKey;        /* Unsigned Tastencode         */
  128.   int         iPrev;       /* Vorheriger Index            */
  129.   EVENT         meinEvent;
  130.   char          *pchT;       /* Temporärer Character-Zeiger */
  131.   static        int fBtnDown = FALSCH;
  132.  
  133.  
  134.     while( WAHR )
  135.     {
  136.         /* Warten bis ein uKey gedrückt wurde, dann diesen auswerten. */
  137.     if ( uKey = GetKey( NO_WAIT ) )
  138.     {
  139.              switch( uKey )
  140.              {
  141.             case U_UP:                   /* NACH OBEN-TASTE */
  142.                      iPrev = iCur;
  143.                      iCur = (iCur > 0) ? (--iCur % cItem) : cItem - 1;
  144.                      break;
  145.             case U_DN:                   /* NACH UNTEN-TASTE */
  146.                      iPrev = iCur;
  147.                      iCur = (iCur < cItem) ? (++iCur % cItem) : 0;
  148.                      break;
  149.               default:
  150.                  if( uKey > 256 )     /* Unbekannte F-Taste ignorieren     */
  151.                     continue;
  152.                 pchT = strchr( achErhellt, (char)tolower( uKey ) );
  153.         if( pchT != NULL )            /* Falls in hervogehobener  */
  154.             iCur = pchT - achErhellt; /* Zeichenfolge, auswerten  */
  155.         else                          /* und 'weiterfallen'       */
  156.                     continue;        /* Unbekannte ASCII-Taste ignorieren */
  157.         case EINGABE:
  158.                 return iCur;
  159.         }
  160.   }
  161.         else if( GetMouseEvent( &meinEvent ) )
  162.         {
  163.         SetZgrSicht( SHOW );
  164.  
  165.             /* Falls die Maus auf dem Menü ist, reagiere auf verschiedene Ereignisse. */
  166.             if( (meinEvent.x >= col) && (meinEvent.x < (col + cchItem)) &&
  167.                 (meinEvent.y >= row) && (meinEvent.y < (row + cItem)) )
  168.             {
  169.                 /* Falls Taste gedrückt, ziehe Auswahlt. */
  170.                 if( meinEvent.fsBtn & LEFT_DOWN )
  171.                 {
  172.             fBtnDown = WAHR;
  173.                     iPrev = iCur;
  174.                     iCur = meinEvent.y - row;
  175.                 }
  176.                 /* Falls Taste losgelassen wird, wähle die aktuelle Stelle. */
  177.                 else if( fBtnDown && !(meinEvent.fsBtn & LEFT_DOWN) )
  178.                 {
  179.             fBtnDown = FALSCH;
  180.                     iCur = meinEvent.y - row;
  181.                     return iCur;
  182.                 }
  183.                 /* Ignoriere, falls keine Taste gedrückt wurde. */
  184.                 else
  185.                     continue;
  186.             }
  187.             /* Ignoriere falls Menü nicht gewählt ist. */
  188.             else
  189.                 continue;
  190.         }
  191.         else
  192.             continue;
  193.  
  194.         /* Gebe die aktuelle und die vorherige aus, falls wir hier durch eine
  195.          * Pfeilbewegung oder Ziehung (?drag) kommen.
  196.          */
  197.         Itemize( row + iCur, col,
  198.          WAHR, aItem[iCur], cchItem - acchItem[iCur] );
  199.         Itemize( row + iPrev, col,
  200.          FALSCH, aItem[iPrev], cchItem - acchItem[iPrev] );
  201.     }
  202. }
  203.  
  204. /* Box - Menükästchen zeichnen; innen mit Blankzeichen der Randfarbe füllen.
  205.  *
  206.  * Parameter:    row und col         - linke obere Ecke des Kästchens
  207.  *               rowLetzt und colLetzt - Höhe und Breite
  208.  *
  209.  * Ergebniswert: Keiner
  210.  *
  211.  * Verwendet:    mnuAtrib
  212.  */
  213. void Box( int row, int col, int rowLetzt, int colLetzt )
  214. {
  215.     int i;
  216.     char achT[MAXITEM + 2];      /* Vorübergehendes Datenfeld von Zeichen */
  217.  
  218.     /* Farbe und Position festlegen. */
  219.     _settextposition( row, col );
  220.     _settextcolor( mnuAtrib.fgRand );
  221.     _setbkcolor( mnuAtrib.bgRand );
  222.  
  223.     /* Obere Kante des Kästchens zeichnen. */
  224.     achT[0] = mnuAtrib.chNW;
  225.     memset( achT + 1, mnuAtrib.chEW, colLetzt );
  226.     achT[colLetzt + 1] = mnuAtrib.chNE;
  227.     achT[colLetzt + 2] = 0;
  228.     _outtext( achT );
  229.  
  230.     /* Seiten und Inneres des Kästchens zeichnen. */
  231.     achT[0] = mnuAtrib.chNS;
  232.     memset( achT + 1, ' ', colLetzt );
  233.     achT[colLetzt + 1] = mnuAtrib.chNS;
  234.     achT[colLetzt + 2] = 0;
  235.     for( i = 1; i <= rowLetzt; ++i )
  236.     {
  237.         _settextposition( row + i, col );
  238.         _outtext( achT );
  239.     }
  240.  
  241.     /* Untere Kante des Kästchens zeichnen. */
  242.     _settextposition( row + rowLetzt + 1, col );
  243.     achT[0] = mnuAtrib.chSW;
  244.     memset( achT + 1, mnuAtrib.chEW, colLetzt );
  245.     achT[colLetzt + 1] = mnuAtrib.chSE;
  246.     achT[colLetzt + 2] = 0;
  247.     _outtext( achT );
  248. }
  249.  
  250. /* Itemize    - Eine Wahlmöglichkeit eines Menüs zeigen. Diese Funktion wird
  251.  *              normalerweise nur von Menue intern benutzt.
  252.  *
  253.  * Parameter: row und col - linke obere Ecke des Menüs
  254.  *            fCur        - Kennung, falls Wahlmöglichkeit gegenwärtig
  255.  *                          ausgewählt ist.
  256.  *            itm         - Struktur mit Text und Index der Kennbuchstaben
  257.  *            cBlank      - Anzahl der zu füllenden Blankzeichen
  258.  *
  259.  * Ergebniswert: Keiner
  260.  *
  261.  * Verwendet:    mnuAtrib
  262.  */
  263. void Itemize( int row, int col, int fCur, ITEM itm, int cBlank )
  264. {
  265.     int i;
  266.     char achT[MAXITEM];          /* Vorübergehendes Datenfeld von Zeichen */
  267.  
  268.     /* Textposition und -farbe einrichten. */
  269.     _settextposition( row, col );
  270.     if( fCur )
  271.     {
  272.         _settextcolor( mnuAtrib.fgAuswahl );
  273.         _setbkcolor( mnuAtrib.bgAuswahl );
  274.     }
  275.     else
  276.     {
  277.         _settextcolor( mnuAtrib.fgNormal );
  278.         _setbkcolor( mnuAtrib.bgNormal );
  279.     }
  280.  
  281.     /* Wahlmöglichkeit anzeigen und Blankzeichen auffüllen. */
  282.     strcat( strcpy( achT, " " ), itm.achItem );
  283.     _outtext( achT );
  284.     memset( achT, ' ', cBlank-- );
  285.     achT[cBlank] = 0;
  286.     _outtext( achT );
  287.  
  288.    /* Position und Farbe des Kennbuchstabens festlegen, ihn dann anzeigen.*/
  289.     i = itm.iErhellt;
  290.     _settextposition( row, col + i + 1 );
  291.     if( fCur )
  292.     {
  293.         _settextcolor( mnuAtrib.fgWahlHell );
  294.         _setbkcolor( mnuAtrib.bgWahlHell );
  295.     }
  296.     else
  297.     {
  298.         _settextcolor( mnuAtrib.fgNormalHell );
  299.         _setbkcolor( mnuAtrib.bgNormalHell );
  300.     }
  301.     _outchar( itm.achItem[i] );
  302. }
  303.  
  304. /* GetKey - Holt einen Tastaturanschlag. Es wird dabei zwischen ASCII- und
  305.  * Funktions- bzw. Steuertasten mit unterschiedlichem Umschaltstatus
  306.  * unterschieden. Kann auch mit Kennung verwendet werden, um sofort
  307.  * zurückzukehren, wenn keine Taste verfügbar ist.
  308.  *
  309.  * Parameter: fWait - Code zur Angabe, wie der Tastatur-Zwischenspeicher
  310.  *                    zu handhaben ist:
  311.  * NO_WAIT     Ergibt 0 wenn keine Taste im Zwischenspeicher, sonst die
  312.  *             Taste
  313.  * WAIT        Ergibt eine Taste, sofern vorhanden, wartet sonst auf Taste
  314.  * CLEAR_WAIT  Evtl. im Zwischenspeicher vorhandene Taste löschen und auf
  315.  *             neue Taste warten
  316.  *
  317.  * Ergebniswert: Einer der folgenden:
  318.  *
  319.  * Tastentyp                         Hochwertiges Byte  Niedrigwertiges Byte
  320.  * ---------                         -----------------  --------------------
  321.  * Keine Taste verfügbar (nur mit NO_WAIT)      0           0
  322.  * ASCII-Wert                                   0        ASCII code
  323.  * F-Taste oder Zahlenblock ohne Umsch.         1        Abtastcode
  324.  * F-Taste oder Zahlenblock mit Umsch.          2        Abtastcode
  325.  * STRG + F-Taste oder Zahlenblock              3        Abtastcode
  326.  * ALT + F-Taste oder Zahlenblock               4        Abtastcode
  327.  *
  328.  * Hinweis: getkey kann keine Codes für solche Tasten ergeben, die nicht
  329.  * vom BIOS erkannt werden, wie beispielsweise STRG+BILD oder die 5er-Taste
  330.  * auf dem Zahlenblock.
  331.  */
  332. unsigned GetKey( int fWait )
  333. {
  334.     unsigned uKey, uShift;
  335.  
  336.     /* Bei CLEAR_WAIT den Tastatur-Zwischenspeicher entleeren. */
  337.     if( fWait == CLEAR_WAIT )
  338.         while( _bios_keybrd( _KEYBRD_READY ) )
  339.             _bios_keybrd( _KEYBRD_READ );
  340.  
  341.     /* Bei NO_WAIT ist Ergebnis 0, wenn keine Taste bereit ist. */
  342.     if( !fWait && !_bios_keybrd( _KEYBRD_READY ) )
  343.     return FALSCH;
  344.  
  345.     /* Tastencode holen. */
  346.     uKey = _bios_keybrd( _KEYBRD_READ );
  347.  
  348.     /* Ist niedrigwertiges Byte ungleich Null, ist es eine ASCII-Taste. Nun
  349.      * Abtastcode prüfen, ob es eine Zahlenblocktaste ist. Ist sie das
  350.      * nicht, hochwertiges Byte löschen und zurück.
  351.      */
  352.     if( uKey & 0x00ff )
  353.         if( (uKey >> 8) < 69 )
  354.             return( uKey & 0x00ff );
  355.  
  356.     /* Für Funktions- und Zahlenblocktasten den Abtastcode in niedrig-
  357.      * wertiges Byte und Codes zum Umschaltstatus in hochwertiges Byte.
  358.      */
  359.     uKey >>= 8;
  360.     uShift = _bios_keybrd( _KEYBRD_SHIFTSTATUS ) & 0x000f;
  361.     switch( uShift )
  362.     {
  363.         case 0:
  364.             return( 0x0100 | uKey );  /* Keiner (1)    */
  365.         case 1:
  366.         case 2:
  367.         case 3:
  368.             return( 0x0200 | uKey );  /* Umschalt (2)   */
  369.         case 4:
  370.             return( 0x0300 | uKey );  /* Strg (3) */
  371.         case 8:
  372.             return( 0x0400 | uKey );  /* Alt (4)     */
  373.     }
  374. }
  375.  
  376. /* _outchar - Stellt ein Zeichen dar, und zwar das _outtext entsprechende
  377.  * Zeichen. Es unterliegt ferner _settextposition, _settextcolor und
  378.  * _setbkcolor. Sollte in Schleifen nicht benutzt werden. Für mehrere
  379.  * Zeichen Zeichenfolgen aufbauen und dann über _outtext anzeigen.
  380.  *
  381.  * Parameter: out - Anzuzeigendes Zeichen
  382.  *
  383.  * Ergebniswert: Keiner
  384.  */
  385. void _outchar( char out )
  386. {
  387.     static char achT[2] = " ";   /* Vorübergehendes Datenfeld von Zeichen */
  388.     achT[0] = out;
  389.     _outtext( achT );
  390. }
  391.  
  392. /* KlickOderDruck - Überprüft, ob eine Taste gedrückt wurde oder ein
  393.  * Maus-Klick erfolgt ist. Ein Maus-Klick ist als drücken und wieder loslassen
  394.  * der Maus-Taste definiert.
  395.  *
  396.  * Parameter: keine
  397.  *
  398.  * Return: WAHR oder FALSCH
  399.  */
  400. int KlickOderDruck()
  401. {
  402.     EVENT ev;
  403.     int i = 0;
  404.  
  405.     /* Check for press. */
  406.     if( GetKey( NO_WAIT ) )
  407.     return WAHR;
  408.  
  409.     /* Check for click. If button is down, wait until it is released. */
  410.     if( !GetMouseEvent( &ev ) )
  411.         return 0;
  412.     if( ev.fsBtn )
  413.     {
  414.     while( WAHR )
  415.             if( GetMouseEvent( &ev ) && !ev.fsBtn )
  416.         return WAHR;
  417.     }
  418.     return FALSCH;
  419. }
  420.