home *** CD-ROM | disk | FTP | other *** search
- /* MENU - Module mit Funktionen zur Anzeige von Menüs auf dem Bildschirm und
- * zur Handhabung von Tastatureingaben. Um dieses Modul anzuwenden, müssen
- * Sie die Einfügdatei MENU.H in Ihr Programm einschließen. Folgende
- * Funktionen sind global:
- *
- * Menue - Bringt ein Menü auf den Bildschirm, liest Eingaben dafür ein
- * Box - Zeichnet Kästchen auf dem Bildschirm (nach Wunsch füllen)
- * GetKey - Holt ASCII- oder Funktionstaste
- * _outchar - Gibt Zeichen an gegenwärtiger Textposition und mit aktueller
- * Farbe aus
- *
- * Folgende Strukturen sind definiert:
- *
- * MENU - Definiert Menüfarben, Kästchen, ob mittig
- * ITEM - Definiert Text der Menü-Wahlmöglichkeit und Index der
- * hervorgehobenen Zeichen
- *
- * Die Globalvariable "mnuAtrib" ist Typ MENU. Um das Aussehen des Menüs zu
- * ändern, müssen Sie diese Variable ändern.
- */
-
- #include <string.h>
- #include <stddef.h>
- #include <ctype.h>
- #include <graph.h>
- #include <bios.h>
- #include "menu.h"
- #include "mouse.h"
-
- /* Prototyp für interne Funktion */
- static void Itemize( int Reihe, int Spalte, int fCur, ITEM itm, int cBlank );
-
- /* Vorgegebenes Menüattribut. Die Vorgabe ist für Farbe und S/W brauchbar.
- * Man kann die Vorgabe außer Kraft setzen, indem man seine eigene MENU-
- * Variable definiert und sie mnuAtrib zuweist bzw. zur Laufzeit bestimmte
- * Felder ändert. So könnte man beispielsweise für Farbbildschirme andere
- * Attribute verwenden als für Schwarz/Weißmonitore.
- */
- MENU mnuAtrib =
- {
- _TBLACK, _TBLACK, _TWHITE, _TBRIGHTWHITE, _TBRIGHTWHITE,
- _TWHITE, _TWHITE, _TBLACK, _TWHITE, _TBLACK,
- WAHR,
- '┌', '┐', '┘', '└', '│', '─'
- };
-
- /* Menue - Bringt Menü zum Bildschirm und liest Menüeingabe von der Tastatur
- * ein. Wurde die Taste für einen hervorgehobenen Buchstaben gedrückt oder
- * EINGABE, ist das Ergebnis der Index der gewählten Menüauswahl.
- *
- * Parameter:
- * row und col - Ist "fMittig" als Attribut von "mnuAtrib" wahr, Reihe und
- * Spalte des Menüs mittigstellen, sonst links oben im Menü.
- * aItem - Datenfeld aus Strukturen mit dem Text einer jeden Wahlmög-
- * lichkeit und Index des betreffenden erhellten Buchstabens
- * iCur - Index der gegenwärtigen Auswahl -- für erste Möglichkeit 0
- * übergeben oder statischen Wert beibehalten
- *
- * Ergibt: Den Index der gewählten Möglichkeit
- *
- * Verwendet: mnuAtrib
- */
- int Menue( int row, int col, ITEM aItem[], int iCur )
- {
- int cItem, cchItem = 2; /* Anzahl von Möglichkeiten und Zeichen je
- * Möglichkeit
- */
- int i; /* Indizes - vorläufig und vorheriger */
- int acchItem[MAXITEM]; /* Datenfeld mit Zeichenanzahl/Möglichkeiten */
- char achErhellt[36]; /* Datenfeld für hervorgehobene Zeichen */
- long bgColor; /* Bildschirmfarbe, Position und Cursor */
- short fgColor;
- struct rccoord rc;
- unsigned fCursor;
-
- /* Bildschirminformation speichern. */
- fCursor = _displaycursor( _GCURSOROFF );
- bgColor = _getbkcolor();
- fgColor = _gettextcolor();
- rc = _gettextposition();
-
- /* Wahlmöglichkeiten zählen, die längste finden und Zeichenanzahl einer
- * jeden in Datenfeld speichern. Auch die jeweils hervorgehobenen
- * Zeichen in ein Datenfeld speichern.
- */
- for( cItem = 0; aItem[cItem].achItem[0]; cItem++ )
- {
- acchItem[cItem] = strlen( aItem[cItem].achItem );
- cchItem = (acchItem[cItem] > cchItem) ? acchItem[cItem] : cchItem;
- i = aItem[cItem].iErhellt;
- achErhellt[cItem] = aItem[cItem].achItem[i];
- }
- cchItem += 2;
- achErhellt[cItem] = 0; /* Null-beendete und Kleinbuchst-Zeichenfolge */
- strlwr( achErhellt );
-
- /* Falls mittig, anpassen und Menükästchewn zeichnen. */
- if( mnuAtrib.fMittig )
- {
- row -= cItem / 2;
- col -= cchItem / 2;
- }
- Box( row++, col++, cItem, cchItem );
-
- /* Wahlmöglichkeiten in Menü plazieren. */
- for( i = 0; i < cItem; i++ )
- {
- if( i == iCur )
- Itemize( row + i, col, WAHR, aItem[i], cchItem - acchItem[i] );
- else
- Itemize( row + i, col, FALSCH, aItem[i], cchItem - acchItem[i] );
- }
-
- iCur = EventSchleife ( row, col, aItem, iCur, cItem, cchItem,
- acchItem, achErhellt);
- _setbkcolor( bgColor );
- _settextcolor( fgColor );
- _settextposition( rc.row, rc.col );
- _displaycursor( fCursor );
- return iCur;
- }
-
-
- int EventSchleife ( int row, int col, ITEM aItem[], int iCur, int cItem,
- int cchItem, int acchItem[], char achErhellt[] )
- {
- unsigned uKey; /* Unsigned Tastencode */
- int iPrev; /* Vorheriger Index */
- EVENT meinEvent;
- char *pchT; /* Temporärer Character-Zeiger */
- static int fBtnDown = FALSCH;
-
-
- while( WAHR )
- {
- /* Warten bis ein uKey gedrückt wurde, dann diesen auswerten. */
- if ( uKey = GetKey( NO_WAIT ) )
- {
- switch( uKey )
- {
- case U_UP: /* NACH OBEN-TASTE */
- iPrev = iCur;
- iCur = (iCur > 0) ? (--iCur % cItem) : cItem - 1;
- break;
- case U_DN: /* NACH UNTEN-TASTE */
- iPrev = iCur;
- iCur = (iCur < cItem) ? (++iCur % cItem) : 0;
- break;
- default:
- if( uKey > 256 ) /* Unbekannte F-Taste ignorieren */
- continue;
- pchT = strchr( achErhellt, (char)tolower( uKey ) );
- if( pchT != NULL ) /* Falls in hervogehobener */
- iCur = pchT - achErhellt; /* Zeichenfolge, auswerten */
- else /* und 'weiterfallen' */
- continue; /* Unbekannte ASCII-Taste ignorieren */
- case EINGABE:
- return iCur;
- }
- }
- else if( GetMouseEvent( &meinEvent ) )
- {
- SetZgrSicht( SHOW );
-
- /* Falls die Maus auf dem Menü ist, reagiere auf verschiedene Ereignisse. */
- if( (meinEvent.x >= col) && (meinEvent.x < (col + cchItem)) &&
- (meinEvent.y >= row) && (meinEvent.y < (row + cItem)) )
- {
- /* Falls Taste gedrückt, ziehe Auswahlt. */
- if( meinEvent.fsBtn & LEFT_DOWN )
- {
- fBtnDown = WAHR;
- iPrev = iCur;
- iCur = meinEvent.y - row;
- }
- /* Falls Taste losgelassen wird, wähle die aktuelle Stelle. */
- else if( fBtnDown && !(meinEvent.fsBtn & LEFT_DOWN) )
- {
- fBtnDown = FALSCH;
- iCur = meinEvent.y - row;
- return iCur;
- }
- /* Ignoriere, falls keine Taste gedrückt wurde. */
- else
- continue;
- }
- /* Ignoriere falls Menü nicht gewählt ist. */
- else
- continue;
- }
- else
- continue;
-
- /* Gebe die aktuelle und die vorherige aus, falls wir hier durch eine
- * Pfeilbewegung oder Ziehung (?drag) kommen.
- */
- Itemize( row + iCur, col,
- WAHR, aItem[iCur], cchItem - acchItem[iCur] );
- Itemize( row + iPrev, col,
- FALSCH, aItem[iPrev], cchItem - acchItem[iPrev] );
- }
- }
-
- /* Box - Menükästchen zeichnen; innen mit Blankzeichen der Randfarbe füllen.
- *
- * Parameter: row und col - linke obere Ecke des Kästchens
- * rowLetzt und colLetzt - Höhe und Breite
- *
- * Ergebniswert: Keiner
- *
- * Verwendet: mnuAtrib
- */
- void Box( int row, int col, int rowLetzt, int colLetzt )
- {
- int i;
- char achT[MAXITEM + 2]; /* Vorübergehendes Datenfeld von Zeichen */
-
- /* Farbe und Position festlegen. */
- _settextposition( row, col );
- _settextcolor( mnuAtrib.fgRand );
- _setbkcolor( mnuAtrib.bgRand );
-
- /* Obere Kante des Kästchens zeichnen. */
- achT[0] = mnuAtrib.chNW;
- memset( achT + 1, mnuAtrib.chEW, colLetzt );
- achT[colLetzt + 1] = mnuAtrib.chNE;
- achT[colLetzt + 2] = 0;
- _outtext( achT );
-
- /* Seiten und Inneres des Kästchens zeichnen. */
- achT[0] = mnuAtrib.chNS;
- memset( achT + 1, ' ', colLetzt );
- achT[colLetzt + 1] = mnuAtrib.chNS;
- achT[colLetzt + 2] = 0;
- for( i = 1; i <= rowLetzt; ++i )
- {
- _settextposition( row + i, col );
- _outtext( achT );
- }
-
- /* Untere Kante des Kästchens zeichnen. */
- _settextposition( row + rowLetzt + 1, col );
- achT[0] = mnuAtrib.chSW;
- memset( achT + 1, mnuAtrib.chEW, colLetzt );
- achT[colLetzt + 1] = mnuAtrib.chSE;
- achT[colLetzt + 2] = 0;
- _outtext( achT );
- }
-
- /* Itemize - Eine Wahlmöglichkeit eines Menüs zeigen. Diese Funktion wird
- * normalerweise nur von Menue intern benutzt.
- *
- * Parameter: row und col - linke obere Ecke des Menüs
- * fCur - Kennung, falls Wahlmöglichkeit gegenwärtig
- * ausgewählt ist.
- * itm - Struktur mit Text und Index der Kennbuchstaben
- * cBlank - Anzahl der zu füllenden Blankzeichen
- *
- * Ergebniswert: Keiner
- *
- * Verwendet: mnuAtrib
- */
- void Itemize( int row, int col, int fCur, ITEM itm, int cBlank )
- {
- int i;
- char achT[MAXITEM]; /* Vorübergehendes Datenfeld von Zeichen */
-
- /* Textposition und -farbe einrichten. */
- _settextposition( row, col );
- if( fCur )
- {
- _settextcolor( mnuAtrib.fgAuswahl );
- _setbkcolor( mnuAtrib.bgAuswahl );
- }
- else
- {
- _settextcolor( mnuAtrib.fgNormal );
- _setbkcolor( mnuAtrib.bgNormal );
- }
-
- /* Wahlmöglichkeit anzeigen und Blankzeichen auffüllen. */
- strcat( strcpy( achT, " " ), itm.achItem );
- _outtext( achT );
- memset( achT, ' ', cBlank-- );
- achT[cBlank] = 0;
- _outtext( achT );
-
- /* Position und Farbe des Kennbuchstabens festlegen, ihn dann anzeigen.*/
- i = itm.iErhellt;
- _settextposition( row, col + i + 1 );
- if( fCur )
- {
- _settextcolor( mnuAtrib.fgWahlHell );
- _setbkcolor( mnuAtrib.bgWahlHell );
- }
- else
- {
- _settextcolor( mnuAtrib.fgNormalHell );
- _setbkcolor( mnuAtrib.bgNormalHell );
- }
- _outchar( itm.achItem[i] );
- }
-
- /* GetKey - Holt einen Tastaturanschlag. Es wird dabei zwischen ASCII- und
- * Funktions- bzw. Steuertasten mit unterschiedlichem Umschaltstatus
- * unterschieden. Kann auch mit Kennung verwendet werden, um sofort
- * zurückzukehren, wenn keine Taste verfügbar ist.
- *
- * Parameter: fWait - Code zur Angabe, wie der Tastatur-Zwischenspeicher
- * zu handhaben ist:
- * NO_WAIT Ergibt 0 wenn keine Taste im Zwischenspeicher, sonst die
- * Taste
- * WAIT Ergibt eine Taste, sofern vorhanden, wartet sonst auf Taste
- * CLEAR_WAIT Evtl. im Zwischenspeicher vorhandene Taste löschen und auf
- * neue Taste warten
- *
- * Ergebniswert: Einer der folgenden:
- *
- * Tastentyp Hochwertiges Byte Niedrigwertiges Byte
- * --------- ----------------- --------------------
- * Keine Taste verfügbar (nur mit NO_WAIT) 0 0
- * ASCII-Wert 0 ASCII code
- * F-Taste oder Zahlenblock ohne Umsch. 1 Abtastcode
- * F-Taste oder Zahlenblock mit Umsch. 2 Abtastcode
- * STRG + F-Taste oder Zahlenblock 3 Abtastcode
- * ALT + F-Taste oder Zahlenblock 4 Abtastcode
- *
- * Hinweis: getkey kann keine Codes für solche Tasten ergeben, die nicht
- * vom BIOS erkannt werden, wie beispielsweise STRG+BILD oder die 5er-Taste
- * auf dem Zahlenblock.
- */
- unsigned GetKey( int fWait )
- {
- unsigned uKey, uShift;
-
- /* Bei CLEAR_WAIT den Tastatur-Zwischenspeicher entleeren. */
- if( fWait == CLEAR_WAIT )
- while( _bios_keybrd( _KEYBRD_READY ) )
- _bios_keybrd( _KEYBRD_READ );
-
- /* Bei NO_WAIT ist Ergebnis 0, wenn keine Taste bereit ist. */
- if( !fWait && !_bios_keybrd( _KEYBRD_READY ) )
- return FALSCH;
-
- /* Tastencode holen. */
- uKey = _bios_keybrd( _KEYBRD_READ );
-
- /* Ist niedrigwertiges Byte ungleich Null, ist es eine ASCII-Taste. Nun
- * Abtastcode prüfen, ob es eine Zahlenblocktaste ist. Ist sie das
- * nicht, hochwertiges Byte löschen und zurück.
- */
- if( uKey & 0x00ff )
- if( (uKey >> 8) < 69 )
- return( uKey & 0x00ff );
-
- /* Für Funktions- und Zahlenblocktasten den Abtastcode in niedrig-
- * wertiges Byte und Codes zum Umschaltstatus in hochwertiges Byte.
- */
- uKey >>= 8;
- uShift = _bios_keybrd( _KEYBRD_SHIFTSTATUS ) & 0x000f;
- switch( uShift )
- {
- case 0:
- return( 0x0100 | uKey ); /* Keiner (1) */
- case 1:
- case 2:
- case 3:
- return( 0x0200 | uKey ); /* Umschalt (2) */
- case 4:
- return( 0x0300 | uKey ); /* Strg (3) */
- case 8:
- return( 0x0400 | uKey ); /* Alt (4) */
- }
- }
-
- /* _outchar - Stellt ein Zeichen dar, und zwar das _outtext entsprechende
- * Zeichen. Es unterliegt ferner _settextposition, _settextcolor und
- * _setbkcolor. Sollte in Schleifen nicht benutzt werden. Für mehrere
- * Zeichen Zeichenfolgen aufbauen und dann über _outtext anzeigen.
- *
- * Parameter: out - Anzuzeigendes Zeichen
- *
- * Ergebniswert: Keiner
- */
- void _outchar( char out )
- {
- static char achT[2] = " "; /* Vorübergehendes Datenfeld von Zeichen */
- achT[0] = out;
- _outtext( achT );
- }
-
- /* KlickOderDruck - Überprüft, ob eine Taste gedrückt wurde oder ein
- * Maus-Klick erfolgt ist. Ein Maus-Klick ist als drücken und wieder loslassen
- * der Maus-Taste definiert.
- *
- * Parameter: keine
- *
- * Return: WAHR oder FALSCH
- */
- int KlickOderDruck()
- {
- EVENT ev;
- int i = 0;
-
- /* Check for press. */
- if( GetKey( NO_WAIT ) )
- return WAHR;
-
- /* Check for click. If button is down, wait until it is released. */
- if( !GetMouseEvent( &ev ) )
- return 0;
- if( ev.fsBtn )
- {
- while( WAHR )
- if( GetMouseEvent( &ev ) && !ev.fsBtn )
- return WAHR;
- }
- return FALSCH;
- }
-