Das Problem der Funktion 'Graf_Dragbox' liegt darin, dass damit nur die Verschiebung eines Objektes dargestellt werden kann. Bei mehreren Objekten ist diese Standardfunktion aber schnell am Ende...
Abhilfe schafft hier NewDrag. Dieses in Turbo-C geschriebene Modul macht es möglich, mehrere Dragboxen gleichzeitig darzustellen. Dabei wird graf_dragbox() allerdings nicht gepatcht, sondern durch eine eigene Funktion ersetzt.
Um die Funktion nachzubilden, muß man zuerst die Funktionsweise von graf_dragbox() verstehen. Diese Funktion sollte dann aufgerufen werden, wenn die linke Maustaste gedrückt ist. Dann wird solange ein Rechteck innerhalb eines bestimmten Bereiches verschoben, bis die Maustaste losgelassen wird. Das Problem liegt weniger in der Abfrage der Maustasten als in der Darstellung des Rechteckes.
Die Grundvorgehensweise ist so: Das Rechteck wird gemalt; danach wartet die Funktion auf eine Mausbewegung oder auf das Loslassen der Maustaste. Jetzt wird das Rechteck an der alten Mausposition mit dem Modus MD_XOR übermalt, und an der neuen Mausposition entsteht das neue Rechteck mit den neuen Koordinaten, sofern die Maustaste nicht losgelassen wurde. Dieser Vorgang wird solange wiederholt, bis die Maustaste losgelassen wird.
Bis jetzt scheint diese Aktion also kein Problem darzustellen. Wenn Sie aber ein Rechteck verschieben, das aus durchgehenden Linien besteht, sieht dies auf grauem Hintergrund sehr gewöhnungsbedürftig aus. Wenn man sich nun das GEM wieder als Vorbild nimmt, entdeckt man schnell ein Verfahren, das dieses Problem schafft. Man ändert ganz einfach den Linientyp in ein Muster, das perfekt in das graue Hintergrundmuster paßt, also ein Muster, in dem abwechselnd
Punkte gesetzt und nicht gesetzt werden. Man errechnet schnell zwei mögliche Muster, die via vsl_udsty() als das aktuelle Linienmuster gesetzt werden können. In dezimaler Schreibweise sind dies 21845 und (int)43690L.
Wer jetzt glaubt, das Problem sei schon gelöst, wird seine Behauptung schnell ad absurdum geführt sehen. Denn jetzt muß man noch unterscheiden, wann welches Muster gewählt werden soll. Die zwei Fälle sieht man in Bild 1. Bei waagerechten Linien muß geprüft werden, ob die y-Koordinate der Linien durch zwei teilbar ist. Bei senkrechten Linien wird der Linientyp in Abhängigkeit davon gewählt, ob x- und y-Koordinate beide durch 2 teilbar sind bzw. beide diese Bedingung nicht erfüllen.
Die Lösung naht nun in den im Listing 1 dargestellten Routinen. Grundlage für alle Routinen ist das modulglobal deklarierte Array rect[], das die Größen der einzelnen Rechtecke enthält. Im Listing hält NewDrag acht solcher Rechtecke bereit; es sollte kein Problem darstellen, diesen Wert zu verändern. Vor dem eigentlichen Verschieben muß der Funktion set_rect() noch die Größe jeden Rechtecks übergeben werden. Dazu übergibt man den Index dieses Rechtecks, der zwischen 0 und der um 1 verringerten Anzahl der Rechtek-ke liegen muß. Danach übergibt man die Koordinaten der einzelnen Rechtecke. Es ist zu beachten, daß als dritter und vierter Wert die Breite und die Höhe übergeben werden.
Danach erfolgt der Aufruf der eigentlichen Funktion move_rect, der man folgende Parameter übergibt:
Noch ein kleiner Tip: Nach der Funktion die Änderung der Koordinaten wie folgt vornehmen:
[alte x-Koordinate] += x_vec;
[alte y-Koordinate] += y_vec;
Nun noch viel Spaß beim Abtippen; auch Benutzer anderer C-Dialekte sollten diese Routinen ohne großen Aufwand nutzen können.
/* drag.h */
void set_rect ( int index, int x, int y, int w, int h );
void move_rect ( int v_handle, int rect_anzahl,
int *result_x, int *result_y, int work_x,
int work_y, int work_w, int work_h );
void draw_boxes ( int v_handle, int anzahl );
/****************************************/
/* DRAG.C : MultipleDragging */
/* von : Markus Hovener, */
/* (c) MAXON Computer 1991 */
/* Datum : 9.1.1991 */
/****************************************/
# include <aes.h>
# include <vdi.h>
# include "drag.h"
/* Die Rechtecke */
static GRECT rect[8] ;
/* Mausparameter & Vektoren */
static int mousex,
mousey,
mousek,
x_vec,
y_yec;
/****************************************/
/* Einträgen */
/****************************************/
void set_rect ( int index, int x, int y, int w, int h )
{
rect[index].g_x = x;
rect[index].g_y = y;
rect[index].g_w = w;
rect[index].g_h = h;
}
/****************************************/
/* Die Hauptroutine */
/****************************************/
void move_rect ( int v_handle, int rect_anzahl,
int *result_x, int *result_y, int work_x,
int work_y, int work_w, int work_h )
{
int i,
big_x = work_w,
big_y = work_h,
big_w = 0,
big_h = 0,
anfang_x,
anfang_y,
_void,
old_x,
old_y;
vswr_mode( v_handle, MD_XOR );
/* Eigener Linientyp */
vsl_type ( v_handle, 7 );
/* Normale Breite */
vsl_width( v_handle, 1 );
/* Großes Rechteck ermitteln */
for ( i=0;i<rect_anzahl;i++ )
{
big_x = ( (rect[i].g_x < big_x ) ? rect[i].g_x : big_x );
big_y = ( (rect[i].g_y < big_y ) ? rect[i] g_y : big_y );
big_w = ( (rect[i].g_x + rect[i].g_w > big_w) ? rect[i].g_x + rect[i].g_w : big_w );
big_h = ( (rect[i].g_y + rect[i].g_h > big_h) ? rect[i].g_y + rect[i].g_h : big_h );
}
/* Mausposition ermitteln */
vq_mouse ( v_handle, &_void, &anfang_x, &anfang_y );
/* Die Hauptschleife */
do
{
vq_mouse ( v_handle, &_void, &old_x, &old_y );
x_vec = old_x - anfang_x;
y_vec = old_y - anfang_y;
if ( big_x + x_vec < work_x )
x_vec = -big_x + work_x;
if ( big_y + y_vec < work_y )
y_vec = -big_y + work_y;
if ( big_w + x_vec > work_w )
x_vec = work_w-big_w;
if ( big_h + y_vec > work_y + work_h )
y_vec = work_h - big_h + work_y;
/* Zum ersten Mal malen */
draw_boxes( v_handle, rect_anzahl );
do
{
/* Warten .. */
vq_mouse ( v_handle, &mousek, &mousex, &mousey );
}
while ( (old_x = mousex) && (old_y == mousey) && (mousek!= 0) );
/* Zum zweiten Mal */
draw_boxes( v_handle, rect_anzahl );
}
while ( mousek != 0 );
/* End-Vektor berechnen */
*result_x = x_vec;
*result_y = y_vec;
/* Alter Modus */
vswr_mode( v_handle, MD_REPLACE );
vsl_type ( v_handle, 1 );
}
/****************************************/
/* Das Malen der Boxen */
/****************************************/
void draw_boxes ( int v_handle, int anzahl )
{
int i,
xy[4];
/* Maus hidden */
graf_mouse ( M_OFF, 0L );
for ( i=0; i<anzahl; i++ )
{
xy[0] = xy[2] = rect[i].g_x + x_vec;
xy[1] = rect[i].g_y + y_vec;
xy[3] = rect[i].g_y + rect[i].g_h + y_vec;
vsl_udsty( v_handle,( ( (xy[0]%2) = (xy[1]%2) ) ? 21845 : (int)43690L ) );
v_pline ( v_handle, 2, xy ) ;
xy[0] = xy[2] = rect[i].g_x + rect[x].g_w + x_vec;
vsl_udsty( v_handle,
( ( (xy[0]%2) == (xy[1]%2) )
? 21845
: (int)43690L ) );
v_pline ( v_handle, 2, xy );
xy[0] = rect[x].g_x + x_vec;
xy[2] = rect[x].g_x + rect[x] g_w + x_vec;
xy[l] = xy[3] = rect[x].g_y + y_vec;
vsl_udsty( v_handle,
( ( (xy[1]%2) )
? (int)43690L
: 21845 ) );
v_pline ( v_handle, 2, xy );
xy[1] = xy[3] = rect[i].g_y + rect[i] g_h + y_vec;
vsl_udsty( v_handle,
( ( (xy[1]%2) )
? (int)43690L
: 21845 ) );
v_pline ( v_handle, 2, xy );
}
/* Maus wieder darstellen */
graf_mouse ( M_ON, 0L );
}