Added getTextBounds() optional arguments xF and yF, with extensive comments in .cpp file.

This commit is contained in:
Ted Toal 2023-07-05 15:32:02 -07:00
parent 15ebe114c4
commit 982d028ce3
2 changed files with 113 additions and 35 deletions

View File

@ -1356,9 +1356,9 @@ void Adafruit_GFX::setFont(const GFXfont *f) {
Broke this out as it's used by both the PROGMEM- and RAM-resident
getTextBounds() functions.
@param c The ASCII character in question
@param x Pointer to x location of character. Value is modified by
@param x Pointer to x cursor position of character. Value is modified by
this function to advance to next character.
@param y Pointer to y location of character. Value is modified by
@param y Pointer to y cursor position of character. Value is modified by
this function to advance to next character.
@param minx Pointer to minimum X coordinate, passed in to AND returned
by this function -- this is used to incrementally build a
@ -1435,26 +1435,86 @@ void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
/**************************************************************************/
/*!
@brief Helper to determine size of a string with current font/size.
Pass string and a cursor position, returns UL corner and W,H.
@param str The ASCII string to measure
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, returned by function
@param y1 The boundary Y coordinate, returned by function
@param w The boundary width, returned by function
@param h The boundary height, returned by function
Pass string and a cursor position, returns UL corner, baseline Y,
and W,H.
@param str ASCII string to measure
@param x Starting cursor X (left side, first character)
@param y Starting cursor Y (on baseline, first character)
@param xL Left text boundary X coordinate, returned by function
@param yT Top text boundary Y coordinate, returned by function
@param w Text boundary width, returned by function
@param h Text boundary height, returned by function
@param xF Ending cursor X (right side of baseline, last char), if not NULL
@param yF Ending cursor Y (on baseline, last char), returned if not NULL
@notes The values of (x, y) on call to this function actually don't
matter to it; they are simply incremented past the string
bounds. However, they COULD BE the CURSOR POSITION used in a
call to setCursor(). More often, the reason for calling this
function is to get the text size so that the starting cursor
position can be adjusted (e.g. for center alignment), so the
cursor position is unknown when this function is called, and
(x, y) can really just be arbitrary values.
Since the returned (xL, yT) values are the coords of the upper
left corner of the text boundary box, then the correct CURSOR
position to use with setCursor() when printing the text, if
the upper-left corner of the text is to be at position (X1,Y1)
(which may or may not equal the (x, y) arguments to this
function), is:
(X1+x-xL, Y1+y-yT)
Suppose (x, y) are indeed set to (X1, Y1) when calling this
function. In that case (x-XL) and (y-yT) will evaluate to a
small positive or negative integer, possibly 0 but not always
0, and adding that small integer to X1 and Y1 will move them
slightly so they can be used in a call to setCursor(). The
cursor position is NOT the upper-left corner of the next
character to be printed. Rather, it is a position on the TEXT
BASELINE (bottom of characters that don't have descenders on
them), used to align the character font data. (y-yT) will
almost always be a positive value that is the distance from
the top of the text (yT) to the text baseline. Note that the
text baseline is NOT Y1+h, because h includes the full string
height including descenders on characters.
If instead of the above setting, the cursor position for
displaying the string is set to (X1, Y1+h), the text will be
shifted left or right slightly when the first character starts
slightly left or right of the cursor position (which some
characters do), and the text will be shifted up if it contains
any characters with descenders that extend below the baseline.
The optional arguments xF and yF provide a way to discover
where to start adding more characters after the string, if
desired. The final cursor position is returned in (xF, yF).
This is NOT the same as (xL+w, yT+h). Instead, XF might be
slightly more or less than that, while yF is probably the same
as the y value given at the start (unless there was text
wrapping). The final CURSOR position to use to print additional
text after the string, if the upper-left corner of the text is
at position (X1, Y1), is:
(X1+xF-xL, Y1+yF-yT)
The position of the lower-right corner of the bounding box,
(X2, Y2), is of course:
(X1+w, Y1+h)
If another character is printed after the string, using the
starting cursor position (X1+xF-xL, Y1+yF-yT), and that new
character has top-left bound box offset (dX, dY) and width
W and height H, then the new lower-right corner of the bounding
box (X2, Y2) is:
(X1+xF-xL+dX+W, Y1+yF-yT+max(0, dY+H))
and so the new total text string width and height are:
new w = xF-xL+dX+W = new X2 - X1
new h = yF-yT+max(0, dY+H) = new Y2 - Y1
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w,
uint16_t *h) {
int16_t *xL, int16_t *yT,
uint16_t *w, uint16_t *h,
int16_t *xF, int16_t *yF) {
uint8_t c; // Current character
int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect
// Bound rect is intentionally initialized inverted, so 1st char sets it
*x1 = x; // Initial position is value passed in
*y1 = y;
*xL = x; // This initialization SHOULD be overwritten below after charBounds()
*yT = y; // is called. (Unless string is empty).
*w = *h = 0; // Initial size is zero
while ((c = *str++)) {
@ -1464,13 +1524,20 @@ void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
}
if (maxx >= minx) { // If legit string bounds were found...
*x1 = minx; // Update x1 to least X coord,
*xL = minx; // Update xL to least X coord,
*w = maxx - minx + 1; // And w to bound rect width
}
if (maxy >= miny) { // Same for height
*y1 = miny;
if (maxy >= miny) { // Same for height as for width
*yT = miny;
*h = maxy - miny + 1;
}
// If xF and yF arguments provided, return final cursor x and y position.
if (xF != NULL)
*xF = x;
if (yF != NULL)
*yF = y;
}
/**************************************************************************/
@ -1480,17 +1547,18 @@ void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
@param str The ascii string to measure (as an arduino String() class)
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param xL The left boundary X coordinate, set by function
@param yT The top boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w,
uint16_t *h) {
int16_t *xL, int16_t *yT,
uint16_t *w, uint16_t *h,
int16_t *xF, int16_t *yF) {
if (str.length() != 0) {
getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
getTextBounds(const_cast<char *>(str.c_str()), x, y, xL, yT, w, h, xF, yF);
}
}
@ -1501,19 +1569,20 @@ void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
@param str The flash-memory ascii string to measure
@param x The current cursor X
@param y The current cursor Y
@param x1 The boundary X coordinate, set by function
@param y1 The boundary Y coordinate, set by function
@param xL The left boundary X coordinate, set by function
@param yT The top boundary Y coordinate, set by function
@param w The boundary width, set by function
@param h The boundary height, set by function
*/
/**************************************************************************/
void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x,
int16_t y, int16_t *x1, int16_t *y1,
uint16_t *w, uint16_t *h) {
int16_t y, int16_t *xL, int16_t *yT,
uint16_t *w, uint16_t *h,
int16_t *xF, int16_t *yF) {
uint8_t *s = (uint8_t *)str, c;
*x1 = x;
*y1 = y;
*xL = x;
*yT = y;
*w = *h = 0;
int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
@ -1522,13 +1591,19 @@ void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x,
charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
if (maxx >= minx) {
*x1 = minx;
*xL = minx;
*w = maxx - minx + 1;
}
if (maxy >= miny) {
*y1 = miny;
*yT = miny;
*h = maxy - miny + 1;
}
// If xF and yF arguments provided, return final cursor x and y position.
if (xF != NULL)
*xF = x;
if (yF != NULL)
*yF = y;
}
/**************************************************************************/

View File

@ -111,12 +111,15 @@ public:
uint16_t bg, uint8_t size);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size_x, uint8_t size_y);
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const char *string, int16_t x, int16_t y,
int16_t *xL, int16_t *yT, uint16_t *w, uint16_t *h,
int16_t *xF=NULL, int16_t *yF=NULL);
void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1,
int16_t *y1, uint16_t *w, uint16_t *h);
int16_t *xL, int16_t *yT, uint16_t *w, uint16_t *h,
int16_t *xF=NULL, int16_t *yF=NULL);
void getTextBounds(const String &str, int16_t x, int16_t y,
int16_t *xL, int16_t *yT, uint16_t *w, uint16_t *h,
int16_t *xF=NULL, int16_t *yF=NULL);
void setTextSize(uint8_t s);
void setTextSize(uint8_t sx, uint8_t sy);
void setFont(const GFXfont *f = NULL);