/*
 *  GUI Designed by : David Ekholm, Datadosen
 */

#include <stdlib.h>     /* atoi() */
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>  /* DrawInfo */
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <gadgets/textfield.h>

#include <intuition/sghooks.h> /* struct SGWork here */
#include <workbench/workbench.h>        /* For AppWindow */
#include <libraries/gadtools.h>
#include <libraries/commodities.h> /* This has a nice qualifier #define */
#include <libraries/iffparse.h>

#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>              /* For my TextAttr struct */
#include <graphics/rastport.h>
#include <utility/hooks.h>              /* For my stringhook */

#include <proto/wb.h>                           /* For AppWindow */
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <string.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/gadtools_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <proto/textfield.h>

#include "dbGUI.h"
#include "db.h"
#include "dbparser.h"
#include "Version.h"


#define TOGGLE_LED *(UBYTE *)0xbfe001 ^= 2

extern Class *TextFieldClass;
extern struct IFFHandle *Iff0;

struct Screen         *Scr = NULL;
struct DrawInfo *DrInfo = NULL;
UWORD *Pens;
APTR                   VisualInfo = NULL;
struct IntuiMessage    DB_Msg;
UWORD                  DB_Zoom[4];
struct Gadget          *LastGad = NULL;
struct Hook                                     MyStrHook;
struct TextAttr       *Font, Attr;
UWORD                  FontX, FontY;
UWORD                  OffX, OffY;
UWORD                  DragKnobWidth, DragKnobHeight;

WORD LastLeftEdge=-1;
WORD LastTopEdge=-1;                                    /* For nice layoutswitching */

/*For gadgetlayout */
UWORD TabSize;

/* For MyStrHookFunc() */
BOOL ReactivateGad = FALSE;
BOOL GadDoubleClicked = FALSE;
struct Gadget *NextGad = NULL;

struct TextAttr UserTextAttr =
{
        NULL, 0, FS_NORMAL, FPF_DISKFONT
};


struct NewMenu DB_NewMenu[] = {
        NM_TITLE, (STRPTR)MSG_PROJECT_MENU , NULL, 0, NULL, NULL,
        NM_ITEM, (STRPTR)MSG_PROJECT_NEW   , NULL, 0, 0L,   (APTR)DB_NEW,
        NM_ITEM, (STRPTR)MSG_PROJECT_OPEN  , NULL, 0, 0L,   (APTR)DB_OPEN,
        NM_ITEM, (STRPTR)MSG_PROJECT_RELOAD, NULL, 0, 0L,   (APTR)DB_RELOAD,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_PROJECT_SAVE   , NULL, 0, 0L,  (APTR)DB_SAVE,
        NM_ITEM, (STRPTR)MSG_PROJECT_SAVE_AS, NULL, 0, 0L,  (APTR)DB_SAVEAS,
        NM_ITEM, (STRPTR)MSG_PROJECT_OUTPUT , NULL, 0, NULL,NULL,
        NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW,
        NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_VIEW_WN, NULL, 0, 0L, (APTR)DB_OUTPUT_VIEW_WN,
        NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_TAB_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_TAB_ASCII,
        NM_SUB, (STRPTR)MSG_PROJECT_OUTPUT_COMMA_ASCII, NULL, 0, 0L, (APTR)DB_OUTPUT_COMMA_ASCII,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_PROJECT_ABOUT, NULL, 0, 0L, (APTR)DB_ABOUT,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_PROJECT_QUIT, NULL, 0, 0L, (APTR)DB_QUIT,
        NM_TITLE, (STRPTR)MSG_EDIT_MENU, NULL, 0, NULL, NULL,
        NM_ITEM, (STRPTR)MSG_EDIT_CUT, NULL, 0, 0L, (APTR)DB_CUT,
        NM_ITEM, (STRPTR)MSG_EDIT_COPY, NULL, 0, 0L, (APTR)DB_COPY,
        NM_ITEM, (STRPTR)MSG_EDIT_PASTE, NULL, 0, 0L, (APTR)DB_PASTE,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_EDIT_ADD, NULL, 0, 0L, (APTR)DB_ADD,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_EDIT_KILL, NULL, 0, 0L, (APTR)DB_KILL,
        NM_TITLE, (STRPTR)MSG_VIEW_MENU, NULL, 0, NULL, NULL,
        NM_TITLE, (STRPTR)MSG_ACTION_MENU, NULL, 0, NULL, NULL,
        NM_ITEM, (STRPTR)MSG_ACTION_FIND, NULL, 0, 0L, (APTR)DB_FIND,
        NM_ITEM, (STRPTR)MSG_ACTION_FIND_NEXT, NULL, 0, 0L, (APTR)DB_FINDNEXT,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_ACTION_SORT, NULL, 0, 0L, (APTR)DB_SORT,
        NM_ITEM, (STRPTR)MSG_ACTION_DIAL, NULL, 0, 0L, (APTR)DB_DIAL,
        NM_ITEM, (STRPTR)MSG_ACTION_BROWSE, NULL, 0, 0L, (APTR)DB_BROWSE,
        NM_TITLE, (STRPTR)MSG_SETTINGS_MENU, NULL, 0, NULL, NULL,
        NM_ITEM, (STRPTR)MSG_SETTINGS_WARNINGS, NULL, CHECKIT|CHECKED|MENUTOGGLE, 0L, (APTR)DB_WARNINGS,
        NM_ITEM, (STRPTR)MSG_SETTINGS_SORTDIR, NULL, 0, NULL, NULL,
        NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_AZ, NULL, CHECKIT|CHECKED, 2L, (APTR)DB_AZ,
        NM_SUB, (STRPTR)MSG_SETTINGS_SORTDIR_ZA, NULL, CHECKIT, 1L, (APTR)DB_ZA,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_ITEM, (STRPTR)MSG_SETTINGS_FIELD_DEFINITION, NULL, NM_ITEMDISABLED, 0L, (APTR)DB_FIELD_DEFINITION,
        NM_ITEM, (STRPTR)MSG_SETTINGS_VIEW_DESIGN, NULL, 0L, 0L, (APTR)DB_VIEW_DESIGN,
        NM_TITLE, (STRPTR)MSG_AREXX_MENU, NULL, 0, NULL, NULL,
        NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX,
        NM_ITEM, (STRPTR)MSG_AREXX_EXECUTE_RELAUNCH, NULL, 0, 0L, (APTR)DB_EXECUTE_AREXX_AGAIN,
        NM_ITEM, (STRPTR)NM_BARLABEL, NULL, 0, 0L, NULL,
        NM_END, NULL, NULL, 0, 0L, NULL };


void LocalizeMenu(struct NewMenu *nm)
{
        /* Replaces the string-indexes in the NewMenu array with localized text */
        /* Gets called once from SetupScreen() */
        UWORD   i=0;

        while (nm[i].nm_Type != NM_END) {
                if (nm[i].nm_Label != NM_BARLABEL) {
                        nm[i].nm_CommKey = GetAppStr((LONG)nm[i].nm_Label);

                        nm[i].nm_Label = nm[i].nm_CommKey+2;
                        if (nm[i].nm_CommKey[0] == ' ') nm[i].nm_CommKey = NULL;
                }
        ++i;
        }
}
/**/
__inline BOOL OkStrGad(struct Gadget *g)
{
        return (BOOL)(g->Flags & GFLG_TABCYCLE && !(g->Flags & GFLG_DISABLED));
}

struct Gadget *PrevStrGad(struct Gadget *Gad, struct Gadget *glist)
{
        /* Returns the previous stringgadget, or NULL if Gad is the first one */

        struct Gadget *strgad = NULL, *g = glist;

        if (g == Gad) return NULL;
        for (; g; g = g->NextGadget) {
                if (OkStrGad(g)) strgad = g;    /* Only return stringgads */
                if (g->NextGadget == Gad) break;
        }
        return strgad;
}

struct Gadget *EndGad(struct Gadget *g)
{
        while (g->NextGadget) g = g->NextGadget;
        return g;
}

struct Gadget *ActivateThisGad(ULONG actions, struct Gadget *current,
 struct Gadget *glist)
{
        /* Takes over the job of deciding which (if any) gadget should be reactivated
         * based upon the SGWork->Actionfield.
         * Without this function, it is impossible to activate other stringgadgets
         * (as responce to an ARexx command) as Intiuition otherwize will have
         * activated some other gadget first if the user cyclesteps thru a gadgetlist.
    */
        struct Gadget *g = NULL;

        if (actions & SGA_NEXTACTIVE) {
                for (g = current->NextGadget;; g = g->NextGadget) {
                        if (!g) g = glist;
                        if (OkStrGad(g)) break;
                }
        }
        else if (actions & SGA_PREVACTIVE) {
                for (g = PrevStrGad(current, glist);; g = PrevStrGad(g, glist)) {
                        if (!g) g = EndGad(glist);
                        if (OkStrGad(g)) break;
                }
        }
        return g;
}


/* Stuff for my stringHook */

ULONG __saveds __asm MyStrHookFunc(register __a0 struct Hook *hook,
                                                                                          register __a2 struct SGWork *sgw,
                                                                                          register __a1 ULONG *msg)
{
        /* This hook does the following modifications to a gadtool stringgadet:
         * Pressing ESC will terminate the gadget without leaving the ESC char.
         * Pressing R-Amiga+Key will terminate the gadget leaving the keycode in
         * the Code field of the GadgetUp IDCMP event that will follow. It will
    * also reuse the inputevent, making Intition select the corresponding menu.
         * Pressing up, down, shift-up or shift-down will navigate between records.
         * It also responds to the keys F1 to F10.
         * Doubleclicking into a stringgadget will invoke a special function
         */

        static ULONG StartSecs=0, StartMicros=0;
        ULONG CurrentSecs, CurrentMicros;
        ULONG return_code = ~0;

        if (*msg == SGH_KEY) {  /* Process some key event */
                if ((sgw->EditOp == EO_REPLACECHAR) || (sgw->EditOp == EO_INSERTCHAR)) {
                        /* sgw->Code is VANILLAKEY, sgw->IEvent->ie_Code is RAWKEY */

                        if (sgw->IEvent->ie_Code == RAW_ESC)    {       /* ESC pressed */
                                sgw->Actions &= ~SGA_USE;       /* ~SGA_BEEP will not prevent beep :-( */
                                sgw->Actions |=  SGA_END;       /* NewEdit does this */
                        }
                        else if (sgw->IEvent->ie_Qualifier &
                         (IEQUALIFIER_RCOMMAND | IEQUALIFIER_LCOMMAND)) {
                                sgw->Actions &= ~SGA_USE;
                                sgw->Actions |=  SGA_END | SGA_REUSE;
/**/                    ReactivateGad = TRUE;
                        }
                }
                else if (sgw->EditOp == EO_ENTER && sgw->Code != RAW_HELP) {
                        if (!(MyArgArray[NORETURNSTEP] ||
                         sgw->IEvent->ie_Qualifier & IXSYM_ALTMASK)) {
                                if (sgw->IEvent->ie_Qualifier & IXSYM_SHIFTMASK) 
                                        sgw->Actions |= SGA_PREVACTIVE;
                                else sgw->Actions |= SGA_NEXTACTIVE;
                        }
                }
                else if (sgw->EditOp == EO_NOOP) {
                        if (sgw->IEvent->ie_Code == RAW_DOWN || sgw->IEvent->ie_Code == RAW_UP) {
                                /* Down or up key pressed */
                                sgw->Actions &= ~SGA_USE;
                                sgw->Actions |=  SGA_END | SGA_REUSE;
                                ReactivateGad = TRUE;
                        }
                        else if (sgw->IEvent->ie_Code == RAW_ESC)       {       /* ESC pressed */
                                sgw->Actions &= ~SGA_USE;       /* ~SGA_BEEP will not prevent beep :-( */
                                sgw->Actions |=  SGA_END;       /* NewEdit does this */
                        }
                        else if (sgw->IEvent->ie_Code >= RAW_F1 && sgw->IEvent->ie_Code <= RAW_F10) {
                                sgw->Actions &= ~SGA_USE;
                                sgw->Actions |=  SGA_END | SGA_REUSE;
                        }
                }
                if (sgw->Actions & SGA_END) {
                        if (NextGad = ActivateThisGad(sgw->Actions, sgw->Gadget,
                         sgw->GadgetInfo->gi_Window->FirstGadget))
                                sgw->Actions &= ~(SGA_PREVACTIVE | SGA_NEXTACTIVE);
                }
        }
        else if (*msg == SGH_CLICK) {                                   /* Process mouse click */
                CurrentSecs = sgw->IEvent->ie_TimeStamp.tv_secs;
                CurrentMicros = sgw->IEvent->ie_TimeStamp.tv_micro;
                
                if (DoubleClick(StartSecs, StartMicros, CurrentSecs, CurrentMicros)
                 && sgw->BufferPos == sgw->StringInfo->BufferPos) {
                        /* Only allow doubleclick if user doubleclicks at the same character */
                        /* to avoid accidental doubleclick if user only wants to position */
                        /* cursor exactly */
                        GadDoubleClicked = TRUE;

                        StartSecs = StartMicros = 0;    /* Prevent "triple clicks" */
                }
                else {
                        StartSecs = CurrentSecs;
                        StartMicros = CurrentMicros;
                }
        }
        else return_code = 0;

        return return_code;
}


void InitHook(struct Hook *hook)
{
        hook->h_Entry = (HOOKFUNC)MyStrHookFunc;
        hook->h_SubEntry = NULL;
        hook->h_Data = 0;
}


int SetupScreen( void )
{
/*
        struct Screen *s;
        if (!Stricmp(MyArgArray[PUBSCREEN] "frontmost")) {
                for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
                        if (s->Flags & PUBLICSCREEN) 
        }
        else {
*/
                if (!(Scr = LockPubScreen((STRPTR)MyArgArray[PUBSCREEN])))
                        if (!(Scr = LockPubScreen(NULL)))       /* Workbench */
                                return( 1L );
/*      } */

        if ( ! ( VisualInfo = GetVisualInfo( Scr, TAG_DONE )))
                return( 2L );

        if ( ! (DrInfo = GetScreenDrawInfo(Scr)))
                return 3L;
        Pens = DrInfo->dri_Pens;


        LocalizeMenu(DB_NewMenu);
        LocalizeMenu(DesignNewMenu);

        InitHook(&MyStrHook);

        return( 0L );
}

void CloseDownScreen( void )
{
        if (DrInfo) FreeScreenDrawInfo(Scr, DrInfo);
        if ( VisualInfo ) {
                FreeVisualInfo( VisualInfo );
                VisualInfo = NULL;
        }

        if ( Scr        ) {
                UnlockPubScreen( NULL, Scr );
                Scr = NULL;
        }
}


int HandleDB_IDCMP(struct Layout *Lay)
{
        struct IntuiMessage     *m;
        struct MenuItem         *n;
        int                     (*func)(void);
        struct Window *Win = Lay->Window;
        struct VisFldInfo *vf;

        BOOL running = TRUE;

        while( m = GT_GetIMsg( Win->UserPort )) {

                CopyMem(( char * )m, ( char * )&DB_Msg, (long)sizeof( struct IntuiMessage ));

                GT_ReplyIMsg( m );
                
                switch ( DB_Msg.Class ) {
                
                        case IDCMP_INTUITICKS:
                                if (GadDoubleClicked) {
                                        running = DB_SpecialAction(TRUE);
                                        GadDoubleClicked = FALSE;
                                }
                                break;

                        case    IDCMP_REFRESHWINDOW:
                                GT_BeginRefresh(Win);
                                GT_EndRefresh(Win, TRUE );
                                break;

                        case    IDCMP_CLOSEWINDOW:
                                running = DB_CloseWindow();
                                break;

                        case    IDCMP_MENUHELP:
                                running = DB_MenuHelp();
                                break;

                        case    IDCMP_NEWSIZE:
                                running = DB_NewSize();
                                break;

                        case    IDCMP_VANILLAKEY:
                                if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
                                        running = DB_VanillaKey();
                                break;

                        case    IDCMP_RAWKEY:
                                if (!(NextGad && (NextGad->Flags & GFLG_SELECTED)))
                                        running = DB_RawKey();
                                        if (running) return running;    /* The window has been closed! */
                                break;

                        case    IDCMP_GADGETUP:
                                {
                                        struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;
                                        if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
                                        else {
                                                if ((gad->GadgetID == CHECKBOX_KIND) ||
                                                         (gad->GadgetID == CYCLE_KIND)) {
                                                        LastGad = gad;
                                                        VisFldSelected(gad);
                                                        vf = GetVisFldInfo(Lay, gad);
                                                        vf->Code = DB_Msg.Code;
                                                }
                                                if (!ReactivateGad)
                                                        running = DB_SpecialAction(FALSE);
                                                if (NextGad) ActivateGadget(NextGad, Win, NULL);
                                        }
                                }
                                break;

                        case    IDCMP_GADGETDOWN:
                                {
                                        struct Gadget *gad = (struct Gadget *)DB_Msg.IAddress;

                                        if (gad->GadgetID == STRING_KIND || gad->GadgetID == TEXTFIELD_KIND) {
                                                LastGad = gad;
                                                VisFldSelected(gad);
                                        }
                                        else if (gad->GadgetID == SCROLLER_KIND) DragGadgetSelected();
                                }
                                break;

                        case    IDCMP_MENUPICK:
                                while( DB_Msg.Code != MENUNULL ) {
                                        n = ItemAddress( Win->MenuStrip, DB_Msg.Code );
                                        func = (int (*)(void))(GTMENUITEM_USERDATA( n ));
                                        running = func();
                                        if (running) return running;    /* The window has been closed! */
                                        DB_Msg.Code = n->NextSelect;
                                }
                                break;

                        /* Added by me as GadToolBox won't do that */
                        case    IDCMP_MOUSEMOVE:
                                DB_MouseMove();
                                break;
                }
        }
        if (ReactivateGad) ReactivateGad = FALSE;
        return( running );
}

void DeleteSoftMenu(struct SoftMenu *sm)
{
        if (sm->Items) FreeMenus((struct Menu *)sm->Items);
        sm->Items = NULL;
        if (sm->NewItems) FreeMem(sm->NewItems, sm->NewItemsNum * sizeof(struct NewMenu));
        sm->NewItems = NULL;
        sm->NewItemsNum = 0;
}

void CloseMenu(struct Pro *Pr)
{
        /* Frees all memory allocated by OpenMenu() */

        if (Pr->Menu) FreeMenus(Pr->Menu);
        Pr->Menu = NULL;
        DeleteSoftMenu(&Pr->ViewMenu);
        DeleteSoftMenu(&Pr->ARexxMenu);
}

int AddViewMenu(struct Pro *Pr)
{
        int n;
        struct Layout *Lay;

        /* Count how many layouts there are */
        for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++);
        if (!n) return 0;       /* No layouts at all. Extra safety */

        Pr->ViewMenu.NewItemsNum = n+1; /* One extra array-closing item */
        /* Allocate memory for the NewMenu structs */
        if (!(Pr->ViewMenu.NewItems =
         AllocMem(Pr->ViewMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;

        /* Fill in the NewMenu structs */
        for (n=0, Lay=Pr->FirstLayout; Lay; Lay=Lay->NextLayout, n++) {
                Pr->ViewMenu.NewItems[n].nm_Type = NM_ITEM;
                Pr->ViewMenu.NewItems[n].nm_Label = (STRPTR)Lay->Name;
                Pr->ViewMenu.NewItems[n].nm_Flags = CHECKIT;
                Pr->ViewMenu.NewItems[n].nm_MutualExclude = ~(1<<n);
                Pr->ViewMenu.NewItems[n].nm_UserData = (APTR)DB_VIEW;
        }
        Pr->ViewMenu.NewItems[n].nm_Type = NM_END;
        Pr->ViewMenu.NewItems[0].nm_Flags |= CHECKED;

        if (!(Pr->ViewMenu.Items = (struct MenuItem *)CreateMenus(Pr->ViewMenu.NewItems, TAG_DONE))) return MENU_ERR;
        Pr->Menu->NextMenu->NextMenu->FirstItem = Pr->ViewMenu.Items;   /* Link in */
        return 0;       /* ok */
}

int AddARexxMenu(struct Pro *Pr)
{
        int n;
        struct RxInfo *ri;
        struct RFFTag *tag;
        char *label;

        /* Count how many ARexx items there are */
        for (n=0, ri=Pr->FirstRxInfo; ri; ri=ri->Next, n++);
        if (n < 2) return 0;    /* No ARexx menu items at all (The global RFF data is in the first node). */

        Pr->ARexxMenu.NewItemsNum = n;  /* One extra array-closing item */
        /* Allocate memory for the NewMenu structs */
        if (!(Pr->ARexxMenu.NewItems =
         AllocMem(Pr->ARexxMenu.NewItemsNum * sizeof(struct NewMenu), MEMF_CLEAR))) return MEM_ERR;

        /* Fill in the NewMenu structs */
        for (n=0, ri=Pr->FirstRxInfo->Next; ri; ri=ri->Next, n++) {
                Pr->ARexxMenu.NewItems[n].nm_Type = NM_ITEM;
                if (!(tag = FindTag(&ri->RxTags, NAME)) && !(tag = FindTag(&ri->RxTags, RXFILE)))
                        label = "« error »";
                else label = tag->Data;
                Pr->ARexxMenu.NewItems[n].nm_Label = (STRPTR)label;
                Pr->ARexxMenu.NewItems[n].nm_UserData = (APTR)DB_AREXX;
        }
        Pr->ARexxMenu.NewItems[n].nm_Type = NM_END;

        if (!(Pr->ARexxMenu.Items = (struct MenuItem *)CreateMenus(Pr->ARexxMenu.NewItems, TAG_DONE))) return MENU_ERR;
        Pr->Menu->NextMenu->NextMenu->NextMenu->NextMenu->NextMenu->
        FirstItem->NextItem->NextItem->NextItem = Pr->ARexxMenu.Items;    /* Link in */
        return 0;       /* ok */
}

int OpenMenu(struct Pro *Pr)
{
        /* Builds a complete menu including the variable View menu */
        int err;

        if (!(Pr->Menu = CreateMenus(DB_NewMenu, TAG_DONE))) return MENU_ERR;

        if (err = AddViewMenu(Pr)) {
                CloseMenu(Pr);
                return err;
        }
        if (err = AddARexxMenu(Pr)) {
                CloseMenu(Pr);
                return err;
        }
        LayoutMenus(Pr->Menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE );
        return 0;
}

void GadSpace(struct VisFldInfo *vf, struct RastPort *rp)
{
        /* Calculate the offset and size of a vf info vf->Pos. */
   /* Take space for the gadgets name into account */
        /* If rp is NULL then topaz 8 is assumed */

        int len;
        char *buffer, *bufp, *namep;
        int diff, rows;
        struct RFFTag *tag;

        vf->Pos.YOffset = vf->Pos.XOffset = 0;
        vf->Label.LeftEdge = vf->Label.TopEdge = 0;     /* textfield gadget */
        
        tag = SearchTag(CurrentPro, vf, NULL, PLACE);
        if (tag && !Stricmp(tag->Data, "above")) {              /* Title is above gadget */
                vf->Pos.YOffset = FontY + (FontY >> 1); /* Seems to look nice */
                vf->Label.TopEdge = -vf->Pos.YOffset;           /* textfield gadget */
        }
        else {  /* Title is to the left of gadget */
                /* gadgetname size */
                len = strlen(vf->Name);
                if (!(buffer = AllocMem(len+1,0))) return;      /* mem fail */

                /* Strip underscore _ in gadetname for correct length */
                for (bufp = buffer, namep = vf->Name;; namep++) {
                        if (*namep != '_') *bufp++ = *namep;
                        if (!(*namep)) break;   /* Also copy the \0 char */
                }
                if (rp) vf->Pos.XOffset = TextLength(rp,buffer,strlen(buffer));
                else vf->Pos.XOffset = FontX * strlen(buffer);  /* Topaz 8 */
                FreeMem(buffer, len+1);
                if (vf->Pos.XOffset) vf->Pos.XOffset += FontX;                  /* If vf->name, add extra space */
                vf->Label.LeftEdge = -vf->Pos.XOffset;  /* textfield gadget */
        }

        vf->Pos.Width = FontX * (vf->VisLen + 2);
        diff = vf->Pos.XOffset % FontX;
        if (diff) vf->Pos.XOffset += FontX - diff;              /* Snap to next FontX tick */

        tag = SearchTag(CurrentPro, vf, NULL, ROWS);
        if (tag && (rows = atoi(tag->Data))) {
                vf->Pos.Height = FontY * rows + STRGADFRAMESHEIGHT;
        }
        else vf->Pos.Height = FontY + STRGADFRAMESHEIGHT;
}


__inline WORD LineOffset(struct VisFldInfo *vf)
{
        /* Return the maximum Y offset needed for a line of visual fields */
        WORD oldmax = 0;
        
        for (; vf; vf = vf->Next) {
                if (vf->Pos.YOffset > oldmax) oldmax = vf->Pos.YOffset;
                if (vf->VisSep == '\n' || vf->VisSep == '\f') break;
        }
        return oldmax;
}

__inline BOOL EndOfLine(struct VisFldInfo *vf)
{
        return (BOOL)(vf->VisSep == '\n' || vf->VisSep == '\f' || !vf->Next);
}

BOOL CalcPos(struct Layout *Lay, struct Space *GLim, WORD *ww, WORD *wh,
 struct RastPort *rp)
{
        struct VisFldInfo *vf;
        WORD curX = 0, curY = 0;
        BOOL firstCol = TRUE;
        int stepsize = 0;
        WORD maxheight = 0;
        
        GLim->XOffset = GLim->Width = GLim->YOffset = GLim->Height = 0;

        /* First set each vf's local offset and size */
        for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next)
                GadSpace(vf, rp);

        /* Now adjust all vf's according to one another */
        for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {

                if (firstCol) {
                        curY += LineOffset(vf); /* This line's max Y offset */
                        if (vf->Pos.XOffset > GLim->XOffset) GLim->XOffset = vf->Pos.XOffset;
                        vf->Pos.XOffset = 0;            /* It will be added later */
                }
                vf->Pos.XOffset += curX;
                vf->Pos.YOffset = curY;

                if (stepsize) {
                        vf->Pos.XOffset += stepsize - vf->Pos.XOffset % stepsize;
                        stepsize = 0;
                }

                if (vf->Pos.XOffset + vf->Pos.Width > GLim->Width)
                        GLim->Width = vf->Pos.XOffset + vf->Pos.Width;
                
                if (vf->Pos.Height > maxheight) maxheight = vf->Pos.Height;

                if (EndOfLine(vf)) {
                        firstCol = TRUE;
                        curX = 0;
                        curY += maxheight;
                        GLim->Height = curY;
                        maxheight = 0;  
                }
                switch (vf->VisSep) {
                        case ' ':
                                curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
                                firstCol = FALSE;
                                stepsize = 0;
                                break;
                        case '\t':
                                curX = vf->Pos.XOffset + vf->Pos.Width + FontX;
                                stepsize = TabSize * FontX;
                                firstCol = FALSE;
                                break;
                        case '\f':
                                curY += (FontY * 3 >> 1);       /* Looks nice */
                                break;
                        case '\n':
                        default:
                                curY += (FontY * 3 >> 3); /* Looks nice */
                                break;
                }
        }
        GLim->Width += GLim->XOffset;
        *ww = OffX + (FontX << 1) + GLim->Width + Scr->WBorRight;
        *wh = OffY + FontY + GLim->Height + Scr->WBorBottom;
        if (MyArgArray[HORIZBAR]) *wh += DragKnobHeight;
        else *ww += DragKnobWidth;

        return TRUE;
}

void DeleteAllGadgets(struct Layout *Lay, char mode)
{
        struct VisFldInfo *vf;
        struct Gadget *g;

        /* Relink the gadgetborders we deleted for sake of speed */
        if (mode == USE_MODE && Lay->FirstSR) SpeedRenderOff(Lay);      /* FirstSR will be cleared */

        if (Lay->GList) {
                if (mode == USE_MODE && Lay->Window) RemoveGList(Lay->Window, Lay->GList, -1);

                /* Remove objects first */
                for (g = Lay->GList; g && g->NextGadget; g = g->NextGadget) {
                        if (g->NextGadget->GadgetID == TEXTFIELD_KIND) {
                                DisposeObject(g->NextGadget);
                                g->NextGadget = g->NextGadget->NextGadget;      /* Objects shall not be freed by FreeGadgets */
                        }
                }
                FreeGadgets(Lay->GList);
                Lay->GList = NULL;
        }
        for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
                vf->Gadget = NULL;
                vf->Code = 0;
        }
        LastGad = NULL;
}

void CloseLayWin(struct Pro *Pr, struct Layout *Lay)
{
        CloseSelect(CurrentPro->CurrentLayout->Browser);
        RemoveAllStrings(CurrentPro->CurrentLayout->Browser);

        DeleteAllGadgets(Lay, USE_MODE);
        if (Lay->Window) {
                /* Remember old window pos */
                LastLeftEdge = Lay->Window->LeftEdge;
                LastTopEdge = Lay->Window->TopEdge;
                /* AppWindow specifics */
                if (Lay->AppWin) RemoveAppWindow(Lay->AppWin);
                Lay->AppWin = NULL;
                ClearMenuStrip(Lay->Window);
                CloseWindow(Lay->Window);
                Lay->Window = NULL;
        }
}

void AdjustVars(struct RastPort *rp)
{
        /* Supportfunction to simplify OpenLayWin */
        if (rp) {
                Font->ta_Name = (STRPTR)rp->Font->tf_Message.mn_Node.ln_Name;
                Font->ta_YSize = FontY = rp->Font->tf_YSize;
                FontX = rp->Font->tf_XSize;
        }
        else {
                Font->ta_Name = (STRPTR)"topaz.font";
                FontX = FontY = Font->ta_YSize = 8;
        }
        DragKnobHeight = FontY;
        if (DragKnobHeight < 12) DragKnobHeight = 12;
        DragKnobWidth = (DragKnobHeight * 5) >> 2;
}

int CalcAllPos(struct Pro *Pr, struct Layout *Lay, WORD *ww, WORD *wh)
{
        /* Calculate the position of all gadgets and put the final windowsize in ww and wh */
        struct RastPort *rp = &Scr->RastPort, *myrp=NULL;
        struct RFFTag *tag;
        struct Space GLim;      /* "rectangle" that gadgets are to be drawn within */
        struct VisFldInfo *vf;

        if (UserTextFont) {
                /* Alloc and init a dummy RastPort for TextLength() with custom fonts */
                if (!(myrp = AllocMem(sizeof(struct RastPort),0))) return MEM_ERR;
                InitRastPort(myrp);
                SetFont(myrp,UserTextFont);
                rp = myrp;
        }

        Font = &Attr;
        OffX = Scr->WBorLeft;
        OffY = Scr->RastPort.TxHeight + Scr->WBorTop + 1;

        /* Get the tabsize from the taglist */
        if (tag = FindTag(&Lay->LayTags, TABSIZE))
                TabSize = atoi(tag->Data);
        else TabSize = DEFTABSIZE;

        AdjustVars(rp);
        CalcPos(Lay, &GLim, ww, wh, rp); 
        if (myrp) FreeMem(myrp, sizeof(struct RastPort));

        if ((*ww>Scr->Width || *wh>Scr->Height) && UserTextFont) { /* Try screen font */
                rp = &Scr->RastPort;
                AdjustVars(rp);
                CalcPos(Lay, &GLim, ww, wh, rp);
        }
                
        if (*ww > Scr->Width || *wh > Scr->Height) {    /* Try Topaz 8 */
                AdjustVars(NULL);
                CalcPos(Lay, &GLim, ww, wh, NULL); 
                if (*ww > Scr->Width || *wh > Scr->Height) return WINSIZE_ERR;
        }
        
        /* Finally add GLim's offsets to all gadgets */
        for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {
                vf->Pos.XOffset += OffX + FontX + GLim.XOffset;
                vf->Pos.YOffset += OffY + (FontY >> 1) + GLim.YOffset;
        }

        /* Window specifics */
        DB_Zoom[0] = 0;
        DB_Zoom[1] = OffY;
        DB_Zoom[2] =
         TextLength( &Scr->RastPort, (UBYTE *)Pr->Name, strlen((char *)Pr->Name))
         + TextLength( &Scr->RastPort, (UBYTE *)Lay->Name, strlen((char *)Lay->Name))
         + FontX + 80;
        DB_Zoom[3] = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
        
        /* Make sure window is not too small */
        if (*ww < (DB_Zoom[2] + 8 * FontX)) *ww = DB_Zoom[2] + 8 * FontX;
        if (*wh < DragKnobHeight * 5) {
                if (!Lay->FirstVisFldInfo) *wh = 10 * DragKnobHeight;
                else *wh = 5 * DragKnobHeight;
        }
        return 0;
}

int CreateAllGadgets(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh, char mode)
{
        /* Create all gadgets with sizes, and positions fixed by CalcAllPos() */
        struct FldInfo *f;
        struct VisFldInfo *vf;
        struct Gadget *g;
        struct NewGadget ng;
        struct RFFTag *tag;
        struct RFFTag *sfmt; /* String format (left, right, center etc) */
        LONG justification;     /* String format (left, right, center etc) */

        if (!(g = CreateContext(&Lay->GList))) return GAD_ERR;

        ng.ng_TextAttr = Font;
        ng.ng_VisualInfo = VisualInfo;
        ng.ng_UserData = 0;

        /* The drag gadget. (No dragbar in design mode) */
        if (mode == USE_MODE) {
                ng.ng_GadgetText = NULL;
                ng.ng_GadgetID = SCROLLER_KIND; /* For our information, from gadtools.h */
                ng.ng_Flags = 0;

                if (MyArgArray[HORIZBAR]) {
                        ng.ng_LeftEdge = Scr->WBorLeft;
                        ng.ng_TopEdge = wh - Scr->WBorBottom - DragKnobHeight;
                        ng.ng_Width = ww - (Scr->WBorLeft + Scr->WBorRight);
                        ng.ng_Height = DragKnobHeight;

                        Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
                                GTSC_Total, 1,
                                GTSC_Arrows, DragKnobWidth,
                                PGA_Freedom, LORIENT_HORIZ,
                                GA_Immediate, TRUE,
                                GA_RelVerify, TRUE,
                                TAG_DONE
                        );
                }
                else {
                        ng.ng_LeftEdge = ww - Scr->WBorRight - DragKnobWidth;
                        ng.ng_TopEdge = OffY;
                        ng.ng_Width = DragKnobWidth;
                        ng.ng_Height = wh - OffY - Scr->WBorBottom;

                        Lay->DragGad = g = CreateGadget(SCROLLER_KIND, g, &ng,
                                GTSC_Total, 1,
                                GTSC_Arrows, DragKnobHeight,
                                PGA_Freedom, LORIENT_VERT,
                                GA_Immediate, TRUE,
                                GA_RelVerify, TRUE,
                                TAG_DONE
                        );
                }
        } /* end-if RUN-MODE */

        /* The other gadgets */
        for (vf = Lay->FirstVisFldInfo; vf; vf = vf->Next) {

                if (!(f = GetFldInfo(Pr, vf->Offset))) return RFF_ERR;

                ng.ng_LeftEdge = vf->Pos.XOffset;
                ng.ng_TopEdge = vf->Pos.YOffset;
                ng.ng_Width = vf->Pos.Width;
                ng.ng_Height = vf->Pos.Height;
                ng.ng_GadgetText = vf->Name;

                tag = SearchTag(CurrentPro, vf, NULL, PLACE);
                if (tag && !Stricmp(tag->Data, "above")) /* Title is above gadget */
                        ng.ng_Flags = PLACETEXT_ABOVE;
                else ng.ng_Flags = PLACETEXT_LEFT;

                if (MyArgArray[HIGHLABEL]) ng.ng_Flags |= NG_HIGHLABEL;

                tag = SearchTag(CurrentPro, vf, NULL, FTYP);

                if (tag && !Stricmp(tag->Data, "checkbox"))
                {
                        Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
                        ng.ng_Width = (ng.ng_Height * 3) >> 1;
                        ng.ng_GadgetID = CHECKBOX_KIND; /* For our information, from gadtools.h */
                        vf->Gadget = g = CreateGadget(CHECKBOX_KIND, g, &ng,
                                GT_Underscore, '_',
                                GTCB_Scaled, TRUE,
                                TAG_DONE
                        );
                }
                else if (tag && !Stricmp(tag->Data, "cycle"))
                {
                        Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
                        ng.ng_GadgetID = CYCLE_KIND;    /* For our information, from gadtools.h */
                        vf->Gadget = g = CreateGadget(CYCLE_KIND, g, &ng,
                                GT_Underscore, '_',
                                GTCY_Labels, vf->CEnt,
                                TAG_DONE
                        );
                }
                else if (tag && !Stricmp(tag->Data, "text"))
                {
                        Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
                        ng.ng_GadgetID = TEXT_KIND;     /* For our information, from gadtools.h */
                        justification = GTJ_LEFT;
                        if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
                                if (!Stricmp(sfmt->Data, "right")) justification = GTJ_RIGHT;
                                else if (!Stricmp(sfmt->Data, "center")) justification = GTJ_CENTER;
                        }
                        vf->Gadget = g = CreateGadget(TEXT_KIND, g, &ng,
                                GTTX_Justification, justification,
                                GT_Underscore, '_',
                                GTTX_Clipped, TRUE,
                                GTTX_Border, TRUE,
                                GTTX_CopyText, TRUE,
                                TAG_DONE
                        );
                }
                else if (tag && !Stricmp(tag->Data, "textfield") && TextFieldClass) {
                        long bordertype = TEXTFIELD_BORDER_DOUBLEBEVEL;

                        vf->Label.FrontPen = MyArgArray[HIGHLABEL] ? Pens[HIGHLIGHTTEXTPEN] : Pens[TEXTPEN];

                        Lay->ComplexGadgets = TRUE;     /* For UpdateGadgets() */
                        if (MyArgArray[NOBORDER]) bordertype = TEXTFIELD_BORDER_NONE;
                        justification = TEXTFIELD_ALIGN_LEFT;
                        if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
                                if (!Stricmp(sfmt->Data, "right")) justification = TEXTFIELD_ALIGN_RIGHT;
                                else if (!Stricmp(sfmt->Data, "center")) justification = TEXTFIELD_ALIGN_CENTER;
                        }
                        vf->Gadget = g = NewObject(TextFieldClass, NULL,
                                                                        GA_ID,                          TEXTFIELD_KIND,
                                                                        GA_Left,                                ng.ng_LeftEdge,
                                                                        GA_Top,                         ng.ng_TopEdge,
                                                                        GA_Width,                       ng.ng_Width,
                                                                        GA_Height,                      ng.ng_Height,
                                                                        GA_Previous,            g,
                                                                        GA_TabCycle,            TRUE,
                                                                        GA_IntuiText,           &vf->Label,
                                                                        TEXTFIELD_ClipStream,   Iff0->iff_Stream,
                                                                        TEXTFIELD_Border,                       bordertype,
                                                                        TEXTFIELD_Alignment,            justification,
                                                                        TEXTFIELD_MaxSize,              f->Len,
                                                                        TEXTFIELD_TextAttr,             (ULONG)Font,
                                                                        TEXTFIELD_BlockCursor,  TRUE,
                                                                        TEXTFIELD_PassCommand,  TRUE,
                                                                        TAG_END);
                        vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
                }
                else {                  /* Assume string type as default */
                        ng.ng_GadgetID = STRING_KIND;   /* For our information, from gadtools.h */

                        /* Handle string formatting */
                        justification = STRINGLEFT;
                        if (sfmt = SearchTag(CurrentPro, vf, NULL, SFMT)) {
                                if (!Stricmp(sfmt->Data, "right")) justification = STRINGRIGHT;
                                else if (!Stricmp(sfmt->Data, "center")) justification = STRINGCENTER;
                        }
                        
                        vf->Gadget = g = CreateGadget(STRING_KIND, g, &ng,
                                STRINGA_ExitHelp, TRUE,
                                GTST_MaxChars, f->Len,
                                STRINGA_Justification, justification,
                                GT_Underscore, '_',
                                GTST_EditHook, &MyStrHook,
                                TAG_DONE
                        );
                        vf->Gadget->Activation |= GACT_IMMEDIATE; /* To get gadgetdown events */
                }                                                                                                                       /* GA_Immediate tag is v39  */
        }

        if (Lay->FirstVisFldInfo) LastGad = Lay->FirstVisFldInfo->Gadget;
        else LastGad = NULL;

        return 0;
}

int AttachAllGadgets(struct Layout *Lay, WORD ww, WORD wh, char mode)
{
        /* Attach all gadgets to an already opened window, and size the window accordingly */
        /* Use DoOpenLayWindow() instead if window is closed */

        struct IntuiMessage     *m;
        ULONG class;
        WORD clearw, clearh;    // Just so we don't clear more than neccesary.

        clearw = (Lay->Window->Width < ww) ? Lay->Window->Width : ww;
        clearh = (Lay->Window->Height < wh) ? Lay->Window->Height : wh;

        /* Resize (and maybe move) window */
//      Lay->Window->Flags |= WFLG_SIMPLE_REFRESH;      /* Speed */
        {
                WORD x = (Lay->XPos >= 0) ? Lay->XPos : Lay->Window->LeftEdge;
                WORD y = (Lay->YPos >= 0) ? Lay->YPos : Lay->Window->TopEdge;
                ChangeWindowBox(Lay->Window, x, y, ww, wh);
        }
        /* The action is delayed until I get a IDCMP_NEWSIZE message. Ugly! */
        for (;;) {
                WaitPort(Lay->Window->UserPort);
                while( m = GT_GetIMsg( Lay->Window->UserPort )) {
                        class = m->Class;
                        GT_ReplyIMsg(m);
                        if (class == IDCMP_NEWSIZE) goto SIZEOK;
                }
        }
        SIZEOK:
//      Lay->Window->Flags &= ~WFLG_SIMPLE_REFRESH;     /* Speed */

        if (mode == USE_MODE && MyArgArray[NOBORDER]) {
                MyArgArray[NOSPEEDRENDER] = FALSE;
                if (!SpeedRenderOn(Lay)) ByeBye();
        }

        AddGList(Lay->Window, Lay->GList, -1, -1, NULL);

        /* Clear old gadget imagery */
        EraseRect(Lay->Window->RPort, Lay->Window->BorderLeft, Lay->Window->BorderTop,
         clearw - Lay->Window->BorderRight-1, clearh - Lay->Window->BorderBottom-1);

//      RefreshWindowFrame(Lay->Window);
        RefreshGList(Lay->GList, Lay->Window, NULL, -1);
        GT_RefreshWindow( Lay->Window, NULL ); /* Must also be called. Works fine without however */

        if (mode == DESIGN_MODE)
                RemoveGList(Lay->Window, Lay->GList, -1);

        else if (!MyArgArray[NOBORDER])
                if (!SpeedRenderOn(Lay)) ByeBye();

        return 0;
}


int DoOpenLayWindow(struct Pro *Pr, struct Layout *Lay, WORD ww, WORD wh)
{
        /* Does the actual opening (in USE_MODE) */
        WORD leftedge, topedge;

        if (MyArgArray[NOBORDER]) {
                MyArgArray[NOSPEEDRENDER] = FALSE;
                if (!SpeedRenderOn(Lay)) ByeBye();
        }

        /* Position window nicely */
        if (LastLeftEdge == -1) {       /* No previous window to use */
                leftedge = (Scr->Width - ww) >> 1;      /* Middle */
                topedge = (Scr->Height - wh) >> 1;      /* Middle */
        }
        else {
                leftedge = LastLeftEdge;
                topedge = LastTopEdge;
        }
        if (Lay->XPos != -1) leftedge = Lay->XPos;
        if (Lay->YPos != -1)    topedge = Lay->YPos;

        if ( ! ( Lay->Window = OpenWindowTags( NULL,
                                WA_Left,           leftedge,
                                WA_Top,         topedge,
                                WA_Width,       ww,
                                WA_Height,      wh,
                                WA_IDCMP,       STRINGIDCMP|SCROLLERIDCMP|ARROWIDCMP|IDCMP_NEWSIZE|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_MENUHELP|IDCMP_REFRESHWINDOW,
                                WA_Flags,       WFLG_NEWLOOKMENUS|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
                                WA_Gadgets,     Lay->GList,
                                WA_Title,       Lay->Title,
                                WA_ScreenTitle, "db v" VERSION_NUMBER "  ©1997-1998 David Ekholm, Marcin Orlowski",
                                WA_PubScreen,   Scr,
                                WA_Zoom,        DB_Zoom,
                                WA_MenuHelp, TRUE,
                                TAG_DONE )))
        return WIN_ERR;

        if (!Pr->Menu) OpenMenu(Pr);
        SetMenuStrip(Lay->Window, Pr->Menu);

        GT_RefreshWindow( Lay->Window, NULL);
        /* AppWindow specifics */
        Lay->AppWin = AddAppWindow(1, 1, Lay->Window, AWPort, NULL);
        /* End of AppWindow specifics */

        /* We delete the reference to the gadget borders to double the update speed */
        /* We relink the information before windowclosing so that memory is freed */
        if (!MyArgArray[NOBORDER])
                if (!SpeedRenderOn(Lay)) ByeBye();

        /* For IDCMP handling used in this file and in main() */
        WinSig = 1L << Lay->Window->UserPort->mp_SigBit;

        return 0;
}


int OpenLayWin(struct Pro *Pr, struct Layout *Lay)
{
        /* Frontend function for the old db code */
        int ret;
        WORD ww, wh; /* Final window width and height */
        
        if ((ret = CalcAllPos(Pr, Lay, &ww, &wh)) < 0) return ret;
        if ((ret = CreateAllGadgets(Pr, Lay, ww, wh, USE_MODE)) < 0) return ret;
        if ((ret = DoOpenLayWindow(Pr, Lay, ww, wh)) < 0) return ret;
        return 0;
}
