/*----------------------------------------------------------------------*
  GadgetED.c version 3.0 - © Copyright 1990-91 Jaba Development

  Autor   : Jan van den Baard
  Purpose : main control program.
 *----------------------------------------------------------------------*/

USHORT pointer[] =
 { 0x0000,0x0000,0xffff,0xffff,0xc007,0xffff,0xaffb,0xffff,
   0xa439,0xffff,0xd77d,0xffff,0xf6fd,0xffff,0xf43d,0xffff,
   0xf7fd,0xffff,0xf70d,0xffff,0xf7dd,0xffff,0xd7bd,0xffff,
   0xa709,0xffff,0xaffb,0xffff,0xc003,0xffff,0xffff,0xffff,
   0x0000,0x0000,0x0000,0x0000 };
USHORT Colors[] =
 { 0x0000,0x0ecb,0x0f00,0x0ff0,0x00f0,0x00c0,0x0090,0x0060,
   0x000f,0x000c,0x0009,0x0ff0,0x0cc0,0x0990,0x0f0f,0x0c0c,
   0x0909,0x0a00,0x0000,0x0f00,0x0444,0x0555,0x0666,0x0777,
   0x0888,0x0999,0x0aaa,0x0bbb,0x0ccc,0x0ddd,0x0fff,0x0f00 };
USHORT info_data[] =
 { 0xee00,0xc600,0xaa00,0xee00,0xee00,0xee00,0xee00,0xaa00,
   0xc600,0xee00,0xfff0,0xef70,0xdfb0,0x8010,0xdfb0,0xef70,
   0xfff0,0xee00,0xc600,0xaa00,0xee00,0xee00,0xee00,0xee00,
   0xee00,0xee00,0xee00,0xfff0,0xeff0,0xdff0,0x8010,0xdff0,
   0xeff0,0xfff0,0xfff0,0xbdf0,0xdbf0,0xe610,0xeff0,0xde10,
   0xbff0,0xfff0,0xfff8,0xbdf8,0xdbf8,0xe708,0xe7f8,0xdb08,
   0xbdf8,0xfff8 };

struct Image HEIGHT_image =
 { 247,0,7,10,1,NULL,0x01,0x00,NULL };
struct Image WIDTH_image  =
 { 197,1,12,7,1,NULL,0x01,0x00,&HEIGHT_image };
struct Image TOP_image    =
 { 150,0,7,10,1,NULL,0x01,0x00,&WIDTH_image };
struct Image LEFT_image   =
 { 100,1,12,7,1,NULL,0x01,0x00,&TOP_image };
struct Image YC_image     =
 { 50,1,12,8,1,NULL,0x01,0x00,&LEFT_image };
struct Image XC_image     =
 { 0,1,13,8,1,NULL,0x01,0x00,&YC_image };

#define DATA_SIZE_TOTAL 100
#define HEIGHT_OFFSET   0
#define WIDTH_OFFSET    10
#define TOP_OFFSET      17
#define LEFT_OFFSET     27
#define YC_OFFSET       34
#define XC_OFFSET       42

UBYTE wdt[80]       = "Work Window";
UBYTE wlb[MAXLABEL] = "new_window";

struct TextAttr std =
 { (STRPTR)"topaz.font",8,FS_NORMAL,FPF_ROMFONT };

/*
 * I'm not using the OS 2.0 headers but I still want the
 * OS 2.0 look when running under OS 2.0. So I put a little quick
 * and dirty hack here to make it possible.
 */
#define PensTag (1 << 31L) + 32 + 0x1A /* SA_Pens Tag      */
#define Extended 0x1000                /* NS_EXTENDED Flag */

struct Tags {   /* A very short taglist with one item */
    ULONG   Tag, *Param, End; };

UWORD   DriPens[10] = { /* The standard WBench dri-pens */
    0,1,1,2,1,3,1,0,1,~0 };
struct Tags st = {  /* Set up a simple tag list */
    PensTag,(ULONG *)&DriPens[0],0L };

struct NewScreen ns_main =
 { 0,0,640,STDSCREENHEIGHT,2,0,1,HIRES,CUSTOMSCREEN,&std,TITLE,NULL,NULL };
/*
 * When this is putten directly after the NewScreen structure and the
 * Extented flag set (under 2.0) the system see's this as a ExtNewScreen
 * structure.
 */
struct Tags *tg = &st;

struct NewWindow nw_main =
 { 50,25,175,50,0,1,IDCMP_NM,FLAGS_NM,NULL,NULL,
   (UBYTE *)&wdt,NULL,NULL,150,50,0,256,CUSTOMSCREEN };

char name[512];

struct FileSelector  *IODir = NULL;
struct Window        *MainWindow = NULL;
struct Screen        *MainScreen = NULL;
struct RastPort      *MainRP;
struct Process       *Proc;
struct Gadget        *Gadget;
struct MemoryChain    Memory;
struct MemoryChain    Misc;
struct GadgetList     Gadgets;
struct SharedList     Images;
struct Requester      dw;
struct ge_prefs       prefs  = { TRUE,TRUE,TRUE };
struct Gadget         TextGadget = { NULL,0,0,1,1,GADGHNONE,NULL,BOOLGADGET,
                                     NULL,NULL,NULL,NULL,NULL,NULL,NULL };

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase       = NULL;
struct ToolBase      *ToolBase      = NULL;

extern struct Library   *SysBase;

void set_info();
void do_info();

APTR    sysreq      = (APTR)-1L;
BYTE    Xoff        = -1, Yoff = 0;
BOOL    Saved       = TRUE;
BOOL    REQUESTER   = FALSE;
BOOL    WORKBENCH   = FALSE;
BOOL    WBSCREEN    = FALSE;
ULONG   WindowFlags = WINDOWSIZING+WINDOWDRAG+WINDOWCLOSE+WINDOWDEPTH+NOCAREREFRESH+SMART_REFRESH+ACTIVATE;
ULONG   IDCMPFlags  = GADGETUP+GADGETDOWN+CLOSEWINDOW;
ULONG   Class;
USHORT  BackFill    = 1, WDBackFill = 0;
USHORT  Code, Qualifier, WBColors[4], LightSide = 2, DarkSide = 1;
USHORT *pd, *data_pointer;
USHORT  FrontPen = 1, BackPen = 0, GadgetCount = 0, id = 0, DEPTH;
SHORT   MainX, MainY;
char   *extension = ".PS";

extern struct MenuItem   SubItems[];
extern struct Menu       Titles[];
extern struct WBStartup *WBenchMsg;
extern struct BorderList SBorders;

void set_coords();
void do_coords();

/*
 * free and close all resources
 */
VOID close_up(msg)
 UBYTE *msg;
{
     Proc->pr_WindowPtr = sysreq;

     if(ToolBase) {
         FreeGList();
         free_all();
         FreeMenuStrip();
         if(IODir)         FreeFreq(IODir);
                           OpenWorkBench();
         if(MainWindow) {
             ClearMenuStrip(MainWindow);
             CloseWindow(MainWindow);
         }
         if(MainScreen)    CloseScreen(MainScreen);
         FreeMemoryChain(&Misc);
         FreeMemoryChain(&Memory);
         CloseLibrary(ToolBase);
     }
     if(msg)           puts(msg);
     exit(0);
}

/*
 * allocate open and setup all resources
 */
VOID open_libs()
{
     int i;

     if(NOT(ToolBase = (struct ToolBase *)
      OpenLibrary("tool.library",8)))
        close_up("   - ERROR: Can't find the tool.library V8++!");

     InitMemoryChain(&Misc,1024L);
     InitMemoryChain(&Memory,(5*1024));

     GfxBase       = ToolBase->GfxBase;
     IntuitionBase = ToolBase->IntuitionBase;

     for(i=0;i<4;i++)
         WBColors[i] = (USHORT)GetRGB4(IntuitionBase->ActiveScreen->ViewPort.ColorMap,i);

     if(NOT(IODir = AllocFreq()))
         close_up("   - ERROR: Out of memory !");

     if(NOT(pd = (USHORT *)
     AllocItem(&Misc,(POINTERSIZE << 1),MEMF_CHIP+MEMF_CLEAR)))
         close_up("   - ERROR: Out of memory !");
     if(NOT(data_pointer = (USHORT *)
     AllocItem(&Misc,DATA_SIZE_TOTAL,MEMF_CHIP+MEMF_CLEAR)))
         close_up("   ERROR: Out of memory !");

     CopyMem((void *)&pointer,(void *)pd,(POINTERSIZE << 1));
     CopyMem((void *)&info_data,(void *)data_pointer,DATA_SIZE_TOTAL);

     HEIGHT_image.ImageData = (USHORT *)&data_pointer[HEIGHT_OFFSET];
     WIDTH_image.ImageData  = (USHORT *)&data_pointer[WIDTH_OFFSET];
     TOP_image.ImageData    = (USHORT *)&data_pointer[TOP_OFFSET];
     LEFT_image.ImageData   = (USHORT *)&data_pointer[LEFT_OFFSET];
     YC_image.ImageData     = (USHORT *)&data_pointer[YC_OFFSET];
     XC_image.ImageData     = (USHORT *)&data_pointer[XC_OFFSET];
}

/*
 * open up the main display
 */
VOID open_display()
{
     if(NOT MainScreen) {
        if(SysBase->lib_Version >= 36)
            ns_main.Type |= Extended;
        if(NOT(MainScreen = OpenScreen(&ns_main)))
             close_up("   - ERROR: Can't open a work screen !");
     }
     nw_main.Screen    = MainScreen;
     nw_main.MaxHeight = MainScreen->Height;

     if(NOT(MainWindow = OpenWindow(&nw_main)))
         close_up("   - ERROR: Can't open a work window !");

     if(TestBits((ULONG)prefs.flag_bits,GP_COORDS)) {
        Forbid();
        MainWindow->Flags |= REPORTMOUSE;
        Permit();
        set_coords();
        do_coords();
     }
     MainRP = MainWindow->RPort;
}

/*
 * disable the edit window by putting up a little requester
 */
VOID disable_window()
{
    InitRequester(&dw);
    dw.LeftEdge = 0;
    dw.TopEdge  = 0;
    dw.Width    = 1;
    dw.Height   = 1;
    dw.BackFill = 1;
    Request(&dw,MainWindow);
}

/*
 * enable the edit window (remove the requester)
 */
VOID enable_window()
{
    EndRequest(&dw,MainWindow);
}

/*
 * show buisy pointer
 */
VOID buisy()
{
    SetPointer(MainWindow,(void *)pd,16,16,Xoff,Yoff);
}

/*
 * erase buisy pointer
 */
VOID ok()
{
    ClearPointer(MainWindow);
}

/*
 * change the depth of the edit screen
 */
VOID change_depth(depth)
    ULONG depth;
{
    if(MainWindow) {
        ClearMenuStrip(MainWindow);
        CloseWindow(MainWindow);
        MainWindow = NULL;
    }
    if(MainScreen) {
        if(depth != MainScreen->BitMap.Depth OR WBSCREEN) {
            CloseScreen(MainScreen);
            MainScreen = NULL;
        }
    }
    ns_main.Depth = depth;

    if(depth == 5) {
        ns_main.ViewModes = NULL;
        ns_main.Width     = 320;
        if(NOT nw_main.MaxWidth) nw_main.MaxWidth  = 320;
    } else {
        ns_main.ViewModes = HIRES;
        ns_main.Width     = 640;
        if(NOT nw_main.MaxWidth) nw_main.MaxWidth  = 640;
    }
    open_display();
    if(REQUESTER) {
        SetDrMd(MainRP,JAM1);
        SetAPen(MainRP,BackFill);
        RectFill(MainRP,0,0,MainWindow->GZZWidth,MainWindow->GZZHeight);
    }
    SetMenu(MainWindow);
}

/*
 * load the preferences file (if available)
 */
VOID load_prefs()
{
    BPTR file;

    if((file = Open("DEVS:PowerSource.PREFS",MODE_OLDFILE))) {
        if(Read(file,(char *)&prefs,sizeof(struct ge_prefs)) <= 0) {
            Close(file);
            Error("Error reading preferences !");
            return;
        }
        Close(file);
    }
}

/*
 * if a gadget has GRELWITH or GRELHEIGHT set and it's
 * a BOOL or STRGADGET gadget with a border this routine
 * sizes the border to fit around the gadget again after
 * a resizing of the window.
 */
VOID grl()
{
    register struct Gadget   *g;
    register struct MyGadget *mg;
    register struct Border   *b;
    register USHORT c1,c2;

    if(Gadgets.TailPred == (struct MyGadget *)&Gadgets) {
        refresh();
        return;
    }

    while(read_msg(MainWindow));

    ModifyIDCMP(MainWindow,SIZEVERIFY);

    buisy();
    disable_window();

    for(mg = Gadgets.Head; mg->Succ; mg = mg->Succ) {
        g = &mg->Gadget;
        un_grel(MainWindow,g);
        if((TestBits((ULONG)g->Flags,GRELWIDTH)) OR (TestBits((ULONG)g->Flags,GRELHEIGHT))) {
            if((NOT TestBits((ULONG)g->Flags,GADGIMAGE)) AND (NOT TestBits((ULONG)g->GadgetType,PROPGADGET))) {

                b = (struct Border *)g->GadgetRender;

                c1 = b->FrontPen;
                if(b->NextBorder)
                    c2 = b->NextBorder->FrontPen;

                if(g->Width < 9)
                    g->Width = 9;
                if(g->Height < 9)
                    g->Height = 9;

                FreeRender(mg);
                add_border(mg);

                b = (struct Border *)g->GadgetRender;
                b->FrontPen = c1;
                if(b->NextBorder)
                    b->NextBorder->FrontPen = c2;

                if(TestBits((ULONG)mg->SpecialFlags,OS20HIGHBORDER)) {
                    b = (struct Border *)g->SelectRender;

                    b->FrontPen = c2;
                    if(b->NextBorder)
                        b->NextBorder->FrontPen = c1;
                }
            }
        }
    }
    grel(MainWindow,g);
    enable_window();
    ok();
    while(read_msg(MainWindow));
    ModifyIDCMP(MainWindow,nw_main.IDCMPFlags);
    refresh();
}

VOID sst(title)
    char *title;
{
    struct RastPort *rp;

    SetWindowTitles(MainWindow,(char *)-1L,title);
    rp = &MainScreen->RastPort;
    SetAPen(rp,1);
    RectFill(rp,0,0,MainScreen->Width,9); /* clear the title bar */
    if(title) {
        SetAPen(rp,0);
        SetBPen(rp,1);
        SetDrMd(rp,JAM2);
        Move(rp,4,7);
        Text(rp,title,strlen(title));
    }
}

void set_coords( void )
{
    struct RastPort *rp = &MainScreen->RastPort;

    YC_image.NextImage = NULL;

    DrawImage(rp,&XC_image,MainScreen->Width - 160,0);
}

void do_coords( void )
{
    struct RastPort *rp = &MainScreen->RastPort;
    SHORT   xx,yy;

    get_xy(&xx,&yy);

    SetAPen(rp,0);
    SetBPen(rp,1);
    SetDrMd(rp,JAM2);

    Move(rp,MainScreen->Width - 145,7);
    FormatText(rp,"%-4ld",xx);
    Move(rp,MainScreen->Width - 96,7);
    FormatText(rp,"%-4ld",yy);
}

/*
 * setup the info display
 */
VOID set_info(how)
    ULONG   how;
{
    struct RastPort *rp;

    if(NOT how) {
        YC_image.NextImage  = &LEFT_image;
        TOP_image.NextImage = &WIDTH_image;
    } else if(how == 1) {
        YC_image.NextImage  = &LEFT_image;
        TOP_image.NextImage = NULL;
    }

    rp = &MainScreen->RastPort;
    sst(NULL);
    DrawImage(rp,&XC_image,0,0);
}

/*
 * update the info line
 */
VOID do_info(text,x,y,x1,y1)
    ULONG           text;
    register SHORT x,y,x1,y1;
{
    char  mx[5],my[5],l[5],t[5],w[5],h[5];
    SHORT xx,yy,tmp;
    struct RastPort *rp;

    rp = &MainScreen->RastPort;

    get_xy(&xx,&yy);

    if(x1 < x) { tmp = x; x = x1; x1 = tmp; }
    if(y1 < y) { tmp = y; y = y1; y1 = tmp; }

    SetAPen(rp,0);
    SetBPen(rp,1);
    SetDrMd(rp,JAM2);

    Move(rp,15,7);
    FormatText(rp,"%-4ld",xx);
    Move(rp,64,7);
    FormatText(rp,"%-4ld",yy);

    Move(rp,114,7);
    FormatText(rp,"%-4ld",x);
    Move(rp,159,7);
    FormatText(rp,"%-4ld",y);

    if(text == 1) return;

    Move(rp,211,7);
    FormatText(rp,"%-3ld",x1-x);
    Move(rp,256,7);
    FormatText(rp,"%-3ld",y1-y);
}

/*
 * Check for the ".ps" extension.
 */
void CheckName( void )
{
    char    buf[4];
    UWORD   i,len;

    len = strlen((char *)IODir->fr_FileName) - 3;

    for(i = 0; i < 3; i++, len++)
        buf[i] = toupper(IODir->fr_FileName[len]);

    if(strncmp((char *)&buf[0],extension,3))
        goto make;

    return;
make:
    strcat((char *)&name[0],extension);
    strcat((char *)IODir->fr_FileName,extension);
}


long IsItADir( void )
{
    struct FileInfoBlock    *fib;
    BPTR                     lock;
    long                     ret = -1L;

    if((fib = (struct FileInfoBlock *)AllocMem((ULONG)sizeof(struct FileInfoBlock),MEMF_PUBLIC))) {
        if((lock = Lock((char *)&name[0],ACCESS_READ))) {
            Examine(lock,(BPTR)fib);
            ret = fib->fib_DirEntryType;
            UnLock(lock);
        }
        FreeMem(fib,(ULONG)sizeof(struct FileInfoBlock));
    }
    return(ret);
}

long ParseName( void )
{
    char  buffer[512];
    char *str;

    strcpy((char *)&buffer[0],(char *)&name[0]);
    if(IsItADir() < 0) {
        str = (char *)&buffer[strlen((char *)&buffer[0])];
        while(*str != ':' AND *str != '/') {
            if(str == (char *)&buffer[0]) goto pwb;
            str--;
        }
        str++;
pwb:
        strcpy((char *)IODir->fr_FileName,str);
        *str = 0;
        strcpy((char *)IODir->fr_DirName,(char *)&buffer[0]);
        CheckName();
        return TRUE;
    } else
        strcpy((char *)IODir->fr_DirName,(char *)&buffer[0]);
        return FALSE;
}


/*
 * entry point
 */
VOID main(argc,argv)
    ULONG argc;
    char *argv[];
{
    SHORT x,y,x1,y1;
    BOOL running = TRUE;
    struct WBArg *wba;

    Proc = (struct Process *)FindTask(NULL);
    sysreq = Proc->pr_WindowPtr;
    Proc->pr_WindowPtr = (APTR)-1L;

    NewList((void *)&Gadgets);
    NewList((void *)&Images);
    NewList((void *)&SBorders);
    open_libs();

    if(NOT argc) {
        if(WBenchMsg->sm_NumArgs > 1) {
            wba = WBenchMsg->sm_ArgList;
            wba++;
            strcpy((char *)&name[0],(char *)wba->wa_Name);
            CurrentDir((struct FileLock *)wba->wa_Lock);
            if(ParseName())
                ReadBinGadgets(TRUE);
            else goto nono;
        } else {
nono:
            load_prefs();
            get_config(FALSE);
            change_depth(DEPTH);
            if(NOT WBSCREEN) LoadRGB4(&MainScreen->ViewPort,(void *)&Colors,(1 << DEPTH));
        }
    }
    else if(argc == 1) {
noway:
        load_prefs();
        get_config(FALSE);
        change_depth(DEPTH);
        if(NOT WBSCREEN) LoadRGB4(&MainScreen->ViewPort,(void *)&Colors,(1 << DEPTH));
    } else if(argc > 2)
        close_up("   - USAGE: PowerSource [name]");
    else {
        strcpy((char *)&name[0],argv[1]);
        if(ParseName())
            ReadBinGadgets(TRUE);
        else
            goto noway;
    }

    do {
        if(NOT TestBits((ULONG)prefs.flag_bits,GP_COORDS)) {
            if(strlen((char *)&wdt[0]))
                SetWindowTitles(MainWindow,(char *)&wdt[0],(char *)TITLE);
            else
                SetWindowTitles(MainWindow,(char *)-1L,(char *)TITLE);
        } else {
            set_coords();
            do_coords();
        }

        Wait(1 << MainWindow->UserPort->mp_SigBit);
        while(read_msg(MainWindow)) {
            if(Class != MOUSEMOVE AND TestBits((ULONG)prefs.flag_bits,GP_COORDS)) {
                set_coords();
                do_coords();
            }
            switch(Class) {
                case MOUSEMOVE:      do_coords();
                                     break;

                case GADGETUP:
                case GADGETDOWN:     break;

                case ACTIVEWINDOW:   while(read_msg(MainWindow));
                                     break;

                case INACTIVEWINDOW: if(NOT IntuitionBase->ActiveWindow)
                                         ActivateWindow(MainWindow);
                                     break;

                case NEWSIZE:        grl();
                                     Saved = FALSE;
                                     break;

                case RAWKEY:         handle_keys(Code,Qualifier);
                                     while(read_msg(MainWindow));
                                     break;

                case MENUPICK:       handle_menus(Code);
                                     break;

                case MOUSEBUTTONS:   if(Code == SELECTDOWN) {
                                         switch_coords(FALSE);
                                         set_info(0);
                                         get_xy(&x,&y);
                                         MainX = x;
                                         MainY = y;
                                         SetAPen(MainRP,FrontPen);
                                         SetDrMd(MainRP,COMPLEMENT);
                                         draw_box(MainWindow,MainX,MainY,x,y);
                                         do_info(0,MainX,MainY,x,y);
                                         while(Code == SELECTDOWN) {
                                             while(read_msg(MainWindow));
                                         }
                                         while(Code != SELECTDOWN) {
                                             while(read_msg(MainWindow)) {
                                                 if(Class == MENUPICK) set_info(0);
                                                 do_info(0,MainX,MainY,x,y);
                                             }
                                             get_xy(&x1,&y1);
                                             if((x1 != x) OR (y1 != y)) {
                                                 draw_box(MainWindow,MainX,MainY,x,y);
                                                 get_xy(&x,&y);
                                                 draw_box(MainWindow,MainX,MainY,x,y);
                                                 do_info(0,MainX,MainY,x,y);
                                             }
                                         }
                                         switch_coords(TRUE);
                                         add_gadget(MainWindow,MainX,MainY,x,y);
                                         refresh();
                                     }
                                     break;

                default:             break;
            }
        }
    } while(running == TRUE);
    close_up("  - BYE BYE");
}
