/*
 *  File:		editor.c
 *  Function:	icon editor code
 *  Author:		Paul Elseth
 *				Copyright (c) 1991, Paul Elseth
 *
 *	Change History:
 *
 *		12/03/91	PBE		created
 */

#ifndef	__EDITOR__
#include "editor.h"
#endif

#ifndef __FOUNDATION__
#include "foundation.h"
#endif
#ifndef	__GLOBALS__
#include "globals.h"
#endif
#ifndef	__FATBITS__
#include "fatbits.h"
#endif
#ifndef	__FILL__
#include "fill.h"
#endif
#ifndef	__FATUTILS__
#include "fatUtils.h"
#endif
#ifndef	__UTILS__
#include "utils.h"
#endif
#ifndef	__MEMUTILS__
#include "memutils.h"
#endif
#ifndef	__OFFSCREEN__
#include "offscreen.h"
#endif
#ifndef	__COLOR__
#include "color.h"
#endif
#ifndef	__MISCTOOL__
#include <miscTool.h>
#endif
#ifndef	__RESOURCES__
#include <resources.h>
#endif
#ifndef	__WINDOW__
#include <window.h>
#endif
#ifndef __QDAUX__
#include <qdaux.h>
#endif
#ifndef __INTMATH__
#include <intmath.h>
#endif
#ifndef __orca__
#include <orca.h>
#endif
#ifndef	__OPTIONS__
#include "options.h"
#endif

#pragma noroot

#define kMenuBarHite	13          /* height of system menu bar */
#define kWTitleHite		12          /* height of standard window title bar */
#define kInfoBarHite	19          /* height of editor window's info bar */
#define kScrollBarHite	13          /* height of standard scrollbar */
#define kScrollBarWidth	26          /* width of standard scrollbar */
/*#define kScrollBarHite	0			/* height of standard scrollbar */
/*##define kScrollBarWidth	0			/* width of standard scrollbar */


Picture	**gToolsPicH;					/* tool palette picture */
short	gToolsPicWidth, gToolsPicHite;	/* size of tool palette picture */	


/*
 *	GetIconResource()
 *		Load an icon resource, creating it if necessary.
 */
static
short GetIconResource(short type, long *id, Boolean gotData, Handle data, Handle *rsrcH)
{		
	short	err;

	if (*id != 0L) {
		err = LoadAResource(type, *id, rsrcH);
        if (err == 0 && rsrcH != nil) {
			SetPurge(0, *rsrcH);
/*          HUnlock(*rsrcH);	*/
			}
		return err;
		}
	else
		return -1;
}


/*
 *	FreeEditor()
 *  	Free the stuff in the editor's data handle.
 */
static
void FreeEditor(IconData** dataH)
{
	IconData	*dataP;

	HLock((Handle) dataH);
	dataP = *dataH;

    DisposeIfHandle((Handle) dataP->oldIconH);
    DisposeIfHandle((Handle) dataP->undoIconH);
	DisposeOffscreen(dataP->imageCache);
	DisposeOffscreen(dataP->maskCache);

	HUnlock((Handle) dataH);
}


/*
 *	CalcFat()
 *  	Calculate all the rects involved in the fatbits window.
 */
void CalcFat(IconData** dataH)
{
    IconData		*dataP;
	QDIconRecord	*iconP;
    unsigned short	width, hite;
    short			x;
	
	dataP = *dataH;
	iconP = *(dataP->iconH);

/* extract the icon and mask rects: */
	width = (unsigned short) iconP->iconWidth * 8 + 2 + 4;
    hite = (unsigned short) iconP->iconHeight * 4 + 3;

	dataP->fatIRect.v1 = 8;
    dataP->fatIRect.h1 = 16;
	dataP->fatIRect.v2 = 8 + hite;
    dataP->fatIRect.h2 = 16 + width;

    dataP->fatMRect.v1 = 8;
    dataP->fatMRect.v2 = 8 + hite;
    dataP->fatMRect.h1 = width + 32;
    dataP->fatMRect.h2 = width + width + 32;

/* calc the size box's rect: */
	dataP->sizeRect.v1 = dataP->fatIRect.v2 - 1;
    dataP->sizeRect.v2 = dataP->sizeRect.v1 + 5;
	dataP->sizeRect.h1 = dataP->fatIRect.h2 - 2;
	dataP->sizeRect.h2 = dataP->sizeRect.h1 + 10;

/* reposition the check box: */
	x = dataP->fatIRect.h1 + 100 > dataP->fatMRect.h1 ? dataP->fatIRect.h1 + 100 : dataP->fatMRect.h1;
	MoveControl(x, dataP->fatIRect.v2 + gFontHite + 3, dataP->control);

/* adjust the window's scroll bars according to the new size: */
	SetDataSize(iconP->iconWidth * 4 + 116 + dataP->fatMRect.h2,
    			dataP->fatIRect.v2 + 50, GetPort());
}


/*
 *	InitFatIcon()
 *		Initialize the fat icon data record.
 */
static
void InitFatIcon(IconData **dataH)
{
    IconData		*dataP;
    FontInfoRecord	fi;
	GrafPort		**imageH, **maskH;
    Handle			uh, oh;
	short			width, hite;
	short			err;

	GetFontInfo(&fi);
    gFontHite = fi.ascent + fi.descent + fi.leading;

	GetNewHandle(10, &uh);
	GetNewHandle(10, &oh);

    dataP = *dataH;
	dataP->dirty = false;
	dataP->imageCache = nil;
	dataP->maskCache = nil;
	dataP->color = 0;
	dataP->tool = 0;
    dataP->undoIconH = (QDIconRecord **) uh;
    dataP->oldIconH = (QDIconRecord **) oh;

	CalcFat(dataH);

/* allocate the offscreen pixelmaps: */
    dataP = *dataH;
	width = dataP->fatIRect.h2 - dataP->fatIRect.h1 - 8;
	hite = dataP->fatIRect.v2 - dataP->fatIRect.v1 - 4;

	err = CopyUndoIcon(dataH);
	err = CopyOldIcon(dataH);

	err = CreateOffPort(width, hite, &imageH);
	if (err == 0) {
		err = CreateOffPort(width, hite, &maskH);
		if (err == 0) {
    		dataP = *dataH;
		    dataP->imageCache = imageH;
		    dataP->maskCache = maskH;

  			DrawFatImage(dataH);
			DrawFatMask(dataH);
			}
		else
			DisposeOffscreen(imageH);
		}
}


/*
 *	SetWindowSize()
 *		Set the size of the fat pixels window.
 */
static
void SetWindowSize(QDIconRecord **iconH, WindowPtr wp)
{
	QDIconRecord	*iconP;
    unsigned short	xyzzy, minWidth, hite, width;
	Rect			wRect;

	iconP = *iconH;

/* calc window top and bottom: */
    xyzzy = kMenuBarHite + kWTitleHite + kInfoBarHite;

	hite = iconP->iconHeight * 4 + 16 + 2 * gFontHite;
    if (hite > 200 - xyzzy - kScrollBarHite)
		hite = 200 - xyzzy - kScrollBarHite;

	wRect.v1 = ((200 - xyzzy - kScrollBarHite) - hite) / 3 + xyzzy;
	wRect.v2 = wRect.v1 + hite;

/* calc left and right: */
	width = iconP->iconWidth * 20 + 88;
	minWidth = kColorBarWidth + gToolsPicWidth + 14;
	if (width < minWidth)
	    width = minWidth;
	if (width > 638 - kScrollBarWidth)
	    width = 638 - kScrollBarWidth;

	wRect.h1 = (((638 - kScrollBarWidth) - width) / 2 + 2) & 0xfffe;
    wRect.h2 = (wRect.h1 + width) & 0xfffe;

/* set window size: */
	ResizeWindow(false, &wRect, wp);
}
      

/*
 *	DrawEm()
 *		Draw the icon in different states.
 */
void DrawEm(IconData **dataH)
{
	short			x, y;
	QDIconRecord	*iconP, **iconH;
    short			oState;

    iconH = (**dataH).iconH;
	oState = HGetState((Handle) iconH);
	HLock((Handle) iconH);
	iconP = *iconH;

	x = (**dataH).fatMRect.h2 + 16;
    y = (**dataH).fatMRect.v1 + 4;

    DrawIcon(iconP, 0, x, y);
    DrawIcon(iconP, 1, x + 4 + iconP->iconWidth * 2, y);
    DrawIcon(iconP, 2, x, y + 8 + iconP->iconHeight);
    DrawIcon(iconP, 4, x + 4 + iconP->iconWidth * 2, y + 8 + iconP->iconHeight);

	HSetState((Handle) iconH, oState);
}


/*
 *	EmRect()
 *		Get the 'em rect.
 */
static
void EmRect(IconData **dataH, Rect *r)
{
    IconData		*dataP;
	QDIconRecord	*iconP;
    
    dataP = *dataH;
    iconP = *(dataP->iconH);

    r->h1 = dataP->fatMRect.h2 + 16;
    r->h2 = r->h1 + iconP->iconWidth * 8 + 32;

    r->v1 = dataP->fatMRect.v1 + 4;
	r->v2 = r->v1 + iconP->iconHeight * 2 + 8;
}   
    

/*
 *	EraseEm()
 *		Erase the sample icon area.
 */
void EraseEm(IconData **dataH)
{
	Rect			r;

	EmRect(dataH, &r);
    EraseRect(&r);
}   
    

/*
 *	UpdateEm()
 *		Update the sample icon area.
 */
void UpdateEm(IconData **dataH)
{
	Rect			r;

	EmRect(dataH, &r);
    InvalRect(&r);
}   


/*
 *	RedrawFatbits()
 *		Redraw the fatbits image or mask.
 */
void RedrawFatbits(IconData **dataH, Boolean mask)
{
    GrafPort	*oPort;
    Cursor		*oCurs;
	IconData	*dataP;
    Rect		r;

    oCurs = GetCursorAdr();
	SetWaitCursor();
	oPort = GetPort();
    StartDrawing(FrontWindow());

    dataP = *dataH;
    r = mask ? dataP->fatMRect : dataP->fatIRect;
	InsetRect(&r, 2, 1);
	InvalRect(&r);

    if (mask) {
		DrawFatMask(dataH);
		EraseEm(dataH);
        UpdateEm(dataH);
        }
    else
  		DrawFatImage(dataH);

	SetOrigin(0, 0);
    SetPort(oPort);
	SetMyCursor(oCurs);
}


/*
 *	PaintImage()
 *		Paint cached icon image or mask to the port.
 */
static
void PaintImage(GrafPort **src, short x, short y)
{
	HLock((Handle) src);

	PPToPort(&(**src).portInfo, &(**src).portRect, x, y, modeCopy);

	HUnlock((Handle) src);
}


/*
 *	DrawEditor()
 *		Draw an icon editor window.
 */
#pragma	databank	1
static
pascal void DrawEditor(void)
{		
	IconData		*dataP, **dataH;
   	QDIconRecord	**iconH, *iconP;
    WindowPtr		wp;

    wp = GetPort();

	dataH = (IconData **) GetPrivateData(wp);
	HLock((Handle) dataH);
	dataP = *dataH;
    iconH = dataP->iconH;

	ShowControl(dataP->control);
	DrawControls(wp);

	SetPenSize(2, 1);
    FrameRect(&dataP->fatIRect);
    FrameRect(&dataP->fatMRect);
	FrameRect(&dataP->sizeRect);

	PenNormal();

/* draw the title strings: */
	MoveTo(dataP->fatIRect.h1, dataP->fatIRect.v1);
	DrawCString("Image");

	MoveTo(dataP->fatMRect.h1, dataP->fatMRect.v1);
	DrawCString("Mask");

    MoveTo(dataP->fatMRect.h2 + 16, dataP->fatMRect.v1);
    DrawCString("Samples:");

/* draw the icon in different modes: */
	DrawEm(dataH);

/* draw the fat icon image: */
	PaintImage(dataP->imageCache, dataP->fatIRect.h1 + 4, dataP->fatIRect.v1 + 2);

/* draw the fat icon mask: */
	PaintImage(dataP->maskCache, dataP->fatMRect.h1 + 4, dataP->fatMRect.v1 + 2);

/* draw the hite/width strings: */
    {
	char 	*hiteStr = "Height: 000  ";
	char	*widStr = "Width: 000  ";

	iconP = *iconH;

    Int2Dec(iconP->iconWidth, &widStr[7], 3, false);
    Int2Dec(iconP->iconHeight, &hiteStr[8], 3, false);

	MoveTo(dataP->fatIRect.h1, dataP->fatIRect.v2 + gFontHite + 3);
    DrawCString(hiteStr);
	MoveTo(dataP->fatIRect.h1, dataP->fatIRect.v2 + gFontHite + gFontHite + 3);
    DrawCString(widStr);
	}
}        
#pragma	databank	0


/*
 *	OpenEditor()
 *		Open the icon editor window.
 */
short OpenEditor(fOpenRec *parms)
{
    IconData		*dataP, **dataH;
    char			wTitle[128];
	CtlRec			**control;
    QDIconRecord	**iconH;
	long			id;
    WindowPtr		wp;
	short			err;

extern char	EditorWindowParamBlock;
extern char	CICheckBox;

	if (gToolsPicH == nil) {
		err = LoadMyResource(rPicture, 0x1000, (Handle *) &gToolsPicH);
		if (err == 0)
			err = DetachMyResource(rPicture, 0x1000);
		if (err != 0)
	        return err;

		gToolsPicWidth = (**gToolsPicH).picFrame.h2 - (**gToolsPicH).picFrame.h1;
		gToolsPicHite = (**gToolsPicH).picFrame.v2 - (**gToolsPicH).picFrame.v1;
		}

	id = parms->resID;
	err = GetIconResource(parms->resType, &id, parms->fFlag & (1 << 9),
    					  parms->Data, (Handle *) &iconH);

	err = GetNewHandle((long) sizeof(IconData), (Handle *) &dataH);
		
    if (err == 0) {
        (void) GetWindowTitle(parms->resType, id, wTitle);
		wp = NewWindow2(wTitle, 0L, DrawEditor, 0L, 0, &EditorWindowParamBlock, rWindParam1);
    	err = toolerror();
		if (err == 0) {
		    SetPort(wp);
			control = NewControl2(wp, 0, &CICheckBox);

			dataP = *dataH;
			dataP->iconH = iconH;
			dataP->control = control;
			dataP->resID = id;
            InitFatIcon(dataH);

			err = AddPrivateData(wp, (Handle) dataH, 0x0020, parms->resType, id);

            SetWindowSize(iconH, wp);
			SetFrameColor(parms->wColorPtr, wp);
			SetInfoDraw(DrawColorBar, wp);

			ShowWindow(wp);
        	}
		}

    return err;
}


/*
 *	UpdateEditor()
 *		Update an icon editor window.
 */
static
short UpdateEditor(WindowPtr wp)
{
	BeginUpdate(wp);
    EndUpdate(wp);

	return -1;
}


/*
 *	InEditorInfo()
 *		Mouse click in a editor window infobar.
 */
static
short InEditorInfo(EventRecord *event)
{
	SelectColor(event);
	return 0;
}


/*
 *	EditorContent()
 *		Handle a mouse click in the contents of an editor window.
 */
short EditorContent(EventRecord *event)
{
	FatClick(event);
	return 0;
}


/*
 *	WriteResourceIf()
 *		Write out the resource if it's been changed.
 */
static
short WriteResourceIf(short resType, long resID, IconData **dataH)
{
    short	err = 0;

    if ((**dataH).dirty) {
		err = WriteAResource(resType, resID);
		if (err == 0)
			(**dataH).dirty = false;
		}

	return err;
}   


/*
 *	EditorMenu()
 *		Menu item selected.
 */
static
short EditorMenu(EventRecord *event)
{
	WindowPtr	wp;
    IconData	**dataH;
	
    wp = FrontWindow();
	dataH = (IconData **) GetPrivateData(wp);
    
    switch ((short) event->wmTaskData) {
	    case 0x8001:					/* colored mask */
	        break;
	    case 0x8002:					/* create mask */
			MakeMask(dataH);
	        break;
	    case 0x8003:					/* copy icon to mask */
	        break;
	    }
	
	return 0;
}


/*
 *	UpdateCursor()
 *		Update the cursor image.
 */
static
void UpdateCursor(Point pt, Word modifiers)
{
	GrafPort	*oPort;
	WindowPtr	wp;
	IconData	**dataH;
	
    wp = FrontWindow();
	dataH = (IconData **) GetPrivateData(wp);

    oPort = GetPort();
	SetPort(wp);
	GlobalToLocal(&pt);

    if (PtInRect(&pt, &(**dataH).fatIRect) ||
    	PtInRect(&pt, &(**dataH).fatMRect)) {
#if	0
		if (modifiers & shiftKey)
			SetMyCursor(&ShifterCursor);
        else if (modifiers &optionKey)
			SetMyCursor(&BucketCursor);
        else
			SetMyCursor(&PencilCursor);
#else
		switch ((**dataH).tool) {
			case kPencilTool:
	            SetMyCursor(&PencilCursor);
                break;
			case kBucketTool:
	            SetMyCursor(&BucketCursor);
                break;
			case kShifterTool:
	            SetMyCursor(&ShifterCursor);
                break;
			case kPickerTool:
				SetMyCursor(&PickerCursor);
            	break;
	        default:
	    		SetArrowCursor();
	        }      
#endif
		}
	else
	    SetArrowCursor();

	SetPort(oPort);
}


/*
 *	EditorEvent()
 *		Handle an icon editor window event.
 */
short EditorEvent(fEventRec *parms)
{
	UpdateCursor(fEventPtr->where, fEventPtr->modifiers);

	switch (parms->taskCode) {
        case updateEvt:
 			return UpdateEditor((WindowPtr) fEventPtr->wmTaskData);
		case wInInfo:
	        return InEditorInfo(fEventPtr);
		case wInContent:
			return EditorContent(fEventPtr);
		case wInMenuBar:
			return EditorMenu(fEventPtr);
        default:
	        return 0;
	    }
}


/*
 *	CloseEditor()
 *	    Close the editor window.
 */
short CloseEditor(fCloseRec *parms)
{
	IconData	**dataH;
    WindowPtr	wp;
	short		err;

	wp = (WindowPtr) parms->windowPtr;

	dataH = (IconData **) GetPrivateData(wp);

    WriteResourceIf(parms->resType, parms->resID, dataH);

	FreeEditor(dataH);
	DisposeIfHandle((Handle) dataH);

	err = CloseAWindow(wp);

	SetArrowCursor();

	return err;
}


/*
 *	WriteEditor()
 *		Write this resource out.
 */
short WriteEditor(fCloseRec *parms)
{
	IconData	**dataH;

	dataH = (IconData **) GetPrivateData((WindowPtr) parms->windowPtr);

    return WriteResourceIf(parms->resType, parms->resID, dataH);
}


/*
 *	ActivateEditor()
 *	    Editor window was activated.
 */
short ActivateEditor(fActivateRec *parms)
{
	IconData	**dataH;
	short		err;

	if (parms->fFlag & 0x8000)			/* activate */
		err = 0;
	else {								/* deactivate */
		dataH = (IconData **) GetPrivateData((WindowPtr) fEventPtr->wmTaskData);
		err = WriteResourceIf(parms->resType, parms->resID, dataH);
		SetArrowCursor();
	    }
	return err;
}


/*
 *	EditorGetLink()
 *	    Resolve resource dependencies.
 */
short EditorGetLink(fLinkRec *parms)
{
	return 0;
}


/*
 *	EditorVidMode()
 *	    Change screen modes.
 */
short EditorVidMode(fVidModeRec *parms)
{
	return 0;
}


/*
 *	EditorPrint()
 *	    Print this window.
 */
short EditorPrint(fCloseRec *parms)
{
	return 0;
}
