/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                         */
/*               PRINTPOP - A "popup" printer setup program                */
/*                                                                         */
/*               by Robbie J Akins, Wellington, NEW ZEALAND                */
/*                                                                         */
/*                            Version 1.0                                  */
/*                            August 1987                                  */
/*                                                                         */
/*  Thanks for help and inspiration for this program must go to:           */
/*                                                                         */
/*      Charles Tyson..................for "Purty" (Fred Fish #66)         */
/*      The Software Distillery........for "PopCLI"                        */
/*      Rob Peck.......................for the examples in RKM             */
/*      Willy Langeveld................for "MXGads" (Fred Fish #52)        */
/*      and especially to Harriet Maybeck Tolly (of TollySoft) and her     */
/*      article in Amazing Computing about Mutual Exclude gadgets.....     */
/*      ...that really helped me to stop tearing my hair out!              */
/*                                                                         */
/*   To compile:  LC:lc1 -iINCLUDE: printpop.c                             */
/*                LC:lc2 -v printpop.c                                     */
/*                                                                         */
/*   To link: Alink with link_printpop                                     */
/*                                                                         */
/*   where "link_printpop" contains: FROM     WBC.o,+*                     */
/*                                   printpop.o                            */
/*                                   TO       PrintPop                     */
/*                                   LIBRARY  lib:lc.lib+lib:amiga.lib     */
/*                                                                         */
/*   SPECIAL NOTE: The way this program has been written (the easy way!)   */
/*                 means that either "printpop.o" (generated by the        */
/*                 compiler) must be 'run through' ATOM, or else the       */
/*                 final executable "printpop" must be run through         */
/*                 FIXHUNK (available on Fred Fish #36) for the program    */
/*                 to run correctly (that is, not crash!) on an Amiga      */
/*                 equipped with expansion memory. Sorry. Maybe the        */
/*                 next version of Lattice C will make this a bit easier!  */
/*                                                                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <exec/execbase.h>
#include <devices/input.h>
#include <devices/printer.h>
#include <intuition/intuition.h>

#include <visuals.h>             /* Visual components of program window */

/*********************** CONSTANTS **********************/
#define F1_KEY 0x50
#define SIGNON "\x1b[33mPRINTPOP\x1b[0m by Robbie J Akins, Wellington NEW ZEALAND\n"
#define DRAFTBUTTON	1
#define NLQBUTTON	2
#define SETTABBUTTON	3
#define CLEARTABBUTTON	4
#define RESETBUTTON	5
#define TENBUTTON	6
#define TWELVEBUTTON	7
#define FIFTEENBUTTON	8
#define PSBUTTON	9
#define ENLARGEDBUTTON	10
#define LMDOWNBUTTON	11
#define LMUPBUTTON	12
#define RMDOWNBUTTON	13
#define RMUPBUTTON	14

/********************** GLOBAL VARIABLES **********************/
struct task          *PopUpTask;
struct Interrupt      handlerStuff;
ULONG                 popupsig;
struct MemEntry       me[20];
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase       *GfxBase = NULL;
long                  DOSBase = 0;
struct Window        *PopWin;
BOOL                  success;
int                   openError;
union  printerIO {
       struct IOStdReq ios;
       struct IODRPReq iodrp;
       struct IOPrtCmdReq iopc;
       };
union  printerIO     *request;
struct MsgPort       *printerPort;
UBYTE  LeftMargBuf[4];
UBYTE  RightMargBuf[4];
UBYTE  SetMarginsBuffer[12];    /* Buffer for set margins command */
int    LeftMargData    = 15;    /* Initial value of left margin */
int    RightMargData   = 95;    /* Initial value of right margin */
SHORT  LeftOffset;
SHORT  RightOffset;

/********************** EXTERNAL ROUTINES **********************/
extern struct MsgPort  *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern void             HandlerInterface();
extern struct task     *FindTask();

/************************************************************************
*  The handler subroutine - called through the handler stub
*************************************************************************/
struct InputEvent *myhandler(ev, mydata)

   struct InputEvent *ev;      /* and a pointer to a list of events */
   struct MemEntry *mydata[];  /* system will pass me a pointer to my 
                                * own data space. */
   {
   register struct InputEvent *ep, *laste;

   /* scan the list of events to see if "pop-up" key pressed */
   for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
      {
      if ((ep->ie_Class == IECLASS_RAWKEY) &&
          (ep->ie_Code  == F1_KEY)     &&
          (ep->ie_Qualifier & IEQUALIFIER_LCOMMAND))
         {
         /* Able to handle this event so take it off the chain */
         if (laste == NULL)
            ev = ep->ie_NextEvent;
         else
            laste->ie_NextEvent = ep->ie_NextEvent;
         /* Signal to "pop-up" task */
         Signal(PopUpTask, popupsig);
         }
      else
         laste = ep;
      }

   /* pass on the pointer to the event */
   return(ev);
   }

/************************************************************************
* The main program to do the printpop stuff
*************************************************************************/
void _main()
{
int    looping;
ULONG  sig,mclass;
LONG   GadPos;
struct Gadget        *maddress;
struct MsgPort       *inputDevPort;
struct IOStdReq      *inputRequestBlock;
struct IntuiMessage  *mesg;
struct RastPort      *ThisRastPort;

   PopUpTask = FindTask(0);
   sig = Output();
   Write(sig, SIGNON, sizeof(SIGNON));

   SetTaskPri( PopUpTask, 20);

   if ((inputDevPort = CreatePort(0,0)) == NULL) /* for input device */
      goto abort0;

   if ((inputRequestBlock = CreateStdIO(inputDevPort)) == 0)
      goto abort;

   if ((sig = AllocSignal(-1)) == -1)
      goto abort;

   popupsig = 1 << sig;

   if ((GfxBase = (struct GfxBase *)
                  OpenLibrary("graphics.library", 33)) == NULL)
      goto abort;

   if ((IntuitionBase = (struct IntuitionBase *)
                        OpenLibrary("intuition.library", 33)) == NULL)
      goto abort;

   handlerStuff.is_Data = (APTR)&me[0];    /* address of handler data area */
   handlerStuff.is_Code = HandlerInterface;/* addr of handler entry point  */
   handlerStuff.is_Node.ln_Pri = 51;       /* set the priority 1 step higher
                                            than Intuition so that handler
                                            enters chain ahead of Intuition*/

   if (OpenDevice("input.device",0,inputRequestBlock,0))
      goto abort;

   inputRequestBlock->io_Command = IND_ADDHANDLER;
   inputRequestBlock->io_Data    = (APTR)&handlerStuff;

   DoIO(inputRequestBlock);


   for(;;)         /* FOREVER */
      {
      sig = Wait( popupsig );

      if (sig & popupsig)
         {
/*=========================================================================*/

WBenchToFront();

if((PopWin=(struct Window *) make_window()) == NULL) /* Open window */
	goto CleanUp;

/* Draw Borders and Intuitexts in window */

ThisRastPort = PopWin -> RPort;
DrawBorder(ThisRastPort,&QualityBorder,0,0); /* Draw boxes around gadgets */
PrintIText(ThisRastPort,&QualityText,0,0);   /* Write titles above gadgets */

/* Convert values of margins into strings for IntuiTexts */

LeftOffset = IntToText(LeftMargData,LeftMargBuf);
RightOffset = IntToText(RightMargData,RightMargBuf);
LeftMargText.IText = &LeftMargBuf[0];
RightMargText.IText = &RightMargBuf[0];
PrintIText(ThisRastPort,&LeftMargText,LeftOffset,0); /* Print left marg value */
PrintIText(ThisRastPort,&RightMargText,RightOffset,0);/* Print rgt marg value */

/* Set up IDCMP read loop and handle events */

looping = TRUE;
while (looping)
{
WaitPort(PopWin->UserPort);
while((mesg=(struct IntuiMessage *) GetMsg(PopWin->UserPort))!=NULL)
	{
	mclass = mesg->Class;
	maddress = (struct Gadget *)mesg->IAddress;
	ReplyMsg(mesg);
	
	if(mclass == CLOSEWINDOW) looping = FALSE;
	if(mclass == GADGETDOWN)
	    {
		switch (maddress->GadgetID)
		{
		case DRAFTBUTTON:
			MXGads(PopWin,&DraftGadget,&NLQGadget,
				&NULLGadget1,&NULLGadget2);
			break;
		case NLQBUTTON:
			MXGads(PopWin,&NLQGadget,&DraftGadget,
				&NULLGadget1,&NULLGadget2);
			break;
		case SETTABBUTTON:
			MXGads(PopWin,&SetTabGadget,&ClearTabGadget,
				&NULLGadget1,&NULLGadget2);
			break;
		case CLEARTABBUTTON:
			MXGads(PopWin,&ClearTabGadget,&SetTabGadget,
				&NULLGadget1,&NULLGadget2);
			break;
		case RESETBUTTON:
			/* "Ghost" all gadgets on Reset */
			GadPos = RemoveGList(PopWin,&RightUpGadget,14L);
			ClearTabGadget.Flags ^= GADGDISABLED;
			SetTabGadget.Flags ^= GADGDISABLED;
			NLQGadget.Flags ^= GADGDISABLED;
			DraftGadget.Flags ^= GADGDISABLED;
			RightUpGadget.Flags ^= GADGDISABLED;
			RightDownGadget.Flags ^= GADGDISABLED;
			LeftUpGadget.Flags ^= GADGDISABLED;
			LeftDownGadget.Flags ^= GADGDISABLED;
			EnlargedGadget.Flags ^= GADGDISABLED;
			
			if((EnlargedGadget.Flags & SELECTED) != SELECTED)
				PSGadget.Flags ^= GADGDISABLED;
			
			FifteenGadget.Flags ^= GADGDISABLED;
			TwelveGadget.Flags ^= GADGDISABLED;
			TenGadget.Flags ^= GADGDISABLED;
			AddGList(PopWin,&RightUpGadget,GadPos,14L,(LONG)NULL);
			RefreshGList(&RightUpGadget,PopWin,(LONG)NULL,14L);
			break;
		case TENBUTTON:
			MXGads(PopWin,&TenGadget,&TwelveGadget,
				&FifteenGadget,&PSGadget);
			break;
		case TWELVEBUTTON:
			MXGads(PopWin,&TwelveGadget,&TenGadget,
				&FifteenGadget,&PSGadget);
			break;	
		case FIFTEENBUTTON:
			MXGads(PopWin,&FifteenGadget,&TwelveGadget,
				&TenGadget,&PSGadget);
			break;
		case PSBUTTON:
			MXGads(PopWin,&PSGadget,&TwelveGadget,
				&FifteenGadget,&TenGadget);
			break;
		case ENLARGEDBUTTON:
			/* "Ghost" PS pitch gadget on Enlarged */
			/* If PS selected, force to 10 pitch selection*/
			if ((PSGadget.Flags & SELECTED) == SELECTED)
				MXGads(PopWin,&TenGadget,&TwelveGadget,
					&FifteenGadget,&PSGadget);
			GadPos = RemoveGList(PopWin,&PSGadget,1L);
			PSGadget.Flags ^= GADGDISABLED;
			AddGList(PopWin,&PSGadget,GadPos,1L,(LONG)NULL);
			RefreshGList(&PSGadget,PopWin,(LONG)NULL,1L);
			break;
		case LMDOWNBUTTON:
			/* Decrement value of left margin */
			if(LeftMargData > 1)
			{
			LeftMargData--;
			LeftOffset = IntToText(LeftMargData,LeftMargBuf);
			LeftMargText.IText = &LeftMargBuf[0];
			PrintIText(ThisRastPort,&BlankText,238,68);
			PrintIText(ThisRastPort,&LeftMargText,LeftOffset,0);
			}
			break;
		case LMUPBUTTON:
			/* Increment value of left margin */
			if(LeftMargData < 998)
			{
			LeftMargData++;
			LeftOffset = IntToText(LeftMargData,LeftMargBuf);
			LeftMargText.IText = &LeftMargBuf[0];
			PrintIText(ThisRastPort,&BlankText,238,68);
			PrintIText(ThisRastPort,&LeftMargText,LeftOffset,0);
			}
			break;	
		case RMDOWNBUTTON:
			/* Decrement value of right margin */
			if(RightMargData > 1)
			{
			RightMargData--;
			RightOffset = IntToText(RightMargData,RightMargBuf);
			RightMargText.IText = &RightMargBuf[0];
			PrintIText(ThisRastPort,&BlankText,322,68);
			PrintIText(ThisRastPort,&RightMargText,RightOffset,0);
			}
			break;
		case RMUPBUTTON:
			/* Increment value of right margin */
			if(RightMargData < 998)
			{
			RightMargData++;
			RightOffset = IntToText(RightMargData,RightMargBuf);
			RightMargText.IText = &RightMargBuf[0];
			PrintIText(ThisRastPort,&BlankText,322,68);
			PrintIText(ThisRastPort,&RightMargText,RightOffset,0);
			}
			break;
		}
	    }
	}
}

CloseWindow(PopWin); /* Close window on way out */

success = FALSE;
printerPort = (struct MsgPort *)CreatePort("HelloPrinter",0);
if(printerPort == NULL) goto ForgetIt;

request = (union printerIO *)CreateExtIO(printerPort,sizeof(union printerIO));
if(request == NULL) goto ForgetIt;

openError = OpenPrinter(request);
if(openError) goto ForgetIt;
success = TRUE;

/* Now execute appropriate printer commands */

if((ResetGadget.Flags & SELECTED) == SELECTED)
	PrintString(request,"\x1b#1"); /* aRIN command */
else
	{
	if((NLQGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b[2\x22z"); /* aDEN2 command */
	else
		PrintString(request,"\x1b[1\x22z"); /* aDEN1 command */
	/* First "reset" the printer to normal (10) pich */
		PrintString(request,"\x1b[0w"); /* aSHORP0 command */
	if((FifteenGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b[4w"); /* aSHORP4 command */
	if((TwelveGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b[2w"); /*aSHORP2 command */
	if((PSGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b[2p"); /* aPROP2 command */
	else
		PrintString(request,"\x1b[1p"); /* aPROP1 command */
	if((EnlargedGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b[6w"); /* aSHORP6 command */
	else
		PrintString(request,"\x1b[5w"); /* aSHORP5 command */

/* Set left & right margins using ESC [ n1 ; n2 s */

	strcpy(SetMarginsBuffer,"\x1b[");
	strcat(SetMarginsBuffer,LeftMargBuf);
	strcat(SetMarginsBuffer,";");
	strcat(SetMarginsBuffer,RightMargBuf);
	strcat(SetMarginsBuffer,"s");
	PrintString(request,SetMarginsBuffer);

	if((SetTabGadget.Flags & SELECTED) == SELECTED)
		PrintString(request,"\x1b#5"); /* aTBSALL command */
	else
		PrintString(request,"\x1b#4");/* aTBCALL command */
	}
PrintString(request,"\x0d"); /* Terminating C/R required by some printers */

goto CleanUp; /* Exit gracefully */

ForgetIt:
	Apologise("Sorry, but unable to send the",
		  "control codes that you requested",
		  "to the printer. Maybe in use?");
CleanUp:
	if(success)     ClosePrinter(request);
	if(printerPort) DeletePort(printerPort);
	if(request)     DeleteExtIO(request);


/*=========================================================================*/
          }

      } /* END OF FOREVER LOOP */

abort:
   if (IntuitionBase != NULL)
      CloseLibrary(IntuitionBase);

   if (GfxBase != NULL)
      CloseLibrary(GfxBase);

   DeletePort(inputDevPort);

abort0:
   XCEXIT(-1);
}

/************************************************************************
*   Function to open window
*************************************************************************/

make_window()
{
struct NewWindow NewWindow;

	NewWindow.LeftEdge=0;
	NewWindow.TopEdge=0;
	NewWindow.Width=402;
	NewWindow.Height=103;
	NewWindow.DetailPen=0;
	NewWindow.BlockPen=1;
	NewWindow.IDCMPFlags= CLOSEWINDOW | GADGETDOWN;
	NewWindow.Flags= ACTIVATE | WINDOWDRAG | WINDOWDEPTH |
                         WINDOWCLOSE | NOCAREREFRESH | GIMMEZEROZERO;
	NewWindow.FirstGadget=&RightUpGadget;
	NewWindow.CheckMark=NULL;
	NewWindow.Title="PRINTPOP - Printer Setup Utility";
	NewWindow.Screen=NULL;
	NewWindow.BitMap=NULL;
	NewWindow.MinWidth=0;
	NewWindow.MinHeight=0;
	NewWindow.MaxWidth=0;
	NewWindow.MaxHeight=0;
	NewWindow.Type=WBENCHSCREEN;

	return(OpenWindow(&NewWindow));
}

/********************************************************************
*   This routine fakes mutual-exclude of four gadgets
********************************************************************/
MXGads(win,gad1,gad2,gad3,gad4)
struct Window *win;
struct Gadget *gad1,*gad2,*gad3,*gad4;
{
LONG GadNumber1,GadNumber2,GadNumber3,GadNumber4;

	GadNumber1 = RemoveGList(win,gad1,1L);
	GadNumber2 = RemoveGList(win,gad2,1L);
	GadNumber3 = RemoveGList(win,gad3,1L);
	GadNumber4 = RemoveGList(win,gad4,1L);

	gad1->Flags |= SELECTED; /* FORCE TO BE SELECTED! */
	if((gad2->Flags & SELECTED) == SELECTED) (gad2->Flags ^= SELECTED);
	if((gad3->Flags & SELECTED) == SELECTED) (gad3->Flags ^= SELECTED);
	if((gad4->Flags & SELECTED) == SELECTED) (gad4->Flags ^= SELECTED);

	AddGList(win,gad4,GadNumber4,1L,(LONG)NULL);		
	RefreshGList(gad4,win,(LONG)NULL,1L);
	AddGList(win,gad3,GadNumber3,1L,(LONG)NULL);
	RefreshGList(gad3,win,(LONG)NULL,1L);
	AddGList(win,gad2,GadNumber2,1L,(LONG)NULL);
	RefreshGList(gad2,win,(LONG)NULL,1L);
	AddGList(win,gad1,GadNumber1,1L,(LONG)NULL);
	RefreshGList(gad1,win,(LONG)NULL,1L);
}
/************************************************************************
*      Printersupport routines from 1.1 Rom Kernel manual
*************************************************************************/

/* OPEN THE PRINTER */
int
OpenPrinter(request)
   union printerIO *request;
      {
      return(OpenDevice("printer.device",0,request,0));
      }

/* CLOSE THE PRINTER */
int
ClosePrinter(request)
   union printerIO *request;
      {
      CloseDevice(request);
      return(0);
      }

/* SEND NULL TERMINATED STRING TO PRINTER */
int
PrintString(request,string)
   union printerIO *request;
    char *string;
    {
    request->ios.io_Command = CMD_WRITE;
    request->ios.io_Data = (APTR)string;
    request->ios.io_Length = -1;
    return(DoIO(request));
    }
    
/************************************************************************
*      Raise an autorequester with (up to) three lines of text
*************************************************************************/

Apologise (line1, line2, line3)
UBYTE  *line1, *line2, *line3;

{
	Sorry[0].IText = line1;
	Sorry[1].IText = line2;
	Sorry[2].IText = line3;
	AutoRequest (NULL, &Sorry, NULL, &Proceed,  0, 0, 300, 66);
}
/************************************************************************
*      Convert margin value into text for IntuiText
*  (returns value to displace text string by for "good" appearance)
*************************************************************************/

IntToText(n,string)
int    n;
UBYTE *string;

{
int displace; /* Amount to displace display of text by */

	string[0] = n/100 +'0';
	if (string[0] == '0')
		{
		string[0] = (n%100)/10 + '0';
		if (string[0] == '0')
			{
			string[0] = (n%100)%10 + '0';
			string[1] = '\0';
			displace = 8;
			}
		else
			{
			string[1] = (n%100)%10 + '0';
			string[2] = '\0';
			displace = 4;
			}
		}
	else
		{
		string[1] =  (n%100)/10 + '0';
		string[2] =  (n%100)%10 + '0';
		string[3] = '\0';
		displace = 0;
		}

	return(displace);
}

