magic/graphics/grText.c

376 lines
9.9 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* grText.c -
*
* Contains functions for manipulating text that are not dependent
* upon the display type.
*
* *********************************************************************
* * 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/graphics/grText.c,v 1.3 2008/12/11 04:20:06 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <math.h>
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "database/database.h"
#include "windows/windows.h"
#include "graphics/graphics.h"
#include "graphics/graphicsInt.h"
#include "utils/utils.h"
/*---------------------------------------------------------
*
* GrFontText ---
*
* This routine is a glorified version of GrPutText
* that draws vector outline fonts according to
* information loaded and stored into the font lists
* (see DBLoadFont() in DBlabel.c). In addition to
* the properties used by GrPutText(), GrFontText()
* uses label scale, rotation, offset, and font.
*
*---------------------------------------------------------
*/
bool
GrFontText(str, style, p, font, size, rotate, clip)
char *str; /* The text to be drawn. */
int style; /* Display style to use for the text */
Point *p; /* Point of origin */
int font; /* Font to use */
int size; /* Scale */
int rotate; /* Rotation (in degrees) */
Rect *clip; /* Clipping area */
{
Rect nClip;
Point pstart;
/* Fall back on X11 text if vectored text unavailable */
if (!grFontTextPtr)
{
GrPutText(str, style, p, GEO_CENTER, GR_TEXT_MEDIUM, FALSE, clip, NULL);
return TRUE;
}
nClip = *clip;
GeoClip(&nClip, &grCurClip);
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
if (style >= 0)
(*grSetWMandCPtr)(GrStyleTable[style].mask, GrStyleTable[style].color);
(*grFontTextPtr)(str, font, size, rotate, p, &nClip, grCurObscure);
return TRUE;
}
/* The following definition defines how much text is offset from
* its positioning point when it isn't centered.
*/
#define TEXTOFFSET 5
/*---------------------------------------------------------
* GrPutText:
* This routine puts a chunk of text on the screen in the given
* color, size, and position. It is clipped to a rectangle.
*
* Results:
* True if the text was able to be displayed.
*
* Side Effects:
* The text is drawn on the screen at pos relative to p, using
* style (text can also be erased by passing a suitable style).
* The rectangle 'actual' is filled in with the actual location of
* the text on the screen (if actual is a non-null pointer). The
* text will be shrunk to a smaller font, if that will help it to
* fit into the clipping rectangle.
*---------------------------------------------------------
*/
bool
GrPutText(str, style, p, pos, size, adjust, clip, actual)
char *str; /* The text to be drawn. */
int style; /* The style for drawing text; if -1 then
* the caller has already set the style
* and we don't have to.
*/
Point *p; /* The point to align with */
int pos; /* The alignment desired (GR_NORTH,
* GR_NORTHEAST, etc.)
*/
int size; /* The desired size of the text
* (such as GR_TEXT_MEDIUM).
*/
bool adjust; /* TRUE means adjust the text (either by
* sliding it around or using a smaller font)
* if that is necessary to make it fit into
* the clipping rectangle. FALSE means
* display the text exactly as instructed,
* clipping it if it doesn't fit.
*/
Rect *clip; /* A clipping rectangle for the text */
Rect *actual; /* To be filled in with the location of the
* text.
*/
{
Rect posR;
Point drawPoint;
int xpos, ypos, hangBelow;
Rect nClip;
nClip = *clip;
GeoClip(&nClip, &grCurClip);
GR_CHECK_LOCK();
if (!grDriverInformed) grInformDriver();
if (actual != (Rect *) NULL)
{
actual->r_xbot = actual->r_ybot = 0;
actual->r_xtop = actual->r_ytop = 0;
}
/* The following loop sees if the text will fit in the clipping
* area. If not, and shrinking is allowed, we try again and
* again with smaller sizes.
*/
while (TRUE)
{
/* what portion of the screen is taken up by the text? */
GrTextSize(str, size, &posR);
hangBelow = -posR.r_ybot;
/* figure out where the text will go, including a border on 1 side */
switch (pos) /* horizontal centering */
{
case GEO_NORTHWEST:
case GEO_WEST:
case GEO_SOUTHWEST:
xpos = p->p_x - TEXTOFFSET - posR.r_xtop;
break;
case GEO_NORTH:
case GEO_CENTER:
case GEO_SOUTH:
xpos = p->p_x - posR.r_xtop/2;
break;
case GEO_NORTHEAST:
case GEO_EAST:
case GEO_SOUTHEAST:
xpos = p->p_x + TEXTOFFSET;
break;
default:
TxError("Illegal position (%d) for text (internal error)\n",
pos);
return FALSE;
break;
}
switch (pos) /* vertical centering */
{
case GEO_NORTH:
case GEO_NORTHEAST:
case GEO_NORTHWEST:
ypos = p->p_y + TEXTOFFSET;
break;
case GEO_CENTER:
case GEO_WEST:
case GEO_EAST:
ypos = p->p_y - (posR.r_ytop / 2);
break;
case GEO_SOUTH:
case GEO_SOUTHEAST:
case GEO_SOUTHWEST:
ypos = p->p_y - posR.r_ytop - TEXTOFFSET;
break;
}
/* move area to screen coordinates */
posR.r_xbot += xpos;
posR.r_xtop += xpos;
posR.r_ybot += ypos;
posR.r_ytop += ypos;
/* will that area fit within the clipping rectangle? */
if ( (posR.r_xtop <= nClip.r_xtop) && (posR.r_xbot >= nClip.r_xbot) &&
(posR.r_ytop <= nClip.r_ytop) && (posR.r_ybot >= nClip.r_ybot) )
{
/* it fits! */
break;
}
/* it doesn't fit, will sliding it be enough? */
if (adjust)
{
if ( ((nClip.r_xtop-nClip.r_xbot) >= (posR.r_xtop - posR.r_xbot)) &&
((nClip.r_ytop - nClip.r_ybot) >= (posR.r_ytop - posR.r_ybot)) )
{
/* it will fit */
break;
}
}
/* Won't fit even with sliding, so shrink if possible. */
if (adjust && (size > 0) )
{
/* maybe shrinking it will help */
size -= 1;
}
else break;
} /* while */
/* ASSERTION: We've shrunk things to the proper size at this point. */
/* Slide the text, if that is allowable and needed. We'll only
* slide the text if there's available space on one side and
* insufficient space on the other.
*/
if (adjust)
{
int top, bottom, left, right; /* Space needed on each side. */
int slide;
right = posR.r_xtop - nClip.r_xtop;
left = nClip.r_xbot - posR.r_xbot;
top = posR.r_ytop - nClip.r_ytop;
bottom = nClip.r_ybot - posR.r_ybot;
slide = 0;
if (right > 0)
{
if (left < 0) slide = MAX(-right, left);
}
else if (left > 0) slide = MIN(left, -right);
posR.r_xbot += slide;
posR.r_xtop += slide;
slide = 0;
if (top > 0)
{
if (bottom < 0) slide = MAX(-top, bottom);
}
else if (bottom > 0) slide = MIN(bottom, -top);
posR.r_ybot += slide;
posR.r_ytop += slide;
}
/* ASSERTION: By now the text is positioned properly. */
/* do all clipping within the grPutTextPtr routine */
(*grSetCharSizePtr)(size);
if (style >= 0)
(*grSetWMandCPtr)(GrStyleTable[style].mask, GrStyleTable[style].color);
drawPoint.p_x = posR.r_xbot;
drawPoint.p_y = posR.r_ybot + hangBelow;
(*grPutTextPtr)(str, &drawPoint, &nClip, grCurObscure);
if (actual != (Rect *) NULL)
*actual = posR;
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* GrLabelSize --
*
* Determines the total size, in pixels, of a label.
* Used to compute how much to redisplay when a label changes.
*
* Results:
* None.
*
* Side effects:
* The parameter "area" is modified to contain the size, in pixels,
* of the given label, relative to its positioning point. This
* size includes just the text, and not any marker (e.g. cross
* displayed at the label position).
*
* ----------------------------------------------------------------------------
*/
void
GrLabelSize(text, pos, size, area)
char *text; /* Text of the label. */
int pos; /* Position of the label relative
* to its positioning point.
*/
int size; /* Text size. */
Rect *area; /* To be filled in with label size. */
{
int xoffset, yoffset; /* Offsets due to label position. */
GrTextSize(text, size, area);
/* Now we now the text's size... but if it's positioned to one
* side of the point, we have to offset it.
*/
switch (pos) /* Get x offset first. */
{
case GEO_NORTHWEST:
case GEO_WEST:
case GEO_SOUTHWEST:
xoffset = - TEXTOFFSET - area->r_xtop;
break;
case GEO_NORTH:
case GEO_CENTER:
case GEO_SOUTH:
xoffset = - area->r_xtop/2;
break;
case GEO_NORTHEAST:
case GEO_EAST:
case GEO_SOUTHEAST:
xoffset = TEXTOFFSET;
break;
}
switch (pos) /* Now get y offset. */
{
case GEO_NORTH:
case GEO_NORTHEAST:
case GEO_NORTHWEST:
yoffset = TEXTOFFSET;
break;
case GEO_CENTER:
case GEO_WEST:
case GEO_EAST:
yoffset = - area->r_ytop/2;
break;
case GEO_SOUTH:
case GEO_SOUTHEAST:
case GEO_SOUTHWEST:
yoffset = - area->r_ytop - TEXTOFFSET;
break;
}
area->r_xbot += xoffset;
area->r_xtop += xoffset;
area->r_ybot += yoffset;
area->r_ytop += yoffset;
}