{Begin SubSec Attached Window Facility}
{Title Attached Window Facility}
{Text

The attached window facility makes it easy to manipulate a group of window as a unit.  Standard operations like {lisp MOVE}, {lisp RESHAPE}, {lisp OPEN} and {lisp CLOSE} can be done so that it appears to the user as if the windows are a single entity.  Each collection of attached windows has one main window and any number of other windows that are "attached" to it.  Moving or reshaping the main window causes all of the attached windows to be moved or reshaped as well.  Moving or reshaping an attached window does not affect the main window.  The initial motivation for attached windows was to allow multiple menus to be associated with the same window but there is no restriction on what windows can be attached.

{FnDef {Name ATTACHWINDOW} {Args WINDOWTOATTACH MAINWINDOW EDGE POSITIONONEDGE WINDOWCOMACTION}
{Text
Associates {arg WINDOWTOATTACH} with {arg MAINWINDOW} so that shape, move, close, shrink and expand operations done to {arg MAINWINDOW} are also done to {arg WINDOWTOATTACH}.  {fn ATTACHWINDOW} moves {arg WINDOWTOATTACH} to its position relative to {arg MAINWINDOW} but does not open it.

{arg EDGE} and {arg POSITIONONEDGE} indicate where {arg WINDOWTOATTACH} is to be positioned.  The argument {arg EDGE} determines which edge: {lisp TOP}, {lisp BOTTOM}, {lisp LEFT}, or {lisp RIGHT}.  The default, used if {arg EDGE} is {lisp NIL}, is {lisp TOP}.  The argument {arg POSITIONONEDGE} determines where along edge the window is positioned:

{Begin LabeledList}

{Label {lisp JUSTIFY}}
{Text means that the attached window is to fill the entire edge.  {fn ATTACHWINDOW} reshapes the window if necessary.}

{Label {lisp LEFT} or {lisp RIGHT}}
{Text for the left or right (for a {lisp TOP} or {lisp BOTTOM} edge).}

{Label {lisp BOTTOM} or {lisp TOP}}
{Text for the bottom or top (of a {lisp LEFT} or {lisp RIGHT} edge).}

{Label {lisp CENTER}}
{Text for the center of the edge.}

{End LabeledList}

The default for {arg POSITIONONEDGE} is {lisp JUSTIFY}.

The size that is filled by the justification includes the extent of any other windows that have already been attached to {arg MAINWINDOW}.  Thus {lisp (ATTACHWINDOW A MW 'RIGHT 'JUSTIFY)} followed by {lisp (ATTACHWINDOW B MW 'TOP 'JUSTIFY)} will put {lisp B} across the top of both {lisp MW} and {lisp A}.

{arg WINDOWCOMACTION} provides a convenient way of setting the way the attached window responds to right buttoning.  If {arg WINDOWCOMACTION} is {lisp MAIN}, the {lisp DOWINDOWCOMFN} of {arg WINDOWTOATTACH} is set to {fn DOMAINWINDOWCOMFN}.  If {arg WINDOWCOMACTION} is {lisp HERE}, the {lisp DOWINDOWCOMFN} of {arg WINDOWTOATTACH} is not changed.  If {arg WINDOWCOMACTION} is {lisp LOCALCLOSE}, the {lisp DOWINDOWCOMFN} of {arg WINDOWTOATTACH} is set to {fn DOATTACHEDWINDOWCOM2}.  Otherwise, the {lisp DOWINDOWCOMFN} of {arg WINDOWTOATTACH} is set to {fn DOATTACHEDWINDOWCOM}.  These functions are described below in the section on "attached window menu commands."
}}


{FnDef {Name DETACHWINDOW} {Args WINDOWTODETACH}
{Text
Detaches {arg WINDOWTODETACH} from its main window.  Returns a dotted pair whose {fn CAR} is {arg EDGE} and whose {fn CDR} is {arg POSITIONONEDGE} if {arg WINDOWTODETACH} was an attached window.  Returns {lisp NIL} otherwise.  This does not close {arg WINDOWTODETACH}.
}}


{Begin SubSec Behavior On Standard Window Operations}
{Title Behavior On Standard Window Operations}
{Text

When a window operation, such as moving or clearing, is performed on a window, there is a question about whether or not that operation also be performed on the windows attached to it or performed on the window it is attached to.  The following are the default behaviors of main and attached windows under the window operations when invoked programmatically, e.g., from the functions {fn MOVEW}, {fn SHAPEW}, etc.

The behavior when an operation is invoked from the window menu depends on the {arg WINDOWCOMACTION} argument to {fn ATTACHWINDOW}, or ultimately the window's {lisp DOWINDOWCOMFN} property.  Mention of "menu" below assumes that the window was attached using the default ({lisp NIL}) {arg WINDOWCOMACTION}.

The behavior for any particular operation can, of course, be changed for particular windows by setting the standard window properties (e.g., {fn MOVEFN} or {fn CLOSEFN}) of the particular attached window.

{Begin Labeledlist}

{Label Move}
{Text
If the main window moves, all attached windows move with it, and the relative positioning between the main window and the attached windows is maintained.  If the region is determined interactively, the prompt region for the move is the union of the extent of the main window and all attached windows.

{fn MOVEW} moves an attached window without affecting the main window.  The Move command in the window menu is by default passed on to the main window, so that all windows in the group move.
}

{Label Reshape}
{Text
If the main window is reshaped, the minimum size of it and all of its attached windows is used as the minimum of the space for the result.  Any space greater than the minimum is distributed among the main window and its attached windows.

{fn SHAPEW} reshapes an attached window independently.  The Shape command in the window menu is by default passed on to the main window.
}

{Label Close}
{Text
If the main window is closed, all of the attached windows are closed also and the links from the attached windows to the main window are broken.  This is necessary for the windows to be garbage collected.

{fn CLOSEW} closes an attached window without affecting the main window.  Close in the window menu is by default passed on to the main window.  If {arg WINDOWCOMACTION} of {lisp LOCALCLOSE} was specified in the call to {fn ATTACHWINDOW}, the menu Close operates independently.  Note that closing an attached window does not detach it.
}

{Label Open}
{Text
If the main window is opened, it opens all attached windows and reestablishes links from them to the main window.

Attached windows can be opened independently and this does not affect the main window.
}

{Label Shrink}
{Text
The collection of windows shrinks as a group.  The {lisp SHRINKFN}s of the attached windows are evaluated but the only icon displayed is the one for the main window.
}

{Label Redisplay}
{Text
The main or attached windows can be redisplayed independently.
}

{Label Totop}
{Text
If any main or attached window is brought to the top, all of the other windows are brought to the top also.
}

{Label Expand}
{Text
Expanding any of the windows expands the whole collection.
}

{Label Scrolling}
{Text
All of the windows involved in the group scroll independently.
}

{Label Clear}
{Text
All windows clear independently of each other.
}

{End Labeledlist}

}{End SubSec Behavior On Standard Window Operations}


{Begin SubSec Attached Window Menu Commands}
{Title Attached Window Menu Commands}
{Text

The question of how to handle the window command menu of any particular window (either by right buttoning or by a call to the function {fn DOWINDOWCOM}) is handled by the window's {lisp DOWINDOWCOMFN} property.  The {arg WINDOWCOMACTION} argument to {fn ATTACHWINDOW} selects one of the following three functions to be the attached window's {lisp DOWINDOWCOMFN} property, or leaves the property {lisp NIL} if {arg WINDOWCOMACTION} is {lisp HERE}, meaning to use the standard window command menu, ignorant of the window's attachments.  The programmer can instead supply her own {lisp DOWINDOWCOMFN} property if some other behavior is desired.  

{FnDef {Name DOATTACHEDWINDOWCOM} {Args ATTACHEDW LOCALCLOSEFLG}
{Text 
The default (when {arg WINDOWCOMACTION} is {lisp NIL}).  Brings up the window command menu and then, depending upon the command selected, either passes the command to the main window of {arg ATTACHEDW} or performs it on {arg ATTACHEDW}.  If {arg LOCALCLOSEFLG} is non-{lisp NIL}, the Close command is applied to {arg ATTACHEDW}.  Otherwise, the Close command is passed to the main window.  The commands Move, Shape, Shrink and Bury are passed to the main window.  The other commands are performed on {arg ATTACHEDW}.
}}

{FnDef {Name DOATTACHEDWINDOWCOM2} {Args ATTACHEDW}
{Text 
Used when {arg WINDOWCOMACTION} is {lisp LOCALCLOSE}.  Performs {lisp (DOATTACHEDWINDOWCOM {arg ATTACHEDW} T)} so that the command Close is performed on {arg ATTACHEDW}.
}}

{FnDef {Name DOMAINWINDOWCOMFN} {Args ATTACHEDW}
{Text 
Used when {arg WINDOWCOMACTION} is {lisp MAIN}.  Performs {fn DOWINDOWCOM} on the window that is the {lisp MAINWINDOW} property of {arg ATTACHEDW}.  In other words, assuming the {lisp DOWINDOWCOMFN} of the main window hasn't been changed, this passes all window commands on to the main window.
}}

}{End SubSec Attached Window Menu Commands}


{Begin SubSec Attaching Menus To Windows}
{Title Attaching Menus To Windows}
{Text

The following functions are provided to associate menus to windows.

{FnDef {Name ATTACHMENU} {Args MENU MAINWINDOW EDGE POSITIONONEDGE NOOPENFLG}
{Text
Creates a window that contains the menu {arg MENU} (by calling {fn MENUWINDOW}, see below) and attaches it to the window {arg MAINWINDOW} on edge {arg EDGE} at position {arg POSITIONONEDGE}.  The menu window is opened unless {arg MAINWINDOW} is closed, or {arg NOOPENFLG} is {lisp T}.
}}

{FnDef {Name MENUWINDOW} {Args MENU VERTFLG}
{Text
Returns a closed window that has the menu {arg MENU} in it.  If {arg MENU} is a list, a menu is created with {arg MENU} as its items.  Otherwise, {arg MENU} should be a menu.  The returned window has the appropriate {lisp RESHAPEFN}, {lisp MINSIZE} and {lisp MAXSIZE} window properties to allow its use in a window group.  {arg VERTFLG} is provided to allow convenient setting of the default menu shape and will only be considered if both the {lisp MENUROWS} and {lisp MENUCOLUMNS} fields of {arg MENU} are {lisp NIL}.  If {arg VERTFLG} is non-{lisp NIL}, the {lisp MENUROWS} field of {arg MENU} will be set to 1; otherwise the {lisp MENUCOLUMNS} field of {arg MENU} will be set to 1.
}}

{FnDef {Name CREATEMENUEDWINDOW} {Args MENU WINDOWTITLE LOCATION WINDOWSPEC}
{Text
Creates a window with an attached menu and returns the main window.  {arg MENU} is the only required argument, and may be a menu or a list of menu items.  {arg WINDOWTITLE} is a string specifying the title of the main window.  {arg LOCATION} specifies the edge on which to place the menu, as with {fn ATTACHWINDOW}'s {arg EDGE} argument; the default is {lisp TOP}.  {arg WINDOWSPEC} is a {lisp REGION}, specifying a region for the aggregate window; if {lisp NIL}, the user is prompted for a region.
}}

Examples:

{lispcode
(SETQ MENUW
  (MENUWINDOW (create MENU
                ITEMS ← '(smaller LARGER)
                MENUFONT ← '(GACHA 12)
                TITLE ← "zoom controls"
                CENTERFLG ← T
                WHENSELECTEDFN ← (FUNCTION ZOOMMAINWINDOW))))}

creates a menu window that contains the two items "{lisp smaller}" and "{lisp LARGER}" with the title "{lisp zoom controls}" and that calls the function {lisp ZOOMMAINWINDOW} when an item is selected.

{lispcode
(ATTACHWINDOW MENUW (CREATEW '(50 50 150 150)) 'TOP 'JUSTIFY)}

creates a window on the screen and attaches the above created menu window to its top.

{lispcode
(CREATEMENUEDWINDOW (CREATE MENU
                ITEMS ← '(smaller LARGER)
                MENUFONT ← '(GACHA 12)
                TITLE ← "zoom controls"
                CENTERFLG ← T
                WHENSELECTEDFN ← (FUNCTION ZOOMMAINWINDOW))))}

creates the same sort of window in one step, prompting the user for a region.

}{End SubSec Attaching Menus To Windows}


{Begin SubSec Attached Prompt Windows}
{Title Attached Prompt Windows}
{Text

Many packages have a need to display status information or prompt for small amounts of user input in a place outside their standard window.  A convenient way to do this is to attach a small window to the top of the program's main window.  The following functions do so in a uniform way that can be depended on among diverse applications.

{FnDef {Name GETPROMPTWINDOW} {Args MAINWINDOW #LINES FONT DONTCREATE}
{Text 
Returns the attached prompt window associated with {arg MAINWINDOW}, creating it if necessary.  The window is always attached to the top of {arg MAINWINDOW}, has {lisp DSPSCROLL} set to {lisp T}, and has a {lisp PAGEFULLFN} of {fn NILL} to inhibit page holding.  The window is at least {arg #LINES} lines high (default 1); if a pre-existing window is shorter than that, it is reshaped to make it large enough.  {arg FONT} is the font to give the prompt window (defaults to the font of {arg MAINWINDOW}), and applies only when the window is first created.  If {arg DONTCREATE} is true, returns the window if it exists, otherwise {lisp NIL} without creating any prompt window.
}}

{FnDef {Name REMOVEPROMPTWINDOW} {Args MAINWINDOW}
{Text 
Detaches the attached prompt window, if any, associated with {arg MAINWINDOW}, and closes it.
}}

}{End SubSec Attached Prompt Windows}


{Begin SubSec Window Properties Of Attached Windows}
{Title Window Properties Of Attached Windows}
{Text

Windows that are involved in a collection either as a main window or as an attached window have properties stored on them.  The only properties that are intended to be set be set by the user are the {lisp MINSIZE} and {lisp MAXSIZE} properties.  The other properties should be considered read only.

{Def {Type (Window Property)} {Name MINSIZE}}
{Def {Type (Window Property)} {Name MAXSIZE}
{Text
Each of these window properties should be a dotted pair {lisp ({arg width} . {arg height})} or a function to apply to the window that returns a dotted pair.  The numbers are used when the main window is reshaped.  The {lisp MINSIZE} is used to determine the size of the smallest region acceptable during reshaping.  Any amount greater than the collective minimum is spread evenly among the windows until each reaches {lisp MAXSIZE}.  Any excess is given to the main window.  This algorithm may change as experience is gained.

Note:  If you give the main window of an attached window group a {lisp MINSIZE} or {lisp MAXSIZE} property, its value is moved to the {lisp MAINWINDOWMINSIZE} or {lisp MAINWINDOWMAXSIZE} property, so that the main window can be given a size function that computes the minimum or maximum size of the entire group.  Thus, if you want to change the main window's minimum or maximum size after attaching windows to it, you should change the {lisp MAINWINDOWMINSIZE} or {lisp MAINWINDOWMAXSIZE} property instead.{index MAINWINDOWMINSIZE (Window Property)}{index MAINWINDOWMAXSIZE (Window Property)}

Note:  This doesn't address the hard problem of overlapping attached windows side to side, for example if window {lisp A} was attached as [{lisp TOP}, {lisp LEFT}] and {lisp B} as [{lisp TOP}, {lisp RIGHT}].  Initially the reshape getregion won't worry about the overlap.
Default {lisp MAXSIZE} is {lisp NIL}, which will let the region grow indefinitely.
}}


{Def {Type (Window Property)} {Name MAINWINDOW}
{Text
Pointer from attached windows to the main window of the group.  This link is not available if the main window is closed.  The function {fn MAINWINDOW} is the preferred way to access this property.
}}


{Def {Type (Window Property)} {Name ATTACHEDWINDOWS}
{Text
Pointer from a window to its attached windows.  For functional access to this information, the function {fn ATTACHEDWINDOWS} is documented below.
}}


{Def {Type (Window Property)} {Name WHEREATTACHED}
{Text
For attached windows, a list whose first element is the {arg EDGE} and whose second element is the {arg POSITIONONEDGE} that determine the placement condition for this window.
}}


The {lisp TOTOPFN} property on attached windows and the properties {lisp TOTOPFN}, {lisp DOSHAPEFN}, {lisp MOVEFN}, {lisp CLOSEFN}, {lisp OPENFN}, {lisp SHRINKFN}, {lisp EXPANDFN} and {lisp CALCULATEREGIONFN} on "main" windows contain elements that implement the attached window manipulation facilities. Care should be used in modifying or replacing these properties.

}{End SubSec Window Properties Of Attached Windows}


{Begin SubSec Notes}
{Title Notes}
{Text

A window can be attached to only one other window.  Attaching a window to a second window will detach it from the first. 

Attachments can not form loops.  That is, a window cannot be attached to itself or to a window that is attached to it.  {fn ATTACHWINDOW} will generate an error if this is attempted.

Attached windows can have other windows attached to them.  Thus, it is possible to attach window A to window B when B is already attached to window C.  Similarly, if A has other windows attached to it it can still be attached to B. 

Moving the main window will maintain the relationships between windows.  

Reshaping the main window will restore the conditions established by the call to {fn ATTACHWINDOW}, moving the main window does not.  Thus, if A is attached to the top of B and then moved by the user, its new position relative to B will be maintained if B is moved.  If B is reshaped, A will be reshaped to the top of B.  Additionally, if, while A is moved away from the top of B, C is attached to the top of B,  C will position itself above where A used to be.

The attached windows can be closed by themselves.  They will be reopened whenever the mainwindow is reshaped.  The closefn for the main window breaks the links from the attached windows to it to allow them to be garbage-collected.  The reopenfn for the main window reestablishes these links.  Thus it is possible to reopen a closed, attached window and not have it linked to its mainwindow.   

}{End SubSec Notes}


{Begin SubSec Examples Of Use}
{Title Examples Of Use}
{Text

{lispcode (ATTACHWINDOW ATWIN MAINWIN 'TOP 'CENTER)}

will move {lisp ATWIN} to immediately above {lisp MAINWIN} and maintain its attachment there.

{lispcode (ATTACHWINDOW NOTHERWIN MAINWIN 'TOP 'CENTER)}

will move {lisp NOTHERWIN} to immediately above {lisp ATWIN} and maintain its attachment there.

}{End SubSec Examples Of Use}


{Begin SubSec Miscellaneous Functions}
{Title Miscellaneous Functions}
{Text

{FnDef {Name MAINWINDOW} {Args WINDOW RECURSEFLG}
{Text 
If {arg WINDOW} is not a {lisp WINDOW}, it generates an error.  If {arg WINDOW} is closed, it returns {arg WINDOW}.  If {arg WINDOW} is not attached to another window, it returns {arg WINDOW} itself.  If {arg RECURSEFLG} is {lisp NIL} and {arg WINDOW} is attached to a window, it returns that window.  If {arg RECURSEFLG} is {lisp T}, it returns the first window up the "main window" chain starting at {arg WINDOW} that is not attached to any other window.
}}

{FnDef {Name WINDOWREGION} {Args WINDOW}
{Text 
Returns the screen region occupied by {arg WINDOW} and its attached windows, if it has any.
}}

{FnDef {Name WINDOWSIZE} {Args WINDOW}
{Text
Returns the size of {arg WINDOW} (a dotted pair of width and height)  and its attached windows, if it has any.
}}

{FnDef {Name MINATTACHEDWINDOWEXTENT} {Args WINDOW}
{Text 
Returns the minimum extent (a dotted pair of width and height) of {arg WINDOW} and its attached windows (if any) will accept.
}}

{FnDef {Name ATTACHEDWINDOWS} {Args MAINWINDOW}
{Text 
Returns the list of windows attached to {arg MAINWINDOW}.
}}

{FnDef {Name ALLATTACHEDWINDOWS} {Args MAINWINDOW}
{Text 
Returns a list of all of the windows attached to {arg MAINWINDOW} or attached to a window attached to it.
}}


{FnDef {Name DETACHALLWINDOWS} {Args MAINWINDOW}
{Text 
Detaches and closes all windows attached to {arg MAINWINDOW}.
}}



}{End SubSec Miscellaneous Functions}

}{End SubSec Attached Window Facility}