CCL Home Page
Up Directory CCL ScianObjFunctions
/*ScianObjFunctions.c
  Eric Pepke
  April 9, 1992
  Definitions and routines for per-object functions
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianLists.h"
#include "ScianWindows.h"
#include "ScianColors.h"
#include "ScianIDs.h"
#include "ScianObjWindows.h"
#include "ScianButtons.h"
#include "ScianErrors.h"
#include "ScianDraw.h"
#include "ScianControls.h"
#include "ScianArrays.h"
#include "ScianScripts.h"
#include "ScianVisWindows.h"
#include "ScianIcons.h"
#include "ScianEvents.h"
#include "ScianStyle.h"
#include "ScianObjFunctions.h"
#include "ScianHelp.h"
#include "ScianFilters.h"
#include "ScianFileSystem.h"
#include "ScianSockets.h"
#include "ScianSnap.h"
#include "ScianMenus.h"
#include "ScianFontSystem.h"
#include "ScianDialogs.h"
#include "ScianDatabase.h"
#include "ScianSymbols.h"


/*Sizes for text menu*/
int textSizes[] =
    {
	9,
	10,
	12,
	14,
	18,
	24,
	36,
	48,
	72
    };

typedef struct
    {
	char *name;
	void (*setupRoutine)();
	void (*finishRoutine)();
	NameTyp funcMessage;
	char *buttonHelp;
	char *menuHelp;
	char *scriptPrefix, *scriptPostfix;
	Bool varPostfix;	/*True iff postfix is variable*/
	ObjPtr postfixObject;	/*Postfix object, used instead of postfix string*/
	int isUsed;
	Bool multObjects;	/*True iff mult objects ok*/
	ObjPtr whichMenu;	/*Which menu function is in*/
	int menuGroup;		/*Menu group*/
	ObjPtr objectsToDo;	/*List of current objects to do this function on*/
    } ObjFunction;

int nObjFunctions = 0;			/*Number of object functions*/

static ObjPtr objectActionClass;	/*Class for all object actions*/

static ObjFunction *objFunctions = NULL;
static int globalFuncNum;
static ObjPtr undoList;			/*List of undo operations*/
static ObjPtr undoClass;		/*Class of undo's*/
static ObjPtr curUndo = NULLOBJ;	/*Current undo being built up*/
static int curUndoType = 0;		/*Current type of undo being built*/

#ifdef PROTO
ObjPtr NewUndo(int undoType)
#else
ObjPtr NewUndo(undoType)
int undoType;
#endif
{
    ObjPtr retVal;

    retVal = NewObject(undoClass, 0L);
    SetVar(retVal, UNDOTYPE, NewInt(undoType));

    /*Do initialization of undo*/
    switch(undoType)
    {
	case UT_CHANGESNAPSHOT:
	    SetVar(retVal, OLDSNAPSHOTS, NewList());
	    break;
    }

    return retVal;
}

#ifdef PROTO
void BeginUndo(int undoType)
#else
void BeginUndo(undoType)
int undoType;
#endif
/*Begins an undo to build up*/
{
    curUndo = NewUndo(undoType);
    curUndoType = undoType;
}

#ifdef PROTO
void SaveSnapshotForUndo(ObjPtr object)
#else
void SaveSnapshotForUndo(object)
ObjPtr object;
#endif
/*Saves a snapshot of object in the current undo*/
{
    ObjPtr list;

    if (!curUndo) return;

    list = GetVar(curUndo, OLDSNAPSHOTS);
    if (!list)
    {
	list = NewList();
	SetVar(curUndo, OLDSNAPSHOTS, list);
    }
    PrefixList(list, TakeSnapshot(object));
}

void EndUndo()
/*Ends an undo in progress*/
{
    if (!curUndo) return;
    EmptyList(undoList);
    PrefixList(undoList, curUndo);
    curUndo = NULLOBJ;
}

#ifdef PROTO
void SaveForUndo(ObjPtr object)
#else
void SaveForUndo(object)
ObjPtr object;
#endif
/*Saves object for undo later*/
{
    ObjPtr snapshot, undo, list;

    if (object)
    {
	BeginUndo(UT_CHANGESNAPSHOT);
	SaveSnapshotForUndo(object);
	EndUndo();
    }
}

void Undo()
/*Do the undo operation*/
{
    ThingListPtr runner;

    runner = LISTOF(undoList);
    if (runner && runner -> thing)
    {
	/*There is something to undo*/
	int undoType;
	ObjPtr var, undo;

	undo = runner -> thing;
	var = GetIntVar("Undo", undo, UNDOTYPE);
	if (!var) return;

	undoType = GetInt(var);
	switch(undoType)
	{
	    case UT_CHANGESNAPSHOT:
		{
		    ObjPtr oldSnapshots, oldSnap, object;
		    ThingListPtr snapRunner;

		    oldSnapshots = GetListVar("Undo", undo, OLDSNAPSHOTS);
		    if (!oldSnapshots) return;

		    /*Set up inverse undo*/
		    BeginUndo(UT_CHANGESNAPSHOT);

		    snapRunner = LISTOF(oldSnapshots);
		    while (snapRunner)
		    {
			oldSnap = snapRunner -> thing;
			object = GetVar(oldSnap, REPOBJ);

			SaveSnapshotForUndo(object);
			ApplySnapshot(oldSnap);

			snapRunner = snapRunner -> next;
		    }

		    EndUndo();
		}
		break;
	}

    }
}

#ifdef PROTO
int NameToObjFunction(char *name)
#else
int NameToObjFunction(name);
char *name;
#endif
/*Converts a name to a function number, or -1*/
{
    int funcNum;

    /*Search for the named function*/
    for (funcNum = 0; funcNum < nObjFunctions; ++funcNum)
    {
	if (0 == strcmp2(name, objFunctions[funcNum] . name))
	{
	    break;
	}
    }

    if (funcNum >= nObjFunctions)
    {
	/*Not found, too bad.*/
	return -1;
    }
    return funcNum;
}


#ifdef PROTO
ObjPtr DefineObjFunction(char *funcName, char *menuName, void (*setupRoutine)(), NameTyp funcMessage,
	void (*finishRoutine)(), char *scriptPrefix, char *scriptPostfix,
	Bool multObjects, char *buttonHelp,
	char *menuHelp, ObjPtr whichMenu, int menuGroup, Bool varPostfix)
#else
ObjPtr DefineObjFunction(funcName, menuName, setupRoutine, funcMessage,
	finishRoutine, scriptPrefix, scriptPostfix,
	multObjects, buttonHelp,
	menuHelp, whichMenu, menuGroup, varPostfix)
char *funcName;
char *menuName;
void (*setupRoutine)();
NameTyp funcMessage;
void (*finishRoutine)();
char *scriptPrefix;
char *scriptPostfix;
Bool multObjects;
char *buttonHelp;
char *menuHelp;
int menuGroup;
ObjPtr whichMenu;
Bool varPostfix;
#endif
/*Defines an object function
    funcName	    is the name of the function for the menu and buttons
    menuName	    is an alternate name for menus
    setupRoutine    is a routine to call at the beginning, or 0
    funcMessage	    is a message to send to every selected object as a single argument
    finishRoutine   is a routine to call when finished
    scriptPrefix    is the script portion to prefix to the object names
    scriptPostfix   is the script portion to postfix to the object names
    multObjects	    is true iff it accepts multiple objects
    buttonHelp	    is the help string for a button, or nothing for no button
    menuHelp	    is the help string for a menu
    whichMenu	    is which menu to use
    menuGroup	    is the group within the menu
    varPostfix	    is true iff the postfix is variable, in which case what
		    is actually there will be passed to the action method

 More than 1 obj function can only be defined if it is a varPostfix function.
 %s in the help will indicate use of postFix value

 Returns the action produced.
*/
{
    ObjPtr action = NULLOBJ;		/*The action*/

    if (NameToObjFunction(funcName) < 0)
    {
    if (nObjFunctions)
    {
	objFunctions = Realloc(objFunctions, (nObjFunctions + 1) * sizeof(ObjFunction));
    }
    else
    {
	objFunctions = Alloc((nObjFunctions + 1) * sizeof(ObjFunction));
    }

    if (funcName)
    {
	objFunctions[nObjFunctions] . name = Alloc(strlen(funcName) + 1);
	strcpy(objFunctions[nObjFunctions] . name, funcName);
    }
    else
    {
	objFunctions[nObjFunctions] . name = (char *) 0;
    }
    objFunctions[nObjFunctions] . setupRoutine = setupRoutine;
    objFunctions[nObjFunctions] . funcMessage = funcMessage;
    objFunctions[nObjFunctions] . finishRoutine = finishRoutine;
    objFunctions[nObjFunctions] . whichMenu = whichMenu;
    objFunctions[nObjFunctions] . multObjects = multObjects;
    AddToReferenceList(objFunctions[nObjFunctions] . objectsToDo = NewList());
    if (scriptPrefix)
    {
	objFunctions[nObjFunctions] . scriptPrefix = Alloc(strlen(scriptPrefix) + 1);
	strcpy(objFunctions[nObjFunctions] . scriptPrefix, scriptPrefix);
    }
    else
    {
	objFunctions[nObjFunctions] . scriptPrefix = (char *) 0;
    }
    objFunctions[nObjFunctions] . postfixObject = NULLOBJ;
    if (scriptPostfix)
    {
	objFunctions[nObjFunctions] . scriptPostfix = Alloc(strlen(scriptPostfix) + 1);
	strcpy(objFunctions[nObjFunctions] . scriptPostfix, scriptPostfix);
    }
    else
    {
	objFunctions[nObjFunctions] . scriptPostfix = (char *) 0;
    }
    objFunctions[nObjFunctions] . varPostfix = varPostfix;
    if (buttonHelp)
    {
	objFunctions[nObjFunctions] . buttonHelp = Alloc(strlen(buttonHelp) + 1);
	strcpy(objFunctions[nObjFunctions] . buttonHelp, buttonHelp);
    }
    else
    {
	objFunctions[nObjFunctions] . buttonHelp = (char *) 0;
    }
    if (menuHelp)
    {
	objFunctions[nObjFunctions] . menuHelp = Alloc(strlen(menuHelp) + 1);
	strcpy(objFunctions[nObjFunctions] . menuHelp, menuHelp);
    }
    else
    {
	objFunctions[nObjFunctions] . menuHelp = (char *) 0;
    }
    objFunctions[nObjFunctions] . menuGroup = menuGroup;


    ++nObjFunctions;
    }

    if (whichMenu)
    {
	/*Put it on whichMenu*/
	char *s, *d;

	/*Go through menuHelp*/
	s = menuHelp;
	d = tempStr;
	while (*s)
	{
	    if (*s == '%' && *(s + 1) == 's')
	    {
		if (scriptPostfix)
		{
		    strcpy(d, scriptPostfix);
		}
		++s;
		++s;
		while (*d) ++d;
	    }
	    else
	    {
		*d++ = *s++;
	    }
	}
	*d = 0;

	action = NewAction(menuName ? menuName : funcName, objectActionClass);
	SetVar(action, FUNCNAME, NewString(funcName));
	SetVar(action, HELPSTRING, NewString(tempStr));
	if (varPostfix && scriptPostfix)
	{
	    SetVar(action, VALUE, NewString(scriptPostfix));
	}
	AddMenuItem(whichMenu, action, menuGroup);
    }
    return action;
}

static void StartObjFunction(funcNum)
int funcNum;
/*Starts object function funcNum*/
{
    globalFuncNum = funcNum;

    /*Do the first bit*/
    if (objFunctions[funcNum] . setupRoutine)
    {
	InhibitLogging(true);
	(*(objFunctions[funcNum] . setupRoutine))();
	InhibitLogging(false);
    }
}

static ObjPtr DoObjFunctionOnObject(object)
ObjPtr object;
/*Does an object function in globalFuncNum, if it is appropriate, on object.  
  Designed to be passable to ForAllSelectedObjects*/
{
    FuncTyp method;
    ObjPtr retVal = ObjFalse;

    method = GetMethod(object, objFunctions[globalFuncNum] . funcMessage);
    if (method)
    {
	InhibitLogging(true);
	if (objFunctions[globalFuncNum] . varPostfix)
	{
	    if (objFunctions[globalFuncNum] . scriptPostfix)
	    {
		retVal = (*method)(object, NewString(objFunctions[globalFuncNum] . scriptPostfix));
	    }
	    else
	    {
		retVal = (*method)(object, objFunctions[globalFuncNum] . postfixObject);
	    }
	}
	else
	{
	    retVal = (*method)(object);
	}
	InhibitLogging(false);
    }
    return retVal;
}

static void FinishObjFunction()
/*Finishes object function funcNum*/
{
    /*Do the last bit*/
    if (objFunctions[globalFuncNum] . finishRoutine)
    {
	InhibitLogging(true);
	(*(objFunctions[globalFuncNum] . finishRoutine))();
	InhibitLogging(false);
    }
}

static Bool firstLoggedObject;

ObjPtr LogSpacedObject(object)
ObjPtr object;
/*Logs all the objects with spaces*/
{
    if (!firstLoggedObject)
    {
	Log(",");
    }
    else
    {
	firstLoggedObject = false;
	if (objFunctions[globalFuncNum] . scriptPrefix)
	{
	    Log(objFunctions[globalFuncNum] . scriptPrefix);
	}
    }
    Log(" ");
    LogObjectName(object);
    return ObjTrue;
}

void LogObjFunction(name, list)
char *name;
ObjPtr list;
/*Logs the object function name on list*/
{
    int funcNum;

    FlushKeystrokes();

    funcNum = NameToObjFunction(name);
    if (funcNum < 0)
    {
	/*No valid function*/
	return;
    }

    /*Emit the log*/
    if (logging)
    {
	ThingListPtr runner;
	globalFuncNum = funcNum;
	firstLoggedObject = true;
	runner = LISTOF(list);
	while (runner)
	{
	    LogSpacedObject(runner -> thing);
	    runner = runner -> next;
	}

	if (!firstLoggedObject)
	{
	    if (objFunctions[funcNum] . scriptPostfix)
	    {
		Log(" ");
		Log(objFunctions[funcNum] . scriptPostfix);
	    }
	    else if (objFunctions[funcNum] . postfixObject)
	    {
		Log(" ");
		LogObjectName(objFunctions[funcNum] . postfixObject);
	    }
	    Log("\n");
	}
    }
}

void LogSelectedObjFunction(name)
char *name;
/*Logs the object function name on all selected objects*/
{
    int funcNum;

    FlushKeystrokes();

    funcNum = NameToObjFunction(name);
    if (funcNum < 0)
    {
	/*No valid function*/
	return;
    }

    /*Emit the log*/
    if (logging)
    {
	globalFuncNum = funcNum;
	firstLoggedObject = true;
	ForAllSelectedObjects(LogSpacedObject);

	if (!firstLoggedObject)
	{
	    if (objFunctions[funcNum] . scriptPostfix)
	    {
		Log(" ");
		Log(objFunctions[funcNum] . scriptPostfix);
	    }
	    else if (objFunctions[funcNum] . postfixObject)
	    {
		Log(" ");
		LogObjectName(objFunctions[funcNum] . postfixObject);
	    }
	    Log("\n");
	}
    }
}

int funcToDo;		/*Function to do*/

void DoAllObjFunctionsLater()
/*Deferred routine to do all the setup object functions*/
{
    int funcNum;

    for (funcNum = 0; funcNum < nObjFunctions; ++funcNum)
    {
	if (IsList(objFunctions[funcNum] . objectsToDo))
	{
	    ThingListPtr runner;

	    runner = LISTOF(objFunctions[funcNum] . objectsToDo);
	    if (runner)
	    {
		StartObjFunction(funcNum);
		while (runner)
		{
		    DoObjFunctionOnObject(runner -> thing);
		    runner = runner -> next;
		}
		FinishObjFunction();
	    }
	    EmptyList(objFunctions[funcNum] . objectsToDo);
	}
    }
}

ObjPtr AddToLaterFunctions(object)
ObjPtr object;
/*Adds object to the function to do later in funcToDo*/
{
    PostfixList(objFunctions[funcToDo] . objectsToDo, object);
    return ObjTrue;
}

void DoObjFunction(name)
char *name;
/*Does object function name on all selected objects*/
{
    funcToDo = NameToObjFunction(name);
    if (funcToDo < 0)
    {
	/*No valid function*/
	return;
    }

    LogSelectedObjFunction(name);

    /*Fill the lists with the functions*/
    ForAllSelectedObjects(AddToLaterFunctions);

    DoUniqueTask(DoAllObjFunctionsLater);
}

ObjPtr ObjectAction(action)
ObjPtr action;
/*Does the action method of an object action from a menu*/
{
    ObjPtr var;
    int k;

    var = GetVar(action, FUNCNAME);
    if (var)
    {
	if (contextHelp)
	{
	    /*Give help on the action*/
	    ContextHelp(action);
	    contextHelp = false;
	    MySetCursor(0);
	}
	else
	{
	    k = NameToObjFunction(GetString(var));
	    if (k >= 0)
	    {
		if (objFunctions[k] . varPostfix)
		{
		    ObjPtr value;
		    value = GetVar(action, VALUE);
		    if (value)
		    {
			if ((objFunctions[k] . scriptPostfix) &&
			    IsString(value))
			{
			    SAFEFREE(objFunctions[k] . scriptPostfix);
			    objFunctions[k] . scriptPostfix = Alloc(strlen(GetString(value)) + 1);
			    strcpy(objFunctions[k] . scriptPostfix, GetString(value));
			}
			else
			{
			    objFunctions[k] . postfixObject = value;
			}
		    }
		}
		DoObjFunction(GetString(var));
	    }
	}
    }
    return ObjTrue;
}

static ObjPtr RenameReally(owner, newName)
ObjPtr owner;
char *newName;
/*Really renames an object*/
{
    int k;
    ObjPtr object;

    object = GetVar(owner, OWNERWINDOW);

    k = NameToObjFunction(OF_RENAME);
    if (k >= 0)
    {
	/*See if the name is valid*/
	ObjPtr searchList, results;

	searchList = NewList();
	PostfixList(searchList, NewSymbol(NAME));
	PostfixList(searchList, NewString(newName));
	PostfixList(searchList, NewSymbol(CLASSID));
	PostfixList(searchList, GetVar(object, CLASSID));
	results = SearchDatabase(searchList);

	if (results && LISTOF(results) && LISTOF(results) -> thing != object)
	{
	    /*Name is invalid.  Whine.*/
	    WinInfoPtr window;
	    ObjPtr name, type;
	    char alertString[400];

	    name = GetVar(object, NAME);
	    type = GetVar(object, TYPESTRING);

	    sprintf(alertString, "There is already a%s %s named %s.  Please choose another name:",
		type ? (ISVOWEL(GetString(type)[0]) ? "n" : "") : "n",
		type ? GetString(type) : "object", newName);
	    window = AskUser((WinInfoPtr) object, alertString, RenameReally, GetString(name));
	    SetVar((ObjPtr) window, INHIBITLOGGING, ObjTrue);
	}
	else
	{
	    /*Name is valid.  Copy the name into the script postfix*/
	    objFunctions[k] . postfixObject = NewString(newName);

	    /*Log it.*/
	    LogNoWindow(objFunctions[k] . scriptPrefix);
	    LogNoWindow(" ");
	    LogNoWindowObjectName(object);
	    LogNoWindow(" ");
	    LogNoWindowObjectName(objFunctions[k] . postfixObject);
	    LogNoWindow("\n");

	    /*Do it.*/
	    globalFuncNum = k;
	    DoObjFunctionOnObject(object);
	}
    }
}

static ObjPtr RenameObject(object)
ObjPtr object;
/*Renames an object*/
{
    char alertString[400];
    ObjPtr name;
    ObjPtr type;
    WinInfoPtr window;

    name = GetVar(object, NAME);
    type = GetVar(object, TYPESTRING);

    sprintf(alertString, "Enter the new name for %s %s:",
	type ? GetString(type) : "object", GetString(name));
    window = AskUser((WinInfoPtr) object, alertString, RenameReally, GetString(name));
    SetVar((ObjPtr) window, INHIBITLOGGING, ObjTrue);

    return ObjTrue;
}

ObjPtr RenameObjectAction(action)
ObjPtr action;
/*Does the action method of an object action from a menu*/
{
    ObjPtr var;
    int k;

    var = GetVar(action, FUNCNAME);
    if (var)
    {
	if (contextHelp)
	{
	    /*Give help on the action*/
	    ContextHelp(action);
	    contextHelp = false;
	    MySetCursor(0);
	}
	else
	{
	    ForAllSelectedObjects(RenameObject);
	}
    }
    return ObjTrue;
}

ObjPtr AddToDoubleClickFunction(object)
ObjPtr object;
/*Adds object to its desired double click function*/
{
    ObjPtr var;
    int funcNum;

    var = GetVar(object, DOUBLECLICK);
    if (var)
    {
	funcNum = NameToObjFunction(GetString(var));
	if (funcNum < 0)
	{
	    ReportError("AddToDoubleClickFunction", "Doubleclick object function not valid");
	}
	else
	{
	    PostfixList(objFunctions[funcNum] . objectsToDo, object);
	}
    }
    else
    {
	ReportError("AddToDoubleClickFunction", "No doubleclick object function");
    }
    return ObjTrue;
}

void DoDoubleClickFunction()
/*Does an appropriate double click function on all selected objects*/
{
    int funcNum;

    /*Distribute all the selected objects in their preferred functions*/
    ForAllSelectedObjects(AddToDoubleClickFunction);

    /*Log all the object functions*/
    for (funcNum = 0; funcNum < nObjFunctions; ++funcNum)
    {
	if (IsList(objFunctions[funcNum] . objectsToDo))
	{
	    if (LISTOF(objFunctions[funcNum] . objectsToDo))
	    {
		LogObjFunction( objFunctions[funcNum] . name,
				objFunctions[funcNum] . objectsToDo);
	    }
	}
    }

    /*Do it later*/
    DoUniqueTask(DoAllObjFunctionsLater);
}

#ifdef PROTO
Bool ObjFunctionScriptLine(char *line)
#else
Bool ObjFunctionScriptLine(line)
char *line;
#endif
/*If s is a script line, finds out if it is a valid script line for an
  object function.  If so, does it and returns true, otherwise does nothing
  and returns false.  Determines whether it is valid by matching the 
  script prefix*/
{
    int funcNum;
    register char *s, *p, *t;

    /*For all possible functions*/
    for (funcNum = 0; funcNum < nObjFunctions; ++funcNum)
    {
	/*Try to match prefix against script*/
	s = line;
	p = objFunctions[funcNum] . scriptPrefix;

	SKIPBLANKS(s);
	SKIPBLANKS(p);

	while (*p)
	{
	    if (isspace(*p))
	    {
		SKIPBLANKS(s);
		SKIPBLANKS(p);
	    }
	    else if (toupper(*p) != toupper(*s))
	    {
		/*Failure to match*/
		break;
	    }
	    else
	    {
		++s;
		++p;
	    }
	}

	if (*p == 0)
	{
	    ObjPtr list;
	    ThingListPtr runner;
	    ObjPtr object;
	    /*It's a match!  Do this function and return true*/

	    list = NewList();

	    do
	    {
		object = ERROBJ;
		s = ParseObjectArg(s, &object);

		if (object != ERROBJ)
		{
		    if (!object)
		    {
			ScriptError("An object name is expected here.");
		    }
		    else
		    {
			if (IsIcon(object) && GetVar(object, REPOBJ))
			{
			    object = GetVar(object, REPOBJ);
			}
			PostfixList(list, object);
		    }
		}

		SKIPBLANKS(s);
	    } while (*s++ == ',');
	    --s;

	    if (objFunctions[funcNum] . varPostfix)
	    {
		/*Variable postfix, set it.*/
		ObjPtr object;

		if (objFunctions[funcNum] . scriptPostfix)
		{
		    SAFEFREE(objFunctions[funcNum] . scriptPostfix);
		    SKIPBLANKS(s);
		
		    objFunctions[funcNum] . scriptPostfix = Alloc(strlen(s) + 1);
		    strcpy(objFunctions[funcNum] . scriptPostfix, s);
		}
		else
		{
		    ParseObjectArg(s, &object);
		    objFunctions[funcNum] . postfixObject = object;
		}

		p = 0;
	    }
	    else
	    {
		/*Check postfix*/
		p = objFunctions[funcNum] . scriptPostfix;

		if (p)
		{
		    SKIPBLANKS(s);
		    SKIPBLANKS(p);

		    while (*p)
		    {
			if (isspace(*p))
			{
			    SKIPBLANKS(s);
			    SKIPBLANKS(p);
			}
			else if (toupper(*p) != toupper(*s))
			{
			    /*Failure to match*/
			    break;
			}
			else
			{
			    ++s;
			    ++p;
			}
		    }
		}
	    }

	    if (!p || (*p == 0))
	    {
		LogObjFunction(objFunctions[funcNum] . name, list);
		StartObjFunction(funcNum);
		runner = LISTOF(list);
		while (runner)
		{
		    DoObjFunctionOnObject(runner -> thing);
		    runner = runner -> next;
		}
		FinishObjFunction();
		return true;
	    }
	}
    }
    return false;
}

void FunctionMenu(item)
int item;
/*Does an object function from an IRIS menu call*/
{
    if (item < 0 || item > nObjFunctions)
    {
	ReportError("ObjFunctionMenu", "Internal error: bad menu value");
	return;
    }

#ifdef INTERACTIVE
    if (contextHelp)
    {
	/*DIKEO Change to do menus as objects, then add context help*/
    }
    else
#endif
    {
	LogSelectedObjFunction(objFunctions[item] . name);
	StartObjFunction(item);
	ForAllSelectedObjects(DoObjFunctionOnObject);
	FinishObjFunction();
    }
}

static WinInfoPtr testWindow = 0;

static ObjPtr TestObjFunctions(object)
ObjPtr object;
/*Tests the obj functions on object*/
{
    int k;

    if (testWindow && !ObjectWhichRepresents(testWindow, object))
    {
	return ObjFalse;
    }

    for (k = 0; k < nObjFunctions; ++k)
    {
	if (GetMethod(object, objFunctions[k] . funcMessage))
	{
	    ++objFunctions[k] . isUsed;
	}
    }
    return ObjTrue;
}

static ObjPtr MakeObjActionActivated(action)
ObjPtr action;
/*Makes an action activated*/
{
    ObjPtr allSelected;
    ThingListPtr runner;
    int f;
    ObjPtr var;
    Bool oneActive;

    var = GetStringVar("MakeObjActionActivated", action, FUNCNAME);
    if (!var) return ObjFalse;
    f = NameToObjFunction(GetString(var));
    if (f < 0) return ObjFalse;

    SetVar(action, ACTIVATED, ObjFalse);
    allSelected = GetListVar("MakeObjActionActivated", action, ALLSELECTED);
    if (allSelected)
    {
	oneActive = false;
	for (runner = LISTOF(allSelected); runner; runner = runner -> next)
	{
	    if (GetMethod(runner -> thing, objFunctions[f] . funcMessage))
	    {
		if (objFunctions[f] . multObjects)
		{
		    SetVar(action, ACTIVATED, ObjTrue);
		    return ObjTrue;
		}
		else if (oneActive)
		{
		    SetVar(action, ACTIVATED, ObjFalse);
		    return ObjTrue;
		}
		else
		{
		    SetVar(action, ACTIVATED, ObjTrue);
		    oneActive = true;
		}
	    }
	}
    }
    return ObjTrue;
}

void AdjustWindowButtons(window)
WinInfoPtr window;
/*Adjusts the object buttons in window*/
{
    ObjPtr var;
    ThingListPtr runner;
    int k;

    /*Figure out which object functions are valid*/
    for (k = 0; k < nObjFunctions; ++k)
    {
	objFunctions[k] . isUsed = 0;
    }
    testWindow = window;
    ForAllSelectedObjects(TestObjFunctions);

    var = GetVar((ObjPtr) window, FUNCTIONBUTTONS);
    if (var)
    {
	runner = LISTOF(var);
	while (runner)
	{
	    var = GetStringVar("AdjustWindowButtons", runner -> thing, NAME);
	    if (var)
	    {
		int k;
		Bool funcIsUsed;
		k = NameToObjFunction(GetString(var));
		if (k >= 0)
		{
		    funcIsUsed = objFunctions[k] . isUsed &&
			((objFunctions[k] . isUsed == 1) ||
			 objFunctions[k] . multObjects);
		    ActivateButton(runner -> thing, 
			funcIsUsed);
		}
	    }
	    runner = runner -> next;
	}
    }
}

void AdjustObjButtons()
/*Task to change all the object buttons in all the windows*/
{
    /*Now go through all the windows adjusting the object buttons*/
    ForAllWindows(AdjustWindowButtons);    
}

ObjPtr ChangeFunctionButton(button)
ObjPtr button;
/*Changed value for a function button*/
{
    ObjPtr var;
    var = GetVar(button, NAME);
    if (var)
    {
	DoObjFunction(GetString(var));
	return ObjTrue;
    }
    else
    {
	return ObjFalse;
    }
}

static ObjPtr SetFunctionButtonValue(theButton, theValue)
ObjPtr	theButton, theValue;
{
    FuncTyp	changer;
    ObjPtr	retVal;

    if (IsInt(theValue))
    {
	SetVar(theButton, VALUE, theValue);
    }
    else if (IsReal(theValue))
    {
	SetVar(theButton, VALUE, NewInt((int) GetReal(theValue)));
    }
    else
    {
	return ObjFalse;
    }

    changer = GetMethod(theButton, CHANGEDVALUE);
    if (changer)
    {
	retVal = (* changer) (theButton);
    }
    else
    {
	retVal = ObjFalse;
    }
    ImInvalid(theButton);

    return retVal;
}

#ifdef PROTO
ObjPtr NewFunctionButton(WinInfoPtr window, int l, int r, int b, int t, char *name)
#else
ObjPtr NewFunctionButton(window, l, r, b, t, name)
WinInfoPtr window; int l; int r; int b; int t; char *name;
#endif
{
    ObjPtr retVal, var;
    int whichFunction;

    whichFunction = NameToObjFunction(name);
    if (whichFunction < 0) return NULLOBJ;

    retVal = NewButton(l, r, b, t, name);
    SetMethod(retVal, SETVAL, SetFunctionButtonValue);
    SetMethod(retVal, CHANGEDVALUE, ChangeFunctionButton);
    ActivateButton(retVal, false);
    if (objFunctions[whichFunction] . buttonHelp)
    {
	SetVar(retVal, HELPSTRING, 
	NewString(objFunctions[whichFunction] . buttonHelp));
    }

    var = GetVar((ObjPtr) window, FUNCTIONBUTTONS);
    if (!var)
    {
	var = NewList();
	SetVar((ObjPtr) window, FUNCTIONBUTTONS, var);
    }
    PrefixList(var, retVal);

    DoUniqueTask(AdjustObjButtons);

    return retVal;
}

void InitObjFunctions()
/*Initializes the object function system*/
{
    int k;
    ObjPtr action;

    /*Make the class for object actions*/
    objectActionClass = NewObject(actionClass, 0L);
    AddToReferenceList(objectActionClass);
    SetMethod(objectActionClass, ACTIONMETHOD, ObjectAction);
    DeclareDependency(objectActionClass, ACTIVATED, ALLSELECTED);
    SetMethod(objectActionClass, ACTIVATED, MakeObjActionActivated);
    SetVar(objectActionClass, ACTIVATED, ObjFalse);

    undoClass = NewObject(NULLOBJ, 0L);
    AddToReferenceList(undoClass);

    undoList = NewList();
    AddToReferenceList(undoList);

    objFunctions = NULL;

    DefineObjFunction(OF_PICK_UP, (char *) 0, InitPickUp, PICKUP, 0,
	"drag", (char *) 0, true,
"Pressing this button picks up the selected objects.  Once you have picked up \
the objects, you can drop them into another icon corral by clicking where you want to \
drop them.  This is useful as a substitute for dragging icons between windows on \
computers that do not support dragging between windows.",
"Choosing this menu picks up the selected objects.  Once you have picked up \
the objects, you can drop them into another icon corral by clicking where you want to \
drop them.  This is useful as a substitute for dragging icons between windows on \
computers that do not support dragging between windows.", objectMenu, 1, false);
    DefineObjFunction(OF_OPEN, (char *) 0, 0, OPEN, 0,
	"open", (char *) 0, true,
	"Pressing this button reads the selected files into the Datasets window and opens new file windows \
for the selected folders.", 
	"Choosing this menu item reads the selected files into the Datasets window and opens new file windows \
for the selected folders.", fileMenu, 1, false); 
    DefineObjFunction(OF_SETFORMAT, (char *) 0, SetUpCollect, COLLECT, ProcessSetFormat,
	"set format", (char *) 0, true,
	"Pressing this button opens a dialog window allowing you to set the data format \
of the selected files.",
	"Choosing this menu item opens a dialog window allowing you to set the data format \
of the selected files.", fileMenu, 1, false);
    DefineObjFunction(OF_SHOW_CONTROLS, (char *) 0, 0, SHOWCONTROLS, 0,
	"show controls", (char *) 0, true,
	"Pressing this button opens windows showing controls for each of the selected objects.",
	"Choosing this menu item opens windows showing controls for each of the selected objects.",
	objectMenu, 1, false);
    DefineObjFunction(OF_EDIT_PALETTE, (char *) 0, 0, EDITPALETTE, 0,
	"edit palette", (char *) 0, true,
	"Pressing this button opens a window to edit the color palette of each of the selected objects.",
	"Choosing this menu item opens a window to edit the color palette of each of the selected objects.",
	objectMenu, 1, false);
    DefineObjFunction(OF_SHOWINFO, (char *) 0, SetUpCollect, COLLECT, ProcessShowInfo,
	"show info", (char *) 0, true,
	"Pressing this button opens a window showing directory information for the selected files.",
	"Choosing this menu item opens a window showing directory information for the selected files.",
	fileMenu, 1, false);
    DefineObjFunction(OF_VISUALIZE, (char *) 0, NewSerializedVisWindow, VISUALIZE, 0,
	"visualize", (char *) 0, true,
"Pressing this button visualizes the selected objects \
together in a new window.  Visualization objects are visualized as they are, and \
datasets are visualized using their default visualization technique.  Hold down \
the Alt or Ctrl key to have the visualizations come up turned off by default.  This \
is useful with complex visualizations if you want to change controls before \
spending the time drawing the visualizations.",
"Choosing this menu item visualizes the selected objects \
together in a new window.  Visualization objects are visualized as they are, and \
datasets are visualized using their default visualization technique.  Hold down \
the Alt or Ctrl key to have the visualizations come up turned off by default.  This \
is useful with complex visualizations if you want to change controls before \
spending the time drawing the visualizations.", datasetsMenu, 1, false);
    DefineObjFunction(OF_VISUALIZE_AS, (char *) 0, NewVisAsWindow, VISUALIZEAS, ProcessVisAsList,
	"visobjectas", (char *) 0, true,
"Pressing this button opens a window \
showing all the basic ways of visualizing the selected datasets.  You will \
then be able to choose the visualization you want to use.",
"Choosing this menu item opens a window \
showing all the basic ways of visualizing the selected datasets.  You will \
then be able to choose the visualization you want to use.", datasetsMenu, 1, false);
    DefineObjFunction(OF_MODIFY, (char *) 0, SetupModifyList, MODIFY, ProcessModifyList,
	"modify", (char *) 0, true,
"Pressing this button opens a window showing all the basic ways to \
modify the selected datasets.  You will then be able to choose the modification \
you want to use.",
"Choosing this menu item opens a window showing all the basic ways to \
modify the selected datasets.  You will then be able to choose which modification \
you want to use.", datasetsMenu, 1, false);
    DefineObjFunction(OF_ACTIVATE, (char *) 0, 0, ACTIVATEOBJECT, 0,
	"activate", (char *) 0, false,
"Pressing this button activates the selected object, deactivating any previously activated objects of that class in the window.",
"Choosing this menu item activates the selected object, deactivating any previously activated objects of that class in the window.", objectMenu, 1, false);
    DefineObjFunction(OF_TURNON, (char *) 0, 0, SHOW, 0,
	"turn on", (char *) 0, true,
"Pressing this button turns on all the selected objects.",
"Choosing this menu item turns on all the selected objects.", objectMenu, 1, false);
    DefineObjFunction(OF_TURNOFF, (char *) 0, 0, HIDE, 0,
	"turn on", (char *) 0, true,
"Pressing this button turns off all the selected objects.",
"Choosing this menu item turns off all the selected objects.", objectMenu, 1, false);
    DefineObjFunction(OF_PUSHTOBOTTOM, (char *) 0, 0, PUSHTOBOTTOM, 0,
	"push to bottom", (char *) 0, true,
"Pressing this button pushes the selected space panel drawings to the bottom of the panel \
below all the others.",
"Choosing this menu item pushes the selected space panel drawings to the bottom of the panel \
below all the others.",
	arrangeMenu, 1, false);
    DefineObjFunction(OF_BRINGTOTOP, (char *) 0, 0, BRINGTOTOP, 0,
	"bring to top", (char *) 0, true,
"Pressing this button brings the selected space panel drawings to the top of the panel \
above all the others.",
"Choosing this menu item brings the selected space panel drawings to the top of the panel \
above all the others.",
	arrangeMenu, 1, false);
    DefineObjFunction(OF_MOVETOBACKPANEL, (char *) 0, 0, MOVETOBACKPANEL, 0,
	"move to back panel", (char *) 0, true,
"Pressing this button moves the selected space panel drawings to the back panel of the space.",
"Choosing this menu item moves the selected space panel drawings to the back panel of the space.",
	arrangeMenu, 1, false);
    DefineObjFunction(OF_MOVETOFRONTPANEL, (char *) 0, 0, MOVETOFRONTPANEL, 0,
	"move to front panel", (char *) 0, true,
"Pressing this button moves the selected space panel drawings to the front panel of the space.",
"Choosing this menu item moves the selected space panel drawings to the front panel of the space.",
	arrangeMenu, 1, false);
    DefineObjFunction(OF_DUPLICATE, (char *) 0, 0, DUPLICATE, 0,
	"duplicate", (char *) 0, true,
"Pressing this button duplicates the selected objects in the current window.",
"Choosing this menu item duplicates the selected objects in the current window.",
	objectMenu, 1, false);
    DefineObjFunction(OF_LOCALCOPY, (char *) 0, 0, LOCALCOPY, 0,
	"localcopy", (char *) 0, true,
"Pressing this button makes copies of the selected objects local to this window.  \
If the objects are shared between windows, the new copies will be detached from the shared objects.\n\n\
For example, if you have a single observer which is in two spaces, produced by \
dragging the observer from one window to the other, then the one observer will control both spaces.  \
Any operations on the observer will affect both spaces, because there's really just one observer controlling \
both spaces.  If you decide that you two observers that word separately, you can select the observer \
and choose Detach Local Copy from within a window.  A new observer will be created which \
is just like the old observer but which will be independent of the old observer.",
"Choosing this menu item makes copies of the selected objects local to this window.  \
If the objects are shared between windows, the new copies will be detached from the shared objects.\n\n\
For example, if you have a single observer which is in two spaces, produced by \
dragging the observer from one window to the other, then the one observer will control both spaces.  \
Any operations on the observer will affect both spaces, because there's really just one observer controlling \
both spaces.  If you decide that you two observers that word separately, you can select the observer \
and choose Detach Local Copy from within a window.  A new observer will be created which \
is just like the old observer but which will be independent of the old observer.",
	objectMenu, 1, false);
    DefineObjFunction(OF_DELETE, (char *) 0, 0, DELETE, 0,
	"delete", (char *) 0, true,
"Pressing this button deletes all the selected objects from the \
window.  If the objects are present in other windows, they will remain in those \
windows.  An object will not go away completely until it is deleted from everywhere \
it appears.",
"Choosing this menu item deletes all the selected objects from the \
window.  If the objects are present in other windows, they will remain in those \
windows.  An object will not go away completely until it is deleted from everywhere \
it appears.",
	objectMenu, 1, false);
#ifdef SOCKETS
    DefineObjFunction(OF_CONNECT_TO_PROCESS, (char *) 0, 0, CONNECTTOPROCESS, 0,
	"connect to process", (char *) 0, true,
	"Pressing this button opens a connection with the selected process or processes.", 
	"Choosing this menu item opens a connection with the selected process or processes.", networkMenu, 1, false); 
    DefineObjFunction(OF_ADVERTISE, (char *) 0, DoEnablePublication, ADVERTISE, 0,
	"publish", (char *) 0, true,
	"Pressing this button publishes the selected objects over the network.", 
	"Choosing this menu item publishes the selected objects over the network.", networkMenu, 1, false); 
    DefineObjFunction(OF_UNADVERTISE, (char *) 0, 0, UNADVERTISE, 0,
	"recall", (char *) 0, true,
	"Pressing this button recalls the selected objects from publication over the network.", 
	"Choosing this menu item recalls the selected objects from publication over the network.", networkMenu, 1, false); 
#endif

    DefineObjFunction(OF_ALIGNLEFT, (char *) 0, 0, ALIGNLEFT, 0,
	"align left", (char *) 0, true,
	"Pressing this button aligns the text in the selected text boxes to the left margin.", 
	"Choosing this menu item aligns the text in the selected text boxes to the left margin.", 
	alignMenu, 1, false); 

    DefineObjFunction(OF_ALIGNCENTER, (char *) 0, 0, ALIGNCENTER, 0,
	"align center", (char *) 0, true,
	"Pressing this button will center the text in the selected text boxes.", 
	"Choosing this menu item will center the text in the selected text boxes.", 
	alignMenu, 1, false); 

    DefineObjFunction(OF_ALIGNRIGHT, (char *) 0, 0, ALIGNRIGHT, 0,
	"align right", (char *) 0, true,
	"Pressing this button aligns the text in the selected text boxes to the right margin.", 
	"Choosing this menu item aligns the text in the selected text boxes to the right margin.", 
	alignMenu, 1, false);

    action = DefineObjFunction(OF_RENAME, (char *) 0, 0, RENAME, 0,
	"rename", (char *) 0, false,
	"Pressing this button lets you rename the selected object.",
	"Choosing this menu item lets you rename the selected object.",
	objectMenu, 1, true);
    SetMethod(action, ACTIONMETHOD, RenameObjectAction);

#ifdef FONTS4D
    for (k = 0; k < sizeof(textSizes) / sizeof(int); ++k)
    {
	char numBuf[20];
	sprintf(numBuf, "%d", textSizes[k]);

	action = DefineObjFunction(OF_SETFONTSIZE, numBuf, 0, SETTEXTSIZE, 0,
	    "set size", (char *) 0, true,
	    "Pressing this button sets the text size of selected objects to %s points.",
	    "Choosing this menu item sets the text size of selected objects to %s points.",
	    fontSizeMenu, 1, true);
	SetVar(action, VALUE, NewInt(textSizes[k]));
    }
#endif

    if (nFonts)
    {
	int k;
	ObjPtr subMenu;
	char mainFontName[300];
	char *s, *d, *f;

	strcpy(mainFontName, "");
	subMenu = NULLOBJ;

	for (k = 0; k < nFonts; ++k)
	{
	    Bool matches;
	    f = strchr(fonts[k], '-');

	    /*See if this one matches what's in the main font name*/
	    if (mainFontName[0])
	    {
		s = mainFontName;
		d = fonts[k];
		while (*s == *d)
		{
		    ++s;
		    ++d;
		}

		if (d == f || *d == 0)
		{
		    matches = true;
		}
		else
		{
		    matches = false;
		}
	    }
	    else
	    {
		matches = false;
	    }

	    /*See if we need to finish up old font*/
	    if (mainFontName[0] && !matches)
	    {
		if (subMenu)
		{
		    /*Put on the old menu as a submenu*/
		    AddMenuItem(fontMenu, subMenu, 1);
		    subMenu = NULLOBJ;
		}
		else
		{
		    /*Just alone*/
		    DefineObjFunction(OF_SETFONT, mainFontName, 0, SETTEXTFONT, 0,
			"set font", mainFontName, true,
			"Pressing this button sets the font of selected objects to %s.",
			"Choosing this menu item sets the font of selected objects to %s.",
			fontMenu, 1, true);
		}
		mainFontName[0] = 0;
	    }

	    if (!mainFontName[0])
	    {
		/*It's a new main font name.  Copy it in*/
		s = fonts[k];
		d = mainFontName;
		if (f)
		{
		    while (s < f)
		    {
			*d++ = *s++;
		    }
		}
		else
		{
		    while (*s)
		    {
			*d++ = *s++;
		    }
		}
		*d = 0;

		matches = true;

		if (f)
		{
		    /*We know there are more than one; make a new submenu*/
		    subMenu = NewMenu(mainFontName);
		    /*Now add us*/
		    DefineObjFunction(OF_SETFONT, f ? (f + 1) : "Plain", 0, SETTEXTFONT, 0,
			"set font", fonts[k], true,
			"Pressing this button sets the font of selected objects to %s.",
			"Choosing this menu item sets the font of selected objects to %s.",
			subMenu, 1, true);
		}
		else
		{
		    /*This may be the only one.  Don't make a submenu*/
		}
	    }
	    else
	    {
		/*It matches a current main font.*/

		if (!subMenu)
		{
		    /*Create a submenu if it's not there, with Plain*/
		    subMenu = NewMenu(mainFontName);
		    DefineObjFunction(OF_SETFONT, "Plain", 0, SETTEXTFONT, 0,
			"set font", fonts[k - 1], true,
			"Pressing this button sets the font of selected objects to %s.",
			"Choosing this menu item sets the font of selected objects to %s.",
			subMenu, 1, true);
		}

		/*Now add us*/
		DefineObjFunction(OF_SETFONT, f ? (f + 1) : "Plain", 0, SETTEXTFONT, 0,
			"set font", fonts[k], true,
			"Pressing this button sets the font of selected objects to %s.",
			"Choosing this menu item sets the font of selected objects to %s.",
			subMenu, 1, true);
	    }
	}
	/*See if we need to finish up old font*/
	if (subMenu)
	{
	    AddMenuItem(fontMenu, subMenu, 1);
	    subMenu = NULLOBJ;
	}
	else
	{
	    /*Just alone*/
	    DefineObjFunction(OF_SETFONT, mainFontName, 0, SETTEXTFONT, 0,
		"set font", mainFontName, true,
		"Pressing this button sets the font of selected objects to %s.",
		"Choosing this menu item sets the font of selected objects to %s.",
		fontMenu, 1, true);
	}
    }
}

void KillObjFunctions()
{
    RemoveFromReferenceList(undoList);
    RemoveFromReferenceList(undoClass);
    while (nObjFunctions)
    {
	--nObjFunctions;
	if (objFunctions[nObjFunctions] . name)
	{
	    Free(objFunctions[nObjFunctions] . name);
	}
	if (objFunctions[nObjFunctions] . scriptPrefix)
	{
	    Free(objFunctions[nObjFunctions] . scriptPrefix);
	}
 	if (objFunctions[nObjFunctions] . scriptPostfix)
	{
	    Free(objFunctions[nObjFunctions] . scriptPostfix);
	}
 	if (objFunctions[nObjFunctions] . buttonHelp)
	{
	    Free(objFunctions[nObjFunctions] . buttonHelp);
	}
  	if (objFunctions[nObjFunctions] . menuHelp)
	{
	    Free(objFunctions[nObjFunctions] . menuHelp);
	}
	DeleteThing(objFunctions[nObjFunctions] . objectsToDo);
    }
    if (objFunctions)
    {
	Free(objFunctions);
    }
    RemoveFromReferenceList(objectActionClass);
}
Modified: Sun Nov 17 17:00:00 1996 GMT
Page accessed 2462 times since Sat Apr 17 21:54:54 1999 GMT