PINDIALS: Pinbare Dialoge auf dem ST

Nach normalen und verschiebbaren Dialogen gibt es jetzt auch pinbare Dialoge auf dem ATARI. Diese Dialoge lassen sich auf dem Desktop ablegen und weiterhin benutzen. Neugierig geworden? Na, dann lesen Sie weiter...

Dialogboxen sind ja an sich eine schöne Sache. Aber wenn man oft eine Einstellung ändern möchte, während man in einem Fenster arbeitet, kann das ständige Anwählen des Dialogs schon Nerven kosten. Wie wäre es schön, wenn der Dialog ständig da wäre! Einige Programme legen ja bereits vielbenutzte Kontrollen (Icons, Buttons etc.) auf dem Desktop an, aber dann liegt meist das ganze Desktop voller (momentan nicht benötigter) Knöpfe. Das führt dazu, daß man immer unter den Fenstern nach den Knöpfen suchen muß. Auf anderen fensterorientierten Oberflächen kann man Dialoge, die man ständig im Auge behalten will, irgendwo auf dem Desktop ablegen. Sie sind dann immer griffbereit und liegen genau dort, wo der Anwender sie gerade benötigt. Besonders bei einem Großbildschirm wird dieser Vorteil deutlich.

Um das ganze nahtlos in das Bild von einem aufgeräumten Schreibtisch einzufügen, wird gern die „Pushpin“-Metapher verwendet, was zu deutsch soviel wie „Reißzwecke“ bedeutet. In der linken oberen Ecke des Dialogs befindet sich dazu eine herausgezogene Reißzwecke. Wird diese nicht beachtet, verhält sich der Dialog wie gewohnt und verschwindet bei Anklicken des OK- oder ABBRUCH-Knopfes. Wird die Reißzwecke jedoch angeklickt, kann man den Dialog irgendwo auf dem Desktop ablegen. Dann erscheint der Dialog mit einer eingesteckten Reißzwecke. Nun ist er ständig verfügbar, und die Einstellungen können jederzeit geändert werden. Soll der Dialog wieder verschwinden, wird die Reißzwecke einfach herausgezogen (indem sie angeklickt wird).

Der Nutzen einer solchen Vorgehensweise liegt auf der Hand: Nicht alle Elemente z.B. eines Zeichenprogrammes werden immer und von allen Benutzern gleichzeitig benutzt. Wer gerade malt, möchte gerne mehrere Pinselarten zur Verfügung haben, die verschiedenen Füllmuster würden auf dem Desktop jedoch nur Platz wegnehmen. In diesem Fall würde man den Pinsel-Dialog auf dem Desktop festpinnen, bis er nicht mehr benötigt wird.

De re, ATARI

Das ist ja schön und gut, aber wie soll das auf dem Atari funktionieren? Naheliegend ist es, den Dialog einfach in ein Fenster zu malen und mit jedem Redraw einfach objc_draw() aufzurufen. Jedoch hat der ATARI ST nur max. sieben Fenster zur freien Verfügung. Wenn weitere Fenster durch Accessories belegt werden, sind es sogar weniger. Sollen z.B. vier Dialoge gleichzeitig verwaltet werden, würde das bis zu vier Fenster kosten, und das ist nicht akzeptabel.

Die andere Lösung liegt darin, die Dialoge direkt in das Desktop einzuhängen. Es ist ja bekannterweise möglich, mittels wind_set(0,WF_NEWDESK,...) einen eigenen Objektbaum anstelle des grauen Hintergrundes einzusetzen. Das AES übernimmt sogar die Aufgabe des Redraws für diesen Baum! Es muß nur unterschieden werden, ob ein Mausklick für einen Dialog auf dem Desktop oder für das Programm bestimmt ist. Doch das übernimmt die wind_find()-Funktion. Mit ihrer Hilfe gelangt man an das Handle des obersten Fensters, das sich unter dem Mauszeiger befindet. Liefert sie Null (das Handle des Desktops), so hat der Anwender auf das Desktop geklickt.

objc_find() tut das übrige und liefert uns den Index des Objektes, das angeklickt wurde. Nun wird nur noch die gewünschte Aktion ausgeführt und gegebenenfalls das entsprechende Objekt neu gezeichnet. Dabei ist selbstverständlich die Rechteckliste des Desktops zu beachten, damit kein Fenster übermalt wird! Also einfach im RCS mehrere Dialoge im Desktop-Baum anlegen, und das war’s?

Leider ist das nur die halbe Miete. Denn wir wollen die Dialoge ja auch auf die traditionelle Weise benutzen, d.h. mit der alten objc_draw()/form_do()-Methode. objc_draw() benötigt als Parameter die Wurzel eines Objektbaumes (sprich: des Dialoges); unser Dialog ist jedoch Teilbaum eines größeren Baumes, nämlich des Desktops. Die sauberste Methode ist die, den Teildialog vom Objektbaum des Desktops abzutrennen. Danach stehen zwei unabhängige Objektbäume zur Verfügung. Leider stimmen dann deshalb die Indizes der einzelnen Objekte im Dialogbaum nicht mehr. Wenn jedoch die Indizes der Objekte angepaßt sind, ist der Rest wieder einfach. Am Ende des Dialogs müssen die alten Indizes natürlich wiederhergestellt und der Objektbaum wieder in den Desktop-Baum eingefügt werden, damit das Desktop ihn wieder zeichnen kann. Soll der Dialog nicht auf dem Desktop erscheinen, braucht nur das HIDETREE-Flag gesetzt zu werden.

Damit der Dialog auch auf Dauer vom Desktop-Baum getrennt werden kann, muß ein Zwischenobjekt eingefügt werden, das im Desktop-Baum über dem Dialog liegt (s. Abb. 2). Im Beispielprogramm ist das eine unsichtbare Box, die in Größe und Position exakt mit denen der untergeordneten Dialogbox übereinstimmt. Beim Abtrennen wird hier als Nachfolgeobjekt -1 eingetragen, damit ist der Baum an dieser Stelle zu Ende.

How to do it...

In der Praxis sieht das so aus: im Resource Construction Set wird eine Dialogbox mit grauem Muster und ohne Rand angelegt, das wird unser neues Desktop. In diesem Dialog wird für jeden pinbaren Dialog eine unsichtbare Box (IBOX) angelegt, in die wiederum eine sichtbare Box mit Attribut OUTLINED und Rand gelegt wird. In die linke obere Ecke noch ein BITBLK mit Attribut TOUCHEXIT, und der Rest des Dialogs wird wie gewohnt (und nach eigenem Geschmack) gestaltet (siehe Abb. 2).

Zum Programm

Das Programm verwaltet gleichzeitig zwei Dialoge, die sich auf dem Desktop ablegen lassen. Das Fenster kann Dialoge abdecken, und die verdeckten Elemente lassen sich naturgemäß nicht ansprechen. Wird in der Hauptschleife eine der beiden Dialogboxen angewählt, wird eine der beiden do_dial()-Routinen aufgerufen. Sie trennen mittels cut_tree() den jeweiligen Dialog aus dem Desktop heraus. Der Rest ist eigentlich wieder Standard-GEM-Programmierung, mit Ausnahme der FONTPIN- bzw. TEXTPIN-Objekte. Sie stellen die „ungepinnten“ Reißzwecken dar. Die Routine find_dialpos() sucht dann interaktiv nach einem freien Plätzchen auf dem Desktop. Anschließend wird der Dialog schließlich von add_tree() an der neuen Position wieder im Desktop-Baum eingehängt und ein Redraw gestartet, damit der Dialog auch zu sehen ist.

Wurde der Dialog mit „OK“ verlassen, wird er ebenfalls wieder im Desktop-Baum eingehängt, jedoch an der alten Stelle und mit dem HIDETREE-Attribut, so daß er weiterhin unsichtbar bleibt.

Abb.: 2

Wird nun ein solcher gepinnter Dialog angeklickt, ruft die Hauptschleife click_desktop() auf, die prüft, ob das gewünschte Objekt bekannt ist und die gewünschte Aktion ausführt. Dann wird noch das jeweilige Objekt neu gezeichnet, und voilä, das war’s.

Das Programm ist mit Turbo-C geschrieben, sollte aber auch leicht auf andere C-Compiler zu übertragen sein. Das Prinzip bleibt schließlich das gleiche. Bleibt nur zu hoffen, daß bald viele Programme von der neuen Möglichkeit Gebrauch machen, Dialoge bequem griffbereit auf dem Desktop abzulegen.


PINDIALS.PRG
=               ; list of modules follows...
TCSTART.O       ; startup code
MAIN.C          ; main program and event handling
WINDOW.C        ; window routines
DIALOG.C        ; dialog boxes
PINS.C          ; utility routines
DESKTOP.C       ; handle pinned dialog boxes
TCSTDLIB.LIB    ; standard library
TCGEMLIB.LIB    ; AES and VDI library
/*
 * PINDIALS.H
 */

#define MENU 0      /* TREE */
#define NEWDESK 1   /* TREE */
#define ABOUT 8     /* OBJECT in TREE #0 */
#define QUIT 17     /* OBJECT in TREE #0 */
#define DIAL1 19    /* OBJECT in TREE #0 */
#define DIAL2 20    /* OBJECT in TREE #0 */
#define FONTIBOX 1  /* OBJECT in TREE #1 */
#define FONTBOX 2   /* OBJECT in TREE #1 */
#define FONTOK 3    /* OBJECT in TREE #1 */
#define FPICA 4     /* OBJECT in TREE #1 */
#define FELITE 5    /* OBJECT in TREE #1 */
#define FTIMES 6    /* OBJECT in TREE #1 */
#define FONTPIN 7   /* OBJECT in TREE #1 */
#define TEXTIBOX 9  /* OBJECT in TREE #1 */
#define TEXTBOX 10  /* OBJECT in TREE #1 */
#define TEXTPIN 11  /* OBJECT in TREE #1 */
#define TKURSIV 12  /* OBJECT in TREE #1 */
#define TUNTER 13   /* OBJECT in TREE #1 */
#define TLEICHT 14  /* OBJECT in TREE #1 */
#define TFETT 15    /* OBJECT in TREE #1 */
#define TEXTOK 16   /* OBJECT in TREE #1 */

/*
 * PINDIALS.RSH 
 */

WORD Pin_Unpinned[] = {
    0x0,0x8,0x14,0x14,0x14,0x1ff4,Oxff4,0x14,
    0x14,0x14,0x3008,0x4800,0x4800,0x3000,0x0,
    0x0
    };

WORD Pin_Pinned[] = {
    0,0,0xf8,0x18c,0x202,0x603,0x401,0x401,0x401,
    0x401,0x603,0x202,0x78c,0xcf8,0x1800,0,0,0
    };

BITBLK rs_bitblk[] = {
    (WORD *)Pin_Unpinned, 2, 16, 0, 0, 1,
    (WORD *)Pin_Pinned, 2, 16, 0, 0, 1
};

TEDINFO rs_tedinfo[] = {
"Pica", "", "", 3, 6, 2, 0x1180, 0x0, -1, 5,1,
"Elite", "", "", 3, 6, 2, 0x1180, 0x0, -1, 6,1,
"Times", "", "", 3, 6, 2, 0x1180, 0x0, -1, 6,1,
"kursiv", "", "", 3, 6, 2, 0x1180, 0x0, -1, 7,1,
"unterstrichen", "", "", 3,6,2,0x1180, 0x0,-1,14,1,
"leicht", "", "",  3, 6, 2, 0x1180, 0x0, -1, 7,1,
"fett", "", "",  3, 6, 2, 0x1180, 0x0, -1, 5,1};

OBJECT rs_object[] = {
-1, 1, 6, G_IBOX, NONE, NORMAL,
    0x0L, 0,0, 90,25,
6, 2, 2, G_BOX, NONE, NORMAL,
    0x1100L, 0,0, 90,513,
1, 3, 5, G_IBOX, NONE, NORMAL,
    0x0L, 2,0, 19,769,
4, -1, -1, G_TITLE, NONE, NORMAL,
    (long)" Desk ", 0,0, 6,769,
5, -1, -1, G_TITLE, NONE, NORMAL,
    (long)" Datei ", 6,0, 7,769,
2, -1, -1, G_TITLE, NONE, NORMAL,
    (long)" Text ", 13,0, 6,769,
0, 7, 18, G_IBOX, NONE, NORMAL,
    0x0L, 0,769, 80,19,
16, 8, 15, G_BOX, NONE, NORMAL,
    0xFF1100L, 2,0, 20,8,
9, -1, -1, G_STRING, NONE, NORMAL,
    (long)" Über PINDIALS... ", 0,0, 20,1,
10, -1, -1, G_STRING, NONE, DISABLED,
    (long)”---------------------", 0,1, 20,1,
11, -1, -1, G_STRING, NONE, NORMAL,
    (long)”1", 0.2, 20,1,
12, -1, -1, G_STRING, NONE, NORMAL,
    (long)"2", 0,3, 20,1,
13, -1, -1, G_STRING, NONE, NORMAL,
    (long)"3", 0,4, 20,1,
14, -1, -1, G_STRING, NONE, NORMAL,
    (long)"4", 0,5, 20,1,
15, -1, -1, G_STRING, NONE, NORMAL,
    (long)"5", 0,6, 20,1,
7, -1, -1, G_STRING, NONE, NORMAL,
    (long)"6", 0,7, 20,1,
18, 17, 17, G_BOX, NONE, NORMAL,
    0xFF1100L, 8,0, 13,1,
16, -1, -1, G_STRING, NONE, NORMAL,
    (long)" Ende", 0,0, 13,1,
6, 19, 20, G_BOX, NONE, NORMAL,
    0xFF1100L, 15,0, 15,2,
20, -1, -1, G_STRING, NONE, NORMAL,
    (long)" Font...", 0,0, 15,1,
18, -1, -1, G_STRING, LASTOB, NORMAL,
    (long)" Attribute...", 0,1, 15,1,
-1, 1, 9, G_BOX, NONE, NORMAL,
    0x1141L, 0,0, 1088,2319,
9, 2, 2, G_IBOX, NONE, NORMAL,
    0x11l00L, 1,1, 1557,522,
1, 3, 8, G_BOX, NONE, OUTLINED,
    0x21100L, 1,1, 1043,1544,
4, -1, -1, G_BUTTON, 0x7, NORMAL,
    (long)"OK", 1797,1542. 8,1,
5, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[0] , 770,770, 15,1,
6, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[1], 770,1795, 15,1,
7, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[2], 770,2820, 15,1,
8, -1, -1, G_IMAGE, TOUCHEXIT, NORMAL,
    (long)&rs_bitblk[0], 1280,768, 1797,2817,
2, -1, -1, G_STRING, NONE, NORMAL,
    (long)"Font", 1287,3072, 6,1,
0, 10, 10, G_IBOX, NONE, NORMAL,
    0x11l00L, 1561,3840, 1045,2314,
9, 11, 17, G_BOX, NONE, OUTLINED,
    0x21100L, 1536,2048, 1811,2825,
12, -1, -1, G_IMAGE, TOUCHEXIT, NORMAL,
    (long)&rs_bitblk[1], 1280,768, 1541,2561,
13, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[3], 1026,2050, 15,1,
14, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[4], 1026,2819, 15,1,
15, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[5], 1026,3588, 15,1,
16, -1, -1, G_BOXTEXT, TOUCHEXIT, NORMAL,
    (long)&rs_tedinfo[6], 1026,262, 15,1,
17, -1, -1, G_BUTTON, 0x7, NORMAL,
    (long)"OK”, 262,2823, 8,1,
10, -1, -1, G_STRING, LASTOB, NORMAL,
    (long)"Text", 1031,1, 6,1};

LONG rs_trindex[] = { 0L, 21L };

struct foobar {
    WORD dummy;
    WORD * *image;
} rs_imdope[2];

#define NUM_OBS 39

/*
 * DEFS.H
 * verschiedene Definitionen
 * by Oliver Scholz
 * (c) 1991 MAXON Computer 
 */

#define ABOUT_PRG   "[1][| Pinbare Dialoge | Demonstration | by Oliver Scholz | (c) 1991 MAXON Computer ][ OK ]"
#define APP_NOT_STARTED "[3][| Applikation konnte nicht initialisiert werden!][ Schade ]" 
#define NO_WINDOW   "[3][| Kein Fenster mehr da!][ OK ]"
#define DIAL_eRR    "[2][| Hier kann der Dialog | nicht abgelegt werden! ][ OK ]"

#define DESKTOP     0
#define TRUE        1
#define FALSE       0
#define ELEMENTS    NAME | MOVER | SIZER

/* nützliche Macros */

#define SHOW_MOUSE graf_mouse(M_ON,0L)
#define HIDE_MOUSE graf_mouse(M_OFF,0L)
#define min(a,b) ((a)<(b) ? (a) (b))
#define max(a,b) ((a)>(b) ? (a) (b))

/* Schriftarten */

#define PICA    0
#define ELITE   1
#define TIMES   2

/* globaler Status f. Zeichensatz u. Attribute */

typedef struct
{
    WORD font;
    WORD kursiv;
    WORD fett;
    WORD leicht;
    WORD unterstrichen;
} STATUS;

typedef struct /* Fensterinformationen */
{
    WORD handle;
    WORD x,y,w,h;
} WINDOW;


/*
 * GLOBALS.H
 * globale Variablen für PINDIALS
 * by Oliver Scholz
 * (c) 1991 MAXON Computer 
 */

GLOBAL STATUS status;
GLOBAL WINDOW window;
GLOBAL OBJECT *menu, *newdesk;
GLOBAL OBJECT *fontbox, *textbox;
GLOBAL WORD gl_apid;
GLOBAL WORD vdi_handle;
GLOBAL WORD xres, yres, hchar;
GLOBAL WORD dummy;
GLOBAL BITBLK *pin_pinned, *pin_unpinned; 
GLOBAL WORD font_pmned, text_pinned;

/*
 * MAIN.C
 * "pinbare" Dialogboxen
 * by Oliver Scholz
 * Copyright (c) 1991 MAXON Computer 
 */

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

#include "defs.h"
#lnclude "pindials.h"
#include "pindials.rsh"

#define GLOBAL 
#include "globals.h"

extern VOID do_dial1(VOID);
extern VOID do_dial2(VOID);
extern VOID init_pins(VOID);
extern VOID open_window(VOID);

extern VOID wm_redraw(WORD whandle,WORD wx,
                      WORD wy,WORD ww,WORD wh); 
extern VOID click_desktop(WORD index);

VOID initial_status(VOID);
VOID get_addresses(VOID);
OBJECT *get_traddr(WORD tree_index);
VOID open_vwork(WORD phys_handle);
VOID events(VOID);
WORD menu_selected(WORD *mesg_buff);

VOID main (VOID)
{
    WORD x,y,w,h;
    WORD phys_handle,

    if ((gl_apid=appl_init())<0)
    {
        form_alert(1,APP_NOT_STARTED); 
        exit(-1);
    }

    initial_status(); 
    get_addresses();
    pin_unpinned = (BITBLK *) &rs_bitblk[0]; 
    pin_pinned = (BITBLK *) &rs_bitblk[1]; 
    init_pins();

    phys_handle=graf_handle(&dummy,&hchar,&dummy,&dummy),
    open_vwork(phys_handle); 
    vswr_mode(vdi_handle,MD_REPLACE);
    vsf_style(vdi_handle,19); 
    vsf_perimeter(vdi_handle, TRUE);

    wind_update(BEG_UPDATE);
    HIDE_MOUSE;

    /* eigenes Desktop installieren */

    wind_get(DESKTOP,WF_WORKXYWH,&x,&y,&w,Sh); 
    newdesk[ROOT].ob_width=x+w; 
    newdesk[ROOT].ob_height=h+y; 
    wind_set(DESKTOP,WF_NEWDESK,newdesk,ROOT);
    objc_draw(newdesk,ROOT,MAX_DEPTH,x,y,w,h);

    window.handle=-1;       /* Fenster ist zu */
    menu_bar(menu,TRUE);    /* Menüzeile anzeigen */

    graf_mouse(ARROW,0L);
    SHOW_MOUSE;

    wind_update(END_UPDATE); 

    open_window();
    events();               /* Hauptschleife */

    /* Programm beenden, alle Fenster schließen */ 
    wind_update(BEG_UPDATE);
    HIDE_MOUSE; 
    if (window.handle>=0)
    {
        wind_close(window.handle);
        wind_delete(window.handle);
    }
    menu_bar(menu,FALSE); 
    rsrc_free();
    SHOW_MOUSE;
    wind_update(END_UPDATE);

    v_clsvwk(vdi_handle); 
    appl_exit(); 
    exit(0);
}

/* Voreinstellung für Textattribute */

VOID initial_status(VOID)
{
    status.font = PICA; 
    status.kursiv = FALSE; 
    status.fett = FALSE; 
    status.leicht = FALSE; 
    status.unterstrichen = FALSE;
}

/* Resource-Koordinaten umrechnen und */
/* Adressen der Bäume holen */

VOID get_addresses(VOID)
{
    WORD i;

    for (i=0; i<NUM_OBS; i++) 
        rsrc_obfix(rs_object,i);

    menu=get_traddr(MENU); 
    newdesk=get_traddr(NEWDESK);
}

/* Adresse eines Baumes ermitteln */

OBJECT *get_traddr(WORD tree_index)
{
    WORD i,j;

    for (i=0,j=0; i<=tree_index; i++) 
        while (rs_object[j++].ob_next!=-1);

    return (&rs_object[—-j]);
}

/* Workstation öffnen */

VOID open_vwork(WORD phys_handle)
{
    WORD i;
    static WORD work_in[12]; 
    static WORD work_out[57];

    for (i=1; i<10; i++) 
        work_in[i]=1; 
    work_in[10]=2; 
    vdi_handle=phys_handle;
    v_opnwk(work_in,&vdi_handle,work_out);

    xres=work_out[0]; /* Bildschirmgröße */ 
    yres=work_out[1];
)

/* Hauptschleife Events behandeln */

VOID events(VOID)
{
    WORD exit_flag=FALSE;
    WORD events;
    WORD mesg_buff[8];
    WORD xmouse,ymouse,mbutton, clicks;
    WORD obj_idx;
    WORD click_window;

    do
    {
        events=evnt_multi(MU_MESAG | MU_BUTTON ,
                2, 1, 1,
                dummy, dummy, dummy, dummy, dummy, 
                dummy, dummy, dummy, dummy, dummy, 
                mesg_buff,
                0, 0,
                &xmouse, &ymouse, &mbutton,
                &dummy, &dummy, &clicks);

        wind_update(BEG_UPDATE);

        if (events & MU_BUTTON) 
        {
            HIDE_MOUSE;

            /* in welches Fenster wurde geklickt */ 
            click_window = wind_find(xmouse,ymouse);

            if (click_window == DESKTOP)
            {
                /* welches Objekt wurde angeklickt */ 
                obj_idx=objc_find(newdesk, ROOT,
                                  MAX_DEPTH, 
                                  xmouse,ymouse);

                if ((obj_idx != -1) && (clicks == 1)) 
                    click_desktop(obj_idx);

                /* warten, bis Knopf losgelassen wurde */ 
                evnt_button(1,1,0,&dummy,&dummy,
                            &dummy,&dummy);
            }

            if (click_window = window.handle)
            {
                /* in das Fenster geklickt: nichts tun */
            }
            SHOW_MOUSE;
        }

        if (events & MU_MESAG)
        {
            HIDE_MOUSE;
            switch (mesg_buff[0])
            {
                case MN_SELECTED:
                    exit_flag=menu_selected(mesg_buff); 
                    break;

                case WM_REDRAW:
                    wm_redraw(mesg_buff[3], 
                              mesg_buff[4], 
                              mesg_buff[5], 
                              mesg_buff[6], 
                              mesg_buff[7]);
                    break;

                case WM_MOVED: 
                case WM_SIZED:
                    wind_set(mesg_buff[3],WF_CURRXYWH, 
                             mesg_buff[4],mesg_buff[5], 
                             mesg_buff[6],mesg_buff[7]);
                    break;

                case WM_NEWTOP: 
                case WM_TOPPED:
                    wind_set(mesg_buff[3],WF_TOP);
                    break;
            }
            SHOW_MOUSE;
        }
        wind_update(END_UPDATE);
    }
    while (!exit_flag);
}

/* ausgewählten Menüeintrag auswerten */

WORD menu_selected(WORD *mesg_buff)
{
    switch(mesg_buff[4])
    {
        case QUIT: return(TRUE);

        case ABOUT: form_alert(1,ABOUT_PRG); 
                    break;

        case DIAL1: do_dial1();
                    break;

        case DIAL2: do_dial2();
                    break;

    }

    menu_tnormal(menu,mesg_buff[3],TRUE);
    return(FALSE);
}

/*
 * WINDOW.C
 * by Oliver Scholz
 * Copyright (c) 1991 MAXON 
 */

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

#include "defs.h"

#define GLOBAL extern 
#include "globals.h"

VOID clipping(GRECT *rect,WORD mode);
WORD rc_intersect(GRECT *r1,GRECT *r2);

VOID open_window (VOID)
{
    WORD x,y,w,h;

    wind_get(DESKTOP,WF_WORKXYWH,&x,&y,&w,&h);

    window.handle = wind_create (ELEMENTS,x,y,w,h); 
    if (window.handle >= 0)
    {
        window.x=x; 
        window.y=y; 
        window.w=w;
        window.h=h;

        wind_set(window.handle,WF_NAME,
                 "Pinbare Dialogboxen - Testfenster");

        wind_open(window.handle, window.x, window.y, window.w, window.h);
    }
    else
    {
        form_alert(1,NO_WINDOW);
    }
}

/* Fensterinhalt neuzeichnen */

VOID wm_redraw(WORD whandle,WORD wx,WORD wy,
               WORD ww,WORD wh)
{
    GRECT t1,t2;
    WORD x,y,h,w;
    WORD pxy[4];

    t2.g_x=wx; 
    t2.g_y=wy;
    t2.g_w=ww;
    t2.g_h=wh;

    wind_get(whandle,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,
             &t1.g_w,&t1.g_h); 
    wind_get(whandle, WF_WORKXYWH, &x, &y, &w, &h);

    while (t1.g_w && t1.g_h)
    {
        if (rc_intersect (&t2, &t1))
        {
            clipping(&t1,TRUE);

            /* Rechteck zeichnen */ 
            vsf_interior(vdi_handle,FIS_SOLID); 
            pxy[0]=x; 
            pxy[1]=y; 
            pxy[2]=x+w; pxy[3]=y+h; 
            vsf_color(vdi_handle,0);
            v_bar(vdi_handle, pxy);

            /* Kreis zeichnen */ 
            vsf_color(vdi_handle,1); 
            vsf_interior(vdi_handle,FIS_PATTERN); 
            v_ellipse(vdi_handle,x+w/2,y+h/2,w/2,h/2);
        }
        wind_get(whandle,WF_NEXTXYWH,&t1.g_x,
                 &t1.g_y,
                 &t1.g_w,&t1.g_h),
    }
    clipping(&t1,FALSE);
}


WORD rc_intersect(GRECT *r1,GRECT *r2)
{
    WORD x, y, w, h;

    x=max(r2->g_x,r1->g_x); 
    y=max(r2->g_y,r1->g_y);
    w=min(r2->g_x+r2->g_w,r1->g_x+r1->g_w); 
    h=min(r2->g_y+r2->g_h,r1->g_y+r1->g_h);

    r2->g_x=x;
    r2->g_y=y;
    r2->g_w=w-x;
    r2->g_h=h-y;

    return((w>x) && (h>y));
}

VOID clipping(GRECT *rect,WORD mode)
{
    WORD pxyarray[4];

    pxyarray[0]=rect->g_x;
    pxyarray[1)=rect->g_y;
    pxyarray[2]=rect->g_x+rect->g_w-1;
    pxyarray[3]=rect->g_y+rect->g_h-1;

    vs_clip(vdi_handle,mode,pxyarray);
}

/*
 * DIALOG.C
 * by Oliver Scholz
 * (c) 1991 MAXON Computer 
 */

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

#include "defs.h"
#include "pindials.h"

#define GLOBAL extern 
#include "globals.h"

VOID redo_obj(OBJECT *tree, WORD index,
              WORD rootindex);
VOID init_font(VOID);
VOID init_text(VOID);
VOID toggle_button(WORD *but, WORD object);

extern VOID redraw_desktop(WORD index); 
extern WORD find_dialpos(WORD x,WORD y,WORD w,
                         WORD h, WORD *xret, WORD *yret); 
extern VOID cut_tree(WORD index,
                     OBJECT **subtree,
                     WORD *old_parent); 
extern VOID add_tree(WORD index,
                     OBJECT *subtree,
                     WORD old_parent); 
extern VOID redraw_dt_obj(WORD index);

/* Font-Dialogbox darstellen und abfragen */
VOID do_dial1(VOID)
{
    WORD cx, cy, cw, ch;
    WORD save_parent;
    WORD exitobj;
    WORD xflag;
    WORD xpos, ypos;

    if (font_pinned) 
        return;

    init_font();

    /* Unterbaum abtrennen */
    cut_tree(FONTBOX, &fontbox, &save_parent);

    /* als eigenständigen Dialog behandeln */ 
    form_center(fontbox,&cx,&cy,&cw,&ch); 
    form_dial(FMD_START, cx, cy, cw, ch, cx, cy, cw, ch);

    objc_draw(fontbox,ROOT,MAX_DEPTH,cx,cy,cw,ch);

    xflag = TRUE;

    do {
        SHOW_MOUSE;
        exitobj = form_do(fontbox,0) & 0x7fff; 
        HIDE_MOUSE;

        /* Objektindex korrigieren */ 
        exitobj += FONTBOX;

        /* Pin angeklickt ? */ 
        switch(exitobj)
        {
            case FONTPIN:
                if(find_dialpos(fontbox[ROOT].ob_x, 
                                fontbox[ROOT].ob_y, 
                                fontbox[ROOT].ob_width, 
                                fontbox[ROOT].ob_height, 
                                &xpos,&ypos))
                {
                    form_dial(FMD_FINISH,cx,cy,cw,ch, cx, cy, cw, ch);
                    /* Dialog wieder im Baum einhängen */ 
                    add_tree(FONTBOX, fontbox, save_parent);

                    /* an neuer Position */ 
                    newdesk[FONTIBOX].ob_x=xpos; 
                    newdesk[FONTIBOX].ob_y=ypos;

                    /* Reißzwecke anzeigen */ 
                    newdesk[FONTPIN].ob_spec.bitblk = pin_pinned;

                    /* ganzen Dialog anzeigen... */ 
                    newdesk[FONTIBOX].ob_flags &= ~HIDETREE;

                    /* .. bis auf OK Knopf */ 
                    newdesk[FONTOK].ob_flags |= HIDETREE;
                    font_jpinned = TRUE;

                    redraw_desktop(FONTIBOX); 
                    return;
                }
                else
                    form_alert(1,DIAL_ERR); 
                break;

            case FONTOK:
                newdesk[FONTOK].ob_state &= ~SELECTED; 
                xflag = FALSE; 
                break;

            case FPICA: 
            case FTIMES: 
            case FELITE:
                switch(status.font)
                {
                    case PICA:
                        newdesk[FPICA].ob_state &= ~SELECTED; 
                        redo_obj(fontbox,FPICA,FONTBOX);
                        break;

                    case TIMES:
                        newdesk[FTIMES].ob_state &= ~SELECTED; 
                        redo_obj(fontbox,FTIMES,FONTBOX);
                        break;

                    case ELITE:
                        newdesk[FELITE].ob_state &= ~SELECTED; 
                        redo_obj(fontbox,FELITE,FONTBOX);
                        break;
                }
                newdesk[exitobj].ob_state |= SELECTED; 
                redo_obj(fontbox,exitobj,FONTBOX);
                switch(exitobj)
                {
                    case FELITE:
                        status.font = ELITE; 
                        break;

                    case FTIMES:
                        status.font = TIMES; 
                        break;

                    case FPICA:
                        status.font = PICA; 
                        break;
                }
                break;
        }

    } while (xflag);

    form_dial(FMD_FINISH, cx, cy, cw, ch,cx,cy,cw,ch); 
    add_tree(FONTBOX, fontbox, save_parent);
}

/* Attribut-Dialogbox darstellen u. abfragen */

VOID do_dial2(VOID)
{
    WORD cx,cy,cw,ch;
    WORD save_parent;
    WORD exitobj;
    WORD xflag;
    WORD xpos, ypos;

    if (text_pinned) 
        return;

    init_text();

    /* Unterbaum abtrennen */
    cut_tree(TEXTBOX, &textbox, &save_parent);

    /* als eigenständigen Dialog behandeln */ 
    form_center(textbox,&cx,&cy,&cw,&ch); 
    form_dial(FMD_START, cx, cy, cw, ch, cx, cy, cw, ch);

    objc_draw(textbox,ROOT,MAX_DEPTH,cx,cy,cw,ch);

    xflag = TRUE;

    do {
        SHOW_MOUSE;
        exitobj = form_do(textbox,0) & 0x7fff; 
        HIDE_MOUSE;

        /* Objektindex korrigieren */ 
        exitobj += TEXTBOX;

        /* Pin angeklickt ? */ 
        switch(exitobj)
        {
            case TEXTPIN:
                if(find_dialpos(textbox[ROOT].ob_x, 
                                textbox[ROOT].ob_y, 
                                textbox[ROOT].ob_width, 
                                textbox[ROOT].ob_height, 
                                &xpos,&ypos))
                {
                    form_dial(FMD_FINISH,cx,cy,cw,ch,cx,cy,cw,ch);

                    /* Dialog wieder im Baum einhängen */ 
                    add_tree(TEXTBOX, textbox, save_parent);

                    /* an neuer Position */ 
                    newdesk[TEXTIBOX].ob_x=xpos; 
                    newdesk[TEXTIBOX].ob_y=ypos;

                    /* Reißzwecke anzeigen */ 
                    newdesk[TEXTPIN].ob_spec.bitblk = pin_pinned;

                    /* ganzen Dialog anzeigen .. */ 
                    newdesk[TEXTIBOX].ob_flags &= ~HIDETREE;

                    /* .. bis auf OK Knopf */
                    newdesk[TEXTOK].ob_flags | = HIDETREE;

                    text_pmned = TRUE;

                    redraw_desktop(TEXTIBOX); 
                    return;
                }
                else
                    form_alert(1,DIAL_ERR); 
                break;

            case TEXTOK:
                newdesk[TEXTOK].ob_state &= ~SELECTED; 
                xflag = FALSE; 
                break;

            case TKURSIV:
                toggle_button(&status.kursiv, exitobj); 
                break;

            case TUNTER:
                toggle_button(&status.unterstrichen, exitobj);
                break;

            case TLEICHT:
                toggle_button(&status.leicht, exitobj);
                break;

            case TFETT:
                toggle_button(&status.fett, exitobj);
                break;
        }
    } while (xflag);

    form_dial(FMD_FINISH,cx,cy,cw,ch,cx,cy,cw,ch); 
    add_tree(TEXTBOX, textbox, save_parent);
}

/* Pinbare Dialoge initialisieren */

VOID init_pins(VOID)
{
    /* Pmnbare Dialoge entpinnen, unsichtbar */ 
    newdesk[FONTPIN].ob_spec.bitblk = pin_unpinned; 
    newdesk[FONTIBOX].ob_flags |= HIDETREE; 
    font_pinned = FALSE;

    newdesk[TEXTPIN].ob_spec.bitblk = pin_unpinned; 
    newdesk[TEXTIBOX].ob_flags |= HIDETREE; 
    text_pinned = FALSE;

    /* IBox und Dialogbox deckungsgleich machen */ 
    newdesk[FONTIBOX].ob_width= newdesk[FONTBOX].ob_width; 
    newdesk[FONTIBOX].ob_height= newdesk[FONTBOX].ob_height; 
    newdesk[FONTBOX].ob_x=0; 
    newdesk[FONTBOX].ob_y=0;

    newdesk[TEXTIBOX].ob_width= newdesk[TEXTBOX].ob_width; 
    newdesk[TEXTIBOX].ob_height= newdesk[TEXTBOX].ob_height; 
    newdesk[TEXTBOX].ob_x=0; 
    newdesk[TEXTBOX].ob_y=0;
}

/* Font Dialogbox initialisieren */

VOID init_font(VOID)
{
    WORD objtable[3] = { FPICA, FELITE, FTIMES };
    WORD i;

    for (i=0; i<3; i++)
        newdesk[objtable[i]].ob_state &= ~SELECTED;

    switch{status.font)
    {
        case PICA:
            newdesk[FPICA].ob_state |= SELECTED; 
            break;

        case ELITE:
            newdesk[FELITE].ob_state |= SELECTED; 
            break;

        case TIMES:
            newdesk[FTIMES].ob_state |= SELECTED; 
            break;
    }
}

/* Text-Dialogbox initialisieren */

VOID init_text(VOID)
{
    if(status.kursiv)
        newdesk[TKURSIV].ob_state |= SELECTED; 
    else
        newdesk[TKURSIV].ob_state &= ~SELECTED;

    if(status.unterstrichen) 
        newdesk[TUNTER].ob_state |= SELECTED; 
    else
        newdesk[TUNTER].ob_state &= ~SELECTED;

    if(status.leicht) 
        newdesk[TLEICHT].ob_state |= SELECTED; 
    else
        newdesk[TLEICHT].ob_state &= ~SELECTED;

    if(status.fett) 
        newdesk[TFETT].ob_state |= SELECTED; 
    else
        newdesk[TFETT].ob_state &= ~SELECTED;
}

/* Objekt im Baum neuzeichnen */

VOID redo_obj(OBJECT *tree, WORD index, WORD rootindex)
{
    WORD x,y,w,h;

    objc_offset(tree,index-rootindex, &x, &y); 
    w = newdesk[index].ob_width; 
    h = newdesk[index].ob_height; 
    objc_draw(tree,ROOT,MAX_DEPTH,x,y,w,h);
}

/* Knopf umschalten, entsprechende */
/* Variable umsetzen und neuzeichnen */

VOID toggle_button(WORD *but, WORD object)
{
    if (*but)
    {
        *but = FALSE;
        newdesk[object].ob_state &= ~SELECTED;
    }
    else
    {
        *but = TRUE;
        newdesk[object].ob_state |= SELECTED;
    }
    redo_obj(textbox,object,TEXTBOX);
}

/*
 * PINS.C
 * Hilfsroutinen für pinbare Dialogboxen
 * by Oliver Scholz
 * (c) 1991 MAXON Computer 
 */

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

#include "defs.h"
#include "pindials.h"

#define GLOBAL extern 
#include "globals.h"

extern WORD rc_intersect(GRECT *r1,GRECT *r2);

VOID node_add(WORD node, WORD index);
WORD intersect(WORD index, GRECT »pos);
VOID redraw_dt_grect(WORD index, GRECT *t2);
VOID get_grect(WORD index, GRECT *t);
VOID enlarge_grect(GRECT *t);

WORD find_dialpos(WORD x, WORD y, WORD w, WORD h, WORD *xret, WORD *yret)
{
    GRECT pos;
    WORD xpos, ypos;

    SHOW_MOUSE;
    graf_mouse(FLAT_HAND,0L);
    /* Rahmen laßt sich aus Desktop rausschieben, 
       bis auf die linke, obere 16x16 Pixel Ecke */ 
    graf_dragbox(w,h,x,y,0,hchar+3,xres+w-16,yres-hchar-3+h-16,&xpos,&ypos); 
    graf_mouse(ARROW,0L);
    HIDE_MOUSE;

    *xret = xpos; *yret = ypos;

    pos.g_x = xpos; /* GRECT für diesen Dialog */ 
    pos.g_y = ypos; 
    pos.g_w = w; 
    pos.g_h = h;

    if(font_pinned) /* mit gepinnten schneiden */
        if(intersect(FONTIBOX, &pos)) 
            return(FALSE);

    if(text_pinned)
        if(intersect(TEXTIBOX, &pos)) 
            return(FALSE);

    return(TRUE);
}

WORD intersect (WORD index, GRECT *pos)
{
    GRECT box, ppos;

    box.g_x = newdesk[index].ob_x; 
    box.g_y = newdesk[index].ob_y; 
    box.g_w = newdesk[index].ob_width; 
    box g_h = newdesk[index].ob_height;

    ppos.g_x = pos->g_x; 
    ppos.g_y = pos->g_y; 
    ppos.g_w = pos->g_w; 
    ppos.g_h = pos->g_h; 
    return(rc_intersect(&box, &ppos));
}

VOID cut_tree (WORD index, OBJECT **subtree, WORD *old_parent)
{
    WORD last;
    WORD this;

    /* Adresse des neuen Unterbaums eintragen */ 

    *subtree = newdesk+index;

    /* alter Parent */
    *old_parent = newdesk[index].ob_next;

    /* Baum ist jetzt Root... */ 
    newdesk[index].ob_next = -1;

    newdesk[*old_parent].ob_head = newdesk[*old_parent].ob_tail = -1;

    this = index; 
    last = this;

    while(this != -1)
        if (newdesk[this].ob_tail != last)
        {
            last = this;
            this = newdesk[last].ob_head; 
            if (this == -1)
            {
                this = newdesk[last].ob_next; 
                node_add(last, (-1)*index);
            }
        }
        else
        {
            last = this;
            this = newdesk[last].ob_next; 
            node_add(last, (-1)*index);
        }
}

VOID add_tree(WORD index, OBJECT *subtree, WORD old_parent)
{
    WORD last;
    WORD this;

    this = ROOT; 
    last = this;

    while(this != -1)
        if(subtree[this].ob_tail != last)
        {
            last = this;
            this = subtree[last].ob_head; 
            if (this == -1)
            {
                this = subtree[last].ob_next; 
                node_add(last+index, index);
            }
        }
        else
        {
            last = this;
            this = subtree[last].ob_next; 
            node_add(last+index, index);
        }

    /* wieder in alten Baum einhängen */ 
    newdesk[index].ob_next = old_parent; 
    newdesk[old_parent].ob_head = newdesk[old_parent].ob_tail = index;
    /* form_center rückgängig machen... */ 
    newdesk[index].ob_x = newdesk[index].ob_y = 0;
}

VOID node_add(WORD node, WORD index)
{   /* Alle Indices != -1 zurückstellen */
    if (newdesk[node].ob_head != -1)
        newdesk[node].ob_head += index; 
    if (newdesk[node].ob_tail != -1)
        newdesk[node].ob_tail += index; 
    if (newdesk[node].ob_next != -1)
        newdesk[node].ob_next += index;
}

VOID redraw_desktop(WORD index)
{
    GRECT t2;

    get_grect(index,&t2); 
    enlarge_grect(&t2); 
    redraw_dt_grect(index, &t2);
}

VOID get_grect(WORD index, GRECT *t)
{
    WORD x,y;

    objc_offset(newdesk, index, &x, &y); 
    t->g_x = x; 
    t->g_y = y;
    t->g_w=newdesk[index].ob_width; 
    t->g_h=newdesk[index].ob_height;
}

/* GRECT vergrößern fur outlined Dialogboxen */ 
VOID enlarge_grect(GRECT *t)
{
    t->g_x -= 4; /* evt1. Rand.. */
    t->g_y -= 4;

    if (t->g_x < 0)
        t->g_x = 0; 
    if (t->g_y < 0)
        t->g_y = 0;

    t->g_w += 8; 
    t->g_h += 8;
}

/* Desktop ab 'index' im GRECT t2 neuzeichnen */ 
VOID redraw_dt_grect(WORD index, GRECT *t2)
{
    GRECT tl;

    wind_get(DESKTOP,WF_FIRSTXYWH,&t1.g_x,&t1.g_y,
             &t1.g_w,&t1.g_h); 
    while (t1.g_w && t1.g_h)
    {
        if (rc_intersect (t2,&t1) )
            objc_draw(newdesk,index,MAX_DEPTH,t1.g_x,t1.g_y,t1.g_w,t1.g_h); 
            wind_get(DESKTOP,WF_NEXTXYWH,&t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
    }
}

VOID redraw_dt_obj(WORD index)
{
    GRECT t;
    get_grect(index,&t); 
    redraw_dt_grect(ROOT,&t);
}

/*
 * DESKTOP.C
 * Verwaltung der auf dem Desktop
 * gepinnten Dialogboxen
 * by Oliver Scholz
 * Copyright (c) 1991 MAXON Computer 
 */

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

#include "defs.h"
#include "pindials.h"

#define GLOBAL extern 
#include "globals.h"

extern VOID redraw_dt_grect(WORD index, GRECT *t2);
extern VOID get_grect(WORD index, GRECT *t); 
extern VOID enlarge_grect(GRECT *t); 
extern VOID redraw_dt_obj(WORD index);

VOID toggle_dt_button(WORD *but, WORD object);

VOID click_desktop(WORD index)
{
    GRECT t2;

    switch (index)
    {
        case FONTPIN:
            if(*font_pinned) 
                return;

            newdesk[FONTPIN].ob_spec.bitblk = pin_unpinned; 
            newdesk[FONTIBOX].ob_flags |= HIDETREE;
            newdesk[FONTOK].ob_flags &= ~HIDETREE; 
            font_pinned = FALSE;

            get_grect(FONTBOX,&t2); 
            enlarge_grect(&t2); 
            redraw_dt_grect(ROOT, &t2);

            break;

        case TEXTPIN:
            if (!text_pinned) /* Tool Dialog Pin */
                return;

            newdesk[TEXTPIN].ob_spec.bitblk = pin_unpinned; 
            newdesk[TEXTIBOX].ob_flags |=HIDETREE; 
            newdesk[TEXTOK].ob_flags &= ~HIDETREE; 
            text_pinned = FALSE;

            get_grect(TEXTBOX,&t2); 
            enlarge_grect(&t2); 
            redraw_dt_grect(ROOT, &t2);

            break;

        case FPICA: 
        case FELITE: 
        case FTIMES:
            switch(status.font)
            {
                case PICA:
                    newdesk[FPICA].ob_state &= ~SELECTED; 
                    redraw_dt_obj(FPICA); 
                    break;

                case TIMES:
                    newdesk[FTIMES].ob_state &= ~SELECTED; 
                    redraw_dt_obj(FTIMES); 
                    break;

                case ELITE:
                    newdesk[FELITE].ob_state &= ~SELECTED; 
                    redraw_dt_obj(FELITE); 
                    break;
            }
            newdesk[index].ob_state |= SELECTED; 
            redraw_dt_obj(index);

            switch(index)
            {
                case FELITE:
                    status.font = ELITE; 
                    break;

                case FTIMES:
                    status.font = TIMES; 
                    break;

                case FPICA
                    status.font = PICA; 
                    break;
            }
            break;

        case TKURSIV:
            toggle_dt_button(&status.kursiv,index); 
            break;

        case TUNTER:
            toggle_dt_button(&status.unterstrichen, index);
            break;

        case TLEICHT:
            toggle_dt_button(&status.leicht,index); 
            break;

        case TFETT:
            toggle_dt_button(&status fett, index); 
            break;

    }
}

/* Knopf umschalten, entsprechende   */
/* Variable umsetzen und neuzeichnen */

VOID toggle_dt_button(WORD *but, WORD object)
{
    if (*but)
    {
        *but = FALSE;
        newdesk[object].ob_state &= ~SELECTED;
    }
    else
    {
        *but = TRUE;
        newdesk[object].ob_state |= SELECTED;
    }
    redraw_dt_obj(object);
}

Oliver Scholz
Aus: ST-Computer 01 / 1992, Seite 100

Links

Copyright-Bestimmungen: siehe Über diese Seite