{Begin SubSec Image Objects}
{Title Image Objects}
{Text

{index *PRIMARY* Image objects}

An Image Object is an object that includes information about an image, such as how to display it, how to print it, and how to manipulate it when it is included in a collection of images (such as a document).  More generally, it enables you to include one kind of image, with its own semantics, layout rules, and editing paradigms, inside another kind of image.  Image Objects provide a general-purpose interface between image users who want to manipulate arbitrary images, and image producers, who create images for use, say, in documents.

Images are encapsulated inside a uniform barrier{emdash}the {lisp IMAGEOBJ}{index IMAGEOBJ (Data Type)} data type.  From the outside, you communicate to the image by calling a standard set of functions.  For example, calling one function tells you how big the image is; calling another causes the image object to be displayed where you tell it, and so on.   Anyone who wants to create images for general use can implement his own brand of {lisp IMAGEOBJ}.  {lisp IMAGEOBJ}s have been implemented (in library packages) for bitmaps, menus, annotations, graphs, and sketches. 

Image Objects were originally implemented to support inserting images into TEdit text files, but the facility is available for use by any tools that manipulate images.  The Image Object interface allows objects to exist in TEdit documents and be edited with their own editor.  It also provides a facility in which objects can be shift-selected (or "copy-selected") between TEdit and non-TEdit windows.  For example, the Image Objects interface allows you to copy-select graphs from a Grapher window into a TEdit window.  The source window (where the object comes from) does not have to know what sort of window the destination window (where the object is inserted) is, and the destination does not have to know where the insertion comes from. 

A new data type, {lisp IMAGEOBJ},{index IMAGEOBJ (Data Type)} contains the data and the procedures necessary to manipulate an object that is to be manipulated in this way.  {lisp IMAGEOBJ}s are created with the function {fn IMAGEOBJCREATE} (below). 

Another new data type, {lisp IMAGEFNS},{index IMAGEFNS (Data Type)} is a vector of the procedures necessary to define the behavior of a type of {lisp IMAGEOBJ}.  Grouping the operations in a separate data type allows multiple instances of the same type of image object to share procedure vectors.  The data and procedure fields of an {lisp IMAGEOBJ} have a uniform interface through the function {fn IMAGEOBJPROP}.  {lisp IMAGEFNS} are created with the function {fn IMAGEFNSCREATE}:

{FnDef {Name IMAGEFNSCREATE} {Args DISPLAYFN IMAGEBOXFN PUTFN GETFN COPYFN BUTTONEVENTINFN COPYBUTTONEVENTINFN WHENMOVEDFN WHENINSERTEDFN WHENDELETEDFN WHENCOPIEDFN WHENOPERATEDONFN PREPRINTFN {anonarg}}
{Text
Returns an {lisp IMAGEFNS} object that contains the functions necessary to define the behavior of an {lisp IMAGEOBJ}.

The arguments {arg DISPLAYFN} through {arg PREPRINTFN} should all be function names to be stored as the "methods" of the {lisp IMAGEFNS}.  The purpose of each {lisp IMAGEFNS} method is described below.

Note:  Image objects must be "registered" before they can be read by TEdit or {fn HREAD} (see {PageRef Term Registering image objects}).  {fn IMAGEFNSCREATE} implicitly registers its {arg GETFN} argument.
}}


{FnDef {Name IMAGEOBJCREATE} {Args OBJECTDATUM IMAGEFNS}
{Text
Returns an {lisp IMAGEOBJ} that contains the object datum {arg OBJECTDATUM} and the operations vector {arg IMAGEFNS}.  {arg OBJECTDATUM} can be arbitrary data.
}}


{FnDef {Name IMAGEOBJPROP} {Args IMAGEOBJECT PROPERTY NEWVALUE}
{Type NoSpread}
{Text
Accesses and sets the properties of an {lisp IMAGEOBJ}.  Returns the current value of the {arg PROPERTY} property of the image object {arg IMAGEOBJECT}.  If {arg NEWVALUE} is given, the property is set to it.

{fn IMAGEOBJPROP} can be used on the system properties {lisp OBJECTDATUM}, {lisp DISPLAYFN}, {lisp IMAGEBOXFN}, {lisp PUTFN}, {lisp GETFN}, {lisp COPYFN}, {lisp BUTTONEVENTINFN}, {lisp COPYBUTTONEVENTINFN}, {lisp WHENOPERATEDONFN}, and {lisp PREPRINTFN}.  Additionally, it can be used to save arbitrary properties on an {lisp IMAGEOBJ}.
}}

{FnDef {Name IMAGEFNSP} {Args X}
{Text
Returns {arg X} if {arg X} is an {lisp IMAGEFNS} object, {lisp NIL} otherwise.
}}


{FnDef {Name IMAGEOBJP} {Args X}
{Text
Returns {arg X} if {arg X} is an {lisp IMAGEOBJ} object, {lisp NIL} otherwise.
}}



{Begin SubSec IMAGEFNS Methods}
{Title IMAGEFNS Methods}
{Text



Note:  Many of the {lisp IMAGEFNS} methods below are passed "host stream" arguments.  The TEdit text editor passes the "text stream" (an object contain all of the information in the document being edited) as the "host stream" argument.  Other editing programs that want to use image objects may want to pass the data structure being edited to the {lisp IMAGEFNS} methods as the "host stream" argument.


{Def {Type (IMAGEFNS Method)}
{Name DISPLAYFN} {Args IMAGEOBJ IMAGESTREAM IMAGESTREAMTYPE HOSTSTREAM}
{Text
The {lisp DISPLAYFN} method is called to display the object {arg IMAGEOBJ} at the current position on {arg IMAGESTREAM}.  The type of {arg IMAGESTREAM} indicates whether the device is the display or some other image stream.

Note:  When the {lisp DISPLAYFN} method is called, the offset and clipping regions for the stream are set so the object's image is at {lisp (0,0)}, and only that image area can be modified.
}}


{Def {Type (IMAGEFNS Method)}
{Name IMAGEBOXFN} {Args IMAGEOBJ IMAGESTREAM CURRENTX RIGHTMARGIN}
{Text
The {lisp IMAGEBOXFN} method should return the size of the object as an {lisp IMAGEBOX},{index IMAGEBOX (Record)} which is a data structure that describes the image laid down when an {lisp IMAGEOBJ} is displayed in terms of width, height, and descender height.  An {lisp IMAGEBOX} has four fields: {lisp XSIZE}, {lisp YSIZE}, {lisp YDESC}, and {lisp XKERN}.  {lisp XSIZE} and {lisp YSIZE} are the width and height of the object image.  {lisp YDESC} and {lisp XKERN} give the position of the baseline and the left edge of the image relative to where you want to position it.  For characters, the {lisp YDESC} is the descent (height of the descender) and the {lisp XKERN} is the amount of left kerning (note: TEdit doesn't support left kerning).{index XSIZE (IMAGEBOX Field)}{index YSIZE (IMAGEBOX Field)}{index YDESC (IMAGEBOX Field)}{index XKERN (IMAGEBOX Field)}

The {lisp IMAGEBOXFN} looks at the type of the stream to determine the output device if the object's size changes from device to device.  (For example, a bit-map object may specify a scale factor that is ignored when the bit map is displayed on the screen.)  {arg CURRENTX} and {arg RIGHTMARGIN} allow an object to take account of its environment when deciding how big it is.  If these fields are not available, they are {lisp NIL}.

Note: TEdit calls the {lisp IMAGEBOXFN} only during line formatting, then caches the {lisp IMAGEBOX} as the {lisp BOUNDBOX} property of the {lisp IMAGEOBJ}.  This avoids the need to call the {lisp IMAGEBOXFN} when incomplete position and margin information is available.
}}


{Def {Type (IMAGEFNS Method)}
{Name PUTFN} {Args IMAGEOBJ FILESTREAM}
{Text
The {lisp PUTFN} method is called to save the object on a file.  It prints a description on {arg FILESTREAM} that, when read by the corresponding {lisp GETFN} method (see below), regenerates the image object.  (TEdit and {fn HPRINT} take care of writing out the name of the {lisp GETFN}.)
}}


{Def {Type (IMAGEFNS Method)}
{Name GETFN} {Args FILESTREAM}
{Text
The {lisp GETFN} method is called when the object is encountered on the file during input.  It reads the description that was written by the {lisp PUTFN} method and returns an {lisp IMAGEOBJ}. 
}}


{Def {Type (IMAGEFNS Method)}
{Name COPYFN} {Args IMAGEOBJ SOURCEHOSTSTREAM TARGETHOSTSTREAM}
{Text
The {lisp COPYFN} method is called during a copy-select operation.  It should return a copy of {arg IMAGEOBJ}.  If it returns the litatom {lisp DON'T}, copying is suppressed.
}}


{Def {Type (IMAGEFNS Method)}
{Name BUTTONEVENTINFN} {Args IMAGEOBJ WINDOWSTREAM SELECTION RELX RELY WINDOW HOSTSTREAM BUTTON}
{Text
The {lisp BUTTONEVENTINFN} method is called when you press a mouse button inside the object.  The {lisp BUTTONEVENTINFN} decides whether or not to handle the button, to track the cursor in parallel with mouse movement, and to invoke selections or edits supported by the object (but see the {lisp COPYBUTTONEVENTINFN} method below).  If the {lisp BUTTONEVENTINFN} returns {lisp NIL}, TEdit treats the button press as a selection at its level.  Note that when this function is first called, a button is down.  The {lisp BUTTONEVENTINFN} should also support the button-down protocol to descend inside of any composite objects with in it.  In most cases, the {lisp BUTTONEVENTINFN} relinquishes control (i.e., returns) when the cursor leaves its object's region.

Note: When the {lisp BUTTONEVENTINFN} is called, the window's clipping region and offsets have been changed so that the lower-left corner of the object's image is at {lisp (0,0)}, and only the object's image can be changed.  The selection is available for changing to fit your needs; the mouse button went down at {lisp ({arg RELX},{arg RELY})} within the object's image.  You can affect how TEdit treats the selection by returning one of several values.  If you return {lisp NIL}, TEdit forgets that you selected an object; if you return the atom {lisp DON'T}, TEdit doesn't permit the selection; if you return the atom {lisp CHANGED}, TEdit updates the screen.  Use {lisp CHANGED} to signal TEdit that the object has changed size or will have side effects on other parts of the screen image.
}}


{Def {Type (IMAGEFNS Method)}
{Name COPYBUTTONEVENTINFN} {Args IMAGEOBJ WINDOWSTREAM}
{Text
The {lisp COPYBUTTONEVENTINFN} method is called when you button inside an object while holding down a copy key.  Many of the comments about {lisp BUTTONEVENTINFN} apply here too.  Also, see the discussion below about copying image objects between windows ({PageRef Term copying image objects between windows}).  
}}


{Def {Type (IMAGEFNS Method)}
{Name WHENMOVEDFN} {Args IMAGEOBJ TARGETWINDOWSTREAM SOURCEHOSTSTREAM TARGETHOSTSTREAM}
{Text
The {lisp WHENMOVEDFN} method provides hooks by which the object is notified when TEdit performs an operation (MOVEing) on the whole object.  It allows objects to have side effects.  
}}


{Def {Type (IMAGEFNS Method)}
{Name WHENINSERTEDFN} {Args IMAGEOBJ TARGETWINDOWSTREAM SOURCEHOSTSTREAM TARGETHOSTSTREAM}
{Text
The {lisp WHENINSERTEDFN} method provides hooks by which the object is notified when TEdit performs an operation (INSERTing) on the whole object.  It allows objects to have side effects.  
}}

{Def {Type (IMAGEFNS Method)}
{Name WHENDELETEDFN} {Args IMAGEOBJ TARGETWINDOWSTREAM}
{Text
The {lisp WHENDELETEDFN} method provides hooks by which the object is notified when TEdit performs an operation (DELETEing) on the whole object.  It allows objects to have side effects.  
}}


{Def {Type (IMAGEFNS Method)}
{Name WHENCOPIEDFN} {Args IMAGEOBJ TARGETWINDOWSTREAM SOURCEHOSTSTREAM TARGETHOSTSTREAM}
{Text
The {lisp WHENCOPIEDFN} method provides hooks by which the object is notified when TEdit performs an operation (COPYing) on the whole object.  The {lisp WHENCOPIEDFN} method is called in addition to (and after) the {lisp COPYFN} method above.  It allows objects to have side effects.
}}


{Def {Type (IMAGEFNS Method)}
{Name WHENOPERATEDONFN} {Args IMAGEOBJ WINDOWSTREAM HOWOPERATEDON SELECTION HOSTSTREAM}
{Text
The {lisp WHENOPERATEDONFN} method provides a hook for edit operations.  {arg HOWOPERATEDON} should be one of {lisp SELECTED}, {lisp DESELECTED}, {lisp HIGHLIGHTED}, and {lisp UNHILIGHTED}.  The {lisp WHENOPERATEDONFN} differs from the {lisp BUTTONEVENTINFN} because it is called when you extend a selection through the object.  That is, the object is treated in toto as a TEdit character.  {lisp HIGHLIGHTED} refers to the selection being highlighted on the screen, and {lisp UNHIGHLIGHTED} means that the highlighting is being turned off.  
}}


{Def {Type (IMAGEFNS Method)}
{Name PREPRINTFN} {Args IMAGEOBJ}
{Text
The {lisp PREPRINTFN} method is called to convert the object into something that can be printed for inclusion in documents.  It returns an object that the receiving window can print (using either {fn PRIN1} or {fn PRIN2},its choice) to obtain a character representation of the object.  If the {lisp PREPRINTFN} method is {lisp NIL}, the {lisp OBJECTDATUM} field of {arg IMAGEOBJ} itself is used.  TEdit uses this function when you indicate that you want to print the characters from an object rather than the object itself (presumably using {fn PRIN1} case).
}}


}{End SubSec IMAGEFNS Methods}


{Begin SubSec Registering Image Objects}
{Title Registering Image Objects}
{Text

{index *PRIMARY* Registering image objects}

Each legitimate {lisp GETFN} needs to be known to the system, to prevent various Trojan-horse problems and to allow the automatic loading of the supporting code for infrequently used {lisp IMAGEOBJ}s.  To this end, there is a global list, {var IMAGEOBJGETFNS},{index IMAGEOBJGETFNS Var} that contains an entry for each {lisp GETFN}.  The existence of the entry marks the {lisp GETFN} as legitimate; the entry itself is a property list, which can hold information about the {lisp GETFN}.

No action needs to be taken for {lisp GETFN}s that are currently in use: the function {fn IMAGEFNSCREATE} automatically adds its {arg GETFN} argument to the list.  However, packages that support obsolete versions of objects may need to explicitly add the obsolete {lisp GETFN}s.  For example, TEdit supports bit-map {lisp IMAGEOBJ}s.  Recently, a change was made in the format in which objects are stored; to retain compatibility with the old object format, there are now two {lisp GETFN}s.  The current {lisp GETFN} is automatically on the list, courtesy of {fn IMAGEFNSCREATE}.   However, the code file that supports the old bit-map objects contains the  clause: {lisp (ADDVARS (IMAGEOBJGETFNS ({arg OLDGETFNNAME})))}, which adds the old {lisp GETFN} to {var IMAGEOBJGETFNS}.

For a given {lisp GETFN}, the entry on {var IMAGEOBJGETFNS} may be a property list of information.  Currently the only recognized property is  {lisp FILE}.

{lisp FILE}{index FILE (GETFN Property)} is the name of the file that can be loaded if the {lisp GETFN} isn't defined.  This file should define the {lisp GETFN}, along with all the other functions needed to support that kind of {lisp IMAGEOBJ}.

For example, the bit-map {lisp IMAGEOBJ} implemented by TEdit use the {lisp GETFN} {lisp BMOBJ.GETFN2}.  Its entry on {var IMAGEOBJGETFNS} is {lisp (BMOBJ.GETFN2 FILE IMAGEOBJ)}, indicating that the support code for bit-map image objects resides on the file {lisp IMAGEOBJ}, and that the {lisp GETFN} for them is {lisp BMOBJ.GETFN2}.

This makes it possible to have entries for {lisp GETFN}s whose supporting code isn't loaded{emdash}you might, for instance, have your init file add entries to {var IMAGEOBJGETFNS} for the kinds of image objects you commonly use.  The system's default reading method will automatically load the code when necessary.

}{End SubSec Registering Image Objects}


{Begin SubSec Reading and Writing Image Objects on Files}
{Title Reading and Writing Image Objects on Files}
{Text

Image Objects can be written out to files using {fn HPRINT} and read back using {fn HREAD}.  The following functions can also be used:

{FnDef {Name WRITEIMAGEOBJ} {Args IMAGEOBJ STREAM}
{Text
Prints (using {fn PRIN2}) a call to {fn READIMAGEOBJ}, then calls the {lisp PUTFN} for {arg IMAGEOBJ} to write it onto {arg STREAM}.  During input, then, the call to {fn READIMAGEOBJ} is read and evaluated; it in turn reads back the object's description, using the appropriate {lisp GETFN}.
}}

{FnDef {Name READIMAGEOBJ} {Args STREAM GETFN NOERROR}
{Text
Reads an {lisp IMAGEOBJ} from {arg STREAM}, starting at the current file position.  Uses the function {arg GETFN} after validating it (and loading support code, if necessary).

{index *PRIMARY* Encapsulated image objects}

If the {arg GETFN} can't be validated or isn't defined, {fn READIMAGEOBJ} returns an "encapsulated image object", an {lisp IMAGEOBJ} that safely encapsulates all of the information in the image object.  An encapsulated image object displays as a rectangle that says, "{lisp Unknown IMAGEOBJ Type}" and lists the {arg GETFN}'s name.  Selecting an encapsulated image object with the mouse causes another attempt to read the object from the file; this is so you can load any necessary support code and then get to the object.

Warning: You cannot save an encapsulated image object on a file because there isn't enough information to allow copying the description to the new file from the old one.

If {arg NOERROR} is non-{lisp NIL}, {fn READIMAGEOBJ} returns {lisp NIL} if it can't successfully read the object.
}}

}{End SubSec Reading and Writing Image Objects on Files}



{Begin SubSec Copying Image Objects Between Windows}
{Title Copying Image Objects Between Windows}
{Text

{index *PRIMARY* Copying image objects between windows}

Copying between windows is implemented as follows:  If a button event occurs in a window when a copy key is down, the window's {lisp COPYBUTTONEVENTFN} window property is called.  If this window supports copy-selection, it should track the mouse, indicating the item to be copied.  When the button is released, the {lisp COPYBUTTONEVENTFN} should create an image object out of the selected information, and call {fn COPYINSERT} to insert it in the current TTY window.  {fn COPYINSERT} calls the {lisp COPYINSERTFN} window property of the TTY window to insert this image object.  Therefore, both the source and destination windows can determine how they handle copying image objects.

If the {lisp COPYBUTTONEVENTFN} of a window is {lisp NIL}, the {lisp BUTTONEVENTFN} is called instead when a button event occurs in the window when a copy key is down, and copying from that window is not supported.  If the {lisp COPYINSERTFN} of the TTY window is {lisp NIL}, {fn COPYINSERT} will turn the image object into a string (by calling the {lisp PREPRINTFN} method of the image object, see {PageRef (Imagefns Method) PREPRINTFN}) and insert it by calling {fn BKSYSBUF} ({PageRef Fn BKSYSBUF}).

{Def {Type (Window Property)} {Name COPYBUTTONEVENTFN}
{Text
The {lisp COPYBUTTONEVENTFN} of a window is called (if it exists) when a button event occurs in the window and a copy key is down.  If no {lisp COPYBUTTONEVENTFN} exists, the {lisp BUTTONEVENTFN} is called.
}}


{Def {Type (Window Property)} {Name COPYINSERTFN}
{Text
The {lisp COPYINSERTFN} of the "destination" window is called by {fn COPYINSERT} to insert something into the destination window.  It is called with two arguments: the object to be inserted and the destination window.  The object to be inserted can be a character string, an {lisp IMAGEOBJ}, or a list of {lisp IMAGEOBJ}s and character strings.  As a convention, the {lisp COPYINSERTFN} should call {fn BKSYSBUF} ({PageRef Fn BKSYSBUF}) if the object to be inserted insert is a character string.
}}


{FnDef {Name COPYINSERT} {Args IMAGEOBJ}
{Text
{fn COPYINSERT} inserts {arg IMAGEOBJ} into the window that currently has the TTY.  If the current TTY window has a {lisp COPYINSERTFN}, it is called, passing it {arg IMAGEOBJ} and the window as arguments.

If no {lisp COPYINSERTFN} exists and if {arg IMAGEOBJ} is an image object, {fn BKSYSBUF} is called on the result of calling its {lisp PREPRINTFN} on it.  If {arg IMAGEOBJ} is not an image object, it is simply passed to {fn BKSYSBUF} ({PageRef Fn BKSYSBUF}).  In this case, {fn BKSYSBUF} will call {fn PRIN2} with a read table taken from the process associated with the TTY window.  A window that wishes to use {fn PRIN1} or a different read table must provide its own {lisp COPYINSERTFN} to do this.
}}

}{End SubSec Copying Image Objects Between Windows}


}{End SubSec Image Objects}