/*

Directory Opus 4
Original GPL release version 4.12
Copyright 1993-2000 Jonathan Potter

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

All users of Directory Opus 4 (including versions distributed
under the GPL) are entitled to upgrade to the latest version of
Directory Opus version 5 at a reduced price. Please see
http://www.gpsoft.com.au for more information.

The release of Directory Opus 4 under the GPL in NO WAY affects
the existing commercial status of Directory Opus 5.

*/

#include "config.h"

#define LIB_VER 22

int CXBRK(void);
void chkabort(void);

int  CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
void chkabort(void) { return; } 

main(argc,argv)
int argc;
char *argv[];
{
    ULONG class;
    USHORT gadgetid,code;
    int num,a;
    char portname[50],rportname[50],oldconfigname[256],oldlanguage[30];
    struct WBStartup *wbmsg;
    struct ConfigUndo *undo;

#ifdef DEBUG
    if (sizeof(struct Config)!=CONFIG_STRUCTURE_SIZE) {
        printf("invalid config size - %ld - should be %ld\n",sizeof(struct Config),CONFIG_STRUCTURE_SIZE);
        _exit(0);
    }
#endif

    if (!(DOpusBase=(struct DOpusBase *)OpenLibrary("dopus.library",LIB_VER)) &&
        !(DOpusBase=(struct DOpusBase *)OpenLibrary("dopus:libs/dopus.library",LIB_VER)))
        _exit(0);

    GfxBase=DOpusBase->GfxBase;
    LayersBase=(struct Library *)DOpusBase->LayersBase;
    IntuitionBase=DOpusBase->IntuitionBase;

//    WorkbenchBase=IconBase=NULL;

    DiskfontBase=OpenLibrary("diskfont.library",0);
    WorkbenchBase=OpenLibrary("workbench.library",37);
    IconBase=OpenLibrary("icon.library",0);
    PPBase=OpenLibrary("powerpacker.library",0);

    network=0;

    Forbid();
    if (FindName(&SysBase->LibList,"services.library")) {
        network=1;
        formatgads[7].NextGadget=&formatgads[8];
    }
    Permit();

    if (SysBase->LibNode.lib_Version>=40) version2=OSVER_40;
    else if (SysBase->LibNode.lib_Version==39) version2=OSVER_39;
    else if (SysBase->LibNode.lib_Version==38) version2=OSVER_38;
    else if (SysBase->LibNode.lib_Version==37) version2=OSVER_37;
    else version2=OSVER_34;

    if (version2<OSVER_37) {
        operationgadgets[OP_UPDATE][10].type=CTYPE_SKIP;
        systemgadgets[SYS_CLOCK][18].type=CTYPE_SKIP;
        scr_generalgadgets[7].type=CTYPE_SKIP;
    }
    if (version2<OSVER_39) {
        scr_generalgadgets[6].type=CTYPE_SKIP;
        systemgadgets[SYS_VIEWPLAY][4].type=CTYPE_SKIP;
        systemgadgets[SYS_VIEWPLAY][5].type=CTYPE_SKIP;
    }
    else if (!(GfxBase->ChipRevBits0&GFXF_AA_ALICE)) {
        systemgadgets[SYS_VIEWPLAY][4].type=CTYPE_SKIP;
    }

    /* ExAll() */

    if (version2<OSVER_40) {
        systemgadgets[SYS_DIRECTORIES][11].type=CTYPE_SKIP;
    }

    conport=cmdport=appport=NULL; appobject=NULL;
    mainkey=buttonkey=gadgetkey=tickkey=clipkey=fontkey=NULL;
    firsttype=NULL; firstbank=curbank=NULL; typekey=NULL; firsthotkey=NULL;
    Screen=NULL; Window=NULL; myproc=NULL; tfont=NULL;
    tickgad=maingad=gadgads=drivegads=menugads=NULL; firstclip=NULL;
    undoconfig=NULL; config=NULL; changed=lchanged=clipcount=tickcount=0;
    curoperation=-1; fontdatabuf=NULL; helpbuffer=NULL; helpkey=NULL;
    cfg_string=NULL;
    stringdata.string_table=NULL;
    stringdata.string_buffer=NULL;

    free_colour_table(NULL);

    help_ok=1;

/*
    clip_port=NULL; clip_io=NULL;
*/
    currenthelpname[0]=0;

    if (!(FindSystemFile("DirectoryOpus.CFG",configname,256,SYSFILE_DATA))) {
        if (CheckExist("DOpus:S",NULL)) strcpy(configname,"DOpus:S/DirectoryOpus.CFG");
        else strcpy(configname,"s:DirectoryOpus.CFG");
    }

    FindSystemFile("DirectoryOpus.CLA",classname,256,SYSFILE_DATA);

    if (!argc) {
        wbmsg=(struct WBStartup *)argv;
        if (wbmsg->sm_NumArgs>1) {
            num=atoi(wbmsg->sm_ArgList[1].wa_Name);
            lsprintf(portname,"dopus4_config_port%ld",num);
            if (!(conport=LCreatePort(portname,20))) quit();
            lsprintf(rportname,"dopus4_config_reply%ld",num);
            Forbid();
            if (!(cmdport=FindPort(rportname))) {
                LDeletePort(conport);
                conport=NULL;
            }
            Permit();
        }
    }

    myproc=(struct Process *)FindTask(0);
    wsave=myproc->pr_WindowPtr;
    myproc->pr_WindowPtr=(APTR)-1;

    for (a=0;a<12;a++)
        if (!(functypelist[a]=LAllocRemember(&mainkey,40,MEMF_CLEAR))) quit();
    functypelist[12]=NULL;

    if (!cmdport && !(config=(struct Config *)AllocMem(sizeof(struct Config),MEMF_CLEAR)))
        quit();
    getconfig();
    strcpy(oldconfigname,configname);

    appport=LCreatePort(NULL,0);
/*
    if (clip_port=LCreatePort(NULL,0))
        clip_io=(struct IOClipReq *)LCreateExtIO(clip_port,sizeof(struct IOClipReq));
*/

    read_strings();
    load_clips();
    readhelp();

    if (config->scrdepth<2) config->scrdepth+=2;

    open_screen();

    undo=makeundo(UNDO_ALL);
    showconfigscreen(CFG_MAINMENU);
    giveconfig();

    FOREVER {
        Wait(1<<Window->UserPort->mp_SigBit);
        while (IMsg=getintuimsg()) {
            class=IMsg->Class; code=IMsg->Code;
            if (class==GADGETUP || class==GADGETDOWN)
                gadgetid=((struct Gadget *)IMsg->IAddress)->GadgetID;
            ReplyMsg((struct Message *)IMsg);
            switch (class) {
                case MENUPICK:
                    if (code==MENUNULL) break;
                    switch ((num=ITEMNUM(code))) {
                        case 0:
                        case 1:
                            if (lchanged && !request(cfg_string[STR_REALLY_DISCARD_CONFIG]))
                                break;
                            strcpy(oldlanguage,config->language);
                            if (doload(CFG_MAINMENU,num)) {
                                if (strcmp(config->language,oldlanguage)) {
                                    busy();
                                    read_strings();
                                    readhelp();
                                    unbusy();
                                }
                                close_screen();
                                open_screen();
                                configmsg(CONFIG_NEW_HOTKEY);
                                showconfigscreen(CFG_MAINMENU);
                            }
                            break;
                    }
                    break;
                case GADGETUP:
                    curoperation=gadgetid;
                    switch (gadgetid) {
                        case CFG_DRIVE:
                            if (dodriveconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_FILETYPE:
                            if (dofiletypeconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_GADGET:
                            if (dogadgetconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_HOTKEYS:
                            if (dohotkeysconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_MENU:
                            if (domenuconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_OPERATION:
                            if (dooperationconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_SCREEN:
                            if (doscreenconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_SYSTEM:
                            if (dosystemconfig()) lchanged=1;
                            showconfigscreen(CFG_MAINMENU);
                            break;
                        case CFG_SAVE:
                            dosave(0);
                            break;
                        case CFG_OKAY:
                        case CFG_CANCEL:
                            if ((gadgetid==CFG_CANCEL || !cmdport) && lchanged &&
                                !do_request(cfg_string[STR_EXIT_WITHOUT_SAVING],
                                    cfg_string[STR_OKAY_TO_QUIT],cfg_string[STR_CANCEL]))
                                break;
                            if (gadgetid==CFG_CANCEL) {
                                doundo(undo,UNDO_ALL);
                                strcpy(configname,oldconfigname);
                            }
                            doundo(undo,0);
                            quit();
                }
                curoperation=-1;
            }
        }
    }
}

void quit()
{
    if (Window) SetBusyPointer(Window);
    if (cmdport) {
        giveconfig();
        configmsg(CONFIG_ALL_DONE);
    }
    else {
        fixcstuff(&cstuff);
        FreeConfig(&cstuff);
        if (config) FreeMem(config,sizeof(struct Config));
    }
    if (myproc) myproc->pr_WindowPtr=wsave;
    if (firstclip) save_clips();
    if (Screen) ScreenToBack(Screen);
    close_screen();
    FreeStringFile(&stringdata);
    if (conport) LDeletePort(conport);
    if (appport) LDeletePort(appport);
    if (tfont) CloseFont(tfont);
/*
    if (clip_io) LDeleteExtIO((struct IORequest *)clip_io);
    if (clip_port) LDeletePort(clip_port);
*/
    LFreeRemember(&mainkey);
    LFreeRemember(&clipkey);
    LFreeRemember(&gadgetkey);
    LFreeRemember(&tickkey);
    LFreeRemember(&fontkey);
    LFreeRemember(&helpkey);
    LFreeRemember(&buttonkey);
    if (DiskfontBase) CloseLibrary(DiskfontBase);
    if (WorkbenchBase) CloseLibrary(WorkbenchBase);
    if (IconBase) CloseLibrary(IconBase);
    if (PPBase) CloseLibrary(PPBase);
    CloseLibrary((struct Library *)DOpusBase);
    _exit(0);
}

void getconfig()
{
    struct configconfig *cfg;

    if (cmdport) {
        configmsg(CONFIG_GET_CONFIG);
        cfg=(struct configconfig *)msg.buffer;
        config=cfg->config;
        firsttype=cfg->firsttype;
        firstbank=cfg->firstbank;
        firsthotkey=cfg->firsthotkey;
        typekey=cfg->typekey;
        changed=cfg->changed;
        strcpy(configname,cfg->configname);
        StrConcat(configname,".CFG",256);
        strcpy(loadnamebuf,configname);
    }
    else readconfig();
}

void giveconfig()
{
    struct configconfig cfg;
    char *ptr;

    if (cmdport) {
        cfg.config=config;
        cfg.firsttype=firsttype;
        cfg.firstbank=firstbank;
        cfg.firsthotkey=firsthotkey;
        cfg.typekey=typekey;
        if (lchanged || changed) cfg.changed=1;
        else cfg.changed=0;
        strcpy(cfg.configname,configname);
        if (ptr=strstri(cfg.configname,".CFG")) *ptr=0;
        cfg.Window=Window;
        cfg.Screen=Screen;
        msg.buffer=(char *)&cfg;
        configmsg(CONFIG_HERES_CONFIG);
    }
}

void readconfig()
{
    fixcstuff(&cstuff);
    if ((ReadConfig(configname,&cstuff))!=1) DefaultConfig(&cstuff);
    strcpy(loadnamebuf,configname);
    cstufffix(&cstuff);
}
    
void configmsg(command)
int command;
{
    if (cmdport) {
        msg.msg.mn_Node.ln_Type=NT_MESSAGE;
        msg.msg.mn_ReplyPort=conport;
        msg.msg.mn_Length=(UWORD)sizeof(struct dopusconfigmsg);
        msg.command=command;
        PutMsg(cmdport,(struct Message *)&msg);
        WaitPort(conport);
        GetMsg(conport);
    }
}

void fixcstuff(cstuff)
struct ConfigStuff *cstuff;
{
    cstuff->config=config;
    cstuff->typekey=typekey;
    cstuff->firsttype=firsttype;
    cstuff->firstbank=firstbank; cstuff->curbank=curbank;
    cstuff->firsthotkey=firsthotkey;
    if (!Screen && Window) {
        config->config_x=Window->LeftEdge;
        config->config_y=Window->TopEdge;
    }
}

void cstufffix(cstuff)
struct ConfigStuff *cstuff;
{
    config=cstuff->config;
    typekey=cstuff->typekey;
    firsttype=cstuff->firsttype;
    firstbank=cstuff->firstbank; curbank=cstuff->curbank;
    firsthotkey=cstuff->firsthotkey;
}

void cleanconfigscreen()
{
    struct Gadget *gad;
    struct Message *msg;

    FOREVER {
        gad=Window->FirstGadget;
        while (gad) {
            if (!(gad->GadgetType&GTYP_SYSGADGET)) {
                RemoveGList(Window,gad,1);
                break;
            }
            gad=gad->NextGadget;
        }
        if (!gad) break;
    }

    SetDrMd(rp,JAM2);
    SetAPen(rp,screen_pens[0].pen);
    RectFill(rp,
        x_off,y_off,
        x_bot,y_bot);

    SetBPen(rp,screen_pens[1].pen);
    SetBPen(rp,screen_pens[0].pen);

    LFreeRemember(&gadgetkey);
    removetickgads();

    while (msg=GetMsg(Window->UserPort))
        ReplyMsg(msg);
}

void showconfigscreen(scr)
int scr;
{
    cleanconfigscreen();

    switch (scr) {
        case CFG_MAINMENU:
            doscreentitle(cfg_string[STR_CONFIGURATION_MAIN_SCREEN]);
            initsidegads(mainmenugads,0,1);
            break;

        case CFG_OPERATION:
            initsidegads(operationgads,1,1);
            doscreentitle(cfg_string[STR_OPERATION_SCREEN]);
            break;

        case CFG_GADGET:
            if (gadgads) {
                AddGadgets(Window,
                    gadgads,
                    NULL,
                    84,
                    screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen,1);
            }
            initsidegads(gadgetgads,0,0);
            maingad[GAD_COPYGADGET].Activation|=GACT_TOGGLESELECT;
            maingad[GAD_SWAPGADGET].Activation|=GACT_TOGGLESELECT;
            maingad[GAD_DELETEGADGET].Activation|=GACT_TOGGLESELECT;
            SetAPen(rp,screen_pens[1].pen);
            UScoreText(rp,cfg_string[STR_LEFT_MOUSE_BUTTON],x_off+38,y_off+71,-1);
            BltTemplate((char *)uparrow_data,0,2,rp,x_off+179,y_off+66,12,6);
            UScoreText(rp,cfg_string[STR_RIGHT_MOUSE_BUTTON],x_off+454,y_off+75,-1);
            BltTemplate((char *)downarrow_data,0,2,rp,x_off+437,y_off+70,12,6);

        case CFG_MENU:
            if (scr==CFG_MENU) {
                if (menugads) AddGList(Window,menugads,-1,MENUCOUNT+5-(HIDDENLINES*5),NULL);
                initsidegads(menugadgets,1,0);
                maingad[MENU_OKAY].Activation&=~GACT_TOGGLESELECT;
                maingad[MENU_CANCEL].Activation&=~GACT_TOGGLESELECT;
                AddGList(Window,menuslidergads,-1,3,NULL);
                AddGadgets(Window,
                    &menuslidergads[1],
                    NULL,
                    2,
                    screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen,0);
                do3dbox(x_off+612,y_off+21,12,144-HIDDENLINES*8);
                DoArrow(rp,
                    x_off+612,y_off+119,
                    12,6,
                    screen_pens[config->arrowfg].pen,screen_pens[config->arrowbg].pen,0);
                DoArrow(rp,
                    x_off+612,
                    y_off+127,
                    12,6,
                    screen_pens[config->arrowfg].pen,screen_pens[config->arrowbg].pen,1);
                menusliderimage.PlaneOnOff=config->slidercol;
                FixSliderBody(Window,&menuslidergads[0],20,20-HIDDENLINES,0);
                FixSliderPot(Window,&menuslidergads[0],0,20,20-HIDDENLINES,2);
                do_menuscreen_title(STR_MENU_SCREEN);
            }

        case CFG_DRIVE:
            if (scr==CFG_DRIVE) {
                if (drivegads) AddGList(Window,drivegads,-1,DRIVECOUNT,NULL);
                initsidegads(drivegadgets,1,0);
                maingad[DRIVE_GETDRIVES].Activation&=~GACT_TOGGLESELECT;
                maingad[DRIVE_OKAY].Activation&=~GACT_TOGGLESELECT;
                maingad[DRIVE_CANCEL].Activation&=~GACT_TOGGLESELECT;
                do_menuscreen_title(STR_DRIVE_SCREEN);
            }
            dogadgetinfo(NULL);
            break;

        case CFG_FILETYPE:
            initsidegads(filetypeactiongadgets,1,0);
            maingad[FILETYPE_NEW].Activation&=~GACT_TOGGLESELECT;
            maingad[FILETYPE_OKAY].Activation&=~GACT_TOGGLESELECT;
            maingad[FILETYPE_CANCEL].Activation&=~GACT_TOGGLESELECT;
            doscreentitle(cfg_string[STR_FILETYPE_SCREEN]);
            setuplist(&filetypeactionlist,12,14);
            filetypeactionlist.itemselected=-1;
            AddListView(&filetypeactionlist,1);
            dogadgetinfo(NULL);
            break;

        case CFG_SCREEN:
            initsidegads(screengadgets,1,1);
            if ((config->screenmode==MODE_WORKBENCHUSE ||
                config->screenmode==MODE_PUBLICSCREENUSE) &&
                version2<OSVER_39)
                DisableGadget(&maingad[SCREEN_PALETTE],rp,2,1);
            doscreentitle(cfg_string[STR_SCREEN_SCREEN]);
            break;

        case CFG_SYSTEM:
            initsidegads(systemgads,1,1);
            doscreentitle(cfg_string[STR_SYSTEM_SCREEN]);
            break;

        case CFG_HOTKEYS:
            initsidegads(hotkeysgadgets,1,0);
            maingad[HOTKEYS_NEWHOTKEY].Activation&=~GACT_TOGGLESELECT;
            maingad[HOTKEYS_OKAY].Activation&=~GACT_TOGGLESELECT;
            maingad[HOTKEYS_CANCEL].Activation&=~GACT_TOGGLESELECT;
            doscreentitle(cfg_string[STR_HOTKEYS_SCREEN]);
            setuplist(&hotkeyslist,12,14);
            hotkeyslist.itemselected=-1;
            hotkeyslist.items=NULL;
            hotkeyslist.topitem=0;
            AddListView(&hotkeyslist,1);
            dogadgetinfo(NULL);
            break;
    }
    if (scr==CFG_MAINMENU) strcpy(currenthelpname,cfg_string[STR_MAIN_MENU]);
    else strcpy(currenthelpname,mainmenugads[scr]);
}

void initsidegads(gads,toggle,vert)
char **gads;
int toggle,vert;
{
    int num,a,x,y,x1,ac,dn,gnum,rnum,w,h;
    struct Gadget *gadbuf;

    if (!gads) return;

    for (num=0,rnum=0;;rnum++) {
        if (!gads[rnum]) break;
        if (gads[rnum][0]) ++num;
    }

    if (!(gadbuf=LAllocRemember(&gadgetkey,sizeof(struct Gadget)*num,MEMF_CLEAR)))
        quit();

    h=12;
    if (vert) {
        x=x_off+8;
        y=y_off+4;
        w=112;
    }
    else {
        dn=rnum/5;
        if (dn*5==rnum) --dn;
        ac=rnum-dn*5;
        w=104;
        x1=x=((Window->Width-(ac*(w+12)))/2)-2;
        y=y_off+172-(dn*(h+2));
    }
    gnum=0;
    for (a=0;a<rnum;a++) {
        if (gads[a][0]) {
            gadbuf[gnum].NextGadget=(gnum<num-1)?&gadbuf[gnum+1]:NULL;
            gadbuf[gnum].LeftEdge=x; gadbuf[gnum].TopEdge=y;
            gadbuf[gnum].Width=w; gadbuf[gnum].Height=h;
            gadbuf[gnum].Flags=GFLG_GADGHCOMP;
            gadbuf[gnum].Activation=GACT_RELVERIFY;
            if (toggle) gadbuf[gnum].Activation|=GACT_TOGGLESELECT;
            gadbuf[gnum].GadgetType=GTYP_BOOLGADGET;
            gadbuf[gnum].GadgetID=gnum;
            ++gnum;
        }
        if (vert) y+=(h+2);
        else {
            x+=(w+16);
            if (x>(Window->Width-10-w)) {
                x=x1;
                y+=(h+2);
            }
        }
    }
    SetAPen(rp,screen_pens[1].pen);
    AddGadgetBorders(&gadgetkey,
        gadbuf,
        gnum,
        screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen);
    AddGadgets(Window,
        gadbuf,
        gads,
        num,
        screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen,1);
    maingad=gadbuf;
}

void inittickgads(gads,flag,flag2)
struct ConfigGadget *gads;
int flag,flag2;
{
    int num,a,y,gad,last,lasty,dy,xp,yp,fl,b;
    char **namearray;
    struct StringInfo *sinfo;

    removetickgads();
    if (!gads) return;

    num=0;
    for (a=0;;a++) {
        if (!gads[a].type) break;
        if (gads[a].type!=CTYPE_TEXT && gads[a].type!=CTYPE_SKIP) ++num;
    }

    if (!num) return;

    if (!(tickgad=LAllocRemember(&tickkey,sizeof(struct Gadget)*num,MEMF_CLEAR)) ||
        !(namearray=LAllocRemember(&tickkey,num*4,MEMF_CLEAR))) return;

    y=y_off+46;
    lasty=y;
    gad=0;
    dy=0;

    SetAPen(rp,screen_pens[1].pen);

    for (a=0;;a++) {
        if (!gads[a].type) break;
        if (gads[a].type==CTYPE_SKIP) continue;
        switch (gads[a].type) {
            case CTYPE_MOVE:
                y=y_off+(gads[a].x-12); dy=0;
                break;
            case CTYPE_MOVEREL:
                dy=gads[a].x;
                break;
            case CTYPE_TEXT:
                if (gads[a].x<0) xp=x_off+158;
                else xp=x_off+(gads[a].x-2);
                if (gads[a].y<0) {
                    yp=y+8; dy=13;
                }
                else {
                    yp=y_off+(gads[a].y-12);
                    if (gads[a].value==1) {
                        y=yp-8;
                        dy=13;
                    }
                    else dy=0;
                }
                if (gads[a].nameentry>-1) UScoreText(rp,cfg_string[gads[a].nameentry],xp,yp,-1);
                break;
            case CTYPE_GAD:
            case CTYPE_RAD:
            case CTYPE_MRAD:
                if (gads[a].nameentry>-1) namearray[gad]=cfg_string[gads[a].nameentry];
                else namearray[gad]=(char *)-1;
                tickgad[gad].NextGadget=(gad<num-1)?&tickgad[gad+1]:NULL;
                if (gads[a].type==CTYPE_GAD) {
                    if (gads[a].w<0) tickgad[gad].Width=26;
                    else tickgad[gad].Width=gads[a].w;
                    if (gads[a].h<0) tickgad[gad].Height=11;
                    else tickgad[gad].Height=gads[a].h;
                    tickgad[gad].GadgetRender=checkoffimage;
                    tickgad[gad].SelectRender=checkonimage;
                    tickgad[gad].MutualExclude=GAD_CHECK;
                    if (gads[a].x<0) xp=x_off+156;
                    else xp=x_off+(gads[a].x-2);
                    if (gads[a].y<0) {
                        yp=y; dy=13;
                    }
                    else {
                        yp=y_off+(gads[a].y-12); dy=0;
                    }
                    tickgad[gad].Activation=RELVERIFY|TOGGLESELECT;
                }
                else {
                    if (gads[a].w<0) tickgad[gad].Width=15;
                    else tickgad[gad].Width=gads[a].w;
                    if (gads[a].h<0) tickgad[gad].Height=7;
                    else tickgad[gad].Height=gads[a].h;
                    tickgad[gad].GadgetRender=(APTR)buttonoffimage;
                    tickgad[gad].SelectRender=(APTR)buttononimage;
                    tickgad[gad].MutualExclude=GAD_RADIO;
                    if (gads[a].x<0) xp=x_off+158;
                    else xp=x_off+(gads[a].x-2);
                    if (gads[a].y<0) {
                        yp=y; dy=10;
                    }
                    else {
                        yp=y_off+(gads[a].y-12); dy=0;
                    }
                    tickgad[gad].Activation=GADGIMMEDIATE|TOGGLESELECT;
                }
                tickgad[gad].LeftEdge=xp; tickgad[gad].TopEdge=yp;
                tickgad[gad].Flags=GADGIMAGE|GADGHIMAGE;
                if (gads[a].value==0) fl=flag;
                else if (gads[a].value==1) fl=flag2;
                if (gads[a].type==CTYPE_MRAD) {
                    b=gads[a].mutualex&(~gads[a].bit);
                    if (!(fl&b)) tickgad[gad].Flags|=SELECTED;
                }
                else if (fl && fl&gads[a].bit) tickgad[gad].Flags|=SELECTED;
                tickgad[gad].GadgetType=BOOLGADGET;
                tickgad[gad].GadgetID=GAD_BASE+(gads[a].value*4000)+gads[a].bit;
                tickgad[gad].UserData=(APTR)&gads[a];
                gads[a].gad=&tickgad[gad];
                last=gads[a].type; ++gad;
                break;
            case CTYPE_STR:
                if (gads[a].y==-2) y=lasty;
                else {
                    if (last==CTYPE_GAD || gads[a].type==CTYPE_RAD || gads[a].type==CTYPE_MRAD)
                        ++y;
                    ++y;
                }
                if (gads[a].bit&4 || gads[a].nameentry==-1) namearray[gad]=(char *)-1;
                else namearray[gad]=cfg_string[gads[a].nameentry];
                tickgad[gad].NextGadget=(gad<num-1)?&tickgad[gad+1]:NULL;
                if (gads[a].bit&4) {
                    if (gads[a].x<0) xp=x_off+338;
                    else xp=x_off+(gads[a].x-2);
                    if (gads[a].y<0) {
                        yp=y; dy=13;
                    }
                    else {
                        yp=y_off+(gads[a].y-12); dy=0;
                    }
                }
                else {
                    if (gads[a].x<0) xp=x_off+306;
                    else xp=x_off+(gads[a].x-2);
                    if (gads[a].y<0) {
                        yp=y; dy=13;
                    }
                    else {
                        yp=y_off+(gads[a].y-12); dy=0;
                    }
                }
                if (gads[a].w<0) {
                    tickgad[gad].Width=Window->Width-xp-30;
                    if (gads[a].bit&4) tickgad[gad].Width-=2;
                }
                else tickgad[gad].Width=gads[a].w;
                if (gads[a].h<0) tickgad[gad].Height=8;
                else tickgad[gad].Height=gads[a].h;
                tickgad[gad].LeftEdge=xp; tickgad[gad].TopEdge=yp;
                tickgad[gad].Flags=GFLG_GADGHCOMP|GFLG_STRINGEXTEND|GFLG_TABCYCLE;
                tickgad[gad].Activation=GACT_RELVERIFY|GACT_TOGGLESELECT;
                if (gads[a].bit&1) tickgad[gad].Activation|=GACT_LONGINT;
                if (gads[a].bit&4) {
                    tickgad[gad].MutualExclude=1;
                    ++y;
                }
                tickgad[gad].GadgetType=GTYP_STRGADGET;
                if (sinfo=(struct StringInfo *)LAllocRemember(&tickkey,sizeof(struct StringInfo),MEMF_CLEAR)) {
                    sinfo->Buffer=(STRPTR)LAllocRemember(&tickkey,gads[a].mutualex,MEMF_CLEAR);
                    sinfo->MaxChars=gads[a].mutualex;
                    sinfo->Extension=&stringex;
                }
                tickgad[gad].SpecialInfo=(APTR)sinfo;
                tickgad[gad].GadgetID=STRING_BASE+gad;
                tickgad[gad].UserData=(APTR)&gads[a];
                gads[a].gad=&tickgad[gad];
                last=gads[a].type; ++gad;
                break;
            case CTYPE_REQ:
                y=lasty;
                if (gads[a].x<0) xp=x_off+302;
                else xp=x_off+(gads[a].x-2);
                if (gads[a].y<0) {
                    yp=y-4; dy=13;
                }
                else {
                    yp=y_off+(gads[a].y-12); dy=0;
                }
                if (gads[a].nameentry>-1) namearray[gad]=cfg_string[gads[a].nameentry];
                else namearray[gad]=(char *)-1;
                tickgad[gad].NextGadget=(gad<num-1)?&tickgad[gad+1]:NULL;
                tickgad[gad].LeftEdge=xp; tickgad[gad].TopEdge=yp;
                if (gads[a].w<0) tickgad[gad].Width=28;
                else tickgad[gad].Width=gads[a].w;
                if (gads[a].h<0) tickgad[gad].Height=14;
                else tickgad[gad].Height=gads[a].h;
                tickgad[gad].Flags=GADGHCOMP;
                tickgad[gad].Activation=RELVERIFY;
                tickgad[gad].GadgetType=BOOLGADGET;
                tickgad[gad].GadgetID=REQ_BASE+gad;
                tickgad[gad].MutualExclude=GAD_GLASS;
                tickgad[gad].UserData=(APTR)&gads[a];
                AddGadgetBorders(&tickkey,
                    &tickgad[gad],
                    1,
                    screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen);
                doglassimage(&tickgad[gad]);
                gads[a].gad=&tickgad[gad-1];
                last=gads[a].type; ++gad;
                break;
        }
        lasty=y; y+=dy;
    }
    AddGadgets(Window,
        tickgad,
        namearray,
        num,
        screen_pens[config->gadgettopcol].pen,screen_pens[config->gadgetbotcol].pen,1);
    tickcount=num;
}

void removetickgads()
{
    if (tickgad && tickcount) {
        RemoveGList(Window,tickgad,tickcount);
        tickgad=NULL; tickcount=0;
    }
    LFreeRemember(&tickkey);
    SetAPen(rp,screen_pens[0].pen);
    RectFill(rp,
        x_off+122,y_off+1,
        x_bot,y_bot);
}

processtickgad(gads,flag,sel,num)
struct ConfigGadget *gads;
int flag,sel,num;
{
    int a,ref=0,hitgad=-1;
    struct Gadget *gad;

    for (a=0;;a++) {
        if (!gads[a].type) break;
        if (num==-1 || gads[a].value==num) {
            if (gads[a].type==CTYPE_GAD || gads[a].type==CTYPE_RAD || gads[a].type==CTYPE_MRAD) {
                if (gads[a].bit==sel) {
                    hitgad=a;
                    break;
                }
            }
        }
    }

    flag=0;
    for (a=0;;a++) {
        if (!gads[a].type) break;
        if (num==-1 || gads[a].value==num) {
            gad=gads[a].gad;
            if (gads[a].type==CTYPE_GAD || gads[a].type==CTYPE_RAD || gads[a].type==CTYPE_MRAD) {
                if (a==hitgad) {
                    if (!(gad->Flags&SELECTED) && gads[a].mutualex&sel) {
                        gad->Flags|=SELECTED;
                        ref=1;
                    }
                }
                else {
                    if (gad->Flags&SELECTED) {
                        if (gads[a].type==CTYPE_MRAD) {
                            if (gads[a].mutualex&sel) {
                                gad->Flags&=~SELECTED;
                                ref=1;
                            }
                        }
                        else if (gads[hitgad].mutualex&gads[a].bit) {
                            gad->Flags&=~SELECTED;
                            ref=1;
                        }
                    }
                }
                if (gads[a].type!=CTYPE_MRAD && gad->Flags&SELECTED) flag|=gads[a].bit;
            }
            else if (gads[a].type==CTYPE_STR) {
                if (gads[a].buffer) {
                    if (gads[a].bit&2) CheckHexGad(gad,Window,0,0xff);
                    strcpy(gads[a].buffer,(char *)((struct StringInfo *)gad->SpecialInfo)->Buffer);
                }
            }
        }
    }
    if (ref) RefreshGList(tickgad,Window,NULL,tickcount);
    return(flag);
}

struct ConfigUndo *makeundo(type)
int type;
{
    struct ConfigUndo *undo;
    struct DOpusRemember *key;
    struct dopusgadgetbanks *bank,*newbank,*curbank;
    struct dopushotkey *hotkey,*newhotkey,*curhotkey;
    int a;

    key=NULL;
    if (!(undo=LAllocRemember(&key,sizeof(struct ConfigUndo),MEMF_CLEAR)))
        return(0);
    if (type&UNDO_MAIN)
        undo->config=(struct Config *)getcopy((char *)config,sizeof(struct Config),&key);
    if (type&UNDO_GADGET) {
        bank=firstbank; curbank=NULL;
        while (bank) {
            if (newbank=(struct dopusgadgetbanks *)
                getcopy((char *)bank,sizeof(struct dopusgadgetbanks),&key)) {
                newbank->next=NULL;
                copygadgets(bank,newbank,&key);
                if (curbank) curbank->next=newbank;
                else undo->firstbank=newbank;
                curbank=newbank;
            }
            bank=bank->next;
        }
    }
    if (type&UNDO_MENU &&
        (undo->menu=(struct newdopusfunction *)
            getcopy((char *)config->menu,sizeof(struct newdopusfunction)*MENUCOUNT,&key))) {
        for (a=0;a<MENUCOUNT;a++) {
            undo->menu[a].name=getcopy(config->menu[a].name,-1,&key);
            undo->menu[a].function=getcopy(config->menu[a].function,-1,&key);
        }
        for (a=0;a<5;a++) strcpy(undo->menutit[a],config->menutit[a]);
    }
    if (type&UNDO_DRIVE &&
        (undo->drive=(struct dopusfunction *)
            getcopy((char *)config->drive,sizeof(struct dopusfunction)*DRIVECOUNT,&key))) {
        for (a=0;a<DRIVECOUNT;a++)
            undo->drive[a].function=getcopy(config->drive[a].function,-1,&key);
    }
    if (type&UNDO_FILETYPE)
        copyfiletypes(firsttype,&undo->firsttype,&key);
    if (type&UNDO_HOTKEYS) {
        hotkey=firsthotkey; curhotkey=NULL;
        while (hotkey) {
            if (newhotkey=(struct dopushotkey *)
                    getcopy((char *)hotkey,sizeof(struct dopushotkey),&key)) {
                newhotkey->func.function=getcopy(hotkey->func.function,-1,&key);
                newhotkey->next=NULL;
                if (curhotkey) curhotkey->next=newhotkey;
                else undo->firsthotkey=newhotkey;
                curhotkey=newhotkey;
            }
            hotkey=hotkey->next;
        }
    }
    undo->key=key;
    return(undo);
}

void copygadgets(bank1,bank2,key)
struct dopusgadgetbanks *bank1,*bank2;
struct DOpusRemember **key;
{
    int a;

    for (a=0;a<84;a++) {
        bank2->gadgets[a].name=getcopy(bank1->gadgets[a].name,-1,key);
        bank2->gadgets[a].function=getcopy(bank1->gadgets[a].function,-1,key);
    }
}

void copyfiletypes(oldfirst,newfirst,key)
struct dopusfiletype *oldfirst,**newfirst;
struct DOpusRemember **key;
{
    struct dopusfiletype *type,*newtype,*curtype=NULL;
    int a;

    type=oldfirst;
    *newfirst=NULL;
    while (type) {
        if (newtype=(struct dopusfiletype *)
            getcopy((char *)type,sizeof(struct dopusfiletype),key)) {
            for (a=0;a<FILETYPE_FUNCNUM;a++)
                newtype->function[a]=getcopy(type->function[a],-1,key);
            newtype->recognition=getcopy(type->recognition,-1,key);
            newtype->iconpath=getcopy(type->iconpath,-1,key);
            if (curtype) curtype->next=newtype;
            else *newfirst=newtype;
            curtype=newtype;
            curtype->next=NULL;
        }
        type=type->next;
    }
}

void doundo(undo,type)
struct ConfigUndo *undo;
int type;
{
    struct DOpusRemember *key;
    struct dopusgadgetbanks *bank,*curbank,*newbank;
    struct dopushotkey *hotkey,*curhotkey,*newhotkey;
    int a;

    if (!undo) return;
    if (!type) {
        key=undo->key;
        LFreeRemember(&key);
    }
    else {
        if (type&UNDO_MENU) {
            for (a=0;a<MENUCOUNT;a++) freenewfunction(&config->menu[a]);
        }
        if (type&UNDO_DRIVE) for (a=0;a<DRIVECOUNT;a++) freefunction(&config->drive[a]);
        if (type&UNDO_MAIN && undo->config)
            copyconfigonly(undo->config,config);
        if (type&UNDO_GADGET) {
            freegadgets(firstbank); firstbank=NULL;
            bank=undo->firstbank; curbank=NULL;
            while (bank) {
                if (newbank=(struct dopusgadgetbanks *)
                    getcopy((char *)bank,sizeof(struct dopusgadgetbanks),NULL)) {
                    newbank->next=NULL;
                    copygadgets(bank,newbank,NULL);
                    if (curbank) curbank->next=newbank;
                    else firstbank=newbank;
                    curbank=newbank;
                }
                bank=bank->next;
            }
        }
        if (type&UNDO_MENU && undo->menu) {
            CopyMem((char *)undo->menu,(char *)config->menu,sizeof(struct newdopusfunction)*MENUCOUNT);
            for (a=0;a<MENUCOUNT;a++) {
                config->menu[a].name=getcopy(undo->menu[a].name,-1,NULL);
                config->menu[a].function=getcopy(undo->menu[a].function,-1,NULL);
            }
            for (a=0;a<5;a++) strcpy(config->menutit[a],undo->menutit[a]);
        }
        if (type&UNDO_DRIVE && undo->drive) {
            CopyMem((char *)undo->drive,(char *)config->drive,sizeof(struct dopusfunction)*DRIVECOUNT);
            for (a=0;a<DRIVECOUNT;a++)
                config->drive[a].function=getcopy(undo->drive[a].function,-1,NULL);
        }
        if (type&UNDO_FILETYPE) {
            LFreeRemember(&typekey); firsttype=NULL;
            copyfiletypes(undo->firsttype,&firsttype,&typekey);
        }
        if (type&UNDO_HOTKEYS) {
            hotkey=firsthotkey;
            while (hotkey) {
                curhotkey=hotkey->next;
                freestring(hotkey->func.function);
                FreeMem(hotkey,sizeof(struct dopushotkey));
                hotkey=curhotkey;
            }
            firsthotkey=NULL; curhotkey=NULL;
            hotkey=undo->firsthotkey;
            while (hotkey) {
                if (newhotkey=(struct dopushotkey *)
                    getcopy((char *)hotkey,sizeof(struct dopushotkey),NULL)) {
                    newhotkey->func.function=getcopy(hotkey->func.function,-1,NULL);
                    newhotkey->next=NULL;
                    if (curhotkey) curhotkey->next=newhotkey;
                    else firsthotkey=newhotkey;
                    curhotkey=newhotkey;
                }
                hotkey=hotkey->next;
            }
        }
    }
}

void freegadgets(first)
struct dopusgadgetbanks *first;
{
    struct dopusgadgetbanks *temp;

    while (first) {
        temp=first->next;
        freegadgetbank(first,1);
        first=temp;
    }
}

void freegadgetbank(bank,free)
struct dopusgadgetbanks *bank;
int free;
{
    int a;

    if (bank) {
        for (a=0;a<GADCOUNT;a++) {
            freestring(bank->gadgets[a].name);
            freestring(bank->gadgets[a].function);
        }
        if (free) FreeMem(bank,sizeof(struct dopusgadgetbanks));
    }
}

void freefunction(func)
struct dopusfunction *func;
{
    freestring(func->function);
    func->function=NULL;
}

void freenewfunction(func)
struct newdopusfunction *func;
{
    freestring(func->name); func->name=NULL;
    freestring(func->function); func->function=NULL;
}

char *getcopy(object,size,key)
char *object;
int size;
struct DOpusRemember **key;
{
    char *newobject;

    if (!object) return(NULL);
    if (size==-1) size=strlen(object)+1;
    if (key) newobject=(char *)LAllocRemember(key,size,MEMF_CLEAR);
    else newobject=AllocMem(size,MEMF_CLEAR);
    if (newobject) CopyMem((char *)object,(char *)newobject,size);
    return(newobject);
}

void makestring(char *buf,...)
{
    va_list ap;
    char *ptr;
    struct Gadget *gad,*first=NULL;
    struct ConfigGadget *cgad;

    if (!tickgad) return;
    gad=tickgad;

    va_start(ap,buf);
    while (buf && gad) {
        if (gad->GadgetType==STRGADGET) {
            cgad=(struct ConfigGadget *)gad->UserData;
            cgad->buffer=buf;
            ptr=(char *)((struct StringInfo *)gad->SpecialInfo)->Buffer;
            strcpy(ptr,buf);
            RefreshStrGad(gad,Window);
            if (!first) first=gad;
            buf=(char *)va_arg(ap,char *);
        }
        gad=gad->NextGadget;
    }
    if (first) ActivateStrGad(first,Window);
}

getstring(text,buf,len,num)
char *text,*buf;
int len,num;
{
    struct DOpusSimpleRequest req;
    char *gads[3];
    static int rets[2]={1,0};
    int a;

    gads[0]=cfg_string[STR_OKAY];
    gads[1]=cfg_string[STR_CANCEL];
    gads[2]=NULL;

    req.text=text;
    req.gads=gads;
    req.rets=rets;
    req.hi=screen_pens[config->gadgettopcol].pen;
    req.lo=screen_pens[config->gadgetbotcol].pen;
    req.fg=screen_pens[config->requestfg].pen;
    req.bg=screen_pens[config->requestbg].pen;
    req.strbuf=buf;
    req.strlen=len;
    req.flags=num|SRF_BORDERS|SRF_RECESSHI|SRF_EXTEND;
    req.value=(int)&stringex;
    req.font=NULL;
    req.title="ConfigOpus";
    busy();
    a=DoSimpleRequest(Window,&req);
    unbusy();
    return(a);
}

request(text)
char *text;
{
    return(do_request(text,cfg_string[STR_OKAY],cfg_string[STR_CANCEL]));
}

do_request(text,pos,neg)
char *text,*pos,*neg;
{
    struct DOpusSimpleRequest req;
    char *gads[3];
    static int rets[2]={1,0};
    int a;

    gads[0]=pos;
    gads[1]=neg;
    gads[2]=NULL;

    req.text=text;
    req.gads=gads;
    req.rets=rets;
    req.hi=screen_pens[config->gadgettopcol].pen;
    req.lo=screen_pens[config->gadgetbotcol].pen;
    req.fg=screen_pens[config->requestfg].pen;
    req.bg=screen_pens[config->requestbg].pen;
    req.strbuf=NULL;
    req.flags=SRF_BORDERS|SRF_RECESSHI;
    req.font=NULL;
    req.title="ConfigOpus";
    busy();
    a=DoSimpleRequest(Window,&req);
    unbusy();
    return(a);
}

void doglassimage(gad)
struct Gadget *gad;
{
    int a,o;

    o=rp->FgPen;
    SetDrMd(rp,JAM1);
    SetAPen(rp,screen_pens[config->gadgetbotcol].pen);
    for (a=0;a<2;a++) {
        BltTemplate((char *)glass_data[a],0,4,rp,gad->LeftEdge+4,gad->TopEdge+2,20,9);
        SetAPen(rp,screen_pens[config->gadgettopcol].pen);
    }
    SetDrMd(rp,JAM2);
    SetAPen(rp,o);
}

void freestring(str)
char *str;
{
    if (str) FreeMem(str,strlen(str)+1);
}

static char lasttitle[80];

void doscreentitle(str)
char *str;
{
    if (str && str!=(char *)-1) strcpy(lasttitle,str);
    SetWindowTitles(Window,lasttitle,(char *)-1);
}

struct IntuiMessage *getintuimsg()
{
    struct IntuiMessage *msg;
    struct MenuItem *item;
    int a;
    char buf[10],c;

    if (msg=(struct IntuiMessage *)GetMsg(Window->UserPort)) {
        if (msg->Class==IDCMP_RAWKEY) {
            if (msg->Qualifier&IEQUALIFIER_RCOMMAND && Window->MenuStrip) {
                if (!(msg->Code&0x80)) {
                    RawkeyToStr(msg->Code,0,NULL,buf,10); c=LToUpper(buf[0]);
                    item=Window->MenuStrip->FirstItem;
                    a=0;
                    while (item) {
                        if (item->Command && c==item->Command) {
                            msg->Class=MENUPICK;
                            msg->Code=a<<5;
                            break;
                        }
                        item=item->NextItem;
                        ++a;
                    }
                }
            }
            else if (msg->Code==0x5f && help_ok) {
                doconfighelp();
                ReplyMsg((struct Message *)msg);
                msg=NULL;
            }
        }
        else if (msg->Class==IDCMP_MENUPICK) {
            doscreentitle((char *)-1);
            if (Window->MenuStrip==&projectmenu && MENUNUM(msg->Code)==0) {
                a=0;
                switch (ITEMNUM(msg->Code)) {
                    case 3: dosave(0); a=1; break;
                    case 4: dosave(1); a=1; break;
                }
                if (a) {
                    ReplyMsg((struct Message *)msg);
                    msg=NULL;
                }
            }
        }
        else if (msg->Class==IDCMP_MOUSEMOVE && Window->MenuStrip) {
            if (msg->MouseY>Window->BorderTop && msg->MouseY<Window->Height &&
                msg->MouseX>=0 && msg->MouseX<Window->Width) Window->Flags|=RMBTRAP;
            else Window->Flags&=~RMBTRAP;
        }
    }
    return(msg);
}

struct TextFont *getfont(font,size,flags)
char *font;
int *size,flags;
{
    BPTR lock;
    struct TextFont *tf;
    static struct TextAttr sfont={NULL,0,0,0};

    sfont.ta_Name=(STRPTR)font; sfont.ta_YSize=*size;
    if ((tf=OpenFont(&sfont)) && tf->tf_YSize==sfont.ta_YSize &&
        (!(tf->tf_Flags&FPF_PROPORTIONAL) || flags!=FFLAG_NOPROP)) return(tf);
    if (tf) CloseFont(tf);
    if (!(lock=Lock("FONTS:",ACCESS_READ))) {
        strcpy(font,"topaz.font"); *size=8; sfont.ta_YSize=8;
        return((OpenFont(&sfont)));
    }
    UnLock(lock);
    if (!DiskfontBase || !(tf=OpenDiskFont(&sfont))) {
        if ((tf=OpenFont(&sfont))) *size=tf->tf_YSize;
    }
    if (!tf ||
        (!tf && flags!=FFLAG_8ONLY) ||
        (tf && flags==FFLAG_NOPROP && tf->tf_Flags&FPF_PROPORTIONAL)) {
        if (tf) CloseFont(tf);
        strcpy(font,"topaz.font"); *size=8; sfont.ta_YSize=8;
        tf=OpenFont(&sfont);
    }
    return(tf);
}

void loadrgb4(scr,pal,num)
struct Screen *scr;
USHORT *pal;
int num;
{
    int a,b;
    ULONG *data;

    if (data=AllocMem(num*3*sizeof(ULONG),0)) {
        for (a=0,b=0;a<num;a++) {
            data[b++]=(((pal[a]>>8)&0xf)<<28)|0x0fffffff;
            data[b++]=(((pal[a]>>4)&0xf)<<28)|0x0fffffff;
            data[b++]=((pal[a]&0xf)<<28)|0x0fffffff;
        }
        load_palette(scr,data,num);
        FreeMem(data,num*3*sizeof(ULONG));
    }
}

void load_palette(screen,palette,numcols)
struct Screen *screen;
ULONG *palette;
{
    if (!screen) {
        if (version2>=OSVER_39) {
            int a,b;

            for (a=0,b=0;a<numcols;a++) {
                SetRGB32(&Window->WScreen->ViewPort,
                    screen_pens[a].pen,
                    palette[b++],palette[b++],palette[b++]);
            }
        }
    }
    else if (version2>=OSVER_39) {
        ULONG *backup_palette;

        if (backup_palette=AllocMem(((numcols*3)+2)*sizeof(ULONG),MEMF_CLEAR)) {
            CopyMem((char *)palette,(char *)&backup_palette[1],(numcols*3)*sizeof(ULONG));
            backup_palette[0]=numcols<<16;
            backup_palette[(numcols*3)+1]=0;
            LoadRGB32(&screen->ViewPort,backup_palette);
            FreeMem(backup_palette,((numcols*3)+2)*sizeof(ULONG));
        }
    }
    else {
        UWORD backup_palette[16];
        int a,b;

        for (a=0,b=0;a<numcols*3;b++) {
            backup_palette[b]=0;
            backup_palette[b]|=(palette[a++]&0xf0000000)>>20;
            backup_palette[b]|=(palette[a++]&0xf0000000)>>24;
            backup_palette[b]|=(palette[a++]&0xf0000000)>>28;
        }

        LoadRGB4(&screen->ViewPort,backup_palette,numcols);
    }
}

void get_palette(screen,palette,numcols)
struct Screen *screen;
ULONG *palette;
int numcols;
{
    if (!screen) {
        if (version2>=OSVER_39) {
            int a,b;

            for (a=0,b=0;a<numcols;a++,b+=3) {
                GetRGB32(Window->WScreen->ViewPort.ColorMap,
                    screen_pens[a].pen, 
                    1,
                    &palette[b]);
            }
        }
    }
    else if (version2>=OSVER_39) {
        GetRGB32(screen->ViewPort.ColorMap,0,numcols,palette);
    }
    else {
        int a,b;
        ULONG colour;

        for (a=0,b=0;a<numcols;a++) {
            colour=GetRGB4(screen->ViewPort.ColorMap,a);
            palette[b++]=(((colour>>8)&0xf)<<28)|0x0fffffff;
            palette[b++]=(((colour>>4)&0xf)<<28)|0x0fffffff;
            palette[b++]=((colour&0xf)<<28)|0x0fffffff;
        }
    }
}

void open_screen()
{
    if (!Window) {
        int a,onworkbench=0;
        struct Screen *wbscreen=NULL,*usescreen;

        if (tfont) CloseFont(tfont);
        a=8;
        tfont=getfont(config->fontbufs[0],&a,FFLAG_8ONLY);
        strcpy(sfont.ta_Name,tfont->tf_Message.mn_Node.ln_Name);

        if (version2>=OSVER_39) {
            if (wbscreen=LockPubScreen(NULL)) {
                if (wbscreen->Height>wbscreen->WBorTop+wbscreen->Font->ta_YSize+189) {
                    int pen,num;
                    struct ColorMap *cm;

                    cm=wbscreen->ViewPort.ColorMap;
                    num=1<<((config->scrdepth > 4) ? 4 : config->scrdepth);

                    for (pen=0;pen<num;pen++) {
                        screen_pens[pen].red=config->new_palette[(pen*3)];
                        screen_pens[pen].green=config->new_palette[(pen*3)+1];
                        screen_pens[pen].blue=config->new_palette[(pen*3)+2];
                        if ((screen_pens[pen].pen=
                            ObtainPen(cm,-1,
                                screen_pens[pen].red,
                                screen_pens[pen].green,
                                screen_pens[pen].blue,
                                PEN_EXCLUSIVE))==(unsigned char)-1) break;
                        screen_pens[pen].alloc=1;
                    }

                    if (pen<num) free_colour_table(cm);
                    else onworkbench=1;
                }
            }
        }

        configscr.Depth=config->scrdepth;
        if (!onworkbench) {
            if (version2 >= OSVER_39) {
              scr_taglist[1].ti_Data = BestModeID(BIDTAG_DesiredWidth, configscr.Width,
                                                  BIDTAG_DesiredHeight, configscr.Height,
                                                  BIDTAG_Depth, configscr.Depth,
                                                  BIDTAG_MonitorID, GetVPModeID(&wbscreen->ViewPort) & MONITOR_ID_MASK,
                                                  TAG_END);
#ifdef DEBUG
kprintf("ConfigOpus ModeID: %lx\n",scr_taglist[1].ti_Data);
#endif
              if (scr_taglist[1].ti_Data == INVALID_ID) scr_taglist[1].ti_Data = 0;
            }
            while (!(Screen=OpenScreen((struct NewScreen *)&configscr))) {
                if (configscr.Depth<=2) quit();
                --configscr.Depth;
            }
            ShowTitle(Screen,FALSE);
            usescreen=Screen;
        }
        else usescreen=wbscreen;

        vp=&usescreen->ViewPort;
        config->scrdepth=configscr.Depth;
        screen_depth=configscr.Depth;

        configwin.Screen=usescreen;
        configwin.Height=usescreen->WBorTop+usescreen->Font->ta_YSize+189;

        configwin.LeftEdge=0;
        configwin.TopEdge=usescreen->Font->ta_YSize+3;

        if (!Screen) {
            if (config->config_x>-1) configwin.LeftEdge=config->config_x;
            if (config->config_y>-1) configwin.TopEdge=config->config_y;
        }

        if (configwin.Width+configwin.LeftEdge>usescreen->Width)
            configwin.LeftEdge=usescreen->Width-configwin.Width;

        if (configwin.Height+configwin.TopEdge>usescreen->Height)
            configwin.TopEdge=usescreen->Height-configwin.Height;

        if (!(Window=OpenWindow(&configwin))) quit();

        if (!Screen) SetWindowTitles(Window,(char *)-1,configscr.DefaultTitle);

        rp=Window->RPort;
        FSSetMenuStrip(Window,&projectmenu);

        x_off=Window->BorderLeft;
        y_off=Window->BorderTop;
        x_bot=Window->Width-Window->BorderRight-1;
        y_bot=Window->Height-Window->BorderBottom-1;

        if (tfont) SetFont(rp,tfont);
        if (wbscreen) UnlockPubScreen(NULL,wbscreen);
    }

    load_palette(Screen,config->new_palette,1<<((screen_depth > 4) ? 4 : screen_depth));

    doradiobuttons();
    fix_gadget_positions();
    if (Screen || cmdport) ScreenToFront(Window->WScreen);
}

void close_screen()
{
    free_colour_table((Window)?Window->WScreen->ViewPort.ColorMap:NULL);
    if (Window) {
        if (Window->MenuStrip) ClearMenuStrip(Window);
        CloseWindow(Window);
        Window=NULL;
    }
    if (Screen) {
        CloseScreen(Screen);
        Screen=NULL;
    }
}

void free_colour_table(cm)
struct ColorMap *cm;
{
    int a;

    if (version2>=OSVER_39 && cm) {
        for (a=0;a<16;a++) {
            if (screen_pens[a].alloc)
                ReleasePen(cm,screen_pens[a].pen);
        }
    }

    for (a=0;a<16;a++) {
        screen_pens[a].pen=a;
        screen_pens[a].alloc=0;
    }
}
