Zones
*****

Zone Basics
===========

Epoch supports the notion of zones (a.k.a. buttons), which are regions that are displayed in different styles.  Two new data types are used for this: zone and style.

zone
     Each zone has the following characteristics:

     start
          The start of the zone.  A marker.

     end
          The end of the zone.  A marker.  The zone covers all characters between START and END.

     style
          Style to be used for displaying the text of the zone.

     read-only
          If set to non-nil, the text of the zone cannot be directly edited.  Attempts to insert or delete any character in the zone will generate an error. (see Read-only Zones)

     data
          Not used internally.  This field can be any Elisp object, and is provided for the programmer to use to attach data to a zone for later retrieval.

     transient
          Flag to indicate zone should be ignored by undo operations.

style
     A style is an object that describes how to display characters. It has the following fields:

     foreground
          The text foreground color.

     background
          The text background color.

     cursor-foreground
          The character foreground color when the text cursor is on the character.

     cursor-background
          The character background color when the text cursor is on the character.

     font
          The font to be used for displaying the text in this style.

     stipple
          The stipple pattern to use for the text.

     cursor-stipple
          The stipple to use when the cursor is on the text.

     background-stipple
          The stipple to use for the background.  Bits that are set in the stipple are displayed in the screen background color.  Cleared bits are displayed in the style background color.

     underline
          The color to use for underlining.  If not set, no underlining is done.

     tag
          Not used internally.  This can be any Elisp object.

Zones were intended as a way of providing ``hotbutton'' capabilities in hypertext-like applications using Epoch as a front-end.  In these cases the data field will hold information for the hotbutton.  Zones can also be used for many other applications, of course.

Each zone is attached to a buffer.  All buffer arguments in the Epoch primitives default to the current buffer.  Arguments of type zone must be zone objects.  A package has been written to store zone information with buffers when they are written to files and then restore zones when the buffer is visisted (see Saving Zones).

Note: To maintain compatibility with older Elisp packages, you may do a (require 'button) to get "button" wrapper functions for the zone primitives.  Old Elisp code may be converted to require zones by using the file convert-buttons.el.

Functions exist to access and change a zone's start and end positions or even the zone's buffer while maintaining the correct position in the zone list.  Note: Elisp code that alters zones by changing the vectors directly will not work correctly.

Zone Primitives
===============

 -- Function: epoch::make-zone
     Used to create a new zone.  Returns a zone pointing nowhere, in no buffer.

 -- Function: epoch::zonep object
     Returns t if object is a zone, otherwise nil

 -- Function: epoch::zone-buffer zone
     Returns the buffer a zone is currently in, or nil.

 -- Function: epoch::zone-start zone
     Returns the zone's STARTING position as an integer.

 -- Function: epoch::zone-end zone
     Returns the zone's END position as an integer.

 -- Function: epoch::move-zone zone &optional start end buffer
     Moves the specified zone to a new position indicated by START and END in BUFFER.  If either START or END is nil, it will remain unchanged.  The zone start and end will be swapped, if necessary, so that the start comes before the end.  Moving zones will cause the respective buffer(s) to redisplay, but will not mark the buffer as modified unless epoch::zones-modify-buffer is t.  Returns the updated zone.

     START and END may be markers, but only the marker position is used.

 -- Function: epoch::add-zone start end attribute &optional data buffer
     Add a zone to BUFFER. START and END must be markers or integers.  ATTRIBUTE is a number. DATA is programmer defined and is not used internally, so it can be anything.  Returns the new zone, or nil on failure.

 -- Function: epoch::zone-at &optional position buffer
     Returns the zone in BUFFER that contains POSITION, or nil.  If POSITION is nil, point is used.

 -- Function: epoch::zones-at &optional position buffer
     Returns a list of zones in BUFFER that contain POSITION, or nil.  If POSITION is nil, point is used.  The zones are ordered by starting position.

 -- Function: epoch::zones start end &optional partial transient buffer
     Returns a list of zones in BUFFER that are contained in the region defined by START and END.  The optional parameter PARTIAL determines if partially-contained zones are included in the list; it defaults to nil.  The optional parameter TRANSIENT is set to t if zones with the transient field are included in the list; it defaults to nil|.  The buffer may be specified, or the current buffer will be used.

 -- Function: epoch::zone-list &optional buffer
     Returns the list of zones for BUFFER. The list contains the actual zones, not copies.  The zones are ordered by starting position.

 -- Function: epoch::zone-style zone
     Returns ZONE's current STYLE value.

 -- Function: epoch::set-zone-style zone value
     Sets ZONE's STYLE to VALUE.

 -- Function: epoch::zone-data zone
     Returns ZONE's current DATA value.

 -- Function: epoch::set-zone-data zone value
     Sets ZONE's DATA to VALUE.

 -- Function: epoch::zone-transient-p zone
     Returns t if ZONE has its transient flag set; else nil.

 -- Function: epoch::set-zone-transient zone flag
     Sets the zone's TRANSIENT to FLAG.  This is useful if the zone should be ignored by undo operations.

 -- Function: zone-text &optional zone
     Returns a string that is the text contained in ZONE.  If ZONE is omitted, the zone-at point is used, if any. Returns the empty string for an empty zone or no zone.

 -- Variable: epoch::zones-modify-buffer
     If non-nil, changing any zones with Epoch primitives will cause the associated buffer to be marked as changed.  Useful if you want to use write-file-hooks that save zone information.

Deleting Zones
==============

 -- Function: epoch::delete-zone zone
     Removes ZONE from the buffer in which it resides.  The argument must be the actual zone itself, not a copy.  This can be obtained by saving the result from epoch::make-zone or other zone-returning primitives.  Returns the zone if successful, nil otherwise.

 -- Function: epoch::delete-zone-at position &optional buffer
     Removes the zone (if any) that contains POSITION in BUFFER. Returns the zone if successful, nil otherwise.  This is equivalent to (epoch::delete-zone (epoch::zone-at position buffer) buffer).

 -- Function: epoch::clear-zones &optional buffer
     Removes all zones from BUFFER.  Returns t if succesful, nil otherwise.

Style Primitives
================

Epoch supports a completely style-based display wherein styles describe the context for displaying normal text, text within zones, text cursors, and modelines.  Each style has a number of different fields.

Foreground and background colors control how normal characters are displayed in the style.

Cursor foreground and background indicate how a character within the text cursor is displayed.  If cursor colors are not set but text colors are, the cursor will use the inverse of the text colors.

The underline color controls how the characters are underlined.  If set to a color, a line of that color is drawn under characters using that style.  If set to nil, no line is drawn.

A stipple pattern must be a X-bitmap resource (see X Objects).  For text, the ``on'' bits in the stipple are displayed in the text foreground color and the ``off'' bits in the text background color.  The character background is either solid background color, or the ``on'' bits are displayed in the screen background color and the ``off'' bits in the text background.  For the cursor, the cursor colors are used, and the cursor stipple (if any) is used in place of the background stipple for the cursor background.  If the cursor stipple is not set and the background stipple is, the cursor background is not stippled.

When displaying text within a given buffer, a hierarchy of styles exists for determining display attributes:

 1. Zone styles

 2. Buffer-local styles

 3. Screen based styles

Note: Screen based styles are changed via primitives such as epoch::foreground epoch::background, epoch::cursor-color, epoch::font.  All style fields are guaranteed to be valid at the screen level.

 -- Function: epoch::make-style
     Creates a style object.  Initially all fields are set to nil.

 -- Function: epoch::stylep object
     Returns t if OBJECT is a style, else nil.

 -- Function: epoch::style-foreground style
     Returns the foreground color of STYLE.

 -- Function: epoch::set-style-foreground style color
     Sets STYLE to foreground COLOR.

 -- Function: epoch::style-background style
     Returns the background color of STYLE.

 -- Function: epoch::set-style-background style color
     Sets STYLE to background COLOR.

 -- Function: epoch::style-cursor-foreground style
     Returns the cursor foreground color of STYLE.

 -- Function: epoch::set-style-cursor-foreground style color
     Sets STYLE to cursor foreground COLOR.

 -- Function: epoch::style-cursor-background style
     Returns the background cursor color of STYLE.

 -- Function: epoch::set-style-cursor-background style color
     Sets STYLE to cursor background COLOR.

 -- Function: epoch::style-underline style
     Returns the underline color.

 -- Function: epoch::set-style-underline style color
     Sets STYLE underline to COLOR.

 -- Function: epoch::style-stipple style
     Returns the text stipple for the STYLE.

 -- Function: epoch::set-style-stipple style stipple
     Sets the text stipple pattern for STYLE to STIPPLE.

 -- Function: epoch::style-background-stipple style
     Returns the background stipple for STYLE.

 -- Function: epoch::set-style-background-stipple style stipple
     Sets the background stipple pattern for STYLE to STIPPLE.

 -- Function: epoch::style-cursor-stipple style
     Returns the stipple pattern for the cursor for STYLE.

 -- Function: epoch::set-style-cursor-stipple style stipple
     Sets the cursor stipple pattern for STYLE to STIPPLE.

 -- Function: epoch::style-font style
     Returns the font associated with STYLE, or nil if none is specified.

 -- Function: epoch::set-style-font style font
     Sets the font for STYLE to be FONT.

 -- Function: epoch::style-tag style
     Returns the tag value associated with STYLE, or nil if none is specified.

 -- Function: epoch::set-style-tag style tag
     Sets the tag value associated with STYLE to TAG.

 -- Variable: motion::style
     This style, which defaults to underlining in the foreground color, is the style used by Epoch mouse dragging code found in motion.el. Its value is set at runtime, and may be superceded by values in the file .emacs.

The following code is used to set up the default style for mouse dragging, and demonstrates the use of Epoch and style primitives.

     (setq motion::style (make-style))
     (set-style-foreground motion::style (foreground))
     (set-style-background motion::style (background))
     (set-style-underline motion::style (foreground))

 -- Variable: buffer-style
     This variable is set to the style used by Epoch to display text in this buffer.  It defaults to nil, and becomes local when set in any fashion.

The variable BUFFER-STYLE may also be set using the local variables list in files.  The following code would specify a major mode of tex-mode and a buffer style of tex-mode-style (which could select a proportional font):

In .emacs:

     (setq tex-mode-style
       (let ((s (make-style)))
         (set-style-font s "variable")
       )
     )

In TeX file:

     #;;; Local Variables: ***
     #;;; mode: tex ***
     #;;; buffer-style: tex-mode-style ***
     #;;; End: ***

Modelines
=========

It is also possible to embed styles into the variables that define the modeline format.  For details on modeline constructs, see section 20.3 of the Emacs Lisp Reference Manual.  Note that modelines being displayed with styles will override the value of mode-line-inverse-video.

 -- Variable: mode-line-inverse-video
     If this variable is non-nil, the modeline will be displayed in inverse video or another suitable display mode.

 -- Variable: default-mode-line-format
     This variable holds the default MODE-LINE-FORMAT for buffers that do not override it.  This is the same as (default-value 'mode-line-format).

 -- Variable: mode-line-format
     The value of this variable is a modeline construct responsible for the mode line format.  This variable is buffer-local.

The following is an example of Elisp code to embed styles in mode lines.

     ;; Hilight "Epoch" and buffer name in current buffer's modeline.
     ;; s1 -> hilight style
     (setq s1 (make-style))
     (set-style-foreground s1 "red")
     (set-style-background s1 "white")
     (set-style-font s1 "fixed")

     ;; s2 -> normal style
     (setq s2 (make-style))
     (set-style-foreground s2 "black")
     (set-style-background s2 "white")
     (set-style-font s2 "variable")

     ;; define modeline format
     (setq mode-line-format
       (list
         s2 "" mode-line-modified
         s1 mode-line-buffer-identification s2
         "   " global-mode-string "   %[(" mode-name minor-mode-alist
         "%n" mode-line-process ")%]----" (cons -3 "%p") "-%-"
     ))

Zone Plotting
=============

When a buffer is plotted, zones are extracted from the buffer zone list and used to change the colors of the text and cursor.  If the zones are disjoint, then the choice of a zone to use for a given character is unambiguous.  Overlapping zones cause a more complex situation.  The algorithm for deciding which style are used when zones overlap is described next.

The zone plotting algorithm assumes that the zone list is sorted by starting position.  If zones overlap, the zone with the largest starting position takes precedence.  This allows zones to nest, so that if one zone is entirely inside another, both zones are visible.  If two zones overlap without containment, the second zone will be entirely visible, and the first truncated.  Whenever there is a reference to the zone ``at'' a location, that means the zone that was plotted at that location.

A zone with a non-null style always has precedence over a zone with null style.  This means that if a zone with an null style follows and overlaps a zone of non-null style, the preceeding zone will be plotted in the overlap region.  Null styles are intended for hidden or non-user zones (such as for tagging a region of text with data), and this rule prevents them from interfering with visible zones.

Read-only Zones
===============

In the case of a read-only zone (in which the READ-ONLY field is t), most attempts to change text within the zone will result in an error analogous to the error caused by attempting to change a read-only buffer.  Two exceptions to this rule exist at zone boundaries.

 1. Attempted changes on the first character of the zone will be allowed, but will be diverted to the left of the zone itself so that the zone is not extended.

 2. Attempted changes to the immediate right of the zone will be permitted, but the zone will not be extended.  This is really a change outside of the zone.

Essentially, this implies that the size of a read-only zone will only change because of explicit commands to change the zone boundaries and not by inserting or deleting text within the zone.  Changing the location of a read-only zone by altering text previous to the zone is permitted; this is even possible with adjoining read-only zones (unless they explicitly overlap).

 -- Function: add-read-only-zone start end attribute &optional data buffer
     This is the same as epoch::add-zone except that the zone is set to be read-only immediately after being created.

 -- Function: epoch::read-only-region-p start end &optional buffer
     Given a region delimited by START and END in BUFFER, checks for read-only zones.  Returns nil if region contains no read-only zones; otherwise it returns the zone.  In cases of overlapping zones, the display rule discussed earlier is obeyed (see Zone Plotting).

     Note: When checking for insert operation, use the insertion point for both START and END.  If this would normally be inside the zone, but because of insertion rules is deflected to the side of the zone, this function will not return the zone.

 -- Function: epoch::zone-read-only zone
     Returns ZONE's current READ-ONLY value.

 -- Function: epoch::set-zone-read-only zone flag
     Sets the zone's READ-ONLY flag to FLAG, which must be either t or nil.

Graphical Zones
===============

Epoch now supports displaying graphical images (X pixmaps) in zones. This requires the Groupe Bull's XPM version 3 library, which is on the X11R5 contrib tape.  The library is also available via anonymous ftp from export.lcs.mit.edu (18.24.0.12) and avahi.inria.fr (192.5.60.47).  To enable graphical zones, you must compile Epoch with HAVE_GRAPHIC_ZONES enabled in config.h.

Note: You may need to edit button.c to include xpm.h appropriately.

Once Epoch has been built in this manner, several new Elisp primitives become available:

 -- Function: add-graphic-zone pixmap-name start end &optional offset data buffer read-only
     Adds a graphical zone corresponding to a pixmap named PIXMAP-NAME from START to END in BUFFER (or current buffer if BUFFER is nil).  Zone will have data value DATA and will be read-only if READ-ONLY is non-nil.  OFFSET describes the percentage of the graphical image which will appear below the baseline; 0 (default) corresponds to an image totally above the baseline, 100 corresponds to totally below.  PIXMAP-NAME can also be an X Resource of type pixmap.  Returns the zone if successful.

 -- Function: epoch::define-opaque-font name width height &optional offset
     Defines a psuedo-font for displaying graphical images.  Font NAME will have width WIDTH and height HEIGHT.  As above, OFFSET describes the percentage of the font which will appear below the baseline.  Returns the NAME, or nil.

 -- Function: epoch::read-pixmap-file filename
     Using the Xpm library, reads in FILENAME and create an X pixmap corresponding to it.  Return an X Resource of type Pixmap if successful, otherwise nil.  FILENAME must correspond to the complete filename (including extensions) of a text file in the X Pixmap Format, or else an X Resource of type Pixmap.

 -- Function: epoch::query-pixmap pixmap
     Returns a list of the form (width height depth) corresponding to an X pixmap.  PIXMAP should be an X Resource of type Pixmap.

 -- Function: epoch::set-style-pixmap style pixmap
     Sets style STYLE to reference PIXMAP. PIXMAP should be an X Resource of type Pixmap, or nil.

 -- Function: epoch::style-pixmap style
     Returns the pixmap associated with STYLE.

Note: If a buffer containing a graphical zone is being displayed in a window which is too small to display the entire graphical image, in most cases no text will be displayed in the window.

Zones and Undo
==============

It is possible for undo operations to restore affected zones to their previous positions.  This is primarily noticeable for undoing delete operations.  This feature is enabled by default, but may be disabled by setting the buffer-local variable undo-restore-zones.  Any zones with the TRANSIENT field set to t will be ignored.

 -- Variable: undo-restore-zones t
     If set to non-nil, then zone information will be stored with all delete operations so that undo may restore the zones to their previous positions.  This variable becomes buffer-local when set in any fashion.