Menutune

Die Menüverwaltung und dazugehörige Funktionen sind beim ATARI ST sicherlich sehr gelungen ausgefallen. Daß man trotzdem noch Verbesserungen anbringen kann, zeigt dieser Artikel.

Das in Pure C entwickelte Modul MENUTUNE enthält zwei universelle Routinen: MenuTune und MenuCorrect. Fangen wir mit der erstgenannten Funktion an ...

Auf Objektsuche

Die Funktion MenuTune erledigt das, was man in Bild 1 sehen kann. Die bekannten grauen Einträge, die verschiedene Sinngruppen im Menü abtrennen, werden durch durchgezogene Rechtecke ersetzt, die optisch besser wirken.

Dazu durchläuft die Routine den gesamten Objektbaum; dies erledigt eine Schleife, die beim nullten Objekt anfängt und beim letzten Objekt abbricht, also bei dem Objekt, bei dem das LASTOB-Flag gesetzt ist. Damit ein Objekt des Menüs als passendes Objekt erkannt wird, muß es vom Typ G_STRING mit dem Status DISABLED sein, und das erste Zeichen des Strings muß ein sein. Wurde während der Suche ein solches Objekt gefunden, wird es zum ...

Userdef

Die vielerorts benutzte Methode, ein Objekt als benutzerdefiniertes Objekt zu deklarieren, wird auch bei dieser Funktion angewandt. Dazu wird dessen Objekttyp auf G_USERDEF gebracht; der Zeiger ob_spec zeigt nun auf eine Struktur vom Typ USERBLK, die in Zeile 16 des Listings 1 deklariert ist. Diese enthält neben dem hier unwichtigen Parameter ub_parm die Variable ub_code, die den Funktions-Pointer der Zeichenfunktion DrawMenuRect enthält. Soll nun das Userdef gemalt werden, springt das AES diese Zeichenfunktion direkt an, so daß diese den grauen Balken malen kann; die Koordinaten des zu malenden Objektes enthält die PARM-BLK-Struktur, die der Malfunktion übergeben wird.

Eine solche Zeichenfunktion darf aber nur VDI-Ausgaben tätigen, so daß ein VDI-Handle benötigt wird. Dieses Handle übergibt man neben dem Pointer auf den Objektbaum des Menüs ebenfalls der Funktion MenuTune, so daß keine eigene VDI-Workstation an- und abgemeldet werden muß.

Den zweiten Teil des Moduls stellt die Funktion MenuCorrect dar, die ein Problem behebt, das in niedrigen Auflösungen auftreten kann.

Jenseits des Bildschirms

Einige Programme verfügen über sehr mächtige Menüs, die, wenn die Programme auch in niedriger Auflösung laufen, so groß werden können, daß das Menü nicht komplett in den Bildschirm paßt oder daß eine Gruppe des Menüs aus dem Bildschirm ragt.

Die Funktion MenuCorrect, der man den Pointer auf den Objektbaum des Menüs übergibt, prüft dabei zuerst, ob das Menü überhaupt in den Bildschirmbereich hineinpaßt, also ob sich der letzte Titel komplett im Bildschirmbereich befindet; tut es das nicht, liefert die Funktion den Wert FALSE zurück, was heißt, daß das Menü in gar keinem Fall für diese

Auflösung geeignet ist. Ist es allerdings geeignet, werden eventuell außerhalb des Bildschirms liegende Gruppen in diesen versetzt, wobei das Funktionsergebnis dann TRUE ist. Um solche Gruppen zu finden, durchläuft die Routine wieder den Objektbaum und sucht nach Objekten vom Typ G_BOX, ermittelt via objc_offset deren absolute Position und setzt diese, wenn sie außerhalb des Bildschirms liegen, in den Bildschirmbereich hinein.

Natürlich sind beide Funktionen vollkommen unabhängig voneinander; auch nicht unwichtig ist die Tatsache, daß Sie die Funktion MenuTune auch auf normale Dialoge oder andere Objektbäume loslassen können.

Literaturhinweise:

[1] Jankowski, Reschke, Rabich ATARI ST-Profibuch

[2] Pure C-Compilerhandbuch

#include <portab.h>

WORD MenuCorrect ( OBJECT *menuptr );

VOID MenuTune( OBJECT *menuptr, WORD v_handle );

Listing 1: MENUTUNE.H

/**********************************************/
/*  MODUL : MENUTUNE.C                        */
/*  AUTOR : Markus Hövener                    */
/*          (c) 1992 MAXON Computer GmbH      */
/*  DATUM : 20.10.1991                        */
/**********************************************/

#include <aes.h>
#include <portab.h>
#include <vdi.h>

#define FALSE   0
#define TRUE    !FALSE

MLOCAL USERBLK  _user;
MLOCAL WORD     gv_handle;

/* Prototyp */
MLOCAL WORD cdecl DrawMenuRect; PARMBLK *parmblock );

/*********************************************/
/*   Aufgabe : Setzt einzelne Menugruppen in */
/*             die Bildschirmgrenzen         */
/* Parameter : Pointer auf Objektbaum        */
/*********************************************/ 
WORD MenuCorrect( OBJECT *menuptr )
{
    WORD  i = menuptr[2].ob_tail + 2, 
          abs_x, abs_y;
    GRECT work;


    /* Arbeitsbereich holen */ 
    wind_get( 0, WF_WORKXYWH,
                 &work.g_x, &work.g_y,
                 &work.g_w, &work.g_h );

    /*****************************/
    /* Menü allgemein zu breit   */
    /*****************************/
    if( menuptr[menuptr[2].ob_tail].ob_x +
        menuptr[menuptr[2].ob_tail].ob_width + 
        menuptr[2].ob_x > 
        work.g_x + work.g_w ) 
        return( FALSE );

    do
    {
        ++i;

        /*****************************/
        /* Ein Hintergrundobjekt. ?? */
        /*****************************/ 
        if( menuptr[i].ob_type == G_BOX )
        {
            if( (menuptr[i].ob_width >= work.g_w) || 
                (menuptr[i].ob_height >= work.g_h))
                return( FALSE );

            /* Absolute Position */
            objc_offset(menuptr,i,&abs_x,&abs_y );

            /* Nicht komplett im Bildschirm ?? */ 
            if ( abs x >= work.g_x + work.g_w - 
                menuptr[i].ob_width ) 
                menuptr[i].ob_x -= abs_x - (work.g_x + work.g_w - menuptr[i].ob_width) + 1;

        }
    }
    while( !(menuptr[i].ob_flags & LASTOB) ); 

    return( TRUE );
}

/*********************************************/ 
/*   Aufgabe : Graue DISABLED-Objekte finden */
/*             und in USERDEFS wandeln       */
/* Parameter : Pointer auf Objektbaum        */
/*             VDI-Handle                    */
/*********************************************/ 
VOID MenuTune( OBJECT *menuptr, WORD v_handle )
{
    WORD i = -1;


    gv_handle = v_handle;

    /* USERBLK-Struktur füllen */ 
    _user.ub_parm = 0L; 
    _user.ub_code = DrawMenuRect;

    do
    {
        ++i;

        /* Ist es ein passendes Objekt */ 
        if( menuptr[i].ob_type == G_STRING ) 
        if( (menuptr[i].ob_state & DISABLED) &&
            (menuptr[i].ob_spec.free_string[0] == '-') )
        {
            menuptr[i].ob_type = G_USERDEF; 
            menuptr[i].ob_spec.userblk = &_user;
        }
    }
    while( !(menuptr[i].ob_flags & LASTOB) );
}

/*********************************************/ 
/*   Aufgabe : Zeichenfunktion für Balken    */ 
/*             (wird vom AES aufgerufen)     */
/* Parameter : Pointer auf PARMBLK-Struktur  */ 
/*********************************************/ 
MLOCAL WORD cdecl DrawMenuRect( PARMBLK *parmblock )
{
    WORD pxy[4];


    /* Koordinaten errechnen */ 
    pxy[0] = parmblock->pb_x;
    pxy[1] = parmblock->pb_y + (parmblock->pb_h / 2) - 1;
    pxy[2] = parmblock->pb_x + parmblock->pb_w 1; 
    pxy[3] = parmblock->pb_y + (parmblock->pb_h / 2);

    /* Grafikmodi setzen */
    vswr_mode( gv_handle, MD_REPLACE );
    vsf_interior( gv_handle, FIS_PATTERN );
    vsf_style ( gv_handle, 4 );
    vsf_color( gv_handle, 1 );

    /* Box malen */
    vr_recfl( gv_handle, pxy );

    return( 0 );
}

Listing 2: MENUTUNE.C


Markus Hövener
Links

Copyright-Bestimmungen: siehe Über diese Seite