/*---------------------------------------------------*
  $Id: req.c,v 1.6 92/11/03 17:16:31 tf Exp $
  dcmp_Request()  a quick requster hack for dcmp.c,v
  This code has been created in haste. So be careful!
 *---------------------------------------------------*/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <stdio.h>

#ifndef AUTOSCROLL
#define AUTOSCROLL 0x4000  /* screen is to autoscoll (V36+) */
#endif

static char rcs_id[] = "$Id: req.c,v 1.6 92/11/03 17:16:31 tf Exp $";

/*
 * Compile with -D xxxx, where xxxx can be one of those: (default: all of them ;)
 *
 * #define INFOBOX      * an infobox has no visible window border
 * #define NICEBORDER   * alternative border for the INFOBOX
 * #define NICEOPEN     * open windows via NiceOpenWindow()
 * #define MAGICTEXT    * Text() odd lines top-down, even lines bottom-up
 */

#define DETAILPEN  (0x0000)  /* compatible Intuition rendering pens */
#define BLOCKPEN   (0x0001)  /* compatible Intuition rendering pens */
#define TEXTPEN    (0x0002)  /* text on background */
#define SHINEPEN   (0x0002)  /* bright edge on 3D objects */
#define SHADOWPEN  (0x0001)  /* dark edge on 3D objects */
#define BACKFILL   (0x0003)  /* window background */

#ifdef NICEOPEN
extern struct Window *NiceOpenWindow(struct NewWindow *);
extern void NiceCloseWindow(struct Window *);
#endif

UBYTE *ReqWindowTitle= (UBYTE *)"dcmp Request";
struct Screen *ReqScreen= (struct Screen *)NULL;

struct TextAttr ReqTextAttr= {
  (STRPTR) "topaz.font",  /* ta_Name  */
  8,                      /* ta_YSize */
  FS_NORMAL,              /* ta_Style */
  FPF_ROMFONT             /* ta_Flags */
};

struct IntuiText ReqGadgetText[2]= {
  { TEXTPEN,BACKFILL,JAM2,4+4,2,&ReqTextAttr,NULL,NULL },
  { TEXTPEN,BACKFILL,JAM2,4+4,2,&ReqTextAttr,NULL,NULL }
};

SHORT ReqBorderPairs0[2][] = {
 { 0,0, 0,11, 1,11, 1,0, 86,0 },
 { 1,11, 86,11, 86,1, 87,0, 87,11 }
};

SHORT ReqBorderPairs1[2][] = {
 { 0,0, 0,11, 1,11, 1,0, 86,0 },
 { 1,11, 86,11, 86,1, 87,0, 87,11 }
};

struct Border ReqBorder0[] = {
  { 0,0,2,0,JAM1,5,(SHORT *)ReqBorderPairs0[0],&ReqBorder0[1] },
  { 0,0,1,0,JAM1,5,(SHORT *)ReqBorderPairs0[1],NULL }
};

struct Border ReqBorder1[] = {
  { 0,0,2,0,JAM1,5,(SHORT *)ReqBorderPairs1[0],&ReqBorder1[1] },
  { 0,0,1,0,JAM1,5,(SHORT *)ReqBorderPairs1[1],NULL }
};

struct Gadget ReqGadget[2]= {
  { NULL,                       /* NextGadget */
    0,0,0,12,                   /* LeftEdge, TopEdge, Width, Height */
    GADGHCOMP,                  /* Flags */
    GADGIMMEDIATE|RELVERIFY,    /* Activation */
    BOOLGADGET,                 /* GadgetType */
    &ReqBorder0[0],NULL,        /* GadgetRender, SelectRender */
    &ReqGadgetText[0],          /* GadgetText */
    NULL,NULL,                  /* MutualExclude, SpecialInfo */
    1L,NULL                     /* GadgetID, UserData */
  },
  { NULL,                       /* NextGadget */
    0,0,0,12,                   /* LeftEdge, TopEdge, Width, Height */
    GADGHCOMP,                  /* Flags */
    GADGIMMEDIATE|RELVERIFY,    /* Activation */
    BOOLGADGET,                 /* GadgetType */
    &ReqBorder1[0],NULL,        /* GadgetRender, SelectRender */
    &ReqGadgetText[1],          /* GadgetText */
    NULL,NULL,                  /* MutualExclude, SpecialInfo */
    0L,NULL                     /* GadgetID, UserData */
  }
};

struct NewWindow ReqNewWindow= { 
  50,50,80,40,                  /* LeftEdge, TopEdge, Width, Height */
  DETAILPEN,BLOCKPEN,           /* DetailPen, BlockPen */
  CLOSEWINDOW|GADGETUP|RAWKEY,  /* IDCMPFlags */
  RMBTRAP|ACTIVATE,             /* Flags */
  NULL,NULL,                    /* FirstGadget, CheckMark */
  NULL,NULL,NULL,               /* Title, Screen, BitMap */
  0,0,0,0,                      /* MinWidth, MinHeight, MaxWidth, MaxHeight */
  WBENCHSCREEN                  /* Type */
};

long dcmp_Request(text, pos, neg)
char *text, *pos, *neg;
{ long whichwitch=0; /* return code */
  BOOL done= FALSE;
  int ReqTextLines[30];
  int i, t, m, c, y;

  /*
   * If you're already using some of these pointers, then don't forget to
   * declare them locally (or as static), because otherwise the global ones
   * will be used!  Note also that this could crash the system because
   * dcmp_Request() closes it's stuff then using the global vectors !
   */

  struct IntuitionBase *IntuitionBase;
  struct GfxBase       *GfxBase;
  struct TextFont      *TextFont;
  struct Screen        *Screen;
  struct Window        *ReqWindow;
  struct RastPort      *RastPort;
  struct IntuiMessage  *IntuiMessage;

  if(!text) return(-1L); /* just to be sure */

  IntuitionBase= (struct IntuitionBase *)OpenLibrary("intuition.library",LIBRARY_VERSION);
  if(!IntuitionBase)
    return(-1L);
  GfxBase= (struct GfxBase *)OpenLibrary("graphics.library",LIBRARY_VERSION);
  if(!GfxBase)
  { CloseLibrary(IntuitionBase);
    return(-1L);
  }
  TextFont= (struct TextFont *)OpenFont(&ReqTextAttr);
  if(!TextFont)
  { CloseLibrary(GfxBase);
    CloseLibrary(IntuitionBase);
    return(-1L);
  }

  m=0; /* length (#of chars) in longest text line */

  for(i=0,t=0; i<30 && !done; i++)
  { c=0; /* char counter (this line) */
    while(text[t]!='\0' && text[t]!='\n') { t++; c++; }
    ReqTextLines[i]= c;
    if(text[t]=='\0') done= TRUE;
    else t++;
    if(c>m) m=c;
  }
  if(i<29) ReqTextLines[i]= (-1);

  ReqNewWindow.Width= 20+ m * TextFont->tf_XSize;
  ReqNewWindow.Height= 30+ i * (1+ TextFont->tf_YSize);

  if(pos && *pos)
  {
    ReqGadget[0].LeftEdge= 10;

#ifdef NICEBORDER
    ReqGadget[0].TopEdge= ReqNewWindow.Height- 17;
#else
    ReqGadget[0].TopEdge= ReqNewWindow.Height- 15;
#endif

    ReqGadget[0].Width= 2* ReqGadgetText[0].LeftEdge
                        + strlen(pos) * TextFont->tf_XSize;

    ReqGadgetText[0].IText= pos;

    ReqBorderPairs0[0][8]= ReqBorderPairs0[1][2]
                         = ReqBorderPairs0[1][4] = ReqGadget[0].Width -2;
    ReqBorderPairs0[1][6]= ReqBorderPairs0[1][8] = ReqGadget[0].Width -1;

    ReqNewWindow.FirstGadget= &ReqGadget[0];
  }

  if(neg && *neg)
  {
    ReqGadget[1].Width= 2* ReqGadgetText[1].LeftEdge
                        + strlen(neg) * TextFont->tf_XSize;

    ReqGadget[1].LeftEdge= ReqNewWindow.Width- ReqGadget[1].Width- 10;

#ifdef NICEBORDER
    ReqGadget[1].TopEdge= ReqNewWindow.Height- 17;
#else
    ReqGadget[1].TopEdge= ReqNewWindow.Height- 15;
#endif

    ReqGadgetText[1].IText= neg;

    ReqBorderPairs1[0][8]= ReqBorderPairs1[1][2]
                         = ReqBorderPairs1[1][4] = ReqGadget[1].Width -2;
    ReqBorderPairs1[1][6]= ReqBorderPairs1[1][8] = ReqGadget[1].Width -1;

    if(pos && *pos) ReqGadget[0].NextGadget= &ReqGadget[1];
    else ReqNewWindow.FirstGadget= &ReqGadget[1];
  }

  /* calculate window's minimum width (as if there were no text) */

  m=  20 + ReqGadget[0].Width + ReqGadget[1].Width + 8;

  if(m < 83) m= 83; /* absolute minimum width: 83 */
  if(ReqNewWindow.Width < m)
  { ReqNewWindow.Width= m;
    if(neg && *neg)
      ReqGadget[1].LeftEdge= ReqNewWindow.Width- ReqGadget[1].Width- 10;
  }

  if(ReqScreen != NULL) Screen= ReqScreen;

  /* Find the Screen on which we're going to pop up. */
   
  else
  { ULONG lock= LockIBase(NULL);
    Screen= IntuitionBase->ActiveScreen;
    UnlockIBase(lock);
    if(!Screen || ReqNewWindow.Width  > Screen->Width
               || ReqNewWindow.Height > Screen->Height )
    { lock= LockIBase(NULL);
      Screen= IntuitionBase->FirstScreen;
      UnlockIBase(lock);
      while(Screen && (Screen->Flags & WBENCHSCREEN) != WBENCHSCREEN)
        Screen= Screen->NextScreen;
      if(!Screen || ReqNewWindow.Width  > Screen->Width
                 || ReqNewWindow.Height > Screen->Height )
      { CloseFont(TextFont);
        CloseLibrary(GfxBase);
        CloseLibrary(IntuitionBase);
        return(-1L);
      }
    }
  }
  ReqNewWindow.Screen= Screen;
  ReqNewWindow.Type= Screen->Flags & SCREENTYPE;

  /*
   * If we're to open up on an AUTOSCROLL screen it would be very annoying
   * for the user to search for our requester... In this case we'll try to
   * center our window under the mouse:
   */

  if((Screen->Flags & AUTOSCROLL) == AUTOSCROLL)
  { ReqNewWindow.LeftEdge= Screen->MouseX - ReqNewWindow.Width/2;
    if(ReqNewWindow.LeftEdge < 0) ReqNewWindow.LeftEdge= 0;
    if(ReqNewWindow.LeftEdge + ReqNewWindow.Width > Screen->Width)
      ReqNewWindow.LeftEdge= Screen->Width - ReqNewWindow.Width;

    ReqNewWindow.TopEdge= Screen->MouseY - ReqNewWindow.Height/2;
    if(ReqNewWindow.TopEdge < 0) ReqNewWindow.TopEdge= 0;
    if(ReqNewWindow.TopEdge + ReqNewWindow.Height > Screen->Height)
      ReqNewWindow.TopEdge= Screen->Height - ReqNewWindow.Height;
  }
  else /* center our window on this screen */
  { ReqNewWindow.LeftEdge= (Screen->Width- ReqNewWindow.Width)/2;
    ReqNewWindow.TopEdge= (Screen->Height- ReqNewWindow.Height)/2;
  }

#ifdef INFOBOX

  ReqNewWindow.Flags |= BORDERLESS;

#else /* => we are to have a visible window border */

  ReqNewWindow.Title= ReqWindowTitle;
  ReqNewWindow.Flags |= WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG;

#endif

#ifdef NICEOPEN
  ReqWindow= (struct Window *)NiceOpenWindow(&ReqNewWindow);
#else
  ReqWindow= (struct Window *)OpenWindow(&ReqNewWindow);
#endif

  if(!ReqWindow)
  { CloseFont(TextFont);
    CloseLibrary(GfxBase);
    CloseLibrary(IntuitionBase);
    return(-1L);
  }
  RastPort= ReqWindow->RPort;

  SetAPen(RastPort,BACKFILL);

#ifdef INFOBOX

  RectFill(RastPort, 0, 0, ReqNewWindow.Width, ReqNewWindow.Height);

#ifdef NICEBORDER

  SetAPen(RastPort,SHINEPEN);
  Move(RastPort,ReqNewWindow.Width-2,0);
  Draw(RastPort,0,0);
  Draw(RastPort,0,ReqNewWindow.Height-1);
  SetAPen(RastPort,SHADOWPEN);
  Move(RastPort,1,ReqNewWindow.Height-1);
  Draw(RastPort,ReqNewWindow.Width-1,ReqNewWindow.Height-1);
  Draw(RastPort,ReqNewWindow.Width-1,0);

  SetAPen(RastPort,SHADOWPEN);
  Move(RastPort,ReqNewWindow.Width-5,1);
  Draw(RastPort,3,1);
  Draw(RastPort,3,ReqNewWindow.Height-2);
  SetAPen(RastPort,SHINEPEN);
  Move(RastPort,4,ReqNewWindow.Height-2);
  Draw(RastPort,ReqNewWindow.Width-4,ReqNewWindow.Height-2);
  Draw(RastPort,ReqNewWindow.Width-4,0);
  y= 5; /* y-position of the first text line */

#else

  SetAPen(RastPort,SHINEPEN);
  Move(RastPort,ReqNewWindow.Width-1,0);
  Draw(RastPort,0,0);
  Draw(RastPort,0,ReqNewWindow.Height-1);
  Move(RastPort,1,0);
  Draw(RastPort,1,ReqNewWindow.Height-2);

  SetAPen(RastPort,SHADOWPEN);
  Move(RastPort,1,ReqNewWindow.Height-1);
  Draw(RastPort,ReqNewWindow.Width-1,ReqNewWindow.Height-1);
  Draw(RastPort,ReqNewWindow.Width-1,0);
  Move(RastPort,ReqNewWindow.Width-2,ReqNewWindow.Height-1);
  Draw(RastPort,ReqNewWindow.Width-2,1);
  y= 6; /* y-position of the first text line */

#endif

#else

  RectFill(RastPort, 4, 11, ReqNewWindow.Width-5, ReqNewWindow.Height-3);
  y= 11;

#endif

  if(ReqNewWindow.FirstGadget) /* we just removed it/them from view */
    RefreshGList(ReqNewWindow.FirstGadget, ReqWindow, NULL, -1L);

  SetAPen(RastPort,TEXTPEN);
  SetBPen(RastPort,BACKFILL);
  SetFont(RastPort,TextFont);

#ifdef MAGICTEXT

  /* Attention: hacky code! */

  for(m=0; m<30 && ReqTextLines[m]>=0; m++); --m; /* get #of lines */
  t= (m>0 && m%2)?(m):(m-1); /* skip last line if #of lines even */
  { int d=strlen(text)-ReqTextLines[t]; /* first character, last line */
    if((m%2)==0) d-= 1+ReqTextLines[m]; /* skip last (even) line */
    y+= (1+ TextFont->tf_YSize);
    for(i=0, c=0; i<=m; i+=2, t-=2)
    { Move(RastPort, 10, y+ i*(1+ TextFont->tf_YSize));
      Text(RastPort, &text[c], ReqTextLines[i]);
      c+= 1+ ReqTextLines[i];   /* skip `\n' character */
      c+= 1+ ReqTextLines[i+1]; /* skip next (odd) line */
      WaitTOF();
      if(t>0)
      { Move(RastPort, 10, y+ t*(1+ TextFont->tf_YSize));
        Text(RastPort, &text[d], ReqTextLines[t]);
        d-= 1+ ReqTextLines[t-1]; /* skip `\n' character */
        d-= 1+ ReqTextLines[t-2]; /* skip previous (even) line */
        WaitTOF();
      }
    }
  }

#else

  for(i=0, c=0; i<30 && ReqTextLines[i]>=0; i++)
  { y+= (1+ TextFont->tf_YSize);
    Move(RastPort, 10,y);
    Text(RastPort, &text[c], ReqTextLines[i]);
    c+= 1+ ReqTextLines[i]; /* skip `\n' character */
  }

#endif

  done= FALSE;
  while(!done)
  { ULONG class;
    USHORT code; /* rawkey code */
    struct Gadget *address;
    Wait(1L<<ReqWindow->UserPort->mp_SigBit);
    while(IntuiMessage= (struct IntuiMessage *)GetMsg(ReqWindow->UserPort))
    { class   = IntuiMessage->Class;
      code    = IntuiMessage->Code;
      address = (struct Gadget *)IntuiMessage->IAddress;
      ReplyMsg(IntuiMessage);
      switch(class)
      { case GADGETUP:
          whichwitch= address->GadgetID;
        case CLOSEWINDOW:
          done= TRUE;
          break;
        case RAWKEY: /* evaluate rawkey code! no conversion (yet) */
        { switch(code)
          { case 0x43: case 0x44: case 0x15: case 0x31:
              whichwitch= 1L;                    /* ENTER, RETURN, Y, Z */
              done= TRUE;
              break;
            case 0x45: case 0x36: case 0x13:   /* ESC, N, R */
              whichwitch= 0L;
              done= TRUE;
              break;
          }
        }
      }
    }
  }

#ifdef NICEOPEN
  NiceCloseWindow(ReqWindow);
#else
  CloseWindow(ReqWindow);
#endif

  CloseFont(TextFont);
  CloseLibrary(GfxBase);
  CloseLibrary(IntuitionBase);
  return(whichwitch);
}
