text: /* DBWhighlights.c -
   *
   *	This file contains routines that allow the highlight plane
   *	to be used to display additional things besides the box.
   *	The routines coordinate all the clients that have highlights
   *	to display so that when one of them updates its highlights
   *	it doesn't trash the others' highlights.
   *
   *     *********************************************************************
   *     * Copyright (C) 1985, 1990 Regents of the University of California. *
   *     * Permission to use, copy, modify, and distribute this              *
   *     * software and its documentation for any purpose and without        *
   *     * fee is hereby granted, provided that the above copyright          *
   *     * notice appear in all copies.  The University of California        *
   *     * makes no representations about the suitability of this            *
   *     * software for any purpose.  It is provided "as is" without         *
   *     * express or implied warranty.  Export of this software outside     *
   *     * of the United States of America may require an export license.    *
   *     *********************************************************************
   */
  
  #ifndef lint
  static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWhlights.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
  #endif  /* not lint */
  
  #include <stdio.h>
  
  #include "utils/magic.h"
  #include "utils/geometry.h"
  #include "utils/styles.h"
  #include "tiles/tile.h"
  #include "utils/hash.h"
  #include "database/database.h"
  #include "windows/windows.h"
  #include "graphics/graphics.h"
  #include "dbwind/dbwind.h"
  #include "textio/textio.h"
  #include "graphics/graphicsInt.h"
  
  #define WINDOW_DEF(w)	(((CellUse *)(w->w_surfaceID))->cu_def)
  
  /* The array below is used to hold the addresses of redisplay
   * procedures for each of the highlight clients.  Whenever
   * highlights must be redisplayed, each highlight client
   * is invoked for each database window.
   */
  
  #define MAXCLIENTS 10
  static int (*(dbwhlClients[MAXCLIENTS]))();
  
  /*
   * ----------------------------------------------------------------------------
   *
   * DBWHLAddClient --
   *
   * 	This procedure is used to add another client to those
   *	that are displaying highlights.  The redisplay procedure
   *	passed in by the client will be invoked in the following
   *	way:
   *		int
   *		redisplayProc(window, plane)
   *		    MagWindow *window;
   *		    Plane *plane;
   *		{
   *		}
   *	The procedure is invoked once for each window that contains
   *	database information (and potentially has highlights).  The
   *	window has been locked via GrLock() before the proc is called,
   *	and the clipping area has already been set up.  The procedure
   *	is given a pointer to the window, and a pointer to a plane.
   *	The plane contains non-space tiles over all areas where highlight
   *	information needs to be redrawn (all of these areas have had
   *	their highlight information erased).  The client should redraw
   *	any of its highlights that touch any non-space areas.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	The client is added to our list of clients.
   *
   * ----------------------------------------------------------------------------
   */
  
  void
  DBWHLAddClient(redisplayProc)
      int (*redisplayProc)();	/* Procedure to call during redisplays. */
  {
      int i;
      for (i = 0; i < MAXCLIENTS; i++)
      {
  	if (dbwhlClients[i] == NULL)
  	{
  	    dbwhlClients[i] = redisplayProc;
  	    return;
  	}
      }
      TxError("Magic error:  ran out of space in highlight client table.\n");
      TxError("Tell your system maintainer to enlarge the table.\n");
  }
  
  /*
   * ----------------------------------------------------------------------------
   *
   * DBWHLRemoveClient --
   *
   * 	This just removes a client from the list of those that we
   *	know about.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	The given redisplay procedure will no longer be invoked
   *	during redisplays.
   *
   * ----------------------------------------------------------------------------
   */
  
  void
  DBWHLRemoveClient(redisplayProc)
      int (*redisplayProc)();		/* A redisplay procedure.  This
  					 * procedure must previously have been
  					 * passed in to DBWHLAddClient.
  					 */
  {
      int i;
      for (i = 0; i < MAXCLIENTS; i += 1)
      {
  	if (dbwhlClients[i] == redisplayProc)
  	{
  	    dbwhlClients[i] = NULL;
  	    return;
  	}
      }
      ASSERT(FALSE, "DBWHLRemoveClient");
  }
  
  /*
   * ----------------------------------------------------------------------------
   *
   * DBWHLRedraw --
   *
   * 	This procedure is invoked to redisplay highlights.  The
   *	clients that manage highlights are free to draw on the screen
   *	at will.  But if a client ever erases highlight information, it
   *	must call this procedure so that the other clients can redraw
   *	any of their highlights that might have been erased.  This
   *	procedure records what has changed.  The information isn't actually
   *	redrawn until the next time WindUpdate is called.  This is done
   *	to avoid repeated redraws when several pieces of highlights change
   *	in the same area at the same time.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Information is recorded so that specified area will have its
   *	highlight information erased and redrawn the next time that
   *	WindUpdate is called.
   *
   * ----------------------------------------------------------------------------
   */
  
  void
  DBWHLRedraw(rootDef, area, erase)
      CellDef *rootDef;		/* Highlight information will be redrawn in
  				 * all windows for which this is the root
  				 * cell definition.
  				 */
      Rect *area;			/* The area over which to redraw.  Highlights
  				 * will be redrawn in this area plus enough
  				 * surrounding area to catch degenerate boxes
  				 * (drawn as crosses) and labels that may
  				 * stick out from their attachment points.
  				 */
      bool erase;			/* TRUE means we should erase are before
  				 * redrawing it.  FALSE means that either the
  				 * client has erased the area, or there's no
  				 * need to erase it because all that's
  				 * happening is to add new information to the
  				 * display.
  				 */
  {
      extern CellDef *dbwhlDef;
      extern bool dbwhlErase;
      extern int dbwhlRedrawFunc();
      Rect ourArea;
  
      dbwhlDef = rootDef;		/* Must pass to search function. */
      dbwhlErase = erase;
  
      /* If we're passed a NULL area, expand it by one unit in both
       * directions so that we're certain to have non-zero area.
       * Otherwise the various search procedures have big troubles.
       */
  
      ourArea = *area;
      if (ourArea.r_xbot >= ourArea.r_xtop)
      {
  	ourArea.r_xtop = ourArea.r_xbot + 1;
  	ourArea.r_xbot--;
      }
      if (ourArea.r_ybot >= ourArea.r_ytop)
      {
  	ourArea.r_ytop = ourArea.r_ybot + 1;
  	ourArea.r_ybot--;
      }
      (void) WindSearch(DBWclientID, (ClientData) NULL, &ourArea,
  	dbwhlRedrawFunc, (ClientData) &ourArea);
  }
  
  CellDef *dbwhlDef;
  bool dbwhlErase;
  
  /* This procedure records the area to be erased (if any) and the
   * area to be redisplayed (which is larger than the area to be
   * erased).
   */
  
  int
  dbwhlRedrawFunc(window, area)
      MagWindow *window;		/* Window to redraw. */
      Rect *area;			/* Passed as client data. */
  {
      Rect erase, expand, redraw;
      DBWclientRec *crec = (DBWclientRec *) window->w_clientData;
  
      if (WINDOW_DEF(window) != dbwhlDef) return 0;
  
      /* The area that we erase must be large enough to include material
       * that sticks out from the area of the highlights.  There are two
       * ways that material sticks out:  (a) zero-size boxes are drawn as
       * crosses, and the crosses stick outside of the box's area;  (b)
       * labels are attached to points or rectangles, but the text usually
       * extends far beyond the attachment point.
       */
  
      WindSurfaceToScreen(window, area, &erase);
      expand = GrCrossRect;
      (void) GeoInclude(&crec->dbw_expandAmounts, &expand);
  
      if (dbwhlErase)
      {
  	bool needErase = TRUE;
  
  	erase.r_xbot += expand.r_xbot;
  	erase.r_ybot += expand.r_ybot;
  	erase.r_xtop += expand.r_xtop;
  	erase.r_ytop += expand.r_ytop;
  
  	/* On some displays (e.g. black-and-white ones), highlights use
  	 * the same color planes as other information.  If this is the
  	 * case, redisplay everything (this will redisplay highlights too,
  	 * so there's nothing additional to do here).
  	 *
  	 * This is also the case if we use backing store but the backing
  	 * store has been removed due to becoming invalid, such as when
  	 * an attempt is made to redraw into an obscured or unmapped
  	 * window.
  	 */
  
  	if (((GrGetBackingStorePtr == NULL) &&
  		((GrStyleTable[STYLE_ERASEHIGHLIGHTS].mask &
  		GrStyleTable[STYLE_ERASEALLBUTTOOLS].mask) != 0)) ||
  		((GrGetBackingStorePtr != NULL) &&
  		window->w_backingStore == (ClientData)NULL))
  
  	{
  	    DBWAreaChanged(dbwhlDef, area, crec->dbw_bitmask,
  			(TileTypeBitMask *) NULL);
  	    WindAnotherUpdatePlease = TRUE;
  	    return 0;
  	}
  
  	DBPaintPlane(crec->dbw_hlErase, &erase,
  		DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
  		(PaintUndoInfo *) NULL);
      }
  
      /* The area whose highlights must be redrawn is the area erased, but
       * it must be expanded again to include the fact that we may have
       * just erased a piece of a label that stuck out from some other point.
       * This area gets translated back into database coordinates and saved
       * in dbwhlRedrawPlane, but first it gets expanded by one more unit just to
       * eliminate edge effects:  all impacted highlights are now guaranteed
       * to OVERLAP an area in dbwhlRedrawPlane, not just touch.
       */
  
      erase.r_xbot -= expand.r_xtop;
      erase.r_ybot -= expand.r_ytop;
      erase.r_xtop -= expand.r_xbot;
      erase.r_ytop -= expand.r_ybot;
      (void) WindScreenToSurface(window, &erase, &redraw);
      GEO_EXPAND(&redraw, 1, &redraw);
      DBPaintPlane(crec->dbw_hlRedraw, &redraw,
  	    DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
  	    (PaintUndoInfo *) NULL);
      return 0;
  }
  
  /*
   * ----------------------------------------------------------------------------
   *
   * DBWHLRedrawPrepWindow --
   *
   * 	This procedure is similar to DBWHLRedraw.  However, it is
   *	intended to indicate areas to redraw highlights for a
   *	single window only.  This is required by the backing store
   *	mechanism when a window is scrolled, and the part of the
   *	window area that remains visible is refreshed from backing
   *	store.  This area does not need to have layout redrawn, but
   *	does need to have all hightlights redrawn, since the
   *	highlights aren't saved in backing store.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Information is recorded so that specified area will have its
   *	highlight information erased and redrawn the next time that
   *	WindUpdate is called.
   *
   * ----------------------------------------------------------------------------
   */
  
  void
  DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
  {
      extern CellDef *dbwhlDef;
      extern bool dbwhlErase;
      extern int dbwhlRedrawFunc();
  
      dbwhlDef = WINDOW_DEF(window);
      dbwhlErase = FALSE;
      dbwhlRedrawFunc(window, area);
  }
  
  /*
   * ----------------------------------------------------------------------------
   *
   * DBWHLRedrawWind --
   *
   * 	This procedure is called to redraw highlight information in a
   *	particular window.  It is normally called as part of WindUpdate
   *	by DBWHLUpdate.  The areas to be erased and redrawn must already
   *	be present in the clientData record.
   *
   * Results:
   *	Always returns 0 to keep searches from aborting.
   *
   * Side effects:
   *	The plane dbw_hlPlane indicates which highlight areas must be
   *	redrawn for this window.  Any highlights that touch any of these
   *	areas are redrawn.  The plane is then cleared.
   *
   * ----------------------------------------------------------------------------
   */
  
  int
  DBWHLRedrawWind(window)
      MagWindow *window;		/* Window in which to redraw highlights. */
  {
      int i;
      DBWclientRec *crec;
      extern int dbwhlEraseFunc();	/* Forward reference. */
  
      GrLock(window, TRUE);
      crec = (DBWclientRec *) window->w_clientData;
  
      /* First erase, then redraw: */
  
      (void) DBSrPaintArea((Tile *) NULL, crec->dbw_hlErase, &TiPlaneRect,
  	    &DBAllButSpaceBits, dbwhlEraseFunc, (ClientData)window);
  
      /* Now call each client to redraw its own stuff. */
  
      for (i = 0; i < MAXCLIENTS; i += 1)
      {
  	if (dbwhlClients[i] == NULL) continue;
  	(void) (*(dbwhlClients[i]))(window, crec->dbw_hlRedraw);
      }
  
      DBClearPaintPlane(crec->dbw_hlErase);
      DBClearPaintPlane(crec->dbw_hlRedraw);
      GrUnlock(window);
      return 0;
  }
  
  /* The procedure below erases highlight information for each tile that
   * it's called with.  Returns 0 to keep the search from aborting.
   */
  
  int
  dbwhlEraseFunc(tile, window)
      Tile *tile;			/* Tile describing area to be erased.	*/
      MagWindow *window;		/* Window that is being altered.	*/
  {
      Rect area;
      bool needErase = TRUE;
  
      TiToRect(tile, &area);
  
      /* If the graphics package allows highlight areas to be	*/
      /* cached in backing store, then we do a quick check to	*/
      /* see if we can just copy the background back in and	*/
      /* avoid repainting.					*/
  
      if (GrGetBackingStorePtr != NULL)
  	if ((*GrGetBackingStorePtr)(window, &area))
  	    needErase = FALSE;
  
      if (needErase) GrClipBox(&area, STYLE_ERASEHIGHLIGHTS);
      return 0;
  }
  
  /*
   * ----------------------------------------------------------------------------
   * DBWHLUpdate --
   *
   * 	This procedure is called once as part of each WindUpdate call.
   *	It checks for any windows that have highlight information that
   *	needs to be redrawn
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Highlights get redrawn on the screen.
   * ----------------------------------------------------------------------------
   */
  
  void
  DBWHLUpdate()
  {
      extern int dbwhlUpdateWindowFunc();
  
      /* Scan through all of the layout windows and redraw their
       * highlight information, if necessary.
       */
  
      (void) WindSearch(DBWclientID, (ClientData) NULL, (Rect *) NULL,
  	    DBWHLRedrawWind, (ClientData) NULL);
  }
  