Programme unter GEM, Teil 2

Der letzte Artikel war mehr theoretisch, heute schreiten wir zur Praxis. Ein Beispielprogramm zeigt uns, wie man sich ein Grundgerüst für ein GEM-Programm verschaffen kann. Das Rahmenprogramm ist in der Lage, einen eigenen Desktop (mit einem Icon) anzumelden, ein Menu darzustellen und natürlich auch, den Desktop und das Menü zu verwalten. Unser Desktop beinhaltet lediglich ein Icon, damit das Prinzip der Programmierung klar wird. Möchte man jedoch mehrere Icons haben, so müssen diese entweder vorher (beim Entwurf mit dem Resource-Construction-Progrannn) deklariert werden oder der Objekt-Baum (ein Array von Objekten, die miteinander verknüpft sind) muß erweitert werden. Die Erweiterung scheitert jedoch daran, daß ein Feld nicht so einfach vergrößert werden kann. Also muß der gesamte Objekt-Baum (das Array, nicht jedoch Texte etc.) an eine andere Stelle kopiert werden, die genügend Platz bietet.

Sollen eigene Dinge auf das Desktop gebracht werden, so darf dies niemals direkt geschehen. Werden Ausgaben direkt auf das Desktop gemacht und wird danach darüber ein Fenster gebracht, so ist die Ausgabe verschwunden, wenn das Fenster geschlossen w ird. Für die eigenen Ausgaben findet die Application-Block-Struktur (USERBLK) Verwendung.

Somit erhält das Programm immer dann eine Meldung (über USERBLK), wenn das Desktop zu erneuern ist.

Das Menü sollte immer die Menüeinträge sperren, die nicht anwählbar sein sollen. Dies geschieht mit menu_ieanble, indem die Adresse des Menüs, die Nummer des Eintrags und eine 0 (für desaktivieren) oder eine 1 (für aktivieren) übergeben wird. Das Beispielprogramm macht das nicht, da gar keine Lade- oder Speicher-Routinen implementiert wurden. Das Tastenkürzel steht jeweils am rechten Rand des Menüeintrags. Das entsprechende Tastaturereignis wird von dem Beispielprogramm ausgewertet. Soll das Programm noch unabhängiger gestaltet werden, so besteht die Möglichkeit, den Text des Menüeintrags nach Programmstart zu untersuchen. Dazu wird der Menü-Objektbaum nach den betreffenden Einträgen abgesucht und das Tastenkürzel ausgewertet. Somit wird auch bei einer Veränderung des Resource-Files der Tastaturaufruf geändert. Das Bild 1 zeigt das Beispiel-Programm in Aktion. Benutzt wurde GEM der Version 2.x, weshalb auch das “Desk'*-Menü am rechten Rand zu finden ist. Eine Alertbox ist auf Bild 2 zu sehen und auf dem dritten Bild eines der beiden Drop-Down-Menüs.

Bild 1: Das Beispielprogramm in Aktion
Bild 2: Eine der Alertboxen
Bild 3: Ein heruntergeklapptes Menü
Bild 4: Im Beispiel-Programm benutzte AES-Funktionen

Wenden wir uns nun dem Programm zu. Es wurde mit Turbo C geschrieben, sollte aber auch mit anderen C-Compilern übersetzbar sein. Im Listing 1 ist die für unser Programm notwendige Projekt-Datei aufgeführt. Die Projekt-Dateien sind Turbo C-spezifisch, für andere Entwicklungssysteme sind entsprechende Vorbereitungen zu treffen.

Im Listing 2 befinden sich zahlreiche Erklärungen zu den einzelnen Schritten, weshalb diese hier nicht ausführlich erklärt werden sollen. Das Hauptprogramm main ist für den groben Rahmen zuständig. Dazu gehört die Initialisierung init_prg und das Abmelden exit_prg. In der while-Schleife wird solange gewartet, bis die Variable finish den Wert 1 (analog zur TRUE) erhält. Für den Fall, daß ein Menüeintrag angeklickt wurde, wird die Routine hdle_menu aufgerufen, bei einem Mausklick hdle_mouse und bei einem Tastaturereignis hdle_key. Die Initialisierungsroutine init_prg meldet das Programm zuerst beim AES an, stellt dann die Maus als Sanduhr (GEM 2.x) bzw. als Biene (GEM 1.x) dar, weil die folgenden Aktionen doch etwas mehr Zeit erfordern. Dann wird das Resource-File geladen und ausgewertet. Direkt nach der Auswertung wird das Desktop in der Größe angepaßt und ausgegeben. Dann wird der Scrap-Pfad gesetzt, falls er noch nicht existiert. Schließlich erfolgt die Ausgabe des Menüs und die Maus wird wieder ein Pfeil. Eine Parameterdatei könnte in dieser Routine auch eingelesen und ausgewertet werden. Die Routine exit_prg ist vergleichsweise kurz. Sie meldet das Menü und das Desktop ab, gibt den Resource-Speicher wieder frei und meldet das Programm ab.

Hdle_menu ist wohl die einfachste unter den Handle-Routinen. Entsprechend dem Menüeintrag wird eine Aktion durchgeführt und schließlich der Menütitel wieder normal dargestellt. Die normale Darstellung ist übrigens spätestens dann zu wählen, wenn das Menü wieder verfügbar ist. Der Menütitel sollte solange invertiert bleiben, wie die “blockierende" Aktion andauert. Wird also beispielsweise eine Datei geladen, so hebt man die Invertierung auf, sobald diese geladen ist. Von hdle_menu aus wird auch die Informationsdialogbox über do_info aufgerufen. In do_info wird ein vollständiger Dialog durchgeführt.

Ruft ein Programm mehrere Dialogboxen auf, so empfiehlt es sich, den Vor- und den Nachbereitungsteil in getrennten Funktionen zu deklarieren, denn diese unterscheiden sich in der Regel nicht. Der Durchführungsteil kann sich erheblich unterscheiden, beispielsweise können wie bei einem Fileselector Dateinamen gescrollt werden. Die dritte Handle-Routine - hdle_key - ist schon etwas komplizierter. Dort werden nicht nur die oberen 8 Bit des Tastencodes ausgewertet, sondern es wird auch entsprechend der gedrückten Taste der Menütitel invertiert und dann wieder normal dargestellt.

Die Handle-Routine hdle_mouse ermittelt zuerst das Objekt, welches sich an der Mausposition befindet. Dann wird zwischen einem Doppel- und einem Eintachklick unterschieden. Bei einem Doppelklick wird das entsprechende Icon invertiert, eine Alertbox ausgegeben und danach die Invertierung wieder aufgehoben. Wurde nur einmal geklickt, ist noch zu unterscheiden, ob die Maustaste mittlerweile losgelassen wurde oder nicht. Ist die linke Maustaste noch gedrückt, wird das Icon bewegt. Ist sie nicht gedrückt, wird das Icon invertiert, wenn sich der Mauszeiger darüber befindet, bzw. die Invertierung aufgehoben, wenn außerhalb des Icons geklickt wurde.

In der Maus-Handling-Routine werden zwei neue Routinen aufgerufen. Dies ist zum einen eine Ausgabe-Routine und zum anderen eine Routine, die die Icon-Bewegung übernimmt. Die Ausgabe-Routine draw_objc gibt ein Objekt unter Berücksichtigung der Rechteckliste aus. Dies ist notwendig, da nicht immer ein komplettes Objekt neu gezeichnet werden muß. Denken Sie nur daran, wenn ein Fenster ein Icon halb überdeckt!

Move_objc versteckt zuerst das Objekt und gibt es über draw2_objc aus. Die zweite Ausgabe-Routine ist erforderlich, da mit HIDETREE versteckte Objekte nicht direkt angesprochen werden können. Dann wird der Arbeitsbereich - der Bereich, in dem das Objekt bewegt werden darf - ermittelt, die Maus als flache Hand dargestellt und das Objekt via graf_dragbox verschoben. Anschließend stehen die neuen Koordinaten des Icons fest. Wenn man nur bestimmte Positionen zuläßt, so ist an dieser Stelle eine Anpassung - beispielsweise auf Byte-Grenze -vorzunehmen. Letztendlich wird die Maus wieder als Pfeil dargestellt und das Icon ausgegeben. Damit seien die Erklärungen beendet. Im Listing 2 finden sich noch weitere Erklärungen und Anregungen. Ich hoffe, daß Ihnen die kleine Einführung in die Benutzung des GEM gefallen hat und sie als nächstes Programm ein wunderschönes GEM-Programm schreiben werden.

Dietmar Rabich

Literatur:

[1] Atari ST Profibuch, H.-D. Jankowski/J. F. Reschke/D. Rabich, Sybex 1987/88189

[2] GEM Programmier-Handbuch, P Balma/W. Fitler, Sybex 1987/88

[3] Professionel GEM, T. Oren, ANTIC 1985/86


                ; GEMPROG.PRJ
                ; -----------
*               ; name of executable pgm is topmost window 
=               ; list of modules follows...
tcstart.o       ; startup code

gemprog (gemprog.h, interna.h, scankey.h) ; Hauptmodul
interna (interna.h) ; ST-interne Funktionen

tcstdlib.lib    ; Standard-Library
tctoslib.lib    ; TOS-Library
tcgemlib.lib    ; GEM-Library

/***************************************************/
/* GEM-Rahmen-Programm      Vers. 1.00c            */
/*                                                 */
/* Datum: 13. Mai 1989                             */
/* Letztes Edier-Datum: 1. September 1989          */
/* Autor: D. Rabich     Entwickelt mit Turbo C     */
/*                                                 */
/* Quelldatei: GEMPROG.C                           */
/***************************************************/


/* Include-Dateien */
# include "gemprog.h"   /* Resource-Datei   */
# include "interna.h"   /* ST-Interna       */
# include "scankey.h"   /* Scancodes        */
# include <aes.h>       /* AES-Routinen     */

/* Definition zweier Funktionen */
# define min(a,b) ((a) < (b) ? (a) : (b))   /* Minimum */
# define max(a,b) ((a) > (b) ? (a) : (b))   /* Maximum */


/* Handle des Desktops definieren */
# define DESK 0


/* Definitionen */
# define MAXSTRING 80

# define INIT_OK 0
# define NO_INIT 1
# define NO_RESOURCE 2


/* Strings */

char no_resource[] = ”[3][ | GEMPROG.RSC|nicht gefunden.   | ][ OK ]";
char no_init[]     = "[3][ | Initialisierung | erfolglos.| ][ OK ]";
char rsc_name[]    = "GEMPROG.RSC";
char std_scrap[]   = "x:\\CLIPBRD";
/* hier auch Parameter-Datei angeben!   */
/* Format <Programm-Name>.INF           */
/* Beispiel: GEMPROG.INF                */


/* Struktur (en) */
typedef struct { int x,y; /* kennzeichnet einen Punkt */
               } POINT;


/* Prototypen */
static int init_prg(void);
static void exit_prg(int);
static void draw_objc(int, OBJECT*, int); 
static void clip(GRECT*, GRECT*); 
static void draw2_objc(int, OBJECT*, int); 
static void move_objc(int, OBJECT*, int); 
static void do_info(void); 
static void hdle_menu(int, int); 
static void hdle_mouse(int, POINT*); 
static void hdle_key(int, int);

/* Variablen */
int     apl_id,     /* Applikations-ID */
        finish =0;  /* Flag für Ende */
OBJECT  *menu,      /* Menü */
        *desktop,   /* Desktop */
        *infodial,  /* Dialogbox */
        *aktion,    /* Alert-Boxen */
        *laden,     /* Alert-Boxen */
        *speichern, /* Alert-Boxen */
        *ausgabe;   /* Alert-Boxen */
GRECT   desksize;   /* Desk-Grösse */

/***********************************************/
/* Anmeldung des Programms                     */
/* Aufgabe: Anmeldung beim AES, laden und      */
/*          auswerten der Resource-Datei,      */
/*          Scrap-Pfad setzen, Menü ausgeben,  */
/*          Desktop setzen,                    */
/*          Mauszeiger auf Pfeil setzen        */
/***********************************************/

static int init_prg (void)

{   char scrp_path[MAXSTRING];

    /* anmelden */ 
    apl_id = appl_init();
    if (apl_id < 0)             /* korrekte ID? */
        return(NO_INIT);

    /* Maus als Biene/Sanduhr */ 
    graf_mouse(HOURGLASS, 0L);

    /* Resource-Datei laden */
    if (!rsrc_load(rsc_name)) /* nicht gefunden? */
    {   form_alert(1,no_resource); 
        return(NO_RESOURCE);
    }
    /* Accessories, die unter GEM 2.x laufen sollen, */
    /* dürfen keine Resource-Dateien laden. */

    /* Anfangsadressen ermitteln */
    rsrc_gaddr(R_TREE, MENUE, &menu);       /* Menü */
    rsrc_gaddr(R_TREE, DESKTOP, &desktop);  /* Desktop */ 
    rsrc_gaddr(R_TREE, INFODIAL,&infodial); /* Dialog */

    rsrc_gaddr(R_STRING,DOPPEL, &aktion);   /* Alert-Boxen */ 
    rsrc_gaddr(R_STRING,LADEN, &laden); 
    rsrc_gaddr(R_STRING,SPEICHER,&speichern); 
    rsrc_gaddr(R_STRING,AUSGABE, &ausgabe);

    /* Grösse des Desktops ermitteln */ 
    wind_get(DESK,WF_WORKXYWH,&desksize.g_x,&desksize.g_y,&desksize.g_w,&desksize.g_h);

    /* Object-Struktur anpassen */ 
    desktop[ROOT].ob_x      = desksize.g_x;
    desktop[ROOT].ob_y      = desksize.g_y;
    desktop[ROOT].ob_width  = desksize g_w: 
    desktop[ROOT].ob_height = desksize.g_h;

    /* Default-Objektbaum setzen (Desktop) */ 
    objc_draw(desktop,ROOT,MAX_DEPTH,
              desksize.g_x,desksize.g_y, 
              desksize.g_w,desksize.g_h); 
    wind_set(DESK,WF_NEWDESK,(long) desktop,0);

    /* Scrap-Pfad setzen */ 
    scrp_read(scrp_path); 
    if (scrp_path[0] == 0)
    {   std_scrap[0] = 'A' + (char) boot_dev();
        scrp_write(std_scrap);
    }

    /* hier kann die INF-Datei geladen werden! */
    /* Der Pfad wird mit shel_find ermittelt.  */

    /* Menü ausgeben */ 
    menu_bar(menu,1);

    /* Maus als Pfeil */ 
    graf_mouse(ARROW,0L);

    return(INIT_OK);
}

/***************************************************/
/* Abmeldung des Programms                         */
/* Aufgabe: Menü abmelden. Desktop zurücksetzen,   */
/*          Resource-Speicher freigeben,           */
/*          Abmeldung beim AES                     */
/***************************************************/

static void exit_prg (int rc)

{

    if (rc == INIT_OK)
    {   /* Menü abmelden */ 
        menu_bar(menu,0);

        /* Leerer Default-Objektbaum */ 
        wind_set(DESK,WF_NEWDESK,0L,0);

        /* Resource-Speicher freigeben */ 
        rsrc_free();
    }

    if ((rc == INIT_OK) || (rc == NO_RESOURCE))
        /* abmelden */ 
        appl_exit();
}

/***************************************************/
/* Objekt ausgeben                                 */
/* Aufgabe: Objekt unter Berücksichtigung der      */
/*          Rechteckliste ausgeben                 */
/***************************************************/

static void draw_objc (int handle, OBJECT *tree, int child)

{   int wi_gw1,wi_gw2,wi_gw3,wi_gw4;

    wind_update(BEG_UPDATE); /* Fenster wird erneuert */

    /* Rechteckliste abarbeiten */
    wind_get(handle,WF_FIRSTXYWH,&wi_gw1,&wi_gw2,&wi_gw3,&wi_gw4); /* erster Rechteck der Liste */ 
    while (wi_gw3 && wi_gw4)
    {   objc_draw(tree,child,MAX_DEPTH,wi_gw1,wi_gw2,wi_gw3,wi_gw4); /* Objekt ausgeben */ 
        wind_get(handle,WF_NEXTXYWH,&wi_gw1,&wi_gw2,&wi_gw3,&wi_gw4); /* nächstes Rechteck */
    }

    wind_update(END_UPDATE); /* Erneuerung beendet */
}

/***************************************************/
/* Clipping                                        */
/* Aufgabe: Clippt das Rechteck a unter            */
/*          Berücksichtigung von b                 */
/***************************************************/

static void clip (GRECT *a, GRECT *b)

{   a->g_x = max(a->g_x,b->g_x); /* linke obere Ecke */
    a->g_y = max(a->g_y,b->g_y);
    a->g_w = min(a->g_x + a->g_w, b->g_x + b->g_w); /* rechte untere Ecke */
    a->g_h = min(a->g_y + a->g_h, b->g_y + b->g_h);

    a->g_w -= a->g_x; /* Breite */
    a->g_h -= a->g_y; /* Höhe */
}

/***************************************************/
/* Object ausgeben                                 */
/* Aufgabe: Object auch unter Berücksichtigung     */
/*          von HIDETREE ausgeben                  */
/***************************************************/

static void draw2_objc (int handle, OBJECT *tree, int child)

{   GRECT a, b;

    wind_update(BEG_UPDATE); /* Fenster erneuern */

    /* Rechteckliste abarbeiten */ 
    wind_get(handle,WF_FIRSTXYWH,&a.g_x,&a.g_y,&a.g_w,&a.g_h); /* erstes Rechteck der Liste */ 
    while (a.g_w && a.g_h)
    {   objc_offset(tree,child,&b.g_x,&b.g_y); /* Position des Objekts */ 
        b.g_w = tree[child].ob_width; 
        b.g_h = tree[child].ob_height; 
        clip(&a,&b); /* Clipping */ 
        objc_draw(tree,ROOT,MAX_DEPTH,a.g_x,a.g_y,a.g_w,a.g_h); /* Objekt ausgeben */ 
        wind_get(handle,WF_NEXTXYWH,&a.g_x,&a.g_y,&a.g_w,&a.g_h); /* nächstes Rechteck */
    }

    wind_update(END_UPDATE); /* Erneuerung beendet */

    /* In dieser Funktion könnte auch form_dial(FMD_FINISH,...) Verwendung */
    /* finden. */
}

/***************************************************/
/* Objekt bewegen                                  */
/* Aufgabe: Objekt verstecken, bewegen und wieder  */
/*          darstellen                             */
/***************************************************/

static void move_objc (int handle, OBJECT *tree, int child)

{   int x,y,ox,oy,nx,ny;

    /* Objekt verstecken */
    tree[child].ob_flags |= HIDETREE;
    draw2_objc(handle,tree,child);

    /* Objekt child innerhalb des Objekts ROOT bewegen */ 
    objc_offset(tree,ROOT,&x,&y); /* Offset berechnen */
    objc_offset(tree,child,&ox,&oy); 
    wind_update(BEG_UPDATE); /* Fenstererneuerung */ 
    wind_update(BEG_MCTRL); /* Mauskontrolle */
    graf_mouse(FLAT_HAND,0); /* Maus auf "flache Hand" */ 
    graf_dragbox(tree[child].ob_width,tree[child].ob_height, /* bewegen */
                 ox,    oy,
                 x,     y,
                 tree[ROOT].ob_width, tree[ROOT].ob_height,
                 &nx, &ny);
    graf_mouse(ARROW,0); /* Maus wieder Pfeil */
    wind_update(END_MCTRL); /* keine Mauskontrolle */ 
    wind_update(END_UPDATE); /* Erneuerung beendet */
    tree[child].ob_x += nx - ox; /* Verschub addieren */
    tree[child].ob_y += ny - oy;

    /* Objekt darstellen */
    tree[child].ob_flags &= ~HIDETREE; 
    draw_objc(handle, tree, child);
}

/***************************************************/
/* Information ausgeben                            */
/* Aufgabe: Dialogbox ausgeben                     */
/***************************************************/

static void do_info (void)

{   GRECT a, b; 
    int   ret;

    /* Position des Menü-Titels berechnen */ 
    objc_offset(menu,MNINFO,&b.g_x,&b.g_y); 
    b.g_w = menu[MNINFO].ob_width; 
    b.g_h = menu[MNINFO].ob_height;

    /* Vorbereitung */ 
    wind_update(BEG_UPDATE); /* Fenstererneuerung */
    form_center(infodial,
                &a.g_x,&a.g_y,&a.g_w,&a.g_h); /* Dialogbox zentrieren */ 
    form_dial(FMD_START,
              a.g_x,a.g_y,a.g_w,a.g_h,
              a.g_x,a.g_y,a.g_w,a.g_h);       /* Hintergrund reservieren */ 
    form_dial(FMD_GROW,
              b.g_x,b.g_y,b.g_w,b.g_h, 
              a.g_x,a.g_y,a.g_w,a.g_h);       /* vergrösserndes Rechteck */ 
    objc_draw(infodial,ROOT,MAX_DEPTH,
              a.g_x,a.g_y,a.g_w,a.g_h);       /* Dialogbox ausgeben */

    /* Durchführung */
    ret=form_do(infodial,0);    /* Dialog durchführen */ 
    infodial[ret].ob_state &= ~SELECTED;      /* SELECTED zurücksetzen */

    /* Nachbereitung */ 
    form_dial(FMD_SHRINK,
              b.g_x,b.g_y,b.g_w,b.g_h, 
              a.g_x,a.g_y,a.g_w,a.g_h);       /* verkleinerndes Rechteck */ 
    form_dial(FMD_FINISH,
              a.g_x,a.g_y,a.g_w,a.g_h, 
              a.g_x,a.g_y,a.g_w,a.g_h);       /* Hintergrund freigeben */ 
    wind_update(END_UPDATE);                  /* Erneuerung beendet */

    /* Vorbereitung und Nachbereitung können auch in eigene Routinen */
    /* ausgelagert werden. */
}

/******************************************************/
/* Menü-Handler                                       */
/* Aufgabe: Auswertung des ausgewählten Menü-Eintrags */
/******************************************************/

static void hdle_menu (int title, int item)

{
    /* Welches Drop-Down-Menü? */ 
    switch (title)
    {
        /* Info-Menü? */ 
        case MNINFO :
        /* Hier gibt es nur einen Eintrag */ 
            if (item == ITINFO) 
                do_info();
            break;

        /* Datei-Menü? */ 
        case MNDATEI :
            /* Welcher Eintrag? */ 
            switch (item)
            {
                /* Datei neu anlegen? (nicht laden!) */ 
                case ITNEU : /* Eigene Routine... */ 
                    form_alert(1,(char*) laden);
                    break;

                /* Datei öffnen? */ 
                case ITOEFFNE : /* Eigene Routine... */
                    form_alert(1,(char*) laden);
                    break;

                /* Datei sichern? */ 
                case ITSICHER : /* Eigene Routine... */
                    form_alert(1,(char*) speichern);
                    break;

                /* Datei unter neuem Namen sichern? */ 
                case ITSICALS : /* Eigene Routine... */
                    form_alert(1,(char*) speichern);
                    break;

                /* Ausgabe-Programm starten? */ 
                case ITAUSGAB : /* Eigene Routine... */
                    form_alert(1,(char*) ausgabe);
                    break;

                /* Programm-Ende? */ 
                case ITENDE :
                    finish = 1; 
                    break;
            }
    }
    menu_tnormal(menu,title,1); /* Invertierung aufheben */
}

/****************************************************/
/* Maus-Handler                                     */
/* Aufgabe: Auswertung des Mausklicks (linke Taste) */
/****************************************************/

static void hdle_mouse (int clicks, POINT *where)

{   int obj,
        dummy, 
        but_state;

    /* Welches Object? */
    obj = objc_find(desktop,ROOT,MAX_DEPTH, where->x,where->y);

    /* Doppelklick? */ 
    if (clicks == 2)
    {
        /* Welches Objekt? */ 
        switch (obj)
        {   case BSPICON : /* invers darstellen */ 
                if (!(SELECTED & desktop[obj].ob_state))
                {
                    desktop[obj].ob_state |= SELECTED; 
                    draw_objc(DESK,desktop, obj) ;
                }
                /* Hier können eigene Routinen */
                /* aufgerufen werden... */
                form_alert(1,(char*) aktion);
                
                /* normal darstellen */ 
                desktop[obj].ob_state &= ~SELECTED; 
                draw_objc(DESK,desktop, obj);
                /* Es könnte auch objc_change benutzt werden! */
                break;

    /* Platz für weitere Auwertungen und Icons... */
        }
    }

    /* Einfachklick? */ 
    else if (clicks == 1)
    {
        /* Status der Maustasten abfragen */ 
        graf_mkstate(&dummy,&dummy,&but_state,&dummy);

        /* linke Maustaste festgehalten? */ 
        if (but_state & 0x01)
        {
            /* Welches Object? */ 
            switch (obj)
            {
                /* Objekt bewegen */
                case BSPICON : move_objc(DESK,desktop,obj);
                               break;

                /* Für weitere Icons... */
            }
        }

        /* einfach geklickt? */ 
    else 
    {
        /* Welches Object? */ 
        switch (obj)
        {
            /* Objekt invertieren */
            case BSPICON : if (!(SELECTED & desktop[obj].ob_state))
                           {
                                desktop[obj].ob_state |= SELECTED;
                                draw_objc(DESK, desktop, obj);
                           }
                           break;

            /* Platz für weitere Aktionen... */

            /* Invertierungen aufheben */ 
            default     : if (SELECTED & desktop[BSPICON],ob_state)
                          {
                            desktop[BSPICON].ob_state &= ~SELECTED;
                            draw_objc(DESK, desktop, BSPICON); 
                          }
                          break;
        }
    }

}

}

/***************************************************/
/* Key-Handler                                     */
/* Aufgabe: Auswertung des Tastendrucks            */
/***************************************************/

static void hdle_key (int key, int special_key)

{
    /* Control gedrückt? */ 
    if (K_CTRL & special_key)

    {
        /* Welche Taste? */
        switch(key >> 8) /* Scancode in den oberen 8 Bit */
        {
            /* N gedrückt? */
            case K_N : menu_tnormal(menu,MNDATEI,0); /* Titel invertieren */

                       /* Eigene Routine... */
                       form_alert(1, (char*) laden);

                       menu_tnormal(menu,MNDATEI,1); /* Titel normal darstellen */

                       break;

            /* O gedrückt? */
            case K_O : menu_tnormal(menu,MNDATEI,0); /* Titel invertieren */

                       /* Eigene Routine... */
                       form_alert(1,(char*) laden);

                       menu_tnormal(menu,MNDATEI,1); /* Titel normal darstellen */

                       break;

            /* S gedrückt? */
            case K_S : menu_tnormal (menu, MNDATEI,0); /* Titel invertieren */

                       /* Eigene Routine... */
                       form_alert(1,(char*)speichern);

                       menu_tnormal(menu,MNDATEI,1); /* Titel normal darstellen */

                       break;

            /* A gedrückt? */
            case K_A : menu_tnormal(menu,MNDATEI,0); /* Titel invertieren */

                       /* Eigene Routine... */
                       form_alert(1,(char*)speichern);

                       menu_tnormal(menu,MNDATEI,1); /* Titel normal darstellen */

                       break;

            /* Q gedrückt? */ 
            case K_Q : finish = 1;
                       break;
        }
    }
}

/**************************************************************/
/* Hauptprogramm                                              */
/* Aufgabe: Initialisierung, Auswertung der Events, Abmeldung */
/**************************************************************/

int main (void)

{   int     events,         /* für Multi-Event */
            mouse_button,   /* für Multi-Event */ 
            sp_key,key,clicks, /* f.Multi-Event */
            msg_buffer[8];  /* für Multi-Event */
    POINT   mouse_pos;      /* für Multi-Event */
    int     ret_code;       /* aus Initialisierung */

    if ((ret_code = init_prg()) == INIT_OK)
    
    {   while (!finish)

        { events=evnt_multi(
            /* Message-, Maustasten- und Tastatatur-Ereignis */
                    MU_MESAG|MU_BUTTON|MU_KEYBD,

            /* Doppelklick und linke Maustaste */
                    0x02,0x01,0x01,

            /* Keine Überwachung von Rechtecken */
                    0,0,0,0,0,0,0,0,0,0,

                    /* Message-Buffer */ 
                    msg_buffer,

                    /* Kein Timer */
                    0,0,

                /* Maus-Position und -Taste */ 
                    &mouse_pos.x, &mouse_pos.y, &mouse_button,

                /* Sondertaste und Taste */ 
                    &sp_key,&key,

                /* Anzahl der Mausklicks */ 
                    &clicks);

            /* Message-Event? */ 
            if (events & MU_MESAG)
            {   switch (msg_buffer[0])
                {
                    /* Menü angeklickt? */ 
                    case MN_SELECTED : hdle_menu(msg_buffer[3],msg_buffer[4]);
                                       break;

/* Platz für weitere Message-Auswertungen...   */ 
/* Z.B. für Fenster: WM_REDRAW, WM_TOPPED, ... */

                }
            }
            else
            {
                /* Maus-Button-Event? */ 
                if (events & MU_BUTTON)
                    hdle_mouse(clicks,&mouse_pos);

                /* Tastatur-Event? */ 
                if (events & MU_KEYBD)
                    hdle_key(key,sp_key);

            }
        }
    }
    else
        form_alert(1,no_init); /* Fehlermeldung */ 

    exit_prg(ret_code); 

    return(0);

}

/***************************************************/

Dietmar Rabich
Aus: ST-Computer 11 / 1989, Seite 137

Links

Copyright-Bestimmungen: siehe Über diese Seite