-*-text-*-  $Id: redraw-protocol,v 1.1 91/08/22 15:40:25 gnb Exp $

This file describes the redraw logic for the Plotter widget set Version 5
-------------------------------------------------------------------------

Some terms to help clarify things:
----------------------------------

Object) Any object that is a subclass of Object.  XtSetValues operates
	on objects.
Widget) Any object that is a subclass of Core and thus has a window.
Graph) The entire display of a Plotter widget.  Includes the widget
	and all children.
Plot) A single data object plotted on a graph.  One subclassed AtPlot
	object per plot, multiple plots per graph.
Refresh) Simply redraw one plot on the graph.  No screen clear or
	redraw of other child objects required.
Redraw) Simply refresh the onscreen image of the whole plotter widget.
	no calculation required.  No screen clear done explicitly (but
	often happens before redraw routine is called).
Relayout) The pixel dimentions of the plot have changed, but not the
	data.  Cause by resizing widget, adding or removing titles,
	etc.
Rescale) The data has changed and the existing axis bounds are not
	sufficient.  New axis bounds are required, but no layout has
	changed and all axes are in the same spot.  Is concerned with
	min/max of axis values, tic values and intervals etc.
Recompute) Either pixel location or data has changed for a plot, and
	the cached pixel values need to be recalculated.

A rescale implies a redraw, and a relayout implies a redraw, but
relayout and rescale are orthogonal (i.e. one doesn't necessarily
imply the other, although either rescale or relayout imply a recalc).

A description of the Xt behaviour:
----------------------------------

In the Xt toolkit, redisplay is forced by the set_values or
constraint.set_values widget class routines, which are called by the
XtSetVaues() routine.  When any of the set_values routines (either
normal or constraint or the older set_values_hook, for the widget
class or any superclasses) returns True, Xt clears the widget window
to the background color with a call to XClearArea.  This call results
in an expose event being put into the event queue.  Eventually, the
expose event comes to the head of the queue and the toolkit calls the
widget redraw routine.

If several XtSetValues calls (that return TRUE from a set_values
routine) are made in succession before returning to the main event
loop, several XClearWindow() calls will be made and several exposure
events will happen.  In the normal run of things, all but the first of
these will do nothing interesting.

If the object in question (i.e. the object having the XtSetValues done
in it) is not a widget (i.e. is a subclass of Object but not Widget
and doesn't have any window), then the toolkit obviously cannot do an
XClearArea.  What happens then is that if the Object is a subclass of
RectObj, XtSetValues looks up the widget hierarchy until it finds an
ancestor of the object that _is_ a widget, and then clears the area of
the ancestor widget's window that corresponds to the rectangle layout.
This means that for non-widget RectObjs, the widget parent (or
ancestor) will get the expose event.  If the object is not a rectObj,
then the return value from the set_values routines are ignored.  Hence
Objects should not return True from a set_values routine, and
constraint widgets should not return True from constraint.set_values
routines called on behalf of a non-RectObj child.

Goals:
------

Children never draw anything themselves.  They request redraws from
the parent.

The parent attempts, as much as possible, to batch the redraw operations.

Avoid the use of XtSetValues unless necessary.  Will require the
addition of some "member functions".  Avoid the axis-to-plotter
callbacks (Ugly!); use member functions.

Split requests for a rescaling from requests for a relayout.  

Have a callback list for rescale and relayout these so that
applications can co-ordinate the position, scaling etc between
multiple instances of the Plotter widget. 

Plot and axis objects can clearly request different levels of rescale,
relayout or redraw, and can distinuish between recale and relayout
requests.

Plotter handles child requests intelligently, with the least possible
amount of redrawing.

Child objects should cache their pixel coordinate data in a way that
allows rapid redraw by using e.g. XDrawLines() with minimal or no
calculation.  the parent plotter will call the object compute routine
to update these stored values.

Slightly More Detailed Design:
------------------------------

ALL drawing to be done as part of the redraw routine, called ONLY by
the Intrinsics on expose events.  No exceptions.

Object set_values routines always returns false.

Plotter constraint.set_value routine always returns false.

Plotter tries to ensure only one outstanding expose event by returning
false from the set_values routine most of the time. (This will require
state in the widget instance record).  To avoid massive redraws on
simple requests, is will be necessary to forge a null expose event
using SendEvent when a call to the redraw routine is required but
clearing the display is not.  (Again, state is required to determine
if such a synthetic event has taken place.)  If a synthetic event has
ben sent and a screen clear is later required, remember the fact and
do an XClearWindow at the start of the redraw routine.

The plotter receives requests from the children and stores enough
local state so that when the redraw routine is eventually called the
required action can take place.  Does no drawing when the requests are
made.  Requests a redraw with a synthetic or real expose as
appropriate.

The redraw routine should look for the most drastic redraw that is
required and do that, forgetting the requests of any less drastic
actions that will be done in the process.  If there are no pending
requests it is an expose and a simple redraw of the entire widget is
in order, clipped by the supplied region. Before returning, should
erase all stored requests (after ensuring they have been satisfied!)

The axis is responsible for all user-space to pixel-space conversions,
as well as specifing endpoints or bounds to the plot.  The parent
plotter widget is responsible for deciding the layout of the graph,
taking into account the size of the components.  The parent also
coordinates all the layour, scaling, calculation and drawing for the
whole graph.

State required:

plotter: 
	rescale required (i.e. axis bounds changed)
	relayout required (i.e. element sizes changed)
	synthetic expose sent
	real expose sent
	current overall bbox (x/x2/y/y2)

Constrains (held on behalf of the child):

	A list of (from, to) pairs awaiting recalc/redraw.
	refresh required (i.e. draw me again but don't need to redraw
			  the whole graph)
	recalc required (i.e. data has changed, and needs to be
			  rescaled to pixel corrdinates once the
			  appropriate scaling factor has been
			  determined. This is indicated by having a
			  non-zero list of (from, to) pairs).
	bbox

Plotter routines the child can call: (Many of these functions are
currently done through XtSetvalues - a long way around; some are done
via calls direct to the axis objects - this has confused redraw semantics.)
All take AtPlotWidget arguiments, even though some of them affect the
parent plotter widget.  This is so the parent can consider the
displayed constraint resource before deciding on the action.  Axis
code has to cast to the appropriate type....

AtPlotterPlotExtended(AtPlotWidget, BoundingBox *, int from, int to) 

	Data had been added to the plot, but existing data hasn't
	changed, and here is the bounding box of the new data.  The
	changed data is located from "from" to "to".  These numbers
	are uninterpreted except that they are passed back to the
	recalc plot instance routine.  It is expected that "to" <
	"from" indicates the entire graph to this routine. The parent
	will merge the bounding box with the stored bounding box for
	the remainder of the plot.  Depending on the other plots on
	the graph, the overall boundingbox may change.  If not, a
	simple refresh of the plot in question would suffice.
	Otherwise, a rescale and redraw will be needed.  Useful for
	incrementally updating plots (which the current XYPlot won't
	do).  It is assumed that the recalc for the extended data
	will be done by the parent before the redraw is done.

AtPlotterPlotDataChanged(AtPlotWidget, BoundingBox *, Boolean)

	The existing data has been changed and this is the new
	boundingbox.  If the overall boundingbox is still OK, then a
	redraw is required, else a rescale followed by a redraw is
	required.  It is assumed a recalc for the whole of the data of
	this plot will be performed for this widget before the redraw.
	If the supplied boolean is true, then the child is operating
	in the fast_update mode and, if no global rescale is required,
	a refresh of just this plot can both erase the old plot and
	draw the new one. This obviates the need for a complete
	redraw. [Not properly tested yet].

AtPlotterRefreshRequired(AtPlotWidget)

	Something that can easily be fixed with a refresh has occured
	(e.g. changed foreground color). It is up to the child to
	determine whether this is enough (e.g.  for an axis, if the
	grid color changes, then a redraw is probably needed.)

AtPlotterRedrawRequired(AtPlotWidget)
	
	Something that cannot be fixed by refresh has changed (e.g.
	background color). Again, up to the child to decide.  NB The
	child is passed so that the redraw can be suppressed for
	children that are not displayed!

AtPlotterLayoutRequired(AtPlotWidget) 

	The widths of an axis object changed and a relayout is needed.
	probably wouldn't be generated from plot objects.  Would be called
	from the axis SetValues routine, for instance.

AtPlotterRescaleRequired(AtPlotWidget)

	An axis object has had the scale changed (and it was not
	autoscaling).  Will need to rescale followed by redraw.

AtPlotterRecalcThisPlot(AtPlotWidget)

	Something involved in the user-to-pixel transformations has
	changed, but the bounding boxes and layout haven't.  Usually
	called by axis objects rather than plot objects.

----------------------------------------------------------------

What the Plot callback routines do:
-----------------------------------

This is a description of what each of the callback routines that are
part of the plot object class are supposed to do.

draw(Display *, Window, AtPlotWidget, Region, Boolean refresh)
	 Display the screen image of the plot clipped by the passed
	 region.  The scaling for the plot has been done with a
	 recalc call. The boolean is true if this is called as a
	 refresh for this plot only, false if it is part of a full
	 redraw.  The fast_update code can use this to decide whether
	 to un-draw the old data.

draw_icon(Display *, Window, AtPlotWidget, int x, int y, int w, int h)
	Draw a little box ("icon") of what the plot element looks like
	for inclusion in the legend.  At position x, y size w, h.

draw_ps(FILE *, AtPlotWidget, AtAxis x, AtAxis y)
	the passed axis elements have been scaled according to the
	desired postscript scale, roatation etc.  Use them to output a
	postscript version of the plot to the passed file.  Should NOT
	affect the internal pixels calulated with the recalc call.

draw_icon_ps(FILE *, AtPlotWidget, int x, int y, int w, int h)
	Dump the postscript for the graph legend to the named file.
	Should fix within the postscript coords specified.

recalc(AtPlotWidget, AtScale x, AtScale y, int from, int to)
	Recalculate the pixel coordinates of the plot data according
	to the given scale axes.  Plot children should maintain a set
	of pixel coordinates that can be plotted efficiently in the
	draw display (e.g. a list of XPoints for an XDrawLines() call).
	This is the only time a widget should change these stored
	pixel values.  The from and to parameters are those passed into
	the AtPlotterPlotExtended routine, or "to" < 0 to indicate
	scale the entire graph.

(The existing system has both rescale and resize calls; they both do
exactly the same thing in all the plot objects currently written.
Also, the original version passes the Axis objects to the draw
routine. They were simply used in a call to the rescale routine if
needed. Now,  they should be ignored and the cached lists used.  The
from and to parameters are a new feature, and allows dynamically
growing graphs with little effort.)

----------------------------------------------------------------

Communicating between Axis objects and the Plotter
--------------------------------------------------

Previously, the Axis and Plotter objects were heavily intertwined, and
policy for scaling and redrawing was diffused throughout both.  That
has changed, with Axis objects being make much more independant.  The
parent plotter no longer has access to the axis widget record.  Axes
will communicate with the parent using exactly the same calls that the
plot children use.  Applications should _NOT_ call the Axis routines
directly but make requests to the plotter via the routines specified
for the callbacks above.

Again, the axis should create a (set of) display lists so the redraw
routine is as fast as possible.

The axis classes are subclasses of AtPlot, and hence use the AtPlot member
functions draw and recalc.  There are no icons for axes, so the icon
functions are NULL.  The draw_ps routine cannot be a member function
due to an extra argument being needed.

The plotter makes requests of Axis objects using the following routines:

int AtAxisWidth(AtAxisObject)

	Returns the width, in pixels, of the portion of the axis that
	is "outside" the plot area.  Should handle mirror, vertical
	etc.

AtAxisSetPosition(AtAxisObject, inx x1, int y1, int x2, int y2, int grid_len)

	The pixel locations of the axis are as specified.  Use them
	(and the previously set bounds) The grid_len parameter is
	added so the axis can draw the grid of the correct size.
	The details are remembers, and the recalc routine will be
	called to actually do the real-pixel conversions.

AtAxisAskRange(AtAxisObject, double min, double max)

	The parent plotter accumulates the min and max for this axis
	from the plot objects, then calls this routine. It should
	apply the auto scaling heuristics to set the min and max
	values of the axis, which will be accepted by the parent. Will
	be followed by a call to the recalc member function to
	calculate the pixel values, but should do enough so that the
	AtAxisWidth routine will return sensible values (close but not
	necessarily exact) after this call is made.

AtAxisGetBounds(AtAxisobject, double *minp, double *maxp)

	Return the minimum and maximum in the pointed-to variables.
	This is used to retrieve the bounds after the Setbounds
	routine to calculate the position of the floating x and y
	axes.

AtAxisGetScale(AtAxisObject)

	Returns the scale associated with this axis.  USed to pass
	scales to the child plot objects.

AtAxisGetTransform(AtAxisObject)

	Returns the transform associated with this axis, used to
	construct a set of AtScale objects to plot the postscript
	graph.
 
AtAxisWidthPS()
AtAxisDrawPS()

	Analogous to the screen cases for Postscript generation.
	The draw_ps routine cannot be an AtPlot member routine as an
	extra AtScale parameter needs to be passed.

