1 /* DBWhighlights.c -
2  *
3  *	This file contains routines that allow the highlight plane
4  *	to be used to display additional things besides the box.
5  *	The routines coordinate all the clients that have highlights
6  *	to display so that when one of them updates its highlights
7  *	it doesn't trash the others' highlights.
8  *
9  *     *********************************************************************
10  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
11  *     * Permission to use, copy, modify, and distribute this              *
12  *     * software and its documentation for any purpose and without        *
13  *     * fee is hereby granted, provided that the above copyright          *
14  *     * notice appear in all copies.  The University of California        *
15  *     * makes no representations about the suitability of this            *
16  *     * software for any purpose.  It is provided "as is" without         *
17  *     * express or implied warranty.  Export of this software outside     *
18  *     * of the United States of America may require an export license.    *
19  *     *********************************************************************
20  */
21 
22 #ifndef lint
23 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 $";
24 #endif  /* not lint */
25 
26 #include <stdio.h>
27 
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "utils/styles.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "windows/windows.h"
35 #include "graphics/graphics.h"
36 #include "dbwind/dbwind.h"
37 #include "textio/textio.h"
38 #include "graphics/graphicsInt.h"
39 
40 #define WINDOW_DEF(w)	(((CellUse *)(w->w_surfaceID))->cu_def)
41 
42 /* The array below is used to hold the addresses of redisplay
43  * procedures for each of the highlight clients.  Whenever
44  * highlights must be redisplayed, each highlight client
45  * is invoked for each database window.
46  */
47 
48 #define MAXCLIENTS 10
49 static int (*(dbwhlClients[MAXCLIENTS]))();
50 
51 /*
52  * ----------------------------------------------------------------------------
53  *
54  * DBWHLAddClient --
55  *
56  * 	This procedure is used to add another client to those
57  *	that are displaying highlights.  The redisplay procedure
58  *	passed in by the client will be invoked in the following
59  *	way:
60  *		int
61  *		redisplayProc(window, plane)
62  *		    MagWindow *window;
63  *		    Plane *plane;
64  *		{
65  *		}
66  *	The procedure is invoked once for each window that contains
67  *	database information (and potentially has highlights).  The
68  *	window has been locked via GrLock() before the proc is called,
69  *	and the clipping area has already been set up.  The procedure
70  *	is given a pointer to the window, and a pointer to a plane.
71  *	The plane contains non-space tiles over all areas where highlight
72  *	information needs to be redrawn (all of these areas have had
73  *	their highlight information erased).  The client should redraw
74  *	any of its highlights that touch any non-space areas.
75  *
76  * Results:
77  *	None.
78  *
79  * Side effects:
80  *	The client is added to our list of clients.
81  *
82  * ----------------------------------------------------------------------------
83  */
84 
85 void
86 DBWHLAddClient(redisplayProc)
87     int (*redisplayProc)();	/* Procedure to call during redisplays. */
88 {
89     int i;
90     for (i = 0; i < MAXCLIENTS; i++)
91     {
92 	if (dbwhlClients[i] == NULL)
93 	{
94 	    dbwhlClients[i] = redisplayProc;
95 	    return;
96 	}
97     }
98     TxError("Magic error:  ran out of space in highlight client table.\n");
99     TxError("Tell your system maintainer to enlarge the table.\n");
100 }
101 
102 /*
103  * ----------------------------------------------------------------------------
104  *
105  * DBWHLRemoveClient --
106  *
107  * 	This just removes a client from the list of those that we
108  *	know about.
109  *
110  * Results:
111  *	None.
112  *
113  * Side effects:
114  *	The given redisplay procedure will no longer be invoked
115  *	during redisplays.
116  *
117  * ----------------------------------------------------------------------------
118  */
119 
120 void
121 DBWHLRemoveClient(redisplayProc)
122     int (*redisplayProc)();		/* A redisplay procedure.  This
123 					 * procedure must previously have been
124 					 * passed in to DBWHLAddClient.
125 					 */
126 {
127     int i;
128     for (i = 0; i < MAXCLIENTS; i += 1)
129     {
130 	if (dbwhlClients[i] == redisplayProc)
131 	{
132 	    dbwhlClients[i] = NULL;
133 	    return;
134 	}
135     }
136     ASSERT(FALSE, "DBWHLRemoveClient");
137 }
138 
139 /*
140  * ----------------------------------------------------------------------------
141  *
142  * DBWHLRedraw --
143  *
144  * 	This procedure is invoked to redisplay highlights.  The
145  *	clients that manage highlights are free to draw on the screen
146  *	at will.  But if a client ever erases highlight information, it
147  *	must call this procedure so that the other clients can redraw
148  *	any of their highlights that might have been erased.  This
149  *	procedure records what has changed.  The information isn't actually
150  *	redrawn until the next time WindUpdate is called.  This is done
151  *	to avoid repeated redraws when several pieces of highlights change
152  *	in the same area at the same time.
153  *
154  * Results:
155  *	None.
156  *
157  * Side effects:
158  *	Information is recorded so that specified area will have its
159  *	highlight information erased and redrawn the next time that
160  *	WindUpdate is called.
161  *
162  * ----------------------------------------------------------------------------
163  */
164 
165 void
DBWHLRedraw(rootDef,area,erase)166 DBWHLRedraw(rootDef, area, erase)
167     CellDef *rootDef;		/* Highlight information will be redrawn in
168 				 * all windows for which this is the root
169 				 * cell definition.
170 				 */
171     Rect *area;			/* The area over which to redraw.  Highlights
172 				 * will be redrawn in this area plus enough
173 				 * surrounding area to catch degenerate boxes
174 				 * (drawn as crosses) and labels that may
175 				 * stick out from their attachment points.
176 				 */
177     bool erase;			/* TRUE means we should erase are before
178 				 * redrawing it.  FALSE means that either the
179 				 * client has erased the area, or there's no
180 				 * need to erase it because all that's
181 				 * happening is to add new information to the
182 				 * display.
183 				 */
184 {
185     extern CellDef *dbwhlDef;
186     extern bool dbwhlErase;
187     extern int dbwhlRedrawFunc();
188     Rect ourArea;
189 
190     dbwhlDef = rootDef;		/* Must pass to search function. */
191     dbwhlErase = erase;
192 
193     /* If we're passed a NULL area, expand it by one unit in both
194      * directions so that we're certain to have non-zero area.
195      * Otherwise the various search procedures have big troubles.
196      */
197 
198     ourArea = *area;
199     if (ourArea.r_xbot >= ourArea.r_xtop)
200     {
201 	ourArea.r_xtop = ourArea.r_xbot + 1;
202 	ourArea.r_xbot--;
203     }
204     if (ourArea.r_ybot >= ourArea.r_ytop)
205     {
206 	ourArea.r_ytop = ourArea.r_ybot + 1;
207 	ourArea.r_ybot--;
208     }
209     (void) WindSearch(DBWclientID, (ClientData) NULL, &ourArea,
210 	dbwhlRedrawFunc, (ClientData) &ourArea);
211 }
212 
213 CellDef *dbwhlDef;
214 bool dbwhlErase;
215 
216 /* This procedure records the area to be erased (if any) and the
217  * area to be redisplayed (which is larger than the area to be
218  * erased).
219  */
220 
221 int
dbwhlRedrawFunc(window,area)222 dbwhlRedrawFunc(window, area)
223     MagWindow *window;		/* Window to redraw. */
224     Rect *area;			/* Passed as client data. */
225 {
226     Rect erase, expand, redraw;
227     DBWclientRec *crec = (DBWclientRec *) window->w_clientData;
228 
229     if (WINDOW_DEF(window) != dbwhlDef) return 0;
230 
231     /* The area that we erase must be large enough to include material
232      * that sticks out from the area of the highlights.  There are two
233      * ways that material sticks out:  (a) zero-size boxes are drawn as
234      * crosses, and the crosses stick outside of the box's area;  (b)
235      * labels are attached to points or rectangles, but the text usually
236      * extends far beyond the attachment point.
237      */
238 
239     WindSurfaceToScreen(window, area, &erase);
240     expand = GrCrossRect;
241     (void) GeoInclude(&crec->dbw_expandAmounts, &expand);
242 
243     if (dbwhlErase)
244     {
245 	bool needErase = TRUE;
246 
247 	erase.r_xbot += expand.r_xbot;
248 	erase.r_ybot += expand.r_ybot;
249 	erase.r_xtop += expand.r_xtop;
250 	erase.r_ytop += expand.r_ytop;
251 
252 	/* On some displays (e.g. black-and-white ones), highlights use
253 	 * the same color planes as other information.  If this is the
254 	 * case, redisplay everything (this will redisplay highlights too,
255 	 * so there's nothing additional to do here).
256 	 *
257 	 * This is also the case if we use backing store but the backing
258 	 * store has been removed due to becoming invalid, such as when
259 	 * an attempt is made to redraw into an obscured or unmapped
260 	 * window.
261 	 */
262 
263 	if (((GrGetBackingStorePtr == NULL) &&
264 		((GrStyleTable[STYLE_ERASEHIGHLIGHTS].mask &
265 		GrStyleTable[STYLE_ERASEALLBUTTOOLS].mask) != 0)) ||
266 		((GrGetBackingStorePtr != NULL) &&
267 		window->w_backingStore == (ClientData)NULL))
268 
269 	{
270 	    DBWAreaChanged(dbwhlDef, area, crec->dbw_bitmask,
271 			(TileTypeBitMask *) NULL);
272 	    WindAnotherUpdatePlease = TRUE;
273 	    return 0;
274 	}
275 
276 	DBPaintPlane(crec->dbw_hlErase, &erase,
277 		DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
278 		(PaintUndoInfo *) NULL);
279     }
280 
281     /* The area whose highlights must be redrawn is the area erased, but
282      * it must be expanded again to include the fact that we may have
283      * just erased a piece of a label that stuck out from some other point.
284      * This area gets translated back into database coordinates and saved
285      * in dbwhlRedrawPlane, but first it gets expanded by one more unit just to
286      * eliminate edge effects:  all impacted highlights are now guaranteed
287      * to OVERLAP an area in dbwhlRedrawPlane, not just touch.
288      */
289 
290     erase.r_xbot -= expand.r_xtop;
291     erase.r_ybot -= expand.r_ytop;
292     erase.r_xtop -= expand.r_xbot;
293     erase.r_ytop -= expand.r_ybot;
294     (void) WindScreenToSurface(window, &erase, &redraw);
295     GEO_EXPAND(&redraw, 1, &redraw);
296     DBPaintPlane(crec->dbw_hlRedraw, &redraw,
297 	    DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
298 	    (PaintUndoInfo *) NULL);
299     return 0;
300 }
301 
302 /*
303  * ----------------------------------------------------------------------------
304  *
305  * DBWHLRedrawPrepWindow --
306  *
307  * 	This procedure is similar to DBWHLRedraw.  However, it is
308  *	intended to indicate areas to redraw highlights for a
309  *	single window only.  This is required by the backing store
310  *	mechanism when a window is scrolled, and the part of the
311  *	window area that remains visible is refreshed from backing
312  *	store.  This area does not need to have layout redrawn, but
313  *	does need to have all hightlights redrawn, since the
314  *	highlights aren't saved in backing store.
315  *
316  * Results:
317  *	None.
318  *
319  * Side effects:
320  *	Information is recorded so that specified area will have its
321  *	highlight information erased and redrawn the next time that
322  *	WindUpdate is called.
323  *
324  * ----------------------------------------------------------------------------
325  */
326 
327 void
DBWHLRedrawPrepWindow(MagWindow * window,Rect * area)328 DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
329 {
330     extern CellDef *dbwhlDef;
331     extern bool dbwhlErase;
332     extern int dbwhlRedrawFunc();
333 
334     dbwhlDef = WINDOW_DEF(window);
335     dbwhlErase = FALSE;
336     dbwhlRedrawFunc(window, area);
337 }
338 
339 /*
340  * ----------------------------------------------------------------------------
341  *
342  * DBWHLRedrawWind --
343  *
344  * 	This procedure is called to redraw highlight information in a
345  *	particular window.  It is normally called as part of WindUpdate
346  *	by DBWHLUpdate.  The areas to be erased and redrawn must already
347  *	be present in the clientData record.
348  *
349  * Results:
350  *	Always returns 0 to keep searches from aborting.
351  *
352  * Side effects:
353  *	The plane dbw_hlPlane indicates which highlight areas must be
354  *	redrawn for this window.  Any highlights that touch any of these
355  *	areas are redrawn.  The plane is then cleared.
356  *
357  * ----------------------------------------------------------------------------
358  */
359 
360 int
DBWHLRedrawWind(window)361 DBWHLRedrawWind(window)
362     MagWindow *window;		/* Window in which to redraw highlights. */
363 {
364     int i;
365     DBWclientRec *crec;
366     extern int dbwhlEraseFunc();	/* Forward reference. */
367 
368     GrLock(window, TRUE);
369     crec = (DBWclientRec *) window->w_clientData;
370 
371     /* First erase, then redraw: */
372 
373     (void) DBSrPaintArea((Tile *) NULL, crec->dbw_hlErase, &TiPlaneRect,
374 	    &DBAllButSpaceBits, dbwhlEraseFunc, (ClientData)window);
375 
376     /* Now call each client to redraw its own stuff. */
377 
378     for (i = 0; i < MAXCLIENTS; i += 1)
379     {
380 	if (dbwhlClients[i] == NULL) continue;
381 	(void) (*(dbwhlClients[i]))(window, crec->dbw_hlRedraw);
382     }
383 
384     DBClearPaintPlane(crec->dbw_hlErase);
385     DBClearPaintPlane(crec->dbw_hlRedraw);
386     GrUnlock(window);
387     return 0;
388 }
389 
390 /* The procedure below erases highlight information for each tile that
391  * it's called with.  Returns 0 to keep the search from aborting.
392  */
393 
394 int
dbwhlEraseFunc(tile,window)395 dbwhlEraseFunc(tile, window)
396     Tile *tile;			/* Tile describing area to be erased.	*/
397     MagWindow *window;		/* Window that is being altered.	*/
398 {
399     Rect area;
400     bool needErase = TRUE;
401 
402     TiToRect(tile, &area);
403 
404     /* If the graphics package allows highlight areas to be	*/
405     /* cached in backing store, then we do a quick check to	*/
406     /* see if we can just copy the background back in and	*/
407     /* avoid repainting.					*/
408 
409     if (GrGetBackingStorePtr != NULL)
410 	if ((*GrGetBackingStorePtr)(window, &area))
411 	    needErase = FALSE;
412 
413     if (needErase) GrClipBox(&area, STYLE_ERASEHIGHLIGHTS);
414     return 0;
415 }
416 
417 /*
418  * ----------------------------------------------------------------------------
419  * DBWHLUpdate --
420  *
421  * 	This procedure is called once as part of each WindUpdate call.
422  *	It checks for any windows that have highlight information that
423  *	needs to be redrawn
424  *
425  * Results:
426  *	None.
427  *
428  * Side effects:
429  *	Highlights get redrawn on the screen.
430  * ----------------------------------------------------------------------------
431  */
432 
433 void
DBWHLUpdate()434 DBWHLUpdate()
435 {
436     extern int dbwhlUpdateWindowFunc();
437 
438     /* Scan through all of the layout windows and redraw their
439      * highlight information, if necessary.
440      */
441 
442     (void) WindSearch(DBWclientID, (ClientData) NULL, (Rect *) NULL,
443 	    DBWHLRedrawWind, (ClientData) NULL);
444 }
445