VDI für jedermann: „Sauberes“ Programmieren übers System

Viele Programmierer machen sich scheinbar immer noch keine Gedanken über ihre Grafik- und Textausgaben, egal ob sie auf dem Bildschirm oder anderen Peripheriegeräte getätigt werden. Da gibt es die wildesten Sachen, ob nun direkt in den Bildschirmspeicher geschrieben wird, womit man die Lauffähigkeit des Programms auf einen Monitor beschränkt, oder ob Zeichen direkt hardwarenah auf den Parallel-Port geschrieben werden, wodurch nur ein spezielles Peripheriegerät mit dem Programm Zusammenarbeiten wird. Das muß nicht so sein, und ich möchte hier zeigen, wie einfach ein Programm alle möglichen Geräte, vor allem andere Bildschirme, unterstützen kann.

Das Geheimnis der portablen Datenausgabe auf Ausgabegeräte aller Art, dazu gehören Bildschirm genauso wie Drucker oder Plotter, ist das sogenannte VDI, das Virtual Device Interface oder auf deutsch das Sichtgeräte-Interface des TOS. Das Interessante ist, daß alle Anpassungsangelegenheiten an die verschiedenen Peripheriegeräte nicht mehr der Applikation (also dem Programmierer) überlassen werden, sondern von sogenannten Treibern erledigt werden. Ganz banal läuft dann die Ausgabe eines Rechtecks ungefähr so ab, daß der Programmierer erst festlegt, auf welches Gerät die Ausgabe gehen soll, und dann die Funktion zum Malen eines Rechtecks aufruft. Das war’s. Keine komplizierten Steuercodes oder ähnliches.

Doch gerade bei der Bestimmung des Ausgabegerätes werden oft Fehler gemacht, so daß der Anwender später die Fehlermeldung „Ungültiges Handle“ auf dem Bildschirm zu Gesicht bekommt. Um eine Ausgabe zu machen, muß man sich nämlich zuerst eine sogenannte Workstation öffnen. Man erhält dadurch eine bestimmte Nummer, ein Handle, das dem VDI später zur Identifikation der Ausgaben und zu deren korrekter Verteilung an die entsprechenden Ausgabegeräte dient. Hier zeigt sich, daß das VDI in der Lage ist, viele Geräte gleichzeitig zu verwalten. Für jedes Gerät wird ein Treiber installiert, und es ist von da an möglich, Workstations auf diesem Gerät zu öffnen und Ausgaben auf dieses Gerät zu tätigen. Die installierten Treiber sind in einer Datei aufgeführt, die ASSIGN.SYS genannt wird. Dazu mehr in [1]. Ein Treiber ist allerdings bereits im ROM fest integriert, nämlich der Bildschirmtreiber. Wie man sich nun eine Workstation für den Bildschirm öffnet, zeigt die Funktion InitVWork (Listing 1).

Virtual Workstation?

Die Spezialität von Bildschirm-Workstations ist die, daß man auf demselben Ausgabegerät ausgibt wie die AES. Das macht durchaus Sinn, denn die AES müssen ja wissen, was das richtige Gerät ist. Man ermittelt also die AES-Workstation mittels graf_handle und öffnet dann auf demselben Gerät parallel eine Workstation durch einen Aufruf von v_opnvwk. Ist das erhaltene Handle gleich Null, mißlang der Aufruf, und die Workstation konnte nicht eingerichtet werden. Ein Feature der Funktion InitVWork ist, daß sie bei Bedarf noch einige spezifische Werte über die Workstation zurückliefert. Hierfür übergibt man ihr Pointer auf die Variablen, in denen die zu ermittelnden Werte stehen sollen. Setzt man Null-Pointer ein, wird auf die Bestimmung dieser spezifischen Werte verzichtet. Ermittelt werden wahlweise die Pixel-Breite und -Höhe in tausendstel Millimetern, die Bildschirmbreite und -höhe in Pixeln, die Höhe und Breite eines Zeichens des Systemzeichensatzes in Pixeln sowie die Anzahl der Planes. Selbstverständlich läßt sich dies noch anders gestalten, ob man nun die Anzahl der Parameter verringert oder eine komplexere Struktur übergibt, liegt in Ihrer Hand.

Um eine Workstation auf einem anderen Ausgabegerät zu öffnen, benutzt man vjopnwk. Dabei erübrigt sich der vorherige Aufruf von graf_handle. Man muß dann selber die Nummer eines Treibers einsetzen, unter der selbiger in der Datei ASSIGN.SYS aufgeführt ist. Näheres dazu finden Sie ebenfalls in [1].

Und nun?

Der interessierte Leser wird sich jetzt fragen: „Und was hab’ ich davon?“. Nun ja, eine Anwendung folgt. Es handelt sich hierbei um die Funktion InitFonts (Listing 5). Diese Funktion initialisiert alle Fonts für eine bestimmte Workstation. Das heißt, erst muß eine Workstation geöffnet worden sein, und dann kann unter Angabe des Handles in v_handle mit der Initialisierung der Fonts begonnen werden. Als weiteren Parameter übergibt man der Funktion noch die Adresse einer Variablen, in der später die Anzahl der Fonts stehen soll, in fonts.

So geht’s

Nun zur Funktionsweise von InitFonts. Zuerst wird die Anzahl der verfügbaren Fonts ermittelt, wobei bei vorhandenem GDOS eventuell noch weitere ebenfalls in ASSIGN.SYS (siehe auch oben) angeführte Fonts dazugeladen werden. Sollte kein GDOS installiert oder keine weiteren Fonts deklariert oder vorhanden sein, wird man auf herkömmlichen Atari-Rechnern nur einen Font installiert bekommen, nämlich den System-Font (mit dem wird auch der Text zum Beispiel in Menüs ausgegeben).

Als nächstes werden die Fonts überprüft. In einer Schleife werden alle Fonts durchgegangen und ihre ID, das ist sozusagen das Handle eines Fonts, sowie ihre Namen ermittelt. Es wird dann überprüft, ob es sich bei dem Zeichensatz um einen proportionalen Font handelt. Hierzu sei gesagt, daß sich InitFonts nur für die nichtproportionalen Fonts interessiert. Außerdem kommt es vor, daß ein Treiber sogenannte ,Dummy fonts' zurückliefert, die auch genauso heißen. Diese sind nicht benutzbar und können sofort vergessen werden. Also ermittelt InitFonts die Anzahl der Fonts, die weder proportional noch Dummy-Fonts sind. Sollte solch ein Font gefunden worden sein, wird zusätzlich die Anzahl aller möglichen Größen dieses Fonts ermittelt. Dies funktioniert folgendermaßen: Es wird die maximal mögliche Größe gesetzt (das ist bei dem Typ Integer nun mal 32767), und die Funktion vst_point setzt die Font-Größe, die möglich und kleiner gleich der angegebenen Größe ist. Dies wäre dann die erste mögliche Font-Größe. Nun veringert man diese Größe, die von vst_point zurückgeliefert wurde, um Eins und setzt sie erneut als Font-Größe, und wieder wird die nächste mögliche „kleinergleiche“ Größe gesetzt. So erhält man die zweite Größe. Von der zieht man wiederum Eins ab, setzt sie wieder usw. Der Vorgang kann abgebrochen werden, wenn der Rückgabewert von vst_point derselbe ist wie beim letzten Durchgang, denn das bedeutet, daß keine kleinere Größe mehr existiert. Man kann dann die Bestimmung der Größenanzahl abbrechen. Es folgt noch eine Abfrage, die zum Abbruch der Funktion führt, falls kein passender Font vorhanden ist, doch das passiert wohl momentan bei Bildschirm-Workstations überhaupt noch nicht, da mindestens der System-Font alle geforderten Eigenschaften erfüllt (doch auch dies kann sich ändern. Vielleicht ist der System-Font bald proportional?). Doch bei Drucker-Workstations z.B., auf denen man ja ebenfalls Fonts initialisieren kann, kann es Vorkommen, daß kein passender Font vorhanden ist.

Speicherstruktur

Durch die Anzahl der Fonts und der möglichen Größen läßt sich nun die Größe des benötigten Speicherblocks errechnen, der zur Ablegung der Font-Daten benötigt wird. Hierzu sind die Strukturen FONTSTRCT und SIZESTRCT gedacht. Die Strukturierung des angeforderten Speicherblocks sieht folgendermaßen aus (Bild 1):

Zuerst liegen soviele Strukturen vom Typ FONTSTRCT hintereinander, wie brauchbare Fonts gefunden wurden. Darauf folgt ein Bereich, der zur Ablage der Font-Größen benutzt wird. Für jede Größe jedes Fonts liegt in diesem Bereich eine Struktur des Typs SIZESTRCT, die mehrere Größenformate des Fonts beschreibt. Sehr relevant ist der Parameter point, der die Font-Größe in Point (1/72 Zoll) beschreibt. Diesen Wert setzt man auch zum Setzen der Font-Größe in vst_point ein. Die anderen Werte beschreiben in Reihenfolge der Auflistung in der Struktur die Zeichenbreite, die Zeichenhöhe, die Zellenbreite und die Zellenhöhe in Pixeln in dieser Font-Größe. Es gibt in jeder FONTSTRCT-Struktur einen Pointer auf eine SIZESTRCT-Struktur, der auf die Struktur der ersten Größe des entsprechenden Fonts zeigt. Darauf folgen eventuell noch weitere SIZESTRCT-Strukturen, in denen noch weitere Größen abgelegt sind. Insgesamt sind es soviele, wie in der FONTSTRCT-Struktur unter sizes angegeben sind. Nachdem der Speicherblock angefordert wurde, wird noch ein lokaler Pointer initialisiert, der auf den Pointer des Bereichs mit den Font-Größen zeigt, also auf die erste Größe des ersten Fonts. Dann folgt das Füllen des Speicherblocks mit Daten.

Daten ablegen

Wie oben schon einmal beschrieben, werden die ID und der Name eines Fonts ermittelt. Daraufhin wird der ermittelte Name getrennt, da der eigentliche Font-Name noch generiert werden muß.

Bild 2a zeigt den Aufbau eines Strings, der einen Font-Namen beschreibt, wie ihn vqt_name zurückliefert. Es werden also der Name von der Beschreibung getrennt, Leerzeichen am Ende abgetrennt und beide wieder zusammengefügt, so daß aus dem String in Bild 2a einer wird, wie in Bild 2b. Daraufhin ermittelt man nach dem oben bereits beschriebenen Verfahren die Font-Größen. Der Unterschied ist hier, daß die Werte nicht vergessen oder in eine _void-Variable gelenkt, sondern gleich in die passende SIZESTRCT-Struktur geschrieben werden. Dann werden die Werte noch alle getauscht, so daß die vorherige Abwärts- in eine Aufwärts-Sortierung umgewandelt wird. Anschließend werden noch die Anzahl der Größen in die entsprechende FONTSTRCT-Struktur eingetragen, der Pointer auf die Größen initialisiert sowie die ID übernommen. Als letztes werden ein lokaler Zähler erhöht, der den Index der nächsten Struktur des nächsten brauchbaren Fonts, beschreibt und der lokale Zeiger auf den Bereich für die Font-Größen auf die erste Größe des nächsten Zeichensatzes gesetzt. Daraufhin beginnt die Schleife wieder bei der Ermittlung des nächsten Fonts und dessen Überprüfung auf Proportionalität und Nutzbarkeit. Zuletzt wird der Zeiger auf den reservierten Speicherbereich zurückgeliefert. Als Tip sei noch gesagt, daß der Zugriff auf eine Font-Größe folgender maßen funktioniert: a = f[index1].size[index2].point.

Bild 1: Die Speicherstrukturierung
Bild 2a: Der Font-Name von vqt_name
Bild 2b: Der bearbeitete Font-Name

Additives

InitFonts ruft zwei Funktionen auf. Zum einen DeleteSpace, eine Funktion, die Leerzeichen am Anfang und Ende eines Strings löscht und den Ergebnis-String zurückliefert, und zum anderen eine Funktion, die einen Font auf Proportionalität überprüft. Zuerst zur String-Manipulation (siehe Listing 9). Sie gestaltet sich sehr einfach. Zuerst werden Leerzeichen am Anfang des Strings einfach übergangen, dann wird das abschließende Nullzeichen solange nach vorne geschoben, solange ein Leerzeichen vor diesem steht. Dann wird der Rest-String, der ja inmitten des Ausgangs-Strings liegen kann (da vorangehende Leerzeichen auch ignoriert werden) dorthin kopiert, wo vorher der Ausgangs-String begann.

Außerdem wäre da noch die Überprüfung auf Proportionalität, das Vorgehen in der Funktion QPropFont (Listing 5) gestaltet sich folgendermaßen. Der übergebene Font wird, identifiziert durch seine ID, auf der Workstation, beschrieben durch v_handle, gesetzt. Dann wird das erste und letzte Zeichen des Zeichensatzes bestimmt und ein String mit nur einem Zeichen Länge gebildet. Von diesem String werden die Ausmaße in extent1 festgehalten. Anschließend wird ein String gebildet, in dem das nachfolgende Zeichen steht, und auch dessen Ausmaße werden, diesmal in extent2, festgehalten. Die beiden Ausmaße werden verglichen und bei Nichtübereinstimmung wird die Schleife abgebrochen. Ansonsten wird der Vorgang wiederholt und das nächste Zeichen mit seinem Nachfolger verglichen. Sollte die Schleife bis zum Ende durchlaufen worden sein, wird eine Null zurückgegeben als Zeichen dafür, daß es sich nicht um einen Proportional-Font handelt (denn die Ausmaße waren dann immer identisch), sonst wird eine Eins zurückgeliefert, was bedeutet, daß es sich um einen Proportional-Font handelt.

Zugabe

Als kleine Zugabe befindet sich in Listing 5 noch die Funktion SetSysFont. Das Problem liegt darin, nach einem Verstellen des Zeichensatzes den Systemzeichensatz wieder einzustellen (falls man mal Ausgaben mit dem Systemzeichensatz machen möchte). Um dies zu erreichen, wird zuerst der System-Font gesetzt. Dann wird die Größe einer Box ermittelt, die jedes Zeichen dieses Zeichensatzes umrahmen kann, also die Zellenbreite und -höhe. Nun wird solange eine ständig inkrementierte (um Eins erhöhte) Größe gesetzt und die tatsächlich gesetzten Werte, die von der Funktion vst_point, mit der die Größe gesetzt wird, zurückgeliefert werden, mit der bereits vorher erfragten System-Fontzellenbreite und -höhe verglichen, bis diese überschritten werden. Dann wird die Schleife abgebrochen und die nächstkleinere Größe gesetzt, da diese ja noch die Bedingung, kleiner gleich der bereits erfragten Größe zu sein, erfüllt. Der Aufwand muß getrieben werden, da die mit graf_handle am Anfang erfragten Zellenausmaße Pixel-Werte sind und keine Point-Werte. Die Point-Werte müssen nämlich erst durch Annäherung mit vst_point, die (unter anderem) Point-Werte zurückliefert, ermittelt werden. SetSysFont erwartet als Parameter das VDI-Handle der zu bearbeitenden Workstation und gibt die Zeichenbreite und -höhe sowie die Zellenbreite und -höhe des gesetzten System-Fonts zurück. Auch hier können bei nicht vorhandenem Bedarf an diesen Parametern einfach Null-Pointer statt wirklicher Adressen von Variablen eingesetzt werden. Dann entfällt die Rückgabe dieser Parameter. Nach Beenden dieser Funktion ist auf der Workstation, die durch v_handle beschrieben wird, der System-Font gesetzt worden. Die Benutzung von vst_height unterlasse ich absichtlich, da diese Funktion nicht immer korrekt arbeitet. Außerdem können Fonts verschiedene Point-Größen, aber trotzdem gleiche Pixel-Größen haben (Ungenauigkeit der Pixel). Die Angabe in Points ist zusätzlich noch ein portabler Standardwert, unter dem man sich mehr vorstellen kann als unter einer Angabe in Pixeln, denn die ist wieder vom Monitor abhängig (Pixel sind schließlich nicht auf allen Monitoren gleich groß).

Abmelden

Das Gegenstück zu InitVWork ist die Funktion ExitVWork (Listing 3), die einfach nur die Workstation wieder schließt. Das Gegenstück zu InitFonts ist ExitFonts (Listing 7), die als einzige Aufgabe hat, den belegten Speicher wieder freizugeben.

Zur Demonstration liegt ein Demoprogramm (Listing 11) mit passender Projektdatei (Listing 12) bei, das sich die besprochenen Funktionen zunutze macht und alle Fonts und deren mögliche Größen ausgibt - selbstverständlich im entsprechenden Font und mit der passenden Größe. Es soll noch einmal eine Erleichterung zum Einbinden dieser Funktionen in eigene Programme sein. Ich wünsche allen, die sich die Arbeit machen, die Listings abzutippen, viel Freude an diesen Funktionen. Aus eigener Erfahrung kann ich nur sagen, daß die Ausgabe von Texten mit verschiedenen Zeichensätzen ungemein reizvoll ist und es Spaß macht zu sehen, daß das Programm so zukunftssicher und sauber programmiert ist.

/***********************************************/
/* Modul  :  INITVDI                           */
/* Aufgabe: VDI-Bildschirm-Workstation anlegen */
/***********************************************/

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

#include "initvwk.h"

int InitVWork( int *v_handle,
               int *pixel_width, 
               int *pixel_height, 
               int *scr_width, 
               int *scr_height, 
               int *ch_width, 
               int *ch_height, 
               int *planes )
{
    int i,
        ch_w, 
        ch_h,
        work_in[11], 
        work_out[57],
        _void;

    *v_handle = graf_handle( &ch_w, &ch_h, &_void, &_void ) ;
    for ( i = 0; i < 10; work_in[i++] = 1 );
    work_in[10] = 2;

    v opnvwk( work_in, v_handle, workout );

    if( !*v_handle ) 
        return( 0 );

    if( pixel_width )
        *pixel_width  = work_out[3]; 
    if( pixel_height )
        *pixel_height = work_out[4]; 
    if( scr_width )
        *scr_width    = work_out[0] + 1; 
    if( scr_height )
        *scr_height   = work_out[1] + 1;

    if( ch_width )
        *ch_width  = ch_w; 
    if( ch_height )
        *ch_height = ch_h;

    if( planes )
    {
        vq_extnd( *v_handle, 1, work_out );
        *planes = work_out[4];
    }

    return( 1 ) ;
}

#ifndef _INITVWK

# define _INITVWK

int InitVWork( int *v_handle,
               int *pixel_width, 
               int *pixel_height, 
               int *scr_width, 
               int *scr_height, 
               int *ch_width, 
               int *ch_height, 
               int *planes );

#endif
/***********************************************/
/* Modul  : EXITVWK                            */
/* Aufgabe: VDI-Bildschirm-Workstation         */
/*          abmelden                           */
/***********************************************/

#include <vdi.h>

#include "exitvwk.h"

void ExitVWork( int v_handle )
{
    v_clsvwk( v_handle );
}
#ifndef _EXITVWK

# define _EXITVWK

void ExitVWork ( int v_handle );

#endif
/***********************************************/
/* Modul  : INITFONT                           */
/* Aufgabe: Fonts initialisieren               */
/***********************************************/

#include <aes.h>
#include <stdio.h>
#include <string.h>
#include <tos.h>
#include <vdi.h>

#include "utility.h"
#include "initfont.h"

/***********************************************/
/* Laden und initialisieren der Fonts          */
/***********************************************/

FONTSTRCT *InitFonts( int v_handle, int *fonts )
{
    char        lname[33],
                name[17], 
                desc[17]; 
    int         i, j, k,
                id,
                fontanz,
                size,
                osize,
                sizes,
                work_out[57],
                _void; 
    long        memsize;
    long        tsizeanz;
    SIZESTRCT   *s;
    FONTSTRCT   *f;

    tsizeanz =0;

    /* Anzahl der Fonts ermitteln */ 
    vq_extnd( v_handle, 0, work_out );

    if ( vq_gdos() == 0 )
        fontanz = work_out[10];
    else
        fontanz = work_out[10]+ vst_load_fonts( v_handle, 0 );

    /* Anzahl der Fonts ermitteln, die nicht 
       'dummy font' heißen und kein 
       Proportionalfont sind */
    *fonts = 0;

    for( i = 0; i < fontanz; i++ )
    {
        id = vqt_name( v_handle, i+1, lname );

        if( strcmp( lname, "dummy font" ) ) 
            if( !QPropFont( v_handle, id ) )
            {
                /* Anzahl der möglichen Größen ermitteln */ 
                vst_font ( v_handle, id );
                size = 32767;

                do
                {
                    osize = size; 
                    size  = vst_point ( v_handle, size - 1, &_void, &_void, &_void, &_void );
                    ++tsizeanz;
                }
                while( size != osize );
                --tsizeanz;

                ++(*fonts);
            }
    }

    if( *fonts <= 0 ) 
        return( 0L );

    /* Speicher reservieren */ 
    memsize  = (long)sizeof( FONTSTRCT ) * ((long)(*fonts)); 
    memsize += (long)sizeof( SIZESTRCT ) * tsizeanz;
    f = (FONTSTRCT*)Mxalloc( memsize, 3 ); 
    if ( !(f) )
        return( 0L ) ;

    /* Font-ID, -namen und -größen ermitteln */ 
    s = (SIZESTRCT*)( (long)sizeof( FONTSTRCT ) * ((long)(*fonts)) + (long)f );
    j = 0;

    for( i = 0; i < fontanz; i++ )
    {
        /* ID und Namen holen */
        id = vqt_name( v_handle, i + 1, lname );

        if( strcmp( lname, "dummy font" ) ) 
            if( !QPropFont( v_handle, id ) )
            {
                /* Den Namen konstruieren */ 
                memmove( name, lname, 16L ); 
                name[16] = 0;
                memmove( desc, &lname[16], 16L ); 
                desc[16] = 0;

                DeleteSpace( name );
                DeleteSpace( desc );


                /* Fontgrößen ermitteln */ 
                vst_font( v_handle, id ); 
                size = 32767; 
                sizes = 0;

                do
                {
                    osize = size; 
                    size =
                        vst_point( v_handle, size - 1,
                                   &s[sizes].chw,
                                   &s[sizes].chh,
                                   &s[sizes].zw,
                                   &s[sizes].zh );
                    s[sizes].point = size;
                    ++sizes;
                }
                while( size != osize );
                —-sizes;

                /* Größen tauschen */
                for( k = 0; k < sizes/2; k++ )
                {
                    Swap( &s[k].chw,&s[sizes - k - 1].chw );
                    Swap( &s[k].chh,&s[sizes - k - 1].chh );
                    Swap( &s[k].zw, &s[sizes - k - 1].zw  );
                    Swap( &s[k].zh, &s[sizes - k - 1].zh );
                    Swap( &s[k].point,&s[sizes - k - 1].point );
                }

                /* Werte in die Struktur übertragen */ 
                sprintf( f[j].name, "%s %s", name, desc ); 
                f[j].id     = id; 
                f[j].size   = s; 
                f[j].sizes  = sizes;

                /* Lokale Variablen aktualisieren */
                ++j;
                s = (SIZESTRCT*)
                    ( (long)s
                      + (long)sizeof( SIZESTRCT )
                      * (long)sizes );
            }
    }

    return( f );

}

/***********************************************/
/* Font auf Proportionalität prüfen            */
/***********************************************/
int QPropFont( int v_handle, int id )
{
    char    string[2]; 
    int     i,
            minADE, 
            maxADE,
            extent1[8], 
            extent2[8],
            _void[5];

    string[1] = 0;

    if( id == -1 ) 
        return( 0 );

    vst_font( v_handle, id );

    /* Erstes und letztes ASCII-Zeichen ermitteln */ 
    vqt_fontinfo( v_handle, &minADE, &maxADE,
                  _void, &_void[0], _void ); 
    minADE = ( (minADE < 1) ? 1 : minADE );

    for( i = minADE; i < maxADE-1; i++ )
    {
        /* Ausmaß des ersten Strings ermitteln */ 
        string[0] = i;
        vqt_extent( v_handle, string, extent1 );

        /* Ausmaß des zweiten Strings ermitteln */ 
        string[0] = i+1;
        vqt_extent( v_handle, string, extent2 );

        /* Ausmaße vergleichen */ 
        if( memcmp( extent1, extent2, 16L ) ) 
            break;
    }

    return( (i==maxADE-1) ? 0 : 1 );
}

/***********************************************/
/* Den Systemfont setzen                       */
/***********************************************/
int SetSysFont( int v_handle, 
                int *ch_width, 
                int *ch_height, 
                int *cell_width, 
                int *cell_height )
{
    int size = 0, 
        cboxw, 
        cboxh, 
        chwidth, 
        chheight, 
        cellwidth, 
        cellheight, 
        dummy;

    /* Systemfont setzen */ 
    vst_font( v_handle, 1 );

    /* Standardzellenbreite und -höhe ermitteln */ 
    graf_handle( &cboxw, &cboxh, &dummy, &dummy );

    /* annähern */ 
    do 
    {
        ++size;
        vst_point ( v_handle, size,
                    &dummy, &dummy,
                    &cellwidth, &cellheight );
    }
    while( cellheight <= cboxh && cellwidth <= cboxw );

    /* setzen */
    size = vst_point( v_handle, --size,
                      &chwidth, &chheight, 
                      &cellwidth, &cellheight );

    /* Parameter zurückliefern? */ 
    if( ch_width )
        *ch_width = chwidth; 
    if( ch_height )
        *ch_height = chheight; 
    if( cell_width )
        *cell_width = cellwidth; 
    if( cell_height )
        *cell_height = cellheight;
    
    return( size );
}

#ifndef _INITFONT

# define _INITFONT

typedef struct
{
    int chw, 
        chh, 
        zw, 
        zh,
        point;
} SIZESTRCT;

typedef struct
{
    int         id,
                sizes; 
    char        name[34];
    SIZESTRCT   *size;
} FONTSTRCT;

FONTSTRCT *InitFonts( int v_handle, int *fonts );

int QPropFont( int v_handle, int id );

int SetSysFont( int v_handle, 
                int *ch_width, 
                int *ch_height, 
                int *cell_width, 
                int *cell_height );

#endif
/***********************************************/
/* Modul : EXITFONT */
/* Aufgabe: Speicher der Fonts abmelden */
/***********************************************/

#include <tos.h>
#include <vdi.h>
#include "initfont.h"

#include "exitfont.h"

void ExitFonts( int v_handle, FONTSTRCT *f )
{
    if ( vq_gdos() )
        vst_unload_fonts( v_handle, 0 );

    Mfree( f );
}

#ifndef _EXITFONT

# define _EXITFONT

# include "initfont.h"

void ExitFonts( int v_handle, FONTSTRCT *f ); 

#endif
/***********************************************/
/* Modul  : UTILITY                            */
/***********************************************/

#include <string.h>
#include "utility.h"

void Swap( int *a, int *b )
{
    int c;

    c  = *a;
    *a = *b;
    *b = c;
}

/***********************************************/
/* Leerzeichen am Anfang und Ende des          */
/* Strings löschen                             */
/***********************************************/
char *DeleteSpace( char *str )
{
    char *ptr,
         *oldbeg;

    oldbeg = str;

    /* Leerzeichen am Anfang überspringen */ 
    while( *str == ' ' )
        ++str;

    /* Das Nullzeichen zum Anfang hin verschieben */ 
    ptr = &str[strlen( str ) - 1]; 
    if( strlen( str ) )
        while( *ptr == ' ' )
        {
            *ptr = 0;
            --ptr;
        }

    /* Den String an der alten Adresse beginnen lassen */ 
    memmove( oldbeg, str, strlen( str ) + 1 );


    return( oldbeg );
}

#ifndef _UTILITY

# define _UTILITY

void Swap( int *a, int *b );

char *DeleteSpace ( char *str );

#endif

#include <aes.h>
#include <ext.h>
#include <stdio.h>
#include <vdi.h>

#include "initfont.h"
#include "initvwk.h"
#include "exitfont.h"
#include "exitvwk.h"

static void CheckStry( int v_handle, 
                       int zh, 
                       int *stry, 
                       int *clip,
                       GRECT *Work );

int main( void )
{
    char        str[100];
    int         i, j,
                v_handle,
                pw,
                ph,
                sw,
                sh,
                syschw,
                syschh,
                syszw,
                syszh,
                planes,
                fonts,
                handle,
                stry,
                clip[4],
                _void;
    GRECT       def, work;
    FONTSTRCT   *f;

    /* Bei den AES anmelden */ 
    if( appl_init() < 0 ) 
        return( -1 );

    /* Ein Fenster anlegen */
    wind_get( 0, WF_WORKXYWH, &def.g_x, &def.g_y,
                              &def.g_w, &def.g_h );

    def.g_x += 4; 
    def.g_y += 4; 
    def.g_w -= 8; 
    def.g_h -= 8;

    handle = wind_create( NAME|CLOSER,
                          def.g_x, def.g_y, 
                          def.g_w, def.g_h );

    if( handle < 0 )
    {
        appl_exit(); 
        return( -1 );
    }
    wind_set( handle, WF_NAME, " VDI-Fonts " );

    /* Bildschirmworkstation öffnen */ 
    if( !InitVWork( &v_handle, &pw, &ph, &sw, &sh, 0L, 0L, &planes ) )
    {
        appl_exit(); 
        return( -1 );
    }

    /* Fonts initialisieren */ 
    f = InitFonts( v_handle, &fonts ); 
    if( !f )
    {
        ExitWork( v_handle );
        appl_exit(); 
        return( -1 );
    }

    /* Fenster öffnen */
    if( !wind_open( handle, def.g_x, def.g_y,
                            def.g_w, def.g_h ) )
    {
        ExitFonts( v_handle, f );
        ExitvWork( v_handle );
        appl_exit(); 
        return( -1 );
    }

    /* Ausgabe */
    wind_calc( WC_WORK, NAME|CLOSER,
               def.g_x, def.g_y, def.g_w, def.g_h, 
               &work.g_x, &work.g_y,
               &work.g_w, &work.g_h );

    clip[0] = work.g_x;
    clip[1] = work.g_y;
    clip[2] = work.g_x + work.g_w - 1;
    clip[3] = work.g_y + work.g_h - 1;

    vsf_interior( v_handle, FIS_HOLLOW ); 
    vswr_mode( v_handle, MD_REPLACE );

    vs_clip( v_handle, 1, clip ); 
    graf_mouse( M_OFF, 0L );

    /* Die Fontnamen, die ID und alle möglichen 
       Größen ausgeben. Dabei immer den 
       entsprechenden Font und die entspr.
       Größe setzen */ 
    for( i = 0; i < fonts; i++ )
    {
        /* weißer Hintergrund */ 
        vr_recfl( v_handle, clip ) ;

        stry = work.g_y + f[i].size[0].zh;

        /* Fontnamen und ID ausgeben */ 
        vst_font( v_handle, f[i].id ); 
        vst_point( v_handle, f[i].size[0].point,
                   &_void, &_void, &_void, &_void );

        sprintf( str, "Der %d. Font heißt \"%s\"" \
                      " und hat die ID %d.", 
                      i+1, f[i].name, f[i].id ); 
        v_gtext( v_handle, work.g_x, stry, str );

        for( j = 0; j < f[i].sizes; j++ )
        {
            /* Eine Kostprobe des Fonts in der Größe */
            vst_point( v_handle, f[i].size[j].point, 
                       &_void, &_void, 
                       &_void, &_void );

            CheckStry( v_handle, f[i].size[j].zh, 
                       &stry, clip, &work ); 
            sprintf( str,
                "So sieht er in %d Point Größe aus.", 
                f[i].size[j].point ); 
            v_gtext( v_handle, work.g_x + 10, stry, str );

            /* Die Ausmaße von Zeichen und Zelle ausgeben */
            CheckStry( v_handle, f[i].size[j].zh, &stry, clip, &work ); 
            sprintf( str, "Zeichenbreite: %d", f[i].size[j].chw ); 
            v_gtext( v_handle, work.g_x + 20, stry, str );

            CheckStry( v_handle, f[i].size[j].zh, &stry, clip, &work ); 
            sprintf( str, "Zeichenhöhe  : %d", f[i].size[j].chh ); 
            v_gtext( v_handle, work.g_x + 20, stry, str );

            CheckStry( v_handle, f[i].size[j].zh, &stry, clip, &work ); 
            sprintf( str, "Zellenbreite : %d", f[i].size[j].zw ); 
            v_gtext( v_handle, work.g_x + 20, stry, str );

            CheckStry( v_handle, f[i].size[j].zh, &stry, clip, &work ); 
            sprintf( str, "Zellenhöhe   : %d", f[i].size[j].zh ); 
            v_gtext( v_handle, work.g_x + 20, stry, str );
        }

        getch();
    }

    /* Noch etwas über den Systemfont */ 
    vr_recfl ( v_handle, clip );
    SetSysFont( v_handle, &syschw, &syschh, &syszw, &syszh ); 
    stry = work.g_y + syszh;

    sprintf( str, "Das ist der Systemfont." ); 
    v_gtext( v_handle, work.g_x, stry, str );

    CheckStry( v_handle, syszh, &stry, clip, &work );
    sprintf( str, "Zeichenbreite: %d   " \ 
                  "Zeichenhöhe: %d", 
             syschw, syschh ); 
    v_gtext( v_handle, work.g_x, stry, str );

    CheckStry( v_handle, syszh, &stry, clip, &work ); 
    sprintf( str, "Zellenbreite: %d " \ 
                  "Zellenhöhe: %d", 
             syszw, syszh ); 
    v_gtext( v_handle, work.g_x, stry, str );

    /* und noch etwas über das System */ 
    CheckStry( v_handle, syszh, &stry, clip, &work ); 
    sprintf( str,
        "Pixelbreite / -höhe in " \
        "tausendstel Millimetern; %d / %d", 
        pw, ph );
    v_gtext( v_handle, work.g_x, stry, str );

    CheckStry( v_handle, syszh, &stry, clip, &work ); 
    sprintf( str,
        "Bildschirmbreite / -höhe in Pixeln: " \ 
        "%d / %d", sw, sh ); 
    v_gtext( v_handle, work.g_x, stry, str );

    CheckStry( v_handle, syszh,
               &stry, clip, &work ); 
    sprintf( str,
        "Anzahl der Planes: %d", planes ); 
    v_gtext( v_handle, work.g_x, stry, str );

    getch();

    /* fertig */ 
    graf_mouse( M_ON, 0L ); 
    vs_clip( v_handle, 0, clip );

    /* alles abmelden */
    ExitFonts( v_handle, f );
    ExitVWork( v_handle ); 
    appl_exit();

    return( 0 );
}

void CheckStry( int v_handle, 
                int zh, 
                int *stry, 
                int *clip,
                GRECT *work )
{
    if( *stry >= work->g_y + work->g_h )
    {
        *stry = work->g_y + zh; 
        getch();
        vr_recfl( v_handle, clip );
    }
    else
        *stry += zh;
}
VDIDEMO.APP

=

PCSTART.O

DEMO.C 

EXITFONT.C 

EXITVWK.C 

INITFONT.C 

INITVWK.C 

UTILITY.C

PCSTDLIB.LIB

PCEXTLIB.LIB 
PCTOSLIB.LIB

Marc René Gardeya
Aus: ST-Computer 10 / 1993, Seite 94

Links

Copyright-Bestimmungen: siehe Über diese Seite