Bewegung auf dem Schreibtisch

Joachim Plasa

Als ich ein kleines Progrämmchen schreiben wollte, das mit eigenem Desktop arbeitet, brauchte ich eine Routine, die all den schönen Icons auf dem Desk Bewegung verschafft. Ich schaute in meine Bücher und diverse Computerzeitschriften und stellte fest, daß zwar über GEM im allgemeinen viel geboten wird, aber herzlich wenig darüber, wie ich die Icons zu behandeln hätte. Dazu muß ich sagen, daß ich gerne Buchwissen nutze, weil eben nicht alles zum zweiten Mal erfunden werden muß.

Selbst ist der Mann, also, es galt: An den Computer setzen, eigene Routine schreiben und anderen Leuten zur Verfügung stellen, weil es eben außer den Profis noch Laien gibt, die - wie z.B. meine Wenigkeit - gerne Hilfe in Anspruch nehmen.

Nach reiflicher Überlegung, beschloß ich, ein kleines Demoprogramm zu schreiben, das zwei Fliegen mit einer Klappe schlägt: Die Routine wird damit vorgestellt und zugleich ihre Benutzung und Wirkung gezeigt.

Bevor wir zum Wesentlichen kommen, ein paar Sätze über das Programm selbst. Geschrieben ist es in C und kompiliert mit dem Megamax-Compiler. Im Initialisierungsteil sind die Resource-Daten eingebunden. Die Resource-Datei wurde mit dem RCS von Digital Resaerch entworfen. Ich habe sie im Urzustand belassen, damit jeder nachvollziehen kann, wie sie als solche aus-sieht. Schauen Sie sich mal das RS_OBJECT-Array an: Da sind zwei Objekte abgelegt, nämlich ein Objekt vom Typ G_BOX, das die DESKTOPFLÄCHE darstellt, und ein G_ICON, also das ICON selbst. Daraus folgt, daß unser ATARI-Schreibtisch nichts anderes ist als ein ‘normaler’ GEM-Baum, in den die Desktopsymbole integriert sind. Das Schöne dabei: Wird so ein Baum beim GEM als DESK angemeldet, muß sich der Anwender um dessen Verwaltung nicht kümmern. Papa (Mama!?) GEM erledigt es allein.

Auf die Einzelheiten will ich nicht eingehen. Erstens kenne ich nicht alle, und zweitens tut es in diesem Zusammenhang nichts zur Sache.

Über eins dürfen Sie sich allerdings wundern: Seit wann kennt der Megamax C-Compiler die Bezeichner WORD, LONG usw.? Kennt er gar nicht! Der Preprozessor redefiniert sie. Die DEFINES dazu befinden sich in der PORTAB.H-Datei. Danach folgen die für GEM üblichen globalen Variablen. Die deklarierten Funktionen RCS_TREE_INIT und RCS_TREE_ADDR finden Sie in der Datei TREEINIT.C. Dieses Modul muß unbedingt dazugelinkt werden, da es die internen Resource-Zeiger setzt und die Adressen der Objekte liefert. Da dieses Modul für sich alleine ein Thema ist, werde ich darüber zu einem späteren Zeitpunkt ein paar Worte verlieren.

Wie die Funktionen benutzt werden, sehen Sie in der MAIN-Funktion. Die Konstanten sind in den Resource-Daten bzw. der Headerdatei definiert. Die Kommentare, die ich hinzugefügt habe, erläutern ihre Bedeutung.

Technisches...

Alle Programme sind nach den Prinzipien der modularen Programmiertechnik erstellt. Um es nicht zu kompliziert zu machen, im folgenden die Schritte:

  1. MOVE_ICON als Quelldatei schreiben und übersetzen. Die Objektdatei ist dann auch für andere Programme nutzbar. Ich habe sie meiner C-Bibliothek hinzugefügt.
  2. Dasselbe mit der Funktion RSC_TREE_INIT und RSC_TREE_ADDR tun (eine Datei).
  3. Beispiel schreiben, übersetzen. Module (1) und (2) dazulinken. Fertig...

Wir kommen der Sache näher...

In der MAIN-Funktion wird die Application angemeldet APPL_INIT, GRAF_HANDLE), die Resource-Zeiger werden mit RCS_TREE_INIT gesetzt und die Adresse des neuen Desktops gesichert (RCS_TREE_ADDR). Nach der Anmeldung des Desktops (DESK_ANMELD) wird in die Funkton EVENTS verzweigt, wo die auftretenden Ereignisse verwaltet werden.

Die Funktion DESK_ANMELD meldet das neue Desktop bei GEM an. Die Zeilen mit dem Kommentar “Icon in die Mitte" haben mit dem Vorgang des Anmeldens nichts zu tun: Sie positionieren nur das Icon auf dem Desktop. Die beigefügten Kommentare machen es überflüssig mehr darüber zu schreiben: Wer sich an das ‘Kochrezept' hält, wird schnell zum Erfolg kommen.

Die Verwaltung aller Ereignisse ist eine aufwendige Aufgabe. In diesem Falle ist es von Bedeutung, sich zu merken, welche Flags und Variablen in der EVNT_MULTI-Funktion gesetzt werden müssen, damit die besagte Funktion überhaupt angesprungen werden kann. Wer darüber mehr wissen möchte, sei auf die Literatur oder Zeitschriften verwiesen.

Damit die Aktion eingeleitet werden kann, müssen entsprechende Ereignisse stattgefunden haben: Es MUSS überhaupt ein Mausereignis aufgetreten sein, und die Maustaste MUSS sich im gedrückten Zustand befinden. Dieses wird in der Abfrage:

if ((event & MU_M1) && clicks == 1 && m_button & 1))

geprüft (Die Klickanzahl ist nicht besonders wichtig). Die Variable CLICKS gibt Auskunft darüber, wieviele Male die Maustaste gedrückt wurde.

Es steht Ihnen frei, zu entscheiden, nach wievielen Klicks die MOVE_ICON-Funktion aufgerufen werden soll. Mit m_button & 1 wird geprüft, ob die linke Maustaste betätigt wurde (dann ist das erste Bit in der Variablen gesetzt). Ist dies der Fall, wird nach dem gewünschten Objekt gesucht (OBJC_FIND). Ist das Objekt gefunden, wird in die BEWEGE_ICON-Funktion verzweigt.

Wir sind beim Thema...

Die Funktion MOVE_ICON wird mit den Parametern:

Diese Daten werden aus den Aufrufen der Funktionen EVNT_MULTI und OBJC_FIND gewonnen.

Zuerst wird festgestellt, ob sich der Mauszeiger über dem Desk befindet (WIND_FIND). Ist das der Fall, liefert die Funktion Null als Ergebnis. Zur Erinnerung: Der Desktop wird wie ein Fenster geführt mit window_handle gleich Null. Die Handles 1-7 sind für 'normale' Fenster reserviert. Ist das Ergebnis ungleich Null, wird mit dem Returnwert -1 deutlich gemacht, daß keine Icon-Operation möglich ist. Diese Vorgehensweise ist notwendig, da die Funktion OBJC_FIND auch ein Icon finden kann, das durch ein Fenster bedeckt ist: Der Mauszeiger flattert hin und her.

Liegt kein Fenster über dem Objekt, wird mit WIND_GET und der Option WORKXYWH die Größe der Desktop-Arbeitsfläche festgehalten. Die Parameter werden durch die Funktion GRAF_DRAGBOX gebraucht, um das Viereck festzulegen, in dem das Icon verschoben werden kann. Die GRAF_DRAGBOX wird erst verlassen, wenn die Maustaste wieder losgelassen ist.

Zur Erinnerung: Die Größe der Arbeitsfläche hängt mit der Auflösung des ATARI zusammen. An dieser Stelle muß ich folgendes zugeben: Meiner Ansicht nach müßte die Funktion in jeder Auflösung ihren Dienst verrichten, aber ich habe leider keine Möglichkeit gehabt, dies zu prüfen.

Jetzt wird wieder mit WIND_FIND eine Prüfung vorgenommen: Diesmal wird geprüft, ob der Benutzer versucht hat, das Icon im Fenster abzulegen, das geht nämlich nicht. Da wir nach dem Verschieben keine zwei Icons gebrauchen können, muß das Objekt an der alten Position gelöscht werden.

Das HIDETREE-Flag des Objekts wird gesetzt und dem Desktop mit FORM_DIAL und der Option FMD_FINISH mitgeteilt, daß das Desk an dieser Stelle zu erneuern sei (wenn das kein Trick ist?). Das Setzen des HIDETREE-Flags sorgt dafür, daß beim Zeichnen das Objekt ausgelassen wird.

Die neuen X-/Y-Koordinaten werden jetzt im OBJECT-Array festgehalten, und das Objekt wird an der neuen Position mit dem Status NORMAL gezeichnet. Das Icon erscheint in seiner ganzen Pracht wieder.

Über Bäume...

Jetzt wird es Zeit, mit ein paar Worten auf die Funktionen zum Initialisieren der Resource-Daten einzugehen. In der Quelldatei TREEINIT.C befinden sich die Funktionen RSC_TREE_INIT und RSC_TREE_ADDR. Es stellt sich dabei die Frage: Wozu das Ganze? Zum Zeitpunkt der Erstellung einer RSC-Datei ist ihre zukünftige Lage im Speicher unbekannt, deshalb arbeitet das RCS-Programm mit einem Trick: Anstatt der Adresse wird ein Index gesetzt, der erst zur Laufzeit ersetzt wird. Wenn Sie sich die Daten von unserem Beispiel ansehen, werden Sie feststellen, daß die Zeiger mit ‘komischen' Werten wie 0L, 1L usw. belegt sind.

Die Modifikation übernimmt die RCS_TREE_INIT-Funktion. Wie es gemacht wird, entnehmen Sie bitte der Quelle: Ich habe entsprechend Kommentare gemacht so daß Verstehen und Nachvollziehen keine Schwierigkeiten bereiten sollten. Die Graphik soll Ihnen verdeutlichen, welche Datenstrukturen und Objekte bei der Erstellung benutzt werden. Der Vorteil dieses Verfahrens ist, daß man auf die RSC-Datei verzichten kann: besonders beim Schreiben von Accessories ist das nützlich. Oder hat schon jemand das Kontrollfeld eine RCS-Datei laden sehen?

Die Funktion RSC_TREE_ADDR liefert die Adresse eines Baumes. GEM stellt eine Funktion zur Verfügung, die dasselbe tut. Ich wollte mit diesem Beispiel beweisen, daß nicht alles kompliziert sein muß, obwohl es kompliziert aussieht. Da ich darauf verzichtet habe, die Adressen der Bäume in das RS_TRINIT-Array einzutragen, benutzen Sie unbedingt die Funktion RCS_TREE_ADDR. Diese Funktion gewinnt die Adresse aus dem Index, der in RS_TRINIT eingetragen ist. Bei Verwendung der GEM-Variante kann es eine ‘Bombenstimmung' geben.

Es bleibt noch die Frage, wie man das Diagramm auf der vorherigen Seite benutzt: Nun. Sie suchen sich ein Objekt aus (z.B. G_ICON), gehen entlang der dünnen Linie - soll für ob_spec-Zeiger stehen - und stellen fest, daß der Zeiger ins RS_ICONBLK-Array zeigt. Jetzt gehen Sie nach unten und stellen fest, daß (6), also der IB_PTEXT-Zeiger, ins RS_STRINGS-Array zeigt und (4) und (5), also IB_PMASK- und IB_PDATA-Zeiger ins RS_IM_DOPE-Array zeigen müssen.

Bye, bye...

An dieser Stelle kann ich nur sagen: Das war’s. Ich hoffe, daß dieser Text klar genug ist, um die Arbeitsweise der Funktion zu verstehen. Als Objektmodul kann sie nützlich sein, und sei es nur beim Selektieren von Objekten auf dem Desk. Die Aufrufe OBJ_SELEC bzw. OBJ_NORMAL erledigen es. Die Kommentare, die ich jeder Programmzeile beigefügt habe, sollten das Verstehen der Funktionsarbeitsweise fördern - denke ich mir, oder?

Ich möchte noch darauf hinweisen, daß die DRAW_DESKOBJ-Funktion aus dem Buch von J. & D. Geiss, ”Softwareentwicklung auf dem ST" stammt.

Literatur:

  1. J. & D. Geiss, "Softnareentwicklung auf dem ST", Hüthig-Verlag, 1986
  2. diverse Ausgaben von ST-Computer
/* PORTAB.H- JoPa 87    */
/* Erweiterung          */

#define TRUE 1 
#define FALSE 0 
#define YES 1 
#define NO 0

#define NULLBYTE '\0'
#define BLANK 0x20

#define BYTE char 
#define WORD int 
#define LONG long 
#define boolean unsigned int 
#define void /**/
#define global /**/

/* Headerdatei zur MOVEICON-Datei.by JoPa .
   (C) 1988 Maxon GmbH.                                        */

extern int move_icon();                       /* Icons bewegen */
extern int draw_deskobj():    /* Überlappende Objekte zeichnen */
extern obj_normal();             /* Objekte NORMAL’ darstellen */
extern obj_selec();     /* Objekte SELECTED’ erscheinen lassen */

/**************************************/ 
/*    SAMPLE APPLICATION SKELETON     */
/* mit Beispiel für Icon-Handhabung   */ 
/*      begonnen 5/28/85 R.Z.         */
/*   Copyright ATARI Corp. 1985       */
/**************************************/ 

#include <obdefs.h>
#include <gemde fs.h>
#include <osbind.h>
#include <portab.h>

#define TOOBJ 0 
#define FREEBB 0 
#define FREEIMG 2 
#define FREESTR 1

BYTE *rs_strings[] * {"ATARI ST"};

WORD IMAG0[] = {
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,  0xFFF, 0xFFFF, 0xFFF0,
 0xFFF, 0xFFFF, 0xFFF0,  0xFFF,
0xFFFF, 0xFFF0,  0xFFF, 0xFFFF,
0xFFF0,  0xFFF, 0xFFFF, 0xFFF0,
 0xFFF, 0xFFFF, 0xFFF0,  0xFFF,
0xFFFF, 0xFFF0,  0xFFF, 0xFFFF,
0xFFF0,    0x0,    0x0,   0x0};

WORD IMAG1[] = {
  0xFF, 0xFFFF, 0xFE00,   0xC0,
   0x0,  0x600,   0xC0, 0x7FFF,
0x8600,   0xC0, 0xC000, 0x8600,
  0xC1, 0x4000, 0x8600,   0xC3,
0xC000, 0x8600,   0xC2,    0x0,
0x8600,   0xC2,    0x0, 0x8600,
  0xC2,    0x0, 0x8600,   0xC2,
   0x0, 0x8600,   0xC2,    0x0,
0x8600,   0xC2,    0x0, 0x8600,
  0xC2,    0x0, 0x8600,   0xC2,
   0x0, 0x8600,   0xC2,    0x0,
0x8600,  0xFC3, 0xFFFF, 0x87F0,
 0xC00,    0x0,   0x30,  0xC1C,
0xF9F9, 0x8830,  0xC08, 0x8109,
0x4830,  0xC08, 0x8109, 0x2830,
 0xCIC, 0xF9F9, 0x1830,  0xC00,
   0x0,   0x30,  0xFFF, 0xFFFF,
0xFFF0,    0x0,    0x0,    0x0};

LONG rs_frstr[] = {0};

BITBLK rs_bitblk[] = {0};

LONG rs_frimg[] = {0};

ICONBLK rs_iconblk[] = {0L, 1L, 0L, 4096,0,0,
                        0,0,48,24, 0,24,48,8};

TEDINFO rs_tedinfo[] = {0};

OBJECT rs_object[]= { -1, 1, 1, G_BOX, NONE,
                     NORMAL,0x11111L, 0,0,1093,2830, 
                     0, -1, -1, G_ICON, LASTOB,
                     NORMAL,0x0L,1795,769,6,3} ;

LONG rs_trindex[] ={0L};

struct foobar
{
    WORD    dummy;
    WORD    *image;
} rs_imdope[] = {0, &IMAG0[0],
                 0, &IMAG1[0]};

#define NUM_STRINGS 1
#define NUM_FRSTR   0
#define NUM_IMAGES  2
#define NUM_BB      0       /* Anzahl Bitblocks */
#define NUM_FRIMG   0
#define NUM_IB      1       /* Anzahl Icons */
#define NUM_TI      0       /* Anzahl TEDINFOs */
#define NUM_OBS     2       /* Anzahl von Objekten */
#define NUM_TREE    1

#define TREE1 0             /* TREE */
#define IMAGE 1             /* OBJECT in TREE #0 */

/*================================================*/

#define DESK_W  640 
#define DESK_H  400 
#define DESKTOP 0 
#define HIRES   2 
#define TRUE    1 
#define FALSE   0
#define WI_KIND (SIZER|MOVER|FULLER|CLOSER|NAME)

#define NO_WINDOW (-1)

#define MIN_WIDTH   (2*gl_wbox)
#define MIN_HEIGHT  (3*gl_hbox)

extern int gl_apid;

int gl_hchar;
int gl_wchar;
int gl_wbox;
int gl_hbox;        /* Systemgrößen */

int phys_handle;    /* Physikalisches Workstation-Handle */ 
int handle;         /* Virtuelles Workstation-Handle */ 
int wi_handle;      /* Window-Handle */
int top_window;     /* Handle des oberen Windows */

int x_desk,y_desk,h_desk,w_desk;
int xdesk,ydesk,hdesk,wdesk;
int xold,yold,hold,wold;
int xwork,ywork,hwork,wwork;    /* desktop and work areas */

int msgbuff[8]; /* Ereignis-Puffer */
int keycode;    /* Ergebnis von event_keyboard */ 
int mx,my;      /* mouse x and y pos. */
int butdown;    /* Button-Status */
int ret;        /* Dummy Return-Variable */

int hidden;     /* aktueller Cursorstatus */

int fulled;     /* aktueller Windowstatus */

extern int rcs_tree_init(); /* init Baumstr. */ 
extern OBJECT *rcs_tree_addr(); /* Liefert Adr. eines Baumes */
extern int bewege_icon(); /* DARUM GEHT'S DOCH */ 

OBJECT *desktop;

int contrl[12];     /* GEM Übergabe-Parameter */
int intin[128);
int ptsin[128];
int intout[128];
int ptsout[128];

int work_in[11];    /*Eingabe GSX Parameter-Feld */ 
int work_out[57];   /*Ausgabe GSX Paramter-Feld */ 
int pxyarray[10];   /*Eingabe Punkt-Feld */

hide_mouse()        /* Maus löschen */
{
    if(! hidden){   /* Maus schon gelöscht ? */
        graf_mouse(M_OFF,0x0L); /* Nein, löschen */
        hidden=TRUE;    /* Status 'gelöscht' merken */
    }
}

show_mouse()        /* Maus anzeigen */
{
    if(hidden){     /* Maus gelöscht ? */
        graf_mouse(M_ON,0x0L); /* Ja, anzeigen */ 
        hidden=FALSE;   /* Status nicht gelöscht */
    }
}

open_vwork()        /* Öffnen der Workstation */
{
    int i;
    for(i=0;i<10;work_in[i++]-1);   /* Feld füllen */ 
    work_in[10]=2; 
    handle=phys_handle;
    v_opnvwk(work_in,&handle,work_out); /* Do it */
}

set_clip(x,y,w,h) /* Setzen des Clippings */ 
int x,y,w,h;
{
    int clip[4];
    clip[0]=x;                  /* X */
    clip[1]=y;                  /* Y */
    clip[2]=x+w;                /* Breite */
    clip[3]=y+h;                /* Höhe */
    vs_clip(handle,1,clip);     /* Do it */
}

open_window()   /* Öffnen eines Fensters */
{
    wi_handle=wind_create(WI_KIND,xdesk,ydesk, wdesk,hdesk); 
    wind_set(wi_handle,WF_NAME," IMA SAMPLE”,0,0); 
    graf_growbox(xdesk+wdesk/2,ydesk+hdesk/2, gl_wbox,gl_hbox,xdesk,ydesk,wdesk,hdesk); 
    wind_open(wi_handle,xdesk,ydesk,wdesk,hdesk); 
    wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
}

do_redraw(xc,yc,wc,hc) /* Neuzeichnen */ 
int xc,yc,wc,hc;    /* Clipping des Bereichs */
{
    GRECT 11,12;    /* Rechteck-Struktur */

    hide_mouse();       /* Maus löschen */
    wind_update(TRUE);  /* stoppe GEM-Events */ 
    t2.g_x=xc; 
    t2.g_y=yc; 
    t2.g_w=wc; 
    t2.g_h=hc;
    wind_get(wi_handle,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h); /* Größe ? */ 
    while (t1.g_w && t1.g_h) {
        if (rc_intersect (&t2,&tl) ) { 
            set_clip (t1.g_x, t1.g_y, t1.g_w, t1.g_h); 
            draw_sample();
        }
        wind_get (wi_handle,WF_NEXTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
    }
    wind_update(FALSE); /* starte Events */ 
    show_mouse();
}

main()
{
    appl_init(); /* GEm initialisieren */ 
    phys_handle=graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox); 
    wind_get(0, WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk); 
    open_vwork(); /* Workstation öffnen */ 
    rcs_tree_init(NUM_OBS,NUM_TI,NUM_IB,NUM_BB); 
    desktop = rcs_tree_addr(TREE1); 
    desk_anmeld();

    open_window();      /* Fenster öffnen */
    graf_mouse(ARROW,0x0L); /* Pfeil-Maus */

    hidden=FALSE; 
    fulled=FALSE; 
    butdown=TRUE;

    multi();
}

multi()
{
int event;
int clicks,m_button,icn; 

    do {
        event =evnt_multi(MU_MESAG | MU_BUTTON| MU__KEYBD | MU_M1,
                1,1,1,1,0,0,0,0,0,0,0,0,0, 
                msgbuff,0,0,&mx,&my,&m_button, 
                &ret,&keycode,&clicks);

        wind_update(TRUE);

        if((event & MU_M1) && clicks == 1 && (m_button & 1)) 
            if((icn=objc_find(desktop,TREE1,8,mx,my))>0) 
                move_icon(desktop,icn,mx,my);

        if (event & MU_MESAG) 
            switch (msgbuff[0])
            {
                    case WM_REDRAW:
                        do_redraw(msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]);
                        break;

                    case WM_NEWTOP: 
                    case WM_TOPPED:
                        wind_set(wi_handle,WF_TOP,0,0,0,0); 
                        break;

                    case WM_SIZED: 
                    case WM_MOVED: 
                        if(msgbuff[6]<MIN_WIDTH) msgbuff[6]=MIN_WIDTH; 
                        if(msgbuff[7]<MIN_HEIGHT) msgbuff[7]=MIN_HEIGHT; 
                        wind_set(wi_handle,WF_CURRXYWH, msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]); 
                        wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
                        break;

                    case WM_FULLED:
                        if(fulled) { 
                            wind_calc(WC_WORK,WI_KIND,xold,yold,wold,hold,&xwork,&ywork,&wwork,&hwork); 
                            wind_set(wi_handle,WF_CURRXYWH,xold, yold,wold,hold);
                        }
                        else {
                            wind_calc(WC_B0RDER,WI_KIND,xwork, ywork,wwork,hwork,
                                      &xold,&yold,&wold,&hold); 
                            wind_calc(WC_W0RK,WI_KIND, xdesk,ydesk,wdesk,hdesk,
                                      &xwork,&ywork,&wwork,&hwork); 
                            wind_set(wi_handle,WF_CURRXYWH,xdesk, ydesk,wdesk,hdesk);
                        }
                        fulled ^= TRUE; 
                        break;

            } /* switch (msgbuff[0]) */

        if ((event & MU_BUTTON)&& (wi_handle == top__window) ) 
            if(butdown)
                butdown = FALSE; 
            else butdown = TRUE;

        if(event & MU_KEYBD){
            do_redraw(xwork,ywork,wwork,hwork);
        }

        wind_update(FALSE);

    }while(!((event & MU_MESAG) && (msgbuff[0] = WM_CLOSED)));

    wind_close(wi_handle); 
    graf_shrinkbox(xwork+wwork/2,ywork+hwork/2,gl_wbox,gl_hbox,xwork, ywork,wwork,hwork); 
    wind_delete(wi_handle); 
    v_clsvwk(handle); 
    appl_exit();

}

draw_sample()
{
int temp[4];
    vsf_interior(handle,2); 
    vsf_style(handle,8); 
    vsf_color(handle,0); 
    temp[0]=xwork; 
    temp[1]=ywork; 
    temp[2]=xwork+wwork-1; 
    temp[3]=ywork+hwork-1;
    v_bar(handle,temp); /*innen löschen */
    vsf_interior(handle,4); 
    vsf_color(handle,1); 
    v_ellipse(handle,xwork+wwork2,ywork+hwork/2,wwork/2,hwork,2);
}

/*---------------------------------------------
            — Meldet neues Desk an —
-----------------------------------------------*/
void desk_anmeld()
{

    if( Getrez() != HIRES )
    {
        form_alert(1,"[3][ Nur S/W-Modus...][ok]"); 
        v_clsvwk(handle); 
        appl_exit(); 
        exit(0);
    }
    wind_get(DESKTOP,WF_WORKXYWH,&x_desk,&y_desk,&w_desk,&h_desk); 
    desktop -> ob_width = DESK_W; /* Deskgröße */ 
    desktop -> ob_height = DESK_H;
    desktop[IMAGE].ob_x = 280; /*Icon in die Mitte*/ 
    desktop[IMAGE].ob_y = 160;
    wind_set(DESKTOP,WF_NEWDESK,desktop,0,0); /* Desk bei GEM anmelden und */ 
    form_dial(FMD_FINISH,0,0,0,0,x_desk,y_desk,w_desk,h_desk); /* zeichnen */
}

/************************************************ 
** Produkt : Beispielprogramm fuer das Bewegen **
**           von Icons auf eigenem Desktop     **
** Modul   : BEISPIEL.C                        **
** Prg-Art : GEM-App.                          **
** Quelle/Comp.: Megamax C                     **
-------------------------------------------------
** System      : Atari ST S/W-Modus            **
** Datum       : Mai 1988                      **
** (c)         : 1988 Maxon GmbH               **
-------------------------------------------------
** Autor(en)   : JoPa Stadtalendorf            **
-------------------------------------------------
** Sonst. : RSC-Daten erstellt mit RCS von DR  **
**        : Die eigentlichen Routinen,um die   **
**        : es in diesem Beispiel geht, müßten **
**        : in jeder Auflösung funktionieren.  **
************************************************/

/* INCLUDE FILES */

#include <osbind.h>
#include <gemdefs.h>
#include <obdefs.h>
#include <portab.h> /* Def. von TRUE,FALSE,WORD,LONG usw. */
#include "moveicon.h" /* Funktionsdeklaration */

/*========================= RSC ===============*/

#define TOOBJ   0 
#define FREEBB  0 
#define FREEIMG 2 
#define FREESTR 1

BYTE *rs_strings[] = {"ATARI ST"};

WORD IMAG0[] = {
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,   0xFF, 0xFFFF, 0xFE00,
  0xFF, 0xFFFF, 0xFE00,   0xFF,
0xFFFF, 0xFE00,   0xFF, 0xFFFF,
0xFE00,  0xFFF, 0xFFFF, 0xFFF0,
 0xFFF, 0xFFFF, 0xFFF0,  0xFFF,
0xFFFF, 0xFFF0,  0xFFF, 0xFFFF,
0xFFF0,  0xFFF, 0xFFFF, 0xFFF0,
 0xFFF, 0xFFFF, 0xFFF0,  0xFFF,
0xFFFF, 0xFFF0,  0xFFF, 0xFFFF,
0xFFF0,    0x0,    0x0,    0x0};

W0RD IMAG1[] = {
  0xFF, 0xFFFF, 0xFE00,   0xC0,
   0x0,  0x600,   0xC0, 0x7FFF,
0x8600,   0xC0, 0xC000, 0x8600,
  0xC1, 0x4000, 0x8600,   0xC3,
0xC000, 0x8600,   0xC2,    0x0,
0x8600,   0xC2,    0x0, 0x8600,
  0xC2,    0x0, 0x8600,   0xC2,
   0x0, 0x8600,   0xC2,    0x0,
0x8600,   0xC2,    0x0, 0x8600,
  0xC2,    0x0, 0x8600,   0xC2,
   0x0, 0x8600,   0xC2,    0x0,
0x8600,  0xFC3, 0xFFFF, 0x87F0,
 0xC00,    0x0,   0x30,  0xC1C,
0xF9F9, 0x8830,  0xC08, 0x8109,
0x4830,  0xC08, 0x8109, 0x2830,
 0xC1C, 0xF9F9, 0x1830,  0xC00,
   0x0,   0x30,  0xFFF, 0xFFFF,
0xFFF0,    0x0,    0x0,    0x0};

LONG rs_frstr[] = {0};

BITBLK rs_bitblk[] = {0};

LONG rs_frimg[] = {0};

ICONBLK rs_iconblk[] = {0L, 1L, 0L, 4096,0,0,0, 
                        0,48,24, 0,24,48,8};

TEDINFO rs_tedinfo[] = {0};

OBJECT rs_object[]={ -1,1,1,G_BOX,NONE,NORMAL, 
                     0x11111L, 0,0,1093,2830,
                     0,-1,-1,G_ICON,LASTOB, 
                     NORMAL,0x0L,1795,769,6, 3};

LONG rs_trindex[] = {OL};

struct foobar
{
    WORD    dummy;
    WORD    *image;
} rs_imdope[] = {
                    0, &IMAG0[0],
                    0, &IMAG1[0]};

#define NUM_STRINGS 1
#define NUM_FRSTR   0
#define NUM_IMAGES  2
#define NUM_BB      0 /* Anzahl Bitblocks */
#define NUM_FRIMG   0
#define NUM_IB      1 /* Anzahl Icons */
#define NUM_TI      0 /* Anzahl TEDINFOs */
#define NUM_OBS     2 /* Anzahl von Objekten */
#define NUM_TREE    1

#define TREE1       0 /* TREE */
#define IMAGE       1 /* OBJECT in TREE #0 */

/*=============================================*/

/* DEFINES */

#define DESK_W  640 
#define DESK_H  400 
#define DESKTOP 0 
#define HIRES   2

/* GLOBALS */

int phys_handle, handle; /* Die Variable braucht GEN */ 
int contrl[12],intin[128],intout[128]; 
int ptsout[128],ptsin[128]; 
int work_in[11],work_out[57];

/* APPLICATION */

extern int rcs_tree_init();     /* init Baum */
extern OBJECT *rcs_tree_addr(); /* Liefert Adr. eines Baumes */

int x_desk,y_desk,w_desk,h_desk; /*Koordinaten*/ 
int msgbuf[8]; /* Für evnt_multi() */
OBJECT *desktop; /* Adr. des neuen Desktops */


/*---------------------------------------------
            —    HAUPTFUNKTION    — 
-----------------------------------------------*/

main ()
{
int ret;

    appl_init(); /*Application beim GEN anmelden*/ 
    phys_handle=graf_handle(&ret,&ret,&ret,&ret); /* Handle erfahren */ 
    open_vwork(); /* Workstation öffnen */
    rcs_tree_init(NUM_OBS,NUM_TI,NUM_IB,NUM_BB); /* Baumzeiger setzen */ 
    desktop = rcs_tree_addr(TREE1); /* Adresse des neuen Desktops */ 
    graf_mouse(ARROW,0L);   /* Maus auf Pfeil */
    desk_anmeld();          /* Neuen Desktop anmelden */
    events();               /* Ereignisse verwalten */
} /* main */


/*---------------------------------------------
            — Ereignisse verwalten —
-----------------------------------------------*/
events()
{
    int event,ret;
    int m_x,m_y,clicks,m_button; 
    int icn;

    while(TRUE) {
        event=evnt_multi(MU_BUTTON|MU_M1,1,1,1,1,
                         0,0,0,0,0,0,0,0,0,msgbuf,
                         0,0,&m_x,&m_y,&m_button,
                         &ret,&ret,&clicks); 
        v_gtext(handle,170,40,"Beenden: Icon zwei Mal anklicken");

        if((event & MU_M1) && clicks == 1 && (m_button & 1)) 
            if((icn=objc_find(desktop,TREE1,8,m_x,m_y))>0) 
                move_icon(desktop,icn,m_x,m_y);

        if(clicks==2 && !(m_button&1)) /*Programmstop*/
        {
            v_clsvwk(handle);       /* Station zu */
            appl_exit();            /* bye... */
            exit(0);
        }
    } /* while */
}

/*---------------------------------------------
            — Meldet neues Desk an —
----------------------------------------------*/

void desk_anmeld()
{
    /* Falls jemand Color besitzt, dann diese Zeilen nicht abtippen */ 
    if( Getrez() != HIRES ) /* 640*400 Modus ? */
    {
        form_alert(1,"[3][ Nur S/W-Modus... ][ ok ]"); 
        v_clsvwk(handle); 
        appl_exit(); 
        exit(0);
    }
    /* Für Desk verfügbare Größe feststellen */ 
    wind_get(DESKTOP,WF_WORKXYWH,&x_desk,&y_desk,&w_desk,&h_desk);
    /* Desk: Länge, Höhe neu festlegen, da es im RCS nicht möglich ist */ 
    desktop -> ob_width = DESK_W;   /* Deskgröße */ 
    desktop -> ob_height = DESK_H;  /* Muß nicht sein...Optik */ 
    desktop[IMAGE].ob_x = 280;      /* Icon in die Mitte */
    desktop[IMAGE].ob_y = 160;
    wind_set(DESKTOP,WF_NEWDESK,desktop,0,0); /* Desk bei GEM anmelden und */ 
    form_dial(FMD_FINISH,0,0,0,0, x_desk, y_desk, w_desk, h_desk); /* zeichnen */
}

/*---------------------------------------------
     — Bei GEM-Programmen immer vorhanden —
-----------------------------------------------*/
void open_vwork()
{
    int i;

    for(i=0;i<10;work_in[i++]=1); 
    work_in[10]=2; 
    handle=phys_handle;
    v_opnvwk(work_in,&handle,work_out);
}
/************************************************** 
** Produkt     : Objektmodul für das Bewegen von **
**             : Icons auf eigenem Desktop.      **
** Modul       : MOVEICN1.C / MOVEICN1.O         **
** Prg-Art     : Objektmodul für GEM-Anwendungen **
** Quelle/Comp.: Megamax C                       **
-------------------------
** System       : Atari ST S/W-Modus             **
** Version/Datum: V.1 Mai 1988                   **
** (c)          : MAXON Computer GmbH            **
-------------------------
** Autor(en)    : JoPa Stadtalendorf             **
-------------------------
** Sonstiges: RSC-Daten erstellt mit RCS/DR.     **
**          : Die eigentlichen Routinen,um die   **
**          : es in diesem Beispiel geht, müßten **
**          : in jeder Aufloesung funktionieren. **
**************************************************/

    /* INCLUDE FILES */

    #include <osbind.h>
    #include <gemdefs.h>
    #include <obdefs.h>
    #include <portab.h>     /* Def. von TRUE,FALSE, WORD,LONG usw. */

    int bewege_icon(addr,icon,mx,my)
    OBJECT *addr;               /* Baumadresse */
    int icon;                   /* Objektindex */
    int mx,my;                  /* Mauspos. bei gedrückter taste */
    {
        int mstate,ret;              /* Maus Status */
        int xdesk,ydesk,wdesk,hdesk; /* Arbeitsflaeche */ 
        int eckx,ecky;               /* X,Y - Pos. der Iconumrahmung */

        eckx = mx; ecky = my;        /* An der Mauspos. Suche beginnen */ 
        if( wind_find(eckx,ecky) == 0 ) /*Nur,wenn kein Fenster Icon bedeckt */
        {
            /* Arbeitsflaeche des Fensters erfahren; noetig,um clipping festzulegen */ 
            wind_get(0,WF_WORKXYWH,&xdesk,&ydesk,&wdesk,&hdesk);
            obj_selec(addr,icon);   /* Icon invers */
            graf_dragbox(addr[icon].ob_width,addr[icon].ob_height,addr[icon] .ob_x,addr[icon].ob_y,xdesk,ydesk,wdesk,hdesk,&eckx,&ecky);
        ) else return(-1); /* Icon unter'm Fenster; Fehler melden (-1) */

        if( wind_find(eckx,ecky) >0 ) /* Zielpos. ist nicht Desktop */
        {
            obj_normal(addr,icon); /* Selektion rückgängig machen */ 
            return(-1); /* Fenster ist für Icons Tabu */
        }
        addr[icon].ob_flags |= HIDETREE; /* Icon als versteckt deklarieren */ 
                /* Auf diese Weise wird gelöscht */ 
        form_dial(FMD_FINISH,0,0,0,0,addr[icon].ob_x,addr[icon].ob_y,addr[icon].ob_width, 
                  addr[icon].ob_height); 
        addr[icon].ob_flags &= ~HIDETREE;/* Flag zuruecksetzen */ 
        addr[icon].ob_x = eckx; /* Neue Icon-X-Pos. */ 
        addr[icon].ob_y = ecky; /* Neue Icon-Y-Pos. */ 
        obj_normal(addr,icon);  /* Icon neuzeichnen */
        return(icon); /* Alles OK! Icon als Bestätigung zurueckgeben */
}

/*-------------
    Object invers darstellen
-------------*/
void obj_selec(addr,objekt)
OBJECT *addr; 
int objekt;
{
    addr[objekt].ob_state |= SELECTED; /* SELECTED-Flag setzen */ 
    draw_deskobj(addr,objekt);/* Objekt zeichnen */
}

/*-------------
  Object normal darstellen
-------------*/
void obj_normal(addr,objekt)
OBJECT *addr; 
int objekt;
{
    addr[objekt].ob_state &= ~SELECTED; /* SELECTED-Flag loeschen */ 
    draw_deskobj(addr,objekt);/* Objekt zeichnen */
}

/*-------------------------
Desktop-Objekt zeichnen.
Diese Funktion stammt aus dem Buch von J & D Geiß, 
"Softwareentwicklung auf dem ST", Huethig-Verlag, Heidelberg 1986
---------------------------*/
void draw_deskobj(addr,obj)
OBJECT *addr;                   /* Baumadresse */
int obj;                        /* Objektindex */
{
GRECT t1,t2;                    /* Objektkoordinaten */

    graf_mouse(M_OFF,0L);       /* Maus, mache Pause */
    wind_update(BEG_UPDATE);    /* Benutzer,du auch... darfst pausen */ 
    objc_offset(addr,obj,&t2.g_x,&t2.g_y); /* x,y-Objektkoord. erfahren */ 
    t2.g_w = addr[obj].ob_width; /* Objektlänge */
    t2.g_h = addr[obj].ob_height;/* Objektbreite */ 
    wind_get(0,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h); /* 1.Rechteck*/ 
    while(t1.g_w && t1.g_h) /* Solange Rechtecke in der Liste vorhanden */
    {
        if(rc_intersect(&t2,&t1)) /* Wenn keine Schnittfläche - zeichnen */ 
            objc_draw(addr,obj,MAX_DEPTH,t1.g_x,t1.g_y,t1.g_w,t1.g_h);
        wind_get(0,WF_NEXTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h); /* weiter */
    }
    wind_update(END_UPDATE); /* Erholung beendet */ 
    graf_mouse(M_ON,0L);
}
/************************************************ 
** rsc_tree_bind - Funktion.                   **
** rsc_tree_addr - Funktion.                   **
** RCS-Datei in Programme direkt einbinden.    **
** RSC-Daten : RCS-Programm.                   **
** Compiler  : Megamax C. System:              **
** Autor: JoPa April / Juli '87.               **
** rsc_tree_init(NUM_OBS,NUM_TI,NUM_IB NUM_BB) ** 
** rsc_tree_addr(Baumindex)                    **
***********************************************/

/* INCLUDE FILES */

#include <osbind.h>
#include <gemdefs.h>
#include <obdefs.h>

/* VARIABLE */

extern struct foobar {      /* Definiert in RCS-Binding */
    int dummy; 
    int *image;
} rs_imdope[];

extern OBJECT rs_object[]; 
extern TEDINFO rs_tedinfo[]; 
extern ICONBLK rs_iconblk[]; 
extern BITBLK rs_bitblk[]; 
extern char *rs_strings[]; 
extern long rs_trindex[];

                    /* RSC-DATEN MITEINANDER VERZEIGERN */

int rcs_tree_init(a,b,c,d) 
int a,b,c,d;
{
    int h;       /* Hilfsvariable für diverse Aufgaben */

    /*
    Die Routinen sind universell einsetzbar, soweit das RCS-Binding
    mit dem RCS des Entwicklungspacketes erstellt wurde und nur
    Objekte vom vorgestellten Typ verwendet wurden.

    Das sind die Routinen, um die es bei dieser Aufgabe eigentlich
    geht. Zuerst werden die Koordinaten der Objekte in Graphik
    Koordinaten umgerechnet (sie sind, wegen der Kompatibilität
    geräteunabhängig) und dabei die Verweise in die Arrays,je
    nach Objekt-Typ hergestellt. Welche Objekte in welche Arrays
    zeigen müssen, kann nam dem Programm-Stück leicht entnehmen.
    */
    for(h=0; h<a; h++) {
        rsrc_obfix(rs_object,h); /* Diese Fkt. rechnet die Koord. um */ 
        switch(rs_object[h].ob_type) { 
            case G_STRING: 
            case G_BUTTON: 
            case G_TITLE: 
                rs_object[h].ob_spec = rs_strings[(int)rs_object[h].ob_spec];
                break;
            case G_FTEXT: 
            case G_TEXT: 
            case G_BOXTEXT: 
            case G_FBOXTEXT: 
                rs_object[h].ob_spec = (char *) &rs_tedinfo[(int)rs_object[h].ob_spec]; 
                break;
            case G_ICON:
                rs_object[h].ob_spec = (char *) &rs_iconblk[(int)rs_object[h].ob_spec]; 
                break; 
            case G_IMAGE: 
                rs_object[h].ob_spec = (char *) &rs_bitblk[(int)rs_object[h].ob_spec]; 
                break; 
            default: break;
        }
    }

    /*
    Da wir ein edierbares Feld benutzen,müssen Verweise vom STRING
    Array in das TEDINFO - Array vorgenommen werden. 
    */

    for(h=0; h<b; h++) {
        rs_tedinfo[h].te_ptext  = rs_strings[(int) rs_tedinfo[h].te_ptext]; 
        rs_tedinfo[h].te_ptmplt = rs_strings[(int) rs_tedinfo[h].te_ptmplt]; 
        rs_tedinfo[h].te_pvalid = rs_strings[(int) rs_tedinfo[h].te_pvalid];
    }

    /*
    Hier ist es bischen schwieriger,weil das ICON-Array sowohl mit
    STRING- als auch mit RS_IMDOPE-Array verbunden werden muß,da
    die Icons Beschriftung mit sich schleppen können.( Ist das
    nicht der Fall, dann die Strings im STRING-Array leer ("").
    */

    for(h=0; h<c; h++) { 
        rs_iconblk[h].ib_ptext = rs_strings[(int) rs_iconblk[h].ib_ptext]; 
        rs_iconblk[h].ib_pmask = rs_imdope[(int) rs_iconblk[h].ib_pmask].image; 
        rs_iconblk[h].ib_pdata = rs_imdope[(int) rs_iconblk[h].ib_pdata].image;
    }

    /*
    Der BI_PDATA - Zeiger des BITBLK-Arrays muß mit RS_IMDOPE
    Array verbunden werden.
    */

    for(h=0; h<d; h++) 
        rs_bitblk[h].bi_pdata = rs_imdope[(int) rs_bitblk[h].bi_pdata].image;

    return (0);

} /* Ende rsc_tree_init() */

/*********************************
** Liefert Adresse eines Baumes ** 
*********************************/
OBJECT *rcs_tree_addr(a) 
int a;
{
    return (&rs_object[(int)rs_trindex[a]]);
}

Joachim Plasa
Aus: ST-Computer 03 / 1989, Seite 91

Links

Copyright-Bestimmungen: siehe Über diese Seite