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

#ifndef	__PICKER__
#include "picker.h"
#endif
#ifndef __FOUNDATION__
#include "foundation.h"
#endif
#ifndef	__UTILS__
#include "utils.h"
#endif
#ifndef	__MEMUTILS__
#include "memutils.h"
#endif
#ifndef	__GLOBALS__
#include "globals.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 kScrollBarWidth	0           /* width of standard scrollbar */


/*
 *	MakeHexString()
 *		Make a hex string from the long parameter.
 */
static
char *MakeHexString(long n, char *s)
{
	Long2Hex(n, s, 8);
	s[8] = '\0';

#if	0
	while (*s == '0')
		++s;

	if (*s == '\0')
		--s;
#endif

	return s;
}


static short	DataHite;

/*
 *	SwizzleIcons()
 *
 */
static
short SwizzleIcons(WindowPtr wp, Boolean (*DoToIcon)(Rect *, PickerItem *dataP, short, long), long parm)
{
	PickerItem 		**dataH;
    unsigned short	numItems, i, j, n;	
	unsigned short	x, y, w, iHite, maxHite;
	unsigned short	windowWidth;
	short			retn;
	Rect			r;

    windowWidth = wp->portRect.h2 - wp->portRect.h1 - kScrollBarWidth;

	dataH = (PickerItem **) GetPrivateData(wp);
	
    numItems = GetHandleSize((Handle) dataH) / sizeof(PickerItem);

	HLock((Handle) dataH);

    y = 10;
	retn = -1;
	n = 0;

	do {		
    	maxHite = 0;

        x = 10;
		for (j = n; j < numItems; ++j) {
			iHite = (*dataH)[j].iHite;
			w = (*dataH)[j].width;

	        if ((x != 10) && (x + w > windowWidth))
				break;

        	x += w + 10;
	        if (iHite > maxHite)
		        maxHite = iHite;
	        }

		r.v1 = y;
        r.v2 = y + maxHite + gFontHite;

        x = 10;
		for (i = n; i < j; ++i) {
    	    w = (*dataH)[i].width;
        	r.h1 = x;
	        r.h2 = x + w;

			if (DoToIcon(&r, &(*dataH)[i], i, parm)) {
				retn = i;
	        	goto stop;
	            }

    	    x += w + 10;
	        }

		y += maxHite + gFontHite + 10;
		n = j;
	    } while (n < numItems);

stop:
	HUnlock((Handle) dataH);

	DataHite = y;

    return retn;
}


/*
 *	SetWindowDataSize()
 *		Set the scrollbars of a picker window.
 */
static
Boolean DoNullFn(Rect *r, PickerItem *dataP, short i, long parm)
{
	return false;
}

static
void SetWindowDataSize(WindowPtr wp)
{
	(void) SwizzleIcons(wp, DoNullFn, 0);

	SetDataSize(0, DataHite, wp);
}


/*
 *	DrawPicker()
 *		Draw an icon picker window.
 */
static
Boolean DoDraw(Rect *bounds, PickerItem *dataP, short i, long parm)
{
    QDIconRecord	**iconH;
	char			numStr[10], *s;
	unsigned short	sWidth, iWidth, iHite, w;
    short			x, y;
	short			oState;
	short			err;

	err = LoadAResource(rIcon, dataP->resID, (Handle *) &iconH);
    if (err != 0)
	    return;

	oState = HGetState((Handle) iconH);
	HLock((Handle) iconH);

	s = MakeHexString(dataP->resID, numStr);
	sWidth = CStringWidth(s);
	iWidth = (unsigned short) (**iconH).iconWidth * 2;
	iHite = (**iconH).iconHeight;

	w = bounds->h2 - bounds->h1;

	x = (bounds->h1 + (w - iWidth) / 2) & 0xfffe;
	y = bounds->v2 - iHite - gFontHite;
	DrawIcon(*iconH, 0, x, y);
	x = bounds->h1 + (w - sWidth) / 2;
	y = bounds->v2;
	MoveTo(x, y);
	DrawCString(s);			

	if (dataP->flag & 0x80) {
		InsetRect(bounds, -6, -4);
		SetPenSize(4, 2);
		FrameRect(bounds);
		SetPenSize(1, 1);
        }

	HSetState((Handle) iconH, oState);

	return false;
}

#pragma	databank 1
static
pascal void DrawPicker(void)
{
    WindowPtr	wp;

    wp = GetPort();

	DrawControls(wp);

	(void) SwizzleIcons(wp, DoDraw, 0);
}
#pragma	databank 0


/*
 *	MakePickerData()
 *		Create the picker data structure.
 */
static
short MakePickerData(ListItem **listH, PickerItem ***itemH)
{
	ListItem		*listP;
	PickerItem		**piH, *piP;
	char			numStr[10];
	unsigned short	numItems, i, sw, iw;
    QDIconRecord	**iconH;
    short			err;

	numItems = GetHandleSize((Handle) listH) / sizeof(ListItem);

    err = GetNewHandle((long) numItems * sizeof(PickerItem), (Handle *) &piH);

    if (err == 0) {
        *itemH = piH;

		HLock((Handle) piH);
        HLock((Handle) listH);
		piP = *piH;
	    listP = *listH;

        for (i = 0; i < numItems; ++i) {
			piP->name = listP->name;
			piP->flag = listP->flag;
			piP->resID = listP->resID;
			err = LoadAResource(rIcon, listP->resID, (Handle *) &iconH);

	        sw = CStringWidth(MakeHexString(piP->resID, numStr));
			iw = (**iconH).iconWidth * 2;
			piP->width = iw > sw ? iw : sw;
			piP->iHite = (**iconH).iconHeight;

			++piP;
			++listP;
	        }

		HUnlock((Handle) piH);
        HUnlock((Handle) listH);
		}            

	return err;
}


/*
 *	FreeIconList()
 *		Release all of the icons in the picker's list.
 */
static
void FreeIconList(PickerItem **itemH)
{
	unsigned short	i, numItems;
	short			err;

#if	0
    numItems = GetHandleSize((Handle) itemH) / sizeof(PickerItem);

	for (i = 0; i < numItems; ++i) {
		err = ReleaseAResource(rIcon, (*itemH)[i].resID);
        if (err != 0)
	        SysError(err);
        }
#endif
}


/*
 *	OpenPicker()
 *		Open the icon picker window.
 */
short OpenPicker(fOpenRec *parms)
{
    PickerItem		**itemH;
    char			wTitle[128];
    WindowPtr		wp;
    FontInfoRecord	fi;
	short			err;

    extern char		PickerWindowParamBlock;

	(void) GetWindowTitle(parms->resType, parms->resID, wTitle);

	wp = NewWindow2(wTitle, 0L, DrawPicker, 0L, 0, &PickerWindowParamBlock, rWindParam1);
   	err = toolerror();
	if (err == 0 && wp != nil) {
		SetPort(wp);
		GetFontInfo(&fi);
    	gFontHite = fi.ascent + fi.descent + fi.leading;

		err = MakePickerData((ListItem **) parms->Data, &itemH);
		DisposeIfHandle((Handle) parms->Data);
		if (err == 0) {
			err = AddPrivateData(wp, (Handle) itemH, 0x0010, parms->resType, parms->resID);
			SetFrameColor(parms->wColorPtr, wp);
			SetWindowDataSize(wp);
			ShowWindow(wp);
	        }
		}

    return err;
}


/*
 *	UpdatePicker()
 *		Update an icon picker window.
 */
static
short UpdatePicker(WindowPtr wp)
{
	BeginUpdate(wp);
    SysBeep();
    EndUpdate(wp);

	return -1;
}


/*
 *	FindIcon()
 *		Which icon is at the specified point.
 */
static
Boolean DoFindIcon(Rect *bounds, PickerItem *dataP, short i, long parm)
{
	InsetRect(bounds, -6, -4);
	return PtInRect((Point *) parm, bounds);
}   

static
pascal short FindIcon(Point pt, WindowPtr wp)
{
	return SwizzleIcons(wp, DoFindIcon, (long) &pt);
}


/*
 *	DeselectIcons()
 *		Deselect the currently selected icon.
 */
static
Boolean DoDeselect(Rect *bounds, PickerItem *dataP, short i, long parm)
{										
	if (dataP->flag & 0x80) {
		dataP->flag &= ~0x80;

		InsetRect(bounds, -6, -4);
		SetSolidPenPat(15);
		SetPenSize(4, 2);
		FrameRect(bounds);
		PenNormal();
        }

	return false;
}

static
pascal void DeselectIcons(WindowPtr wp)
{
	(void) SwizzleIcons(wp, DoDeselect, 0);
}   


/*
 *	SelectIcon()
 *		Select an icon.
 */
static
Boolean DoSelect(Rect *bounds, PickerItem *dataP, short i, long parm)
{
	if (i == (short) parm) {
		dataP->flag |= 0x80;

		InsetRect(bounds, -6, -4);
		SetPenSize(4, 2);
		FrameRect(bounds);
		SetPenSize(1, 1);

        return true;
		}
	else
		return false;
}

static
pascal void SelectIcon(WindowPtr wp, short item)
{
	(void) SwizzleIcons(wp, DoSelect, item);
}   


/*
 *	GetSelectedIcon()
 *		Return the number, type, and id of the currently selected icon.
 */
static
pascal Boolean GetSelectedIcon(WindowPtr wp, short *item, short *type, long *id)
{
	PickerItem 		**dataH;
    unsigned short	numItems, i;
	
	dataH = (PickerItem **) GetPrivateData(wp);

    numItems = GetHandleSize((Handle) dataH) / sizeof(PickerItem);

	for (i = 0; i < numItems; ++i)
		if ((*dataH)[i].flag & 0x80) {
			*item = i;
			*type = rIcon;
			*id = (*dataH)[i].resID;
			return true;
			}
	return false;
}   


/*
 *	PickerContent()
 *		Handle a click in the contents of the picker window.
 */
static
short PickerContent(EventRecord *event)
{
	WindowPtr	wp;
	Point		pt;
	short		item;
    short		type;
    long		id;
	short		err;

    err = 0;

    wp = (WindowPtr) fEventPtr->wmTaskData;
    pt = fEventPtr->where;

	StartDrawing(wp);

    GlobalToLocal(&pt);

	DeselectIcons(wp);
    item = FindIcon(pt, wp);
    if (item != -1) {
    	SelectIcon(wp, item);

        if (fEventPtr->wmClickCount > 1)
			if (GetSelectedIcon(wp, &item, &type, &id))
		        err = SelectAction(type, id, ActEditNative);
		}

	SetOrigin(0, 0);

    return err;
}


/*
 *	PickerMenu()
 *		Menu item selected.
 */
static
short PickerMenu(EventRecord *event)
{
	WindowPtr	wp;
	short		menuItem;
    long		id;
	short		item, type;
	short		err;

    wp = FrontWindow();
    err = 0;

	menuItem = (short) (event->wmTaskData & 0x0000ffffL);
	if (menuItem >= 0x2f0 && menuItem < 0x300) {
		if (GetSelectedIcon(wp, &item, &type, &id))
			err = SelectAction(type, id, menuItem & 0x000f);
		}

	return err;
}


/*
 *	PickerEvent()
 *		Handle an icon picker window event.
 */
short PickerEvent(fEventRec *parms)
{
	WindowPtr	wp, oPort;

	switch (parms->taskCode) {
		case 0:
			switch ((short) (fEventPtr->wmTaskData & 0xffffL)) {
	            case wInZoom:
				case wInGrow:
					wp = FrontWindow();
	                SetWindowDataSize(wp);
					oPort = GetPort();
					SetPort(wp);
					EraseRect(&wp->portRect);
					InvalRect(&wp->portRect);
					SetPort(oPort);
	                break;
				}
			return 0;
        case updateEvt:
			return UpdatePicker((WindowPtr) fEventPtr->wmTaskData);
		case wInContent:               
			return PickerContent(fEventPtr);
		case wInMenuBar:
			return PickerMenu(fEventPtr);
	    }    
	return 0;
}


/*
 *	ClosePicker()
 *	    Close the picker window.
 */
short ClosePicker(fCloseRec *parms)
{
	Handle		dataH;
    WindowPtr	wp;
	short		err;

	wp = (WindowPtr) parms->windowPtr;

	dataH = GetPrivateData(wp);
	FreeIconList((PickerItem **) dataH);
	DisposeIfHandle(dataH);
	err = CloseAWindow(wp);

	return err;
}   


/*
 *	WritePicker()
 *		Write this resource out.
 */
short WritePicker(fCloseRec *parms)
{
	return 0;
}


/*
 *	ActivatePicker()
 *	    Picker window was activated.
 */
short ActivatePicker(fActivateRec *parms)
{
	if (parms->fFlag & 0x8000)			/* activate */
		AddPickerMenu(1);

	return 0;
}


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


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