[comp.sys.mac.programmer] Pop-ups in SFFGetFile + SFFPutFile - How?

topix@gpu.utcs.utoronto.ca (R. Munroe) (10/05/90)

Anyone had any experience adding pop-up menus to a get file or put file
procedure?  For example, programs like PhotoShop and most word processing
packages have an Open As ... and Save As ... choice in the file menu.
When you choose Open As ... or Save As ... you get a fairly standard 
looking SFGetFile or SFPutFile dialog.  The difference is that there is
a pop-up that lets you select file formats.  How is that done?  Is it a
simple process or do you have to spend a good month or two coding it into
your application?  Any pointers to example code would be greatly appreciated.
(BTW: I am familiar with how to add pop-ups to the menu.  I am 
specifically hoping to get my hands on source that deals with pop-ups
in dialogs).

One more thing - in PhotoShop, when you choose Open from the file menu you
again get a standard looking SFGetFile.  However, if you hilite a file in the
list the file's format (type) is displayed.  That is tres cool.  Any ideas
how it's done?

Thanks for any help.

Bob Munroe
topix@utcs.utoronto.ca

tim@efi.com (Tim Maroney) (10/06/90)

In article <1990Oct5.025518.18973@gpu.utcs.utoronto.ca>
topix@gpu.utcs.utoronto.ca (R. Munroe) writes:
>Anyone had any experience adding pop-up menus to a get file or put file
>procedure?  For example, programs like PhotoShop and most word processing
>packages have an Open As ... and Save As ... choice in the file menu.
>When you choose Open As ... or Save As ... you get a fairly standard 
>looking SFGetFile or SFPutFile dialog.  The difference is that there is
>a pop-up that lets you select file formats.  How is that done?  Is it a
>simple process or do you have to spend a good month or two coding it into
>your application?  Any pointers to example code would be greatly appreciated.

It's not too hard.  Here's some completely uncommented C code that uses
Dialog Manager utilities that you don't have, and also dialog and
string list resources you don't have, and also precompiled C headers
which (all together now) you don't have, which may either help you or
baffle you completely....

Promise to pay me lots of money and I will make this more like
sample code for general use.

#pragma load HEADER

#include "fileutils.h"
#include "document.h"
#include "xdialogs.h"

/* globals used by Save As standard file dialog */
static WindowPtr theWindow;
static MenuHandle theMenu;
static Str255 typeName;
static Boolean good;

static pascal void SaveAsMenu(DialogPtr dialog, short item)
{	Rect r;
	GetIRect(dialog, item, &r);
	MoveTo(r.left + 2, r.bottom); LineTo(r.right, r.bottom);
	MoveTo(r.right, r.top + 2); LineTo(r.right, r.bottom);
	FrameRect(&r);
	InsetRect(&r, 2, 2); r.left += 10;
	TextBox(typeName + 1, typeName[0], &r, teJustLeft);
}

static Boolean SaveAsInit(DialogPtr dialog)
{	short i; DocOperations **ops; WindowExtra **extra;
	if ((extra = FindExtra(theWindow)) == 0) return false;
	SetUserProc(dialog, 10, (ProcPtr)SaveAsMenu);
	for (i = 0, ops = (*extra)->ops; i < (*ops)->numSaveTypes; i++)
		FillSaveAsTypes(theMenu, (*ops)->saveTypes[i],
				(*extra)->doc.type);
	if (CountMItems(theMenu) < 1) return false;
	GetItem(theMenu, 1, typeName);
	return true;
}

static void FixSaveAs(DialogPtr dialog)
{	Str255 name;
	GetDText(dialog, 7, name);
	if (name[0] == 0 || GetIHilite(dialog, 1) == 255)
		HiliteItem(dialog, 11, 255);
	else	HiliteItem(dialog, 11, 0);
}

static void PopUpTypes(DialogPtr dialog)
{	short i, lim; Str255 name; long result; Rect r; Point pt;
	for (i = 1, lim = CountMItems(theMenu); i <= lim; i++) {
		GetItem(theMenu, i, name);
		if (IUCompString(name, typeName) == 0) break;
	}
	InsertMenu(theMenu, -1);
	GetIRect(dialog, 10, &r);
	SetPt(&pt, r.left + 1, r.top + 1); LocalToGlobal(&pt);
	GetIRect(dialog, 9, &r); InvertRect(&r);
	result = PopUpMenuSelect(theMenu, pt.v, pt.h, i);
	DeleteMenu((*theMenu)->menuID); InvertRect(&r);
	if (HiWord(result) == 0 || LoWord(result) == 0) return;
	GetItem(theMenu, LoWord(result), typeName);
	GetIRect(dialog, 10, &r); InsetRect(&r, 1, 1);
	EraseRect(&r); SaveAsMenu(dialog, 10);
}

static pascal short SaveAsItems(short item, DialogPtr dialog)
{	switch (item) {
	case -1:	if (SaveAsInit(dialog))	break;
	case 2:		good = false, item = 2;	break;
	case 11:	good = true, item = 1;	break;
	case 10:	PopUpTypes(dialog);	break;
	}
	if (item != 2) FixSaveAs(dialog);
	return item;
}

static pascal Boolean
SaveAsEvents(DialogPtr dialog, EventRecord *event, short *item)
{	if (event->what == keyDown || event->what == autoKey) {
		char c = event->message & 0xff;
		if (c == 0x1b || (c == '.' && (event->modifiers & cmdKey)))
			{ *item = 2; return true; }
		if ((c == 3 || c == 13) && GetIHilite(dialog, 11) == 0)
			{ *item = 11; return true; }
		if (c == 9 && GetIHilite(dialog, 6) == 0)
			{ *item = 6; return true; }
	}
	return false;
}

SaveAs(WindowPtr window)
{	Point pt; short volume; long folder, type;
	SFReply reply; Str255 buf, name;
	if ((theMenu = NewMenu(1234, "\p ")) == 0) return MemError();
	SetPt(&pt, 60, 60);
	GetWTitle(window, name);
	GetIndString(buf, 15, 6);
	theWindow = window;
	SFPPutFile(pt, buf, name, SaveAsItems, &reply, 1, SaveAsEvents);
	DisposHandle((Handle)theMenu);
	if (!good) return userCancelled;
	if ((type = TypeByName(typeName)) == 0) return badTypeErr;
	volume = -SFSaveDisk, folder = CurDirStore;
	return SaveTo(window, reply.fName, volume, folder, type);
}

Oh, all right, here are the Dialog Manager utilities....

Handle GetIHandle(DialogPtr dialog, short item)
{	short type; Handle h; Rect r;
	GetDItem(dialog, item, &type, &h, &r);
	return h;
}

void GetIRect(DialogPtr dialog, short item, Rect *r)
{	short type; Handle h;
	GetDItem(dialog, item, &type, &h, r);
}

short GetIType(DialogPtr dialog, short item)
{	short type; Handle h; Rect r;
	GetDItem(dialog, item, &type, &h, &r);
	return type;
}

void HiliteItem(DialogPtr dialog, short item, short hilite)
{ HiliteControl((ControlHandle)GetIHandle(dialog, item), hilite); }

GetIHilite(DialogPtr dialog, short item)
{	ControlHandle ch = (ControlHandle)GetIHandle(dialog, item);
	return (*ch)->contrlHilite;
}

void SetITitle(DialogPtr dialog, short item, StringPtr s)
{ SetCTitle((ControlHandle)GetIHandle(dialog, item), s); }

void SetIValue(DialogPtr dialog, short item, short v)
{ SetCtlValue((ControlHandle)GetIHandle(dialog, item), v); }

GetIValue(DialogPtr dialog, short item)
{ return GetCtlValue((ControlHandle)GetIHandle(dialog, item)); }

void GetDText(DialogPtr dialog, short item, StringPtr s)
{ GetIText(GetIHandle(dialog, item), s); }

void SetDText(DialogPtr dialog, short item, StringPtr s)
{ SetIText(GetIHandle(dialog, item), s); }

void SetUserProc(DialogPtr dialog, short item, ProcPtr proc)
{	Rect r; GetIRect(dialog, item, &r);
	SetDItem(dialog, item, userItem, (Handle)proc, &r);
}

void InvalItem(DialogPtr dialog, short item)
{	GrafPtr save; Rect r;
	GetPort(&save); SetPort(dialog);
	GetIRect(dialog, item, &r); InvalRect(&r);
	SetPort(save);
}