#ifndef _EXP_DISPLAY_H_
#define _EXP_DISPLAY_H_ 80

/*
  0504941617 <- last update (yymmddhh'')
     _____________________________________________________________
    /                                                             \
    | Headerfile:   display.h
    \_____________________________________________________________/

    Description:    explib's video display classes
    Refers to:      explib.h
    Included by:    explib.h
    Used by:        everywhere

    Contents:

        PixelDisplay :  totally hardware/graphic adapter dependent class;
                        must be implemented again on each new hardware;
                        provides hardware-independent graphic functions,
                        except coordinates which depent upon graphic adapter.
                        Should NOT be used directly whenever possible!

        VectorDisplay : hardware-independent display with completely virtual
                        coordinate system. derived from PixelDisplay class.

    Known problems:

        WINM_USERGB doesn't work well, the background shows unexpected colors.
        Always use palette (default) for the time being.


    Developers: ID: Name:
    =========== --- -----
                JTH Juergen Thumm
  _____________________________________/VERSION HISTORY\____________________
 /Date_ Version Who What____________________________________________________\
 yymmdd ------- --- ---------------------------------------------------------
 930823 0.800   JTH added this header
 940124             mousepos() added
 940125             readpix, ObjectDisplay, DisplayObj
 940130             loadcol(), drawmode NORMAL2
 940203             PixelDisplay::charsize[]
 940302             AmigaDisplay
 940405             AmDSection cleanup, UpdateCLEntry() commented out

 940908             changed hwfrm[2] definition: defines now valid
                    absolute coordinate frame including right/bottom coords;
                    added hwsize[2] as a replacement for old usages
                    of hwfrm[2]/[3].
 941016             PixelDisplay::cfrm/csize added
 941030             PixelDisplay::readpix now inline
 941111             PixelDisplay::scanline prehitpos added
 941125             PD:: minor fixes, PIXD_MAXDEPTH now 6 with WIN16
 941127             PD::open Initial Palette parameters.
                    Made some more functions inline.
 941209             PD::DrawModes enum now global.
 941216             data types 'cpix' and 'pcol' introduced,
                    changed 'int' into cpix and pcol where needed.
 941217             FrameBuffer::ladr and some more inlining.
 950325             ColorManager for PixelDisplay.
 950326             CMan truecolor mode support w/o color mapping.
 950404             PD::wincolref.
 950408             PD::plotby,unplot.
 950416             PD::lineby,unline.
 951112             PD::backMap.
*/

#   ifndef  _EXPDEF_H_
#   include "expdef.h"
#   endif
#   ifndef  _EXP_LIST_H_
#   include "list.h"
#   endif
#   ifndef  _EXP_FIXES_H_
#   include "fixes.h"
#   endif

#ifdef AMIGA
#   include <intuition/intuition.h>
#   include <exec/memory.h>
#   include <graphics/gfx.h>
#   include <graphics/gfxbase.h>
#   include <graphics/copper.h>
#endif

#ifdef  WIN16
#   ifndef __WINDOWS_H
#       include <windows.h>
#   endif
#endif

//  -------------- MOST BASIC TYPES ---------------

#   define  cpix short  // coordinate in pixel
#   define  pcol short  // palette color

//  ------------------ the "PixelDisplay" class ------------------------
//
//  The "PixelDisplay" class represents the direct interface
//  to system dependent graphics routines.
//  It
//  - is two-dimensional
//  - uses direct hardware coordinates (depends upon the graphic adapter)
//  - !!!!! should usually NOT be used directly !!!!!
//  - is used by the "VectorDisplay" class
//
//  NOTE: if open() fails, DO NOT USE the other functions on the object!

//  ------------------ COLOR MANAGER ---------------------

//  the Color Manager handles an upto 256 color system RGB palette.
//  on construction, all color codes which are to be used later
//  MUST be initialized with an RGB color. later access to higher
//  codes is NOT supported.
//  then, if loadcol(idx,rgb) is called, color manager tries to
//  give color 'idx' an rgb as close as possible to 'rgb'.
//  ColorManager does NOT really modify the system's palette,
//  it just keeps the rgb table.
//  if loadcol() returns with rcode OK, color 'idx' was assigned
//  a system color index which could be queried by sysindexof(idx).
//  you then could select the system color index and paint with it.
//  if loadcol() returns SPECIAL, the system color 'sysindexof(idx)'
//  must first be updated (including RealizePalette), before the
//  changed RGB will be visible.

class   ColorManager
{
 public:
    ColorManager(ushort numberOfStaticColors);
    // under Windows, there are some static colors.
    // if we include them into the bottom of our logical Windows palette,
    // we must tell ColorManager how many there are
    // so his methods sysmaxcols() and sysindexof()
    // will then return adjusted values. Besides that,
    // the number of static colors has no other effect
    // in the ColorManager, as he does not manage them.

    rcode   loadpalette(ushort nInitColors, ushort* initPalette);
    // if there was on old palette, it is completely removed.
    // NOTE that after this call, only colors with
    // indexes 0 to nInitColors-1 could be used!
    // this call does NOT change system colors, it just creates the
    // internal mapping information. you must load the whole system
    // palette yourself after this call.

    rcode   goTrueColor(ushort nInitColors, ushort* pInitPalette);
    // run cman in true color mode without any color mapping.
    // this calls loadpalette().

    rcode   goPalette(ushort nInitColors, ushort* pInitPalette);
    // run cman in palette mode with mapping (default).
    // this calls loadpalette().

    rcode   loadcol(ushort icolor, ushort rgb);
    // load a single color with a(nother) rgb value.
    // returns OK if just internal indices were updated.
    // returns SPECIAL if a complete system palette update is necessary.

    ulong   col16to32(ushort rgb);  // map AMIGA rgb to Windows rgb
    ushort  col32to16(ulong  rgb);  // map Windows rgb to AMIGA rgb
    // NOTE that Windows rgb has stupid byte order Blue,Green,Red
    // and that AMIGA rgb has senseful nibble order Red,Green,Blue.

    ulong   rgb32of(ushort icolor); // get 32bit Windows RGB of this icolor
    ushort  rgb16of(ushort icolor); // get 16bit Amiga RGB of this icolor

    short   colorremain(void);  // no. of free system colors
    // this is always constant in truecolor mode.

    ushort  sysindexof(ushort icolor);  // return system color index
    // this logical color is assigned to
    // DO NOT call this in truecolor mode!

    ushort  sysmaxcols(void);
    // maximum no. of used system colors, important for creation
    // of system's logical palette.
    // DO NOT create a system palette in truecolor mode!

    void    splitrgb(ulong rgb32,  ushort& red, ushort& green, ushort& blue);
    void    splitrgb(ushort rgb16, ushort& red, ushort& green, ushort& blue);

    ushort  sysindexofunused(void);
    // returns Windows logical palette index of 1st not yet used color.
    // check colorremain() first before calling this! 

 private:

    void    reset(void);    // complete (re)init, drop palette (if any)

    bool    truecol;        // true color mode y/n

    // this maps pixdisplay to system color indexes
    uchar   map_pdsys[256];

    // this maps system color index to system RGB value
    ulong   sysrgb[256];

    // upto so many system colors supported (palette mode)
    const   ushort SYSMAXCOLS;

    // index of next free system color, if any
    ushort  isysfree;
    // if that's == SYSMAXCOLS, there are no free colors remaining
    // valid indexes range from 0 to isysfree-1,
    // if isysfree >0

    ulong   colordiff(ulong rgb1, ulong rgb2);

    ushort  nstatcols;
    // number of not-managed static colors
};

inline void ColorManager::splitrgb(ulong rgb, ushort& r,ushort& g,ushort& b)
{
    // split stupid order Windows RGB
    b = (rgb >> 16) & 0xFFU;
    g = (rgb >>  8) & 0xFFU;
    r = (rgb      ) & 0xFFU;
}

inline void ColorManager::splitrgb(ushort rgb, ushort& r,ushort& g,ushort& b)
{
    // split senseful order Amiga RGB
    r = (rgb >> 8) & 0xFU;
    g = (rgb >> 4) & 0xFU;
    b = (rgb     ) & 0xFU;
}

//  ------------------ FRAME BUFFER ----------------------

#ifdef  WIN16

class FrameBuffer {

    ulong   virtwidth;  // virtual width (iwidth is more important)
    ulong   height;

    ulong   iwidth; // internal width on power-of-2 boundary
    ulong   iwmask; // width mask = iwidth - 1
    uchar   iwbits; // iwidth = 2 ^ iwbits

    uchar   HUGE *mem;

    //  --- direct pixel line adress access ---

    uchar   FAR  *ladr[1024];   // MUST be a power of 2 !
    const   ushort  iadrmsk;    // ladr[] index size - 1

    //  --- ---

    rcode   checkbnd(cpix x, cpix y);

  public:

    FrameBuffer() : iadrmsk(sizeof(ladr) / sizeof(uchar FAR *) - 1)

        {   virtwidth=height=0; iwidth=0;iwbits=0; mem=0;   }

    bool    valid() {return mem ? 1 : 0;}

    rcode   open(cpix width, cpix height);
    void    close();

    void    clear(pcol withcol=0);

    //  put/get DO NOT CHECK the coordinates, they just make sure
    //  no memory crash occurs by masking them.

    void    put(cpix x, cpix y, pcol c)
            {
              *(ladr[(ushort)y & iadrmsk] + ((ushort)x & iwmask)) = (uchar)c;
            }

    pcol    get(cpix x, cpix y)
            {
              return *(ladr[(ushort)y & iadrmsk] + ((ushort)x & iwmask));
            }

    pcol    getold(cpix x, cpix y); // redundant get for surveillance

    rcode   rectfill(cpix x1, cpix y1, cpix x2, cpix y2, pcol col);

friend class Shape;
    };

#endif

//||PixelDisplay

enum PIXD_Options {

    PIXD_NIL        = 0,    // no special options
    PIXD_DOUBLEBUF  = 1,    // for animations
    PIXD_NOHIRES    = 2,    // force no-hires for screens with width  >= 640
    PIXD_NOLACE     = 4,    // force no-lace  for screens with height >= 400

    };  // current options

enum PIXD_DrawModes {

    NORMAL=0,   // overlapping texts aaa and bbb are both visible
    NORMAL2,    // bbb overwrites aaa (aaa invisible)
    INVERSE     // bbb inverts some pixel of aaa

    };

class PixelDisplay {

    friend class PixelDisplayDA;    // direct access class

 protected:

#ifdef  AMIGA
    Screen      *scr;
    Window      *win;
    RastPort    *rport;
    ViewPort    *vport;

    struct  {
        Screen      *scr;
        Window      *win;
        RastPort    *rport;
        ViewPort    *vport;
        }   other,tmp;
        // if DOUBLEBUFFERED, this is the other display
        // 'tmp' is used by db_swap()

    void db_swap(); // swap the two display's control variables
    // this will NOT swap the sequence in which they're displayed!
#endif

#ifdef  AMIGA
#   define  PIXD_MAXDEPTH   5
#else
#   define  PIXD_MAXDEPTH   7
#endif

#   define  PIXD_MAXCOLORS  (1<<PIXD_MAXDEPTH)
#   define  PIXD_COLMASK    (PIXD_MAXCOLORS-1)

    ColorManager cman;  // PixDisp-to-System color mapping

    COLORREF vpal[256]; // for truecolor mode

    static  ushort DefPalette[32];  // default palette

 public:

    rcode   goTrueColor(ushort nInitColors=0, ushort* pInitPalette=0);
    // run PD in true color mode without any color mapping.
    // DO NOT call this on a non-open display!

    rcode   goPalette(ushort nInitColors=0, ushort* pInitPalette=0);
    // run PD in palette mode with mapping (default).
    // DO NOT call this on a non-open display!

    HPALETTE logpal()   { return hlogpal; }

 protected:

    void    killPalette(void);
    // this deletes hlogpal and horgpal, if set.
    // DO NOT access these (in)directly after this!
    // call goPalette() before you do any palette stuff again.

#ifdef  WIN16

    HWND        win;    // window handle

    // the following two are opened
    // at open() and closed at close().

    PAINTSTRUCT ps;
    HDC         hdcfront;   // screen device context
    HDC         hdcback;    // backgrnd context, if any
    HDC         hdccur;     // current context (front or back)
    HBITMAP     hbmpback;   // background, if any

    FrameBuffer fbuf;

    // palette stuff

    HPALETTE    hlogpal,horgpal,horgbackpal;

#   define  WINM_TRUECOLOR      1   // don't use system palette
//# define  WINM_SETPIXRGB      2   // SetPixel(): use RGB
#   define  WINM_SETPIXSWAPRB   4   // SetPixel(): swap red/blue
//# define  WINM_SWAPRB         8   // all: swap red/blue

    ushort  winmodes;

    cpix cpos[2];   // cursor pos'n after move()

#endif

    cpix hwfrm[4];  // current hardware coordinate frame

    //  [0] =  lowest valid x-coordinate (left)
    //  [1] =  lowest valid y-coordinate (top)
    //  [2] = highest valid x-coordinate (right)
    //  [3] = highest valid y-coordinate (bottom)

    cpix hwsize[2]; // current hardware coordinate sizes

    //  [0] =  width in pixel
    //  [1] = height in pixel

    short   ncol;       // current no. of colors available

    pcol    col;        // current color
    pcol    ibackcol;   // current background color
    short   cdrawmode;  // current drawmode

    rcode check()   // checks if display opened. If NOT, returns FAILED
    {
#ifdef  AMIGA
        if(rport)   return OK;
#endif

#ifdef  WIN16
        if(fbuf.valid())    return OK;
#endif
        return FAILED;
    }

    bool frozen;    // used in DOUBLEBUFFERED mode: set if frozen

    cpix imousepos[2];  // internal current mouse position in pixels

#ifdef  AMIGA
    struct {

        ulong mclass;   // last message's class
        uword  mcode;   // last message's code

        } lmsg; // last message (set e.g. after testbutton())

    IntuiMessage* scanMsg(Window* win,ulong mclass);
    // testbutton() subfunction
#endif

    ulong   copt;   // current option settings

 public:

    PixelDisplay();
    ~PixelDisplay();

    // open display, returns OK if success.

    rcode open(
                cpix width=640, cpix height=512, ushort depth=2,

                ulong options = PIXD_NIL,

                ushort  InitNColors  = 0,   // no. of colors in
                ushort  *InitPalette = 0    // this initial palette
                //  NOTE: InitNColors MUST be a power of 2,
                //        and of course <= 1 << depth !
              );

    void    close();    // close display

    void    clear();    // clear whole display area

    inline  rcode color(pcol pen);  // set (front) pen color
    inline  rcode backcol(pcol pen);    // set background color

    rcode checkbnd(cpix x, cpix y)  // returns OK if coord is valid
        {
            if(     x < hwfrm[0] || x > hwfrm[2]
                ||  y < hwfrm[1] || y > hwfrm[3]    )

                return FAILED;

            return OK;
        }

    inline  rcode move(cpix x, cpix y);         // set absolute cursor position

    rcode   plot(cpix x, cpix y, pcol col=-1);  // set single pixel
    rcode plotby(cpix x, cpix y, pcol col);     // ", bypassing framebuffer
    //  MUST specify color code with plotby - current color is NOT changed
    //  by this call!
    rcode unplot(cpix x, cpix y);   // unplot pixel set with plotby()

    //  return color of a pixel
    pcol readpix(cpix x, cpix y)    // returns -1 if coord is out of bounds
        {
#           ifdef   AMIGA
            return  ReadPixel(rport, x, y);
#           endif

#           ifdef   WIN16
            if(checkbnd(x,y))   return -1;

            return  fbuf.get(x,y);
#           endif
        }

    rcode draw(cpix x, cpix y); // draw line from current cursorpos. to newpos.

    rcode line(cpix x1, cpix y1, cpix x2, cpix y2, pcol col=-1);

    // line with framebuffer bypassing, and undo function for it:
    rcode lineby(cpix x1, cpix y1, cpix x2, cpix y2, pcol col=-1);
    rcode unline(cpix x1, cpix y1, cpix x2, cpix y2);

    rcode text(cpix x, cpix y, const char *str);     // prt txt at abs. positn
    rcode text(cpix x, cpix y, char *format, ...); // printf-style text line
    rcode text(const char *str);    // print text at gfx cursor pos.
    rcode text();   // perform a newline

    rcode verttext(const char *str);    // prt vertical text
    rcode verttext(cpix x, cpix y, const char *str);

#ifdef  AMIGA

    rcode testbutton(); // returns OK if mouse button pressed

    rcode waitbutton(); // waits for button to be pressed & then released

    short whichbutton();    // which button(s) were pressed at last
    // test/waitbutton() etc. call? result: 0=none 1=left 2=right 3=both

    void msg(const char *str,...);  // print a one-line message
    // to be used like printf

    // /-if DOUBLEBUFFERED chosen, these funcs are available:
    void freeze();      // freeze currently frontmost display;
    // all subsequent actions are performed on the background display
    // and NOT SHOWN until ...
    void unfreeze();    // ... THIS is called.
    // this simply swaps the two displays. All subsequent drawing actions
    // \-can now be seen 'live' until freeze() is called again.

#endif

    rcode mousepos(cpix pos[2]);    // gimme current mouse position

    void drawmode(PIXD_DrawModes dm = NORMAL);  // set drawing mode

    // Color Palette management:
    // loading color(s) into the video palette

    // load single color with 4-bit(!) RGB values.
    rcode loadcol(pcol num, ushort rgb);    // rgb: e.g. 0xFF0 for yellow

    rcode loadcolors(short ncol, ushort *RGB_palette);
    // load new color palette into display

    rcode rectfill(cpix x1, cpix y1, cpix x2, cpix y2, pcol col=-1);
    // draw filled rectangle; color is optional

    cpix charsize[2];
    // presuming a non-proportional font is used,
    // this gives the horizontal[0] and vertical[1] size of every char.

    pcol scanline(cpix start[2], cpix end[2], pcol forcolors[2],
                  cpix firsthit[2], cpix *prehitpos = 0);
    // this scans all pixels from start[] to end[] if they're >= forcolors[0]
    // and <= forcolors[1]. if so, the pixel color is returned and firsthit[]
    // contains the position of that pixel.
    // if illegal coords are reached (e.g. end[] out of display bounds),
    // or if no matching colors are found, -1 is returned.
    // if line has just one pixel -1 is always returned.
    // if prehitpos is given, position of pixel BEFORE match is stored there.
    // (this is same as firsthit if 1st pix is match). prehitpos is cpix[2].

    cpix cfrm(uchar x)  {   return hwfrm[x & 3];    }
    // coordinate frame info
    //  (0) = lowest x  (1) = lowest y  (2) = highest x (3) = highest y

    cpix csize(uchar x) {   return hwsize[x & 1];   }
    // coordinate size info
    //  (0) = usable width  (1) = usable height in pixels

#ifdef WIN16
    COLORREF WinCol(pcol c);    // returns native Windows color

    COLORREF wincolref(pcol c)  // native Windows color ref for pd color
        {   return WinCol(c);   }

    HBITMAP getbackmap(void)
        {   return hbmpback;    }

    HDC getfronthdc(void)       {   return hdcfront;    }
    HDC getbackhdc(void)        {   return hdcback;     }
    HDC getcurhdc(void)         {   return hdccur;      }

    rcode   allocBackMap    (void); // allocate backgrnd bitmap
    void    freeBackMap     (void); // free     "        "
    rcode   copyToBackMap   (void); // copy foreground into backgrnd
    rcode   copyFromBackMap (void); // copy backgrnd into foreground
    // with a backMap, overlayed RShape displaying will be improved.
    rcode   transRect       (cpix x1,cpix y1,cpix x2,cpix y2,short toback=0);
    // transfer-blit rectangle between fore- and background.
    // if 'toback' is not specified as non-zero, copies from back to front,
    // else copies from front to back
    rcode   transPix        (cpix x,cpix y,short toback=0);
    // same as transRect for a single pixel
    rcode   setLevel        (short frontBack);
    // frontBack == 0: all subsequent drawings go to front level,
    //                 hdccur returns fronthdc.
    // frontBack == 1: all subsequent drawings go to backmap,
    //                 hdccur returns backhdc.
#endif

    rcode   setUnusedSystemColorsTo(ushort rgb);
    // sets all colors in the Windows palette which are not yet used
    // to this rgb value. this is of use when drawing in xor-mode.
    // this will do nothing if there are no free system colors remaining.

friend class Shape;
    };

//|| PixDA

class PixelDisplayDA {
        PixelDisplay* pd;   // this accessor's display instance
    public:
        PixelDisplayDA(PixelDisplay* xpd)   {   pd = xpd;   }
        ~PixelDisplayDA()   {   pd = 0; }
#ifdef  WIN16
        ushort SetWinMode(uchar x);
        ushort ClrWinMode(uchar x);
#endif
    };

//  ---------------------- EO_PixelDisplay -----------------------------

//||VectorDisplay

class VectorDisplay : public PixelDisplay {

 protected:

    int hwfrm[4];   // hardware coordinate frame
    // [0]=xmin [1]=ymin [2]=width [3]=height

    int infrm[4];   // input coordinate frame
    // see hwfrm

    int vhdiv[2];
    // divide virtual width[0]/height[1] by (this/100)
    // to get hw width/height

    struct {
        int h[2];   // hw coords
        int v[2];   //  v coords
        } cs;   // graphics cursor

    rcode cin(int x, int y, int frm[4]);
    // 'coordinate in ...' function: checks if (x,y) is in the
    // frame 'frm'. Returns OK if so.

    rcode xform(int virt_x, int virt_y, int &hw_x, int &hw_y);
    // transform virtual coords into hw coords
    // RC: if non-zero, given coords were illegal.

    rcode xback(int hx, int hy, int &vx, int &vy);
    // transform hw coords into virtual coords
    // RC as xform

    rcode xbacksize(int hx, int hy, int &vx, int &vy);
    // transform hw size (e.g. 8x8 pixels) into virtual coord's size
    // RC: non-zero if resulting size is > DisplaySize

 public:

    VectorDisplay(
        int v_left=0, int v_top=0, int v_width=32767, int v_height=32767,
        int hw_left=0, int hw_top=0, int hw_width=640, int hw_height=400
        );

    rcode SetDimensions(
        int v_left=0, int v_top=0, int v_width=32767, int v_height=32767,
        int hw_left=-1, int hw_top=-1, int hw_width=-1, int hw_height=-1
        );
    // \ -1 means if the value is not supplied, old value will be used

    rcode move(int vx, int vy); // set absolute cursor position

    rcode plot(int vx, int vy, int col=-1); // set single pixel
    // \ graphics cursor position stays unaffected

    // the following implies of course that 'vector display'
    // has a PixelDisplay underlying:
    int readpix(int vx, int vy);
    // \ return color of pixel on this coordinates
    // \ graphics cursor position stays unaffected

    rcode draw(int vx, int vy); // draw line from curr. cursorpos. to newpos.

    rcode line(int x1, int y1, int x2, int y2, int col=-1); // draw a line

    rcode text(int vx, int vy, const char *str);    // prt txt at abs. posn

    rcode verttext(int vx, int vy, const char *str);
    // print vertical text, parms like 'text'

    rcode mousepos(int pos[2]); // current mouse position in virtual coords
    };

// ------------------ StructView declaration --------------------------
/*
//|| StrucVDec

#define ALE &errno  // "adress list end" marker

class StructView {

    int dispcbnd[2];    // display coordinate boundaries

    const int maxdep=5; // max. no of dependencies between two objects

    const int maxlevels=30; // max. no of levels (used only by solve())

    enum dtype {horiz, vert};

    enum {no=0, yes=1} solved;

    class Obj : public ListNode {

      public:

        char *id;   // id string
        void *adr;  // object's adress

        void *dep[maxdep];          // pointers to other objects
        enum dtype deptype[maxdep]; // type of those pointers
        uchar solved[maxdep];       // was reference solved during
        // the solve pass, i.e. if this is 0 there was no matching 'Obj'
        // found, so user forgot to add some objects.
        int ndep;   // number of dependent objects in table

        uchar orgdepn[maxdep];
        // the dependency 'depo[x]' had during the 'addobj' call
        // this number in the user-supplied parameter list.
        // this is for understandable error messages.

        Obj()   {ndep=0;}

        int x,y;    // display virtual coordinates

        Obj *depo[maxdep];  // adresses of the 'obj' instances
        // of the dependent objects. backtracked on display() call.
        int ndepo;
        // no. of adresses entered in depo[]. should usually be == ndep
        int depocnt[maxdep];
        // how MANY dependencies are between this Obj and depo[x]?

        int level;  // after PASS1, every object has it's level.
        // the objects standing topmost in the graphic have level 0.

        uchar corrupt;
        // if TRUE: during solve(), it was encountered that this object
        // has open dependencies which can't be solved.
        // the object will then be drawn in an extra color.

        uchar picposdone;
        // during solve(), as soon as this Obj has it's position in
        // the picture, this is set, so the pos'n won't be changed
        // by backward references from following Obj's

        };

    int nopl[maxlevels];    // number of objects per level
    // after solve(), nopl[x] is the number of objects
    // associated with a level in the graphic.

    ListHead ols;   // list of objects

    class VectorDisplay *vd;

 public:

    rcode addobj(char *id, void *adr, ...);
    // adding an object.
    // Returns OK if success.

    void  remobjlist(); // remove whole object list

    rcode solve();  // compile all open adresses between objects

    rcode open();   // display

    void  close();  // display

    rcode redraw(); // display after another solve() call

    rcode testbutton(); // check if mouse button pressed on display

    rcode waitbutton();

    StructView()    {solved=no; vd=0;}

    ~StructView();

    };
*/
//  ---------------- Object-oriented displaying --------------------

//|| ObjDisply

class DisplayObjList : public ListHead {

 public:

    class DisplayObj* first()
        {   return (class DisplayObj*)ListHead::first();    };

    class DisplayObj* last()
        {   return (class DisplayObj*)ListHead::last();     };

    };

class ObjectDisplay : public VectorDisplay, private DisplayObjList {

 friend class DisplayObj;

    bool isopen;

    int cfsize[2];  // click field size in virtual coords

    static int charsize[2]; // width/height of 1 char in virtual coords

 public:

    ObjectDisplay() {isopen=0;}

    // add a display object to object list
    rcode add(class DisplayObj* dobj);

    rcode redraw(); // redraw all objects whose parent has 'visible' set

    rcode run();    // display as long as not CLOSE clicked

    // determine what object lies under the current mouse position
    DisplayObj* whatobj(int mousepos[2]);

    };

//|| DisplyObj

class DisplayObj : public ListNode, public DisplayObjList {

  friend class ObjectDisplay;

#   define  BACK_COLOR  0
#   define  LINE_COLOR  2   // draw lines between objects with this color

    bool    visible;    // if set, all MEMBERS are visible
    // (root object is always visible)

  public:
    char*   idstr;      // DYNAMIC string with name and some infos
  private:
    int     pos[2];     // virtual position

    DisplayObj* parent; // pointer to parent (0 if none)

    short   walkcnt;    // counts down while walking;
    // as soon as zero, object stops

  public:

    DisplayObj()    {visible=0; parent=0; walkcnt=0;}
    ~DisplayObj()   {if(idstr)  delete [] idstr;}

    rcode   drawya(
                int pos[2],     // draw ya at this position
                int step[2],    // draw your members in this distance to you
                VectorDisplay* vd,  // drawing commands to this display
                bool reallydraw,    // if 0, don't exec drawing commands
                int maxpos[2]   // if your pos>this, adjust this
                );

    DisplayObj* next()  {return (DisplayObj*)ListNode::next();}
    DisplayObj* prev()  {return (DisplayObj*)ListNode::prev();}

    void    add(DisplayObj* newmemb);   // add new member

    // determine if this object lies under the supplied mouse position;
    // if so, enter yourself in 'result' and return OK;
    // otherwise command all your members to check themselves
    rcode   whoisclicked(int mpos[2], int cfsize[2], DisplayObj* &result);
    // cfs is the click field size

    void wind(int maxpos[2]);   // uahh

    void walk(int border[4], int step[2], VectorDisplay* vd);
    // object, walk to free space

    rcode freeplace(int x, int y, int step[2], VectorDisplay* vd);
    // walk'ing sub: check if a position (x,y) has no pixels around
    };

#ifdef  AMIGA
//   _____________________________________________________________
//  /                                                             \
//  |   AMIGA Dynamic Soft-Scroll HyperBitMap Support Display
//  \_____________________________________________________________/

//  Base created 0103942346 in 1 hour 45 min's

//|| AmDSection - Amiga Display Section

class AmDSection : public ListNode {

    /*
    struct HWCL {

        uword*  syshwpos;           // pos'n of our instr's in sys coplst

        const   int MAXPLANES=8;
        uword   instr[MAXPLANES][2][2];
        int     icnt;

        HWCL()  {
                    syshwpos = 0;   // no custom instr's yet in syslist
                    icnt = 0;
                }

        }   hwcl;   // hardware coplist stuff
    */

    inline void EncodeCopInstr(uword src[3], uword dest[2]);
    inline void DecodeCopInstr(uword src[2], uword dest[3]);

 public:

    class AmigaDisplay* disp;   // backward pointer to display

    short   video_x;    // x position on monitor
    short   video_y;    // y position on monitor

    short   mem_x;      // x position in screen memory
    short   mem_y;      // y position in screen memory

    struct  {

        short   vp[2];  // old video pos'n \ to detect
        short   mp[2];  // old mem   pos'n / pos'n changes

        }   old;

    void    CopyNewToOld()
        {
            old.vp[0]=video_x;  old.vp[1]=video_y;
            old.mp[0]=mem_x;    old.mp[1]=mem_y;
        }

    AmDSection(short vx, short vy)
        {
            video_x = vx;
            video_y = vy;
            mem_x   =  0;
            mem_y   =  0;

            CopyNewToOld();
        }

    rcode SetMemPos(short memx, short memy)
        {
            old.mp[0]   = mem_x;
            old.mp[1]   = mem_y;

            mem_x   = memx;
            mem_y   = memy;

            return OK;
        }

    AmDSection* next()  {return (AmDSection*)ListNode::next();}

    /*
    rcode UpdateCLEntry(

        uword** hw_clist_pos,   // start pos'n in hardware copper list
        int     instr_remain,   // so many instructns 'til end of coplist

        Screen* scr

        );  // returns OK if successfully updated
    */

    };

struct AmDSecList : public ListHead {

    AmDSection* first() {return (AmDSection*)ListHead::first();}

    };

//|| AmigaDisplay

class AmigaDisplay : public PixelDisplay {

    DCL_DESTR;  // compiler bug fix

    AmDSecList  secs;

    CopList     clist;  // a copper list
    UCopList    UCL;    // user copper list
    UCopList*   OldUCL; // old user copper list
/*
    uword   *blankvline;    // a blank video line for coplist support
    size_t  bvlsize;        // size of it in bytes
*/

    void    EncodeCopInstr(uword src[3], uword dest[2]);
    void    DecodeCopInstr(uword src[2], uword dest[3]);

 public:

    bool    dead;

    AmigaDisplay();
    ~AmigaDisplay();

    rcode   open(int width=640, int height=512, int depth=2);
    void    close();

    void    AddDSection(AmDSection* sec)
            {   secs.add(sec);  sec->disp = this;   }

    AmDSection* FirstDSection()
            {   return secs.first();}

    rcode   ReDisplay();    // re-calc user copper list
    // after adding or changing AmDSection's of this display,
    // this funtion will make changes visible.

    void    AdjustPositions();
    // this scans the system's hardware copper list directly
    // and replaces the copper instructions for AmigaDisplay's
    // bitplane posn's by the new positions.

    };
#endif  // defined AMIGA

#   endif   // of file
