2017-04-25 14:41:48 +02:00
|
|
|
/* DBWfeedback.c -
|
|
|
|
|
*
|
|
|
|
|
* This file provides a standard set of procedures for Magic
|
|
|
|
|
* commands to use to provide feedback to users. Feedback
|
|
|
|
|
* consists of areas of the screen that are highlighted, along
|
|
|
|
|
* with text describing why those particular areas are important.
|
|
|
|
|
* Feedback is used for things like displaying CIF, and for errors
|
|
|
|
|
* in CIF-generation and routing.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWfdback.c,v 1.2 2010/06/24 12:37:16 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.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 "utils/utils.h"
|
|
|
|
|
#include "utils/styles.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Use a reference-counted character structure for feedback info */
|
|
|
|
|
|
|
|
|
|
typedef struct rcstring
|
|
|
|
|
{
|
|
|
|
|
int refcount;
|
|
|
|
|
char *string;
|
|
|
|
|
} RCString;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/* Each feedback area is stored in a record that looks like this: */
|
|
|
|
|
|
|
|
|
|
typedef struct feedback
|
|
|
|
|
{
|
|
|
|
|
Rect fb_area; /* The area to be highlighted, in coords of
|
|
|
|
|
* fb_rootDef, but prior to scaling by
|
|
|
|
|
* fb_scale.
|
|
|
|
|
*/
|
|
|
|
|
Rect fb_rootArea; /* The area of the feedback, in Magic coords.
|
|
|
|
|
* of fb_rootDef, scaled up to the next
|
|
|
|
|
* integral Magic unit.
|
|
|
|
|
*/
|
|
|
|
|
RCString *fb_text; /* Text explanation for the feedback. */
|
|
|
|
|
CellDef *fb_rootDef; /* Root definition of windows in which to
|
|
|
|
|
* display this feedback.
|
|
|
|
|
*/
|
|
|
|
|
int fb_scale; /* Scale factor to use in redisplaying
|
|
|
|
|
* (fb_scale units in fb_area correspond
|
|
|
|
|
* to one unit in fb_rootDef).
|
|
|
|
|
*/
|
|
|
|
|
int fb_style; /* Display style to use for this feedback. */
|
|
|
|
|
} Feedback;
|
|
|
|
|
|
|
|
|
|
/* The following stuff describes all the feedback information we know
|
|
|
|
|
* about. The feedback is stored in a big array that grows whenever
|
|
|
|
|
* necessary.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static Feedback *dbwfbArray = NULL; /* Array holding all feedback info. */
|
|
|
|
|
global int DBWFeedbackCount = 0; /* Number of active entries in
|
|
|
|
|
* dbwfbArray.
|
|
|
|
|
*/
|
|
|
|
|
static int dbwfbSize = 0; /* Size of dbwfbArray, in entries. */
|
|
|
|
|
static int dbwfbNextToShow = 0; /* Index of first feedback area that
|
|
|
|
|
* hasn't been displayed yet. Used by
|
|
|
|
|
* DBWFBShow.
|
|
|
|
|
*/
|
|
|
|
|
static CellDef *dbwfbRootDef; /* To pass root cell definition from
|
|
|
|
|
* dbwfbGetTransform back up to
|
|
|
|
|
* DBWFeedbackAdd.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBWFeedbackRedraw --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is called by the highlight manager to redisplay
|
|
|
|
|
* feedback highlights. The window is locked before entry.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Any feedback information that overlaps a non-space tile in
|
|
|
|
|
* plane is redrawn.
|
|
|
|
|
*
|
|
|
|
|
* Tricky stuff:
|
|
|
|
|
* Redisplay is numerically difficult, particularly when feedbacks
|
|
|
|
|
* have a large internal scale factor: the tendency is to get
|
|
|
|
|
* integer overflow and get everything goofed up. Be careful
|
|
|
|
|
* when making changes to the code below.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBWFeedbackRedraw(window, plane)
|
|
|
|
|
MagWindow *window; /* Window in which to redraw. */
|
|
|
|
|
Plane *plane; /* Non-space tiles on this plane mark what
|
|
|
|
|
* needs to be redrawn.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
dlong x, y;
|
|
|
|
|
int i, halfScale, curStyle, newStyle, curScale;
|
|
|
|
|
CellDef *windowRoot;
|
|
|
|
|
Rect worldArea, screenArea, tmp;
|
|
|
|
|
Feedback *fb;
|
|
|
|
|
extern int dbwFeedbackAlways1(); /* Forward reference. */
|
|
|
|
|
|
|
|
|
|
if (DBWFeedbackCount == 0) return;
|
|
|
|
|
|
|
|
|
|
windowRoot = ((CellUse *) (window->w_surfaceID))->cu_def;
|
|
|
|
|
curStyle = -1;
|
|
|
|
|
curScale = -1;
|
|
|
|
|
for (i = 0, fb = dbwfbArray; i < DBWFeedbackCount; i++, fb++)
|
|
|
|
|
{
|
|
|
|
|
/* We expect that most of the feedbacks will have the same
|
|
|
|
|
* style and scale, so compute information with the current
|
2020-05-23 23:13:14 +02:00
|
|
|
* values, and recompute only when the values change.
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
|
|
|
|
if (fb->fb_scale != curScale)
|
|
|
|
|
{
|
|
|
|
|
curScale = fb->fb_scale;
|
|
|
|
|
halfScale = curScale / 2;
|
|
|
|
|
worldArea.r_xbot = window->w_surfaceArea.r_xbot * curScale;
|
|
|
|
|
worldArea.r_xtop = window->w_surfaceArea.r_xtop * curScale;
|
|
|
|
|
worldArea.r_ybot = window->w_surfaceArea.r_ybot * curScale;
|
|
|
|
|
worldArea.r_ytop = window->w_surfaceArea.r_ytop * curScale;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check to make sure this feedback area is relevant.
|
|
|
|
|
* Clip it to TiPlaneRect as a sanity check against
|
|
|
|
|
* callers who provide a feedback area that extends
|
|
|
|
|
* out somewhere in never-never land.
|
|
|
|
|
*/
|
|
|
|
|
if (fb->fb_rootDef != windowRoot) continue;
|
|
|
|
|
tmp = fb->fb_rootArea;
|
|
|
|
|
GeoClip(&tmp, &TiPlaneRect);
|
|
|
|
|
if (!DBSrPaintArea((Tile *) NULL, plane, &tmp,
|
|
|
|
|
&DBAllButSpaceBits, dbwFeedbackAlways1, (ClientData) NULL))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Transform the feedback area to screen coords. This is
|
|
|
|
|
* very similar to the code in WindSurfaceToScreen, except
|
|
|
|
|
* that there's additional scaling involved.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
tmp = fb->fb_area;
|
|
|
|
|
|
|
|
|
|
/* Don't clip non-Manhattan tiles, or else the diagonals are */
|
|
|
|
|
/* clipped to an incorrect position. */
|
|
|
|
|
|
|
|
|
|
if (!(fb->fb_style & TT_DIAGONAL))
|
|
|
|
|
GeoClip(&tmp, &worldArea);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ignore areas which have been clipped out of existence
|
|
|
|
|
*/
|
|
|
|
|
if (tmp.r_xtop < tmp.r_xbot || tmp.r_ytop < tmp.r_ybot)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
x = ((dlong)(tmp.r_xbot - worldArea.r_xbot) * window->w_scale) + halfScale;
|
|
|
|
|
screenArea.r_xbot = (int)((x/curScale + window->w_origin.p_x) >> SUBPIXELBITS);
|
|
|
|
|
x = ((dlong)(tmp.r_xtop - worldArea.r_xbot) * window->w_scale) + halfScale;
|
|
|
|
|
screenArea.r_xtop = (int)((x/curScale + window->w_origin.p_x) >> SUBPIXELBITS);
|
|
|
|
|
y = ((dlong)(tmp.r_ybot - worldArea.r_ybot) * window->w_scale) + halfScale;
|
|
|
|
|
screenArea.r_ybot = (int)((y/curScale + window->w_origin.p_y) >> SUBPIXELBITS);
|
|
|
|
|
y = ((dlong)(tmp.r_ytop - worldArea.r_ybot) * window->w_scale) + halfScale;
|
|
|
|
|
screenArea.r_ytop = (int)((y/curScale + window->w_origin.p_y) >> SUBPIXELBITS);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sanity check on integer bounds
|
|
|
|
|
*/
|
|
|
|
|
if (screenArea.r_xtop < screenArea.r_xbot ||
|
|
|
|
|
screenArea.r_ytop < screenArea.r_ybot)
|
|
|
|
|
{
|
|
|
|
|
TxError("Internal error: Feedback area exceeds integer bounds "
|
|
|
|
|
"on screen rectangle!\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newStyle = fb->fb_style & (TT_LEFTMASK | TT_RIGHTMASK);
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/* Another little trick: when the feedback area is very small ("very
|
2017-04-25 14:41:48 +02:00
|
|
|
* small" is a hand-tuned constant), change all stippled styles to
|
|
|
|
|
* solid.
|
|
|
|
|
* (The usefulness of this trick is questionable, as it generally
|
|
|
|
|
* creates very bothersome output for the "cif see" function and
|
|
|
|
|
* other places where the feedback is generated from tiles.)
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
if (((GEO_WIDTH(&screenArea) < 18) || (GEO_HEIGHT(&screenArea) < 18))
|
|
|
|
|
&& ((newStyle == STYLE_MEDIUMHIGHLIGHTS)
|
|
|
|
|
|| (newStyle == STYLE_PALEHIGHLIGHTS)))
|
|
|
|
|
newStyle = STYLE_SOLIDHIGHLIGHTS;
|
|
|
|
|
*/
|
|
|
|
|
if (newStyle != curStyle)
|
|
|
|
|
{
|
|
|
|
|
curStyle = newStyle;
|
|
|
|
|
GrSetStuff(curStyle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fb->fb_style & TT_DIAGONAL)
|
|
|
|
|
GrDiagonal(&screenArea, fb->fb_style);
|
|
|
|
|
|
|
|
|
|
/* Special case (i.e., "hack")---to get a diagonal line */
|
|
|
|
|
/* instead of a triangle, set TT_SIDE but not */
|
|
|
|
|
/* TT_DIAGONAL. TT_DIRECTION still indicates / or \ */
|
|
|
|
|
|
|
|
|
|
else if (fb->fb_style & TT_SIDE)
|
|
|
|
|
{
|
|
|
|
|
if (fb->fb_style & TT_DIRECTION)
|
|
|
|
|
GrClipLine(screenArea.r_xbot, screenArea.r_ytop,
|
|
|
|
|
screenArea.r_xtop, screenArea.r_ybot);
|
|
|
|
|
else
|
|
|
|
|
GrClipLine(screenArea.r_xbot, screenArea.r_ybot,
|
|
|
|
|
screenArea.r_xtop, screenArea.r_ytop);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
GrFastBox(&screenArea);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbwFeedbackAlways1()
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBWFeedbackClear --
|
|
|
|
|
*
|
|
|
|
|
* This procedure clears all existing feedback information from
|
|
|
|
|
* the screen.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Any existing feedback information is cleared from the screen
|
|
|
|
|
* and from our database.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBWFeedbackClear(text)
|
|
|
|
|
char *text;
|
|
|
|
|
{
|
|
|
|
|
int i, oldCount;
|
|
|
|
|
Feedback *fb, *fl, *fe;
|
|
|
|
|
Rect area;
|
|
|
|
|
CellDef *currentRoot;
|
|
|
|
|
RCString *quickptr = NULL;
|
|
|
|
|
|
|
|
|
|
/* Clear out the feedback array and recycle string storage. Whenever
|
|
|
|
|
* the root cell changes, make a call to erase from the screen.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
currentRoot = (CellDef *) NULL;
|
|
|
|
|
oldCount = DBWFeedbackCount;
|
|
|
|
|
DBWFeedbackCount = 0;
|
|
|
|
|
for (fb = dbwfbArray; fb < dbwfbArray + oldCount; fb++)
|
|
|
|
|
{
|
|
|
|
|
if ((text == NULL) ||
|
|
|
|
|
((quickptr != NULL) && (fb->fb_text == quickptr)) ||
|
|
|
|
|
(strstr(fb->fb_text->string, text) != NULL))
|
|
|
|
|
{
|
|
|
|
|
// Track the last refcount string that matched the
|
|
|
|
|
// text so we can run through lists of matching text
|
|
|
|
|
// without having to call strstr()
|
|
|
|
|
|
|
|
|
|
if (text != NULL) quickptr = fb->fb_text;
|
|
|
|
|
|
|
|
|
|
if (currentRoot != fb->fb_rootDef)
|
|
|
|
|
{
|
|
|
|
|
if (currentRoot != (CellDef *) NULL)
|
|
|
|
|
DBWHLRedraw(currentRoot, &area, TRUE);
|
|
|
|
|
area = GeoNullRect;
|
|
|
|
|
}
|
|
|
|
|
(void) GeoInclude(&fb->fb_rootArea, &area);
|
|
|
|
|
currentRoot = fb->fb_rootDef;
|
|
|
|
|
|
|
|
|
|
// Decrement refcount and free if zero.
|
|
|
|
|
fb->fb_text->refcount--;
|
|
|
|
|
if (fb->fb_text->refcount == 0)
|
|
|
|
|
{
|
|
|
|
|
freeMagic(fb->fb_text->string);
|
|
|
|
|
freeMagic(fb->fb_text);
|
|
|
|
|
}
|
|
|
|
|
fb->fb_text = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (currentRoot != NULL)
|
|
|
|
|
DBWHLRedraw(currentRoot, &area, TRUE);
|
|
|
|
|
dbwfbNextToShow = 0;
|
|
|
|
|
|
|
|
|
|
if (text != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Close up feedback list around removed text entries */
|
|
|
|
|
|
|
|
|
|
fl = dbwfbArray;
|
|
|
|
|
fe = fl + oldCount;
|
|
|
|
|
for (fb = dbwfbArray; fb < fe; fb++)
|
|
|
|
|
{
|
|
|
|
|
while ((fb->fb_text == NULL) && (fb < fe)) fb++;
|
|
|
|
|
if (fb < fe) *fl++ = *fb;
|
|
|
|
|
}
|
|
|
|
|
DBWFeedbackCount = (int)(fl - dbwfbArray);
|
|
|
|
|
|
|
|
|
|
for (fb = fl; fb < dbwfbArray + oldCount; fb++)
|
|
|
|
|
fb->fb_text = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free up feedback memory whenever we have removed all feedback entries */
|
|
|
|
|
if (DBWFeedbackCount == 0)
|
|
|
|
|
{
|
|
|
|
|
if (dbwfbArray != NULL) {
|
|
|
|
|
freeMagic((char *) dbwfbArray);
|
|
|
|
|
dbwfbArray = NULL;
|
|
|
|
|
}
|
|
|
|
|
dbwfbSize = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBWFeedbackAdd --
|
|
|
|
|
*
|
|
|
|
|
* Adds a new piece of feedback information to the list we have
|
|
|
|
|
* already.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* CellDef's ancestors are searched until its first root definition
|
|
|
|
|
* is found, and the coordinates of area are transformed into the
|
|
|
|
|
* root. Then the feedback area is added to our current list, using
|
|
|
|
|
* the style and scalefactor given. This stuff will be displayed on
|
|
|
|
|
* the screen at the end of the current command.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBWFeedbackAdd(area, text, cellDef, scaleFactor, style)
|
|
|
|
|
Rect *area; /* The area to be highlighted. */
|
|
|
|
|
char *text; /* Text associated with the area. */
|
|
|
|
|
CellDef *cellDef; /* The cellDef in whose coordinates area
|
|
|
|
|
* is given.
|
|
|
|
|
*/
|
|
|
|
|
int scaleFactor; /* The coordinates provided for feedback
|
|
|
|
|
* areas are divided by this to produce
|
|
|
|
|
* coordinates in Magic database units.
|
|
|
|
|
* This will probably be 1 most of the time.
|
|
|
|
|
* By making it bigger, say 10, and scaling
|
|
|
|
|
* other coordinates appropriately, it's
|
|
|
|
|
* possible to draw narrow lines on the
|
|
|
|
|
* screen, or to handle CIF, which isn't in
|
|
|
|
|
* exactly the same coordinates as other Magic
|
|
|
|
|
* stuff.
|
|
|
|
|
*/
|
|
|
|
|
int style; /* A display style to use for the feedback.
|
|
|
|
|
* Use one of:
|
|
|
|
|
* STYLE_OUTLINEHIGHLIGHTS: solid outlines
|
|
|
|
|
* STYLE_DOTTEDHIGHLIGHTS: dotted outlines
|
|
|
|
|
* STYLE_SOLIDHIGHLIGHTS: solid fill
|
|
|
|
|
* STYLE_MEDIUMHIGHLIGHTS: medium stipple
|
|
|
|
|
* STYLE_PALEHIGHLIGHTS: pald stipple
|
|
|
|
|
* At very coarse viewing scales, the last
|
|
|
|
|
* two styles are hard to see, so they are
|
|
|
|
|
* turned into STYLE_SOLIDHIGHLIGHTS.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
Rect tmp, tmp2, tmp3;
|
|
|
|
|
Transform transform;
|
|
|
|
|
int i;
|
|
|
|
|
Feedback *fb, *fblast;
|
|
|
|
|
extern int dbwfbGetTransform(); /* Forward declaration. */
|
|
|
|
|
|
|
|
|
|
/* Find a transform from this cell to the root, and use it to
|
|
|
|
|
* transform the area. If the root isn't an ancestor, just
|
|
|
|
|
* return.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!DBSrRoots(cellDef, &GeoIdentityTransform,
|
|
|
|
|
dbwfbGetTransform, (ClientData) &transform)) return;
|
|
|
|
|
|
|
|
|
|
/* SigInterruptPending screws up DBSrRoots */
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Don't get fooled like I did. The translations for
|
|
|
|
|
* this transform are in Magic coordinates, not feedback
|
|
|
|
|
* coordinates. Scale them into feedback coordinates.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
transform.t_c *= scaleFactor;
|
|
|
|
|
transform.t_f *= scaleFactor;
|
|
|
|
|
GeoTransRect(&transform, area, &tmp2);
|
|
|
|
|
area = &tmp2;
|
|
|
|
|
|
|
|
|
|
/* Make sure there's enough space in the current array. If
|
|
|
|
|
* not, make a new array, copy the old to the new, then delete
|
|
|
|
|
* the old array. Use memcpy() to make sure this happens very fast.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (DBWFeedbackCount == dbwfbSize)
|
|
|
|
|
{
|
|
|
|
|
Feedback *new;
|
|
|
|
|
|
|
|
|
|
if (dbwfbSize == 0) dbwfbSize = 32;
|
|
|
|
|
else dbwfbSize <<= 1;
|
|
|
|
|
|
|
|
|
|
new = (Feedback *) mallocMagic(dbwfbSize * sizeof(Feedback));
|
|
|
|
|
memcpy((char *)new, (char *)dbwfbArray, DBWFeedbackCount * sizeof(Feedback));
|
|
|
|
|
|
|
|
|
|
for (i = DBWFeedbackCount; i < dbwfbSize; i++) new[i].fb_text = NULL;
|
|
|
|
|
|
|
|
|
|
if (dbwfbArray != NULL) freeMagic((char *) dbwfbArray);
|
|
|
|
|
dbwfbArray = new;
|
|
|
|
|
}
|
|
|
|
|
fb = &dbwfbArray[DBWFeedbackCount];
|
|
|
|
|
fb->fb_area = *area;
|
|
|
|
|
fblast = (DBWFeedbackCount == 0) ? NULL : &dbwfbArray[DBWFeedbackCount - 1];
|
|
|
|
|
|
|
|
|
|
if (fblast && (!strcmp(fblast->fb_text->string, text)))
|
|
|
|
|
{
|
|
|
|
|
fb->fb_text = fblast->fb_text;
|
|
|
|
|
fb->fb_text->refcount++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fb->fb_text = (RCString *)mallocMagic(sizeof(RCString));
|
|
|
|
|
fb->fb_text->refcount = 1;
|
|
|
|
|
fb->fb_text->string = StrDup(NULL, text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fb->fb_rootDef = dbwfbRootDef;
|
|
|
|
|
fb->fb_scale = scaleFactor;
|
|
|
|
|
fb->fb_style = style;
|
|
|
|
|
DBWFeedbackCount++;
|
|
|
|
|
|
|
|
|
|
/* Round the area up into Magic coords, and save it too. */
|
|
|
|
|
if (area->r_xtop > 0)
|
|
|
|
|
tmp.r_xtop = (area->r_xtop + scaleFactor - 1)/scaleFactor;
|
|
|
|
|
else tmp.r_xtop = area->r_xtop/scaleFactor;
|
|
|
|
|
if (area->r_ytop > 0)
|
|
|
|
|
tmp.r_ytop = (area->r_ytop + scaleFactor - 1)/scaleFactor;
|
|
|
|
|
else tmp.r_ytop = area->r_ytop/scaleFactor;
|
|
|
|
|
if (area->r_xbot > 0) tmp.r_xbot = area->r_xbot/scaleFactor;
|
|
|
|
|
else tmp.r_xbot = (area->r_xbot - scaleFactor + 1)/scaleFactor;
|
|
|
|
|
if (area->r_ybot > 0) tmp.r_ybot = area->r_ybot/scaleFactor;
|
|
|
|
|
else tmp.r_ybot = (area->r_ybot - scaleFactor + 1)/scaleFactor;
|
|
|
|
|
|
|
|
|
|
/* Clip to ensure well within TiPlaneRect */
|
|
|
|
|
tmp3.r_xbot = TiPlaneRect.r_xbot + 10;
|
|
|
|
|
tmp3.r_ybot = TiPlaneRect.r_ybot + 10;
|
|
|
|
|
tmp3.r_xtop = TiPlaneRect.r_xtop - 10;
|
|
|
|
|
tmp3.r_ytop = TiPlaneRect.r_ytop - 10;
|
|
|
|
|
GeoClip(&tmp, &tmp3);
|
|
|
|
|
|
|
|
|
|
fb->fb_rootArea = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This utility procedure is invoked by DBSrRoots. Save the root definition
|
|
|
|
|
* in dbwfbRootDef, save the transform in the argument, and abort the search.
|
|
|
|
|
* Make sure that the root we pick is actually displayed in a window
|
|
|
|
|
* someplace (there could be root cells that are no longer displayed
|
|
|
|
|
* anywhere).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbwfbGetTransform(use, transform, cdarg)
|
|
|
|
|
CellUse *use; /* A root use that is an ancestor
|
|
|
|
|
* of cellDef in DBWFeedbackAdd.
|
|
|
|
|
*/
|
|
|
|
|
Transform *transform; /* Transform up from cellDef to use. */
|
|
|
|
|
Transform *cdarg; /* Place to store transform from
|
|
|
|
|
* cellDef to its root def.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
extern int dbwfbWindFunc();
|
|
|
|
|
if (use->cu_def->cd_flags & CDINTERNAL) return 0;
|
|
|
|
|
if (!WindSearch((ClientData) DBWclientID, (ClientData) use,
|
|
|
|
|
(Rect *) NULL, dbwfbWindFunc, (ClientData) NULL)) return 0;
|
|
|
|
|
if (SigInterruptPending)
|
|
|
|
|
return 0;
|
|
|
|
|
dbwfbRootDef = use->cu_def;
|
|
|
|
|
*cdarg = *transform;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This procedure is called if a window is found for the cell in
|
|
|
|
|
* dbwfbGetTransform above. It returns 1 to abort the search and
|
|
|
|
|
* notify dbwfbGetTransform that there was a window for that root
|
|
|
|
|
* cell.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dbwfbWindFunc()
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Client initialization
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dbwFeedbackInit()
|
|
|
|
|
{
|
|
|
|
|
DBWHLAddClient(DBWFeedbackRedraw);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBWFeedbackShow --
|
|
|
|
|
*
|
|
|
|
|
* Causes new feedback information actually to be displayed on
|
|
|
|
|
* the screen.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* All new feedback information that has been created since the
|
|
|
|
|
* last call to this procedure is added to the display.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
DBWFeedbackShow()
|
|
|
|
|
{
|
|
|
|
|
Rect area;
|
|
|
|
|
CellDef *currentRoot;
|
|
|
|
|
Feedback *fb;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Scan through all of the feedback areas starting with dbwfbNextToShow.
|
|
|
|
|
* Save up the total bounding box until the root definition changes,
|
|
|
|
|
* then redisplay what's been saved up so far.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
currentRoot = NULL;
|
|
|
|
|
for (i = dbwfbNextToShow, fb = &(dbwfbArray[dbwfbNextToShow]);
|
|
|
|
|
i < DBWFeedbackCount; i++, fb++)
|
|
|
|
|
{
|
|
|
|
|
if (currentRoot != fb->fb_rootDef)
|
|
|
|
|
{
|
|
|
|
|
if (currentRoot != NULL)
|
|
|
|
|
DBWHLRedraw(currentRoot, &area, FALSE);
|
|
|
|
|
area = GeoNullRect;
|
|
|
|
|
}
|
|
|
|
|
(void) GeoInclude(&fb->fb_rootArea, &area);
|
|
|
|
|
currentRoot = fb->fb_rootDef;
|
|
|
|
|
}
|
|
|
|
|
if (currentRoot != NULL)
|
|
|
|
|
DBWHLRedraw(currentRoot, &area, FALSE);
|
|
|
|
|
dbwfbNextToShow = DBWFeedbackCount;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* DBWFeedbackNth --
|
|
|
|
|
*
|
|
|
|
|
* Provides the area and text associated with a particular
|
|
|
|
|
* feedback area.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns a pointer to the text associated with the Nth feedback
|
|
|
|
|
* entry.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* The parameter "area" is filled with the area of the nth
|
|
|
|
|
* feedback, and the text of that feedback is returned. *pRootDef
|
|
|
|
|
* is filled in with rootDef for window of feedback area. *pStyle
|
|
|
|
|
* is filled in with the display style for the feedback area. If
|
|
|
|
|
* the particular area doesn't exist (nth >= DBWFeedbackCount),
|
|
|
|
|
* area and *pRootDef and *pStyle are untouched and NULL is
|
|
|
|
|
* returned. NULL may also be returned if there simply wasn't
|
|
|
|
|
* any text associated with the selected feedback.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
DBWFeedbackNth(nth, area, pRootDef, pStyle)
|
|
|
|
|
int nth; /* Selects which feedback area to return
|
|
|
|
|
* stuff from. (0 <= nth < DBWFeedbackCount)
|
|
|
|
|
*/
|
|
|
|
|
Rect *area; /* To be filled in with area of feedback, in
|
|
|
|
|
* rounded-outward Magic coordinates.
|
|
|
|
|
*/
|
|
|
|
|
CellDef **pRootDef; /* *pRootDef gets filled in with root def for
|
|
|
|
|
* this feedback area. If pRootDef is NULL,
|
|
|
|
|
* nothing is touched.
|
|
|
|
|
*/
|
|
|
|
|
int *pStyle; /* *pStyle gets filled in with the display
|
|
|
|
|
* style for this feedback area. If NULL,
|
|
|
|
|
* nothing is touched.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
if (nth >= DBWFeedbackCount) return NULL;
|
|
|
|
|
*area = dbwfbArray[nth].fb_rootArea;
|
|
|
|
|
if (pRootDef != NULL) *pRootDef = dbwfbArray[nth].fb_rootDef;
|
|
|
|
|
if (pStyle != NULL) *pStyle = dbwfbArray[nth].fb_style;
|
|
|
|
|
return dbwfbArray[nth].fb_text->string;
|
|
|
|
|
}
|