Closed paynterf closed 3 years ago
@paynterf @mjs513 - I think it has a lot more to do with the character - than anything else.
That is if I strip your sketch down to just the drawing and a few things drawn, like:
/*
Name: Teensy_LCDClockV4.ino
Created: 3/9/2021 11:12:31 AM
Author: FRANKNEWXPS15\Frank
This project was cloned from Teensy_LCDClockV3 to re-investigate the use of proportional fonts
*/
#include <XPT2046_Touchscreen.h>
#include <ILI9341_t3n.h>
#include "CustomBox.h"
#include "ili9341_t3n_font_Arial.h"
#define N0_DIAGNOSTICS
//****************************************************************************
// Settings and objects
//****************************************************************************
#pragma region DISPLAY_PIN_ASSIGNMENTS
//02/15/21 pin assignments from https://www.pjrc.com/store/display_ili9341_touch.html
#define TFT_DC 9
#define TFT_CS 7
#define TFT_RST 8
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TOUCH_CS 6
#pragma endregion DISPLAY_PIN_ASSIGNMENTS
XPT2046_Touchscreen ts(TOUCH_CS);
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);
elapsedMillis mSecSinceLastClockUpdate;
const int CLOCK_UPDATE_MSEC = 1000;
#pragma region DISP_AND_ADJ_BOX_PARAMETERS
// Size of the color selection boxes and the paintbrush size
#define MAX_DISPLAY_X 240
#define MAX_DISPLAY_Y 320
#define SCREEN_ORIENTATION_1
#define TS_MINX 600
#define TS_MINY 600
#define TS_MAXX 3758
#define TS_MAXY 3612
const int PLUSBOX_X = 20;
const int PLUSBOX_Y = 180;
const int PLUSBOX_WIDTH = 50;
const int PLUSBOX_HEIGHT = 50;
const int PLUSBOX_COLOR = ILI9341_BLUE;
const int MINUSBOX_X = 120;
const int MINUSBOX_Y = 180;
const int MINUSBOX_WIDTH = 50;
const int MINUSBOX_HEIGHT = 50;
const int MINUSBOX_COLOR = ILI9341_YELLOW;
const String nextstr = "NEXT";
const int nextstr_width = 70;
const int nextstr_height = 20;
const int NEXTBOX_X = 220;
const int NEXTBOX_Y = 180;
const int NEXTBOX_COLOR = ILI9341_GREEN;
const int NEXTBOX_WIDTH = 100;
const int NEXTBOX_HEIGHT = 50;
CustomBox PlusBox(PLUSBOX_X, PLUSBOX_Y, PLUSBOX_WIDTH, PLUSBOX_HEIGHT, PLUSBOX_COLOR);
CustomBox MinusBox(MINUSBOX_X, MINUSBOX_Y, MINUSBOX_WIDTH, MINUSBOX_HEIGHT, MINUSBOX_COLOR);
CustomBox NextBox(NEXTBOX_X, NEXTBOX_Y, NEXTBOX_WIDTH, NEXTBOX_HEIGHT, NEXTBOX_COLOR);
CustomBox Plus2Box(PLUSBOX_X, PLUSBOX_Y-100, PLUSBOX_WIDTH, PLUSBOX_HEIGHT, PLUSBOX_COLOR);
CustomBox Minus2Box(MINUSBOX_X, MINUSBOX_Y-100, MINUSBOX_WIDTH, MINUSBOX_HEIGHT, MINUSBOX_COLOR);
void setup()
{
Serial.begin(9600);
delay(3000);
Serial.println("Teensy 3.2 TFT Clock Program");
#pragma region DISPLAY INITIALIZATION
Serial.println("Initializing TFT display");
tft.begin();
// Note: you can now set the SPI speed to any value
// the default value is 30Mhz, but most ILI9341 displays
// can handle at least 60Mhz and as much as 100Mhz
// tft.setClock(60000000);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_YELLOW);
tft.setTextSize(2);
tft.setRotation(1);
tft.setFont(Arial_40);
int16_t x1, y1, w, h;
tft.setCursor(50,20);
tft.getTextBounds("-", 50, 20, &x1, &y1, &w, &h);
tft.print("-");
tft.drawRect(x1, y1, w, h, ILI9341_RED);
tft.setCursor(100,20);
tft.getTextBounds("+", 100, 20, &x1, &y1, &w, &h);
tft.print("+");
tft.drawRect(x1, y1, w, h, ILI9341_RED);
tft.setCursor(150,20);
tft.getTextBounds("X", 150, 20, &x1, &y1, &w, &h);
tft.print("X");
tft.drawRect(x1, y1, w, h, ILI9341_RED);
PlusBox.Draw(&tft, '+', ILI9341_BLACK, Arial_40, true);
MinusBox.Draw(&tft, '-', ILI9341_BLACK, Arial_40, true);
NextBox.Draw(&tft, "NEXT", ILI9341_BLACK, Arial_20, true);
Plus2Box.Draw(&tft, "X", ILI9341_BLACK, Arial_40, true);
Minus2Box.Draw(&tft, "Z", ILI9341_BLACK, Arial_40, true);
}
void loop(void)
{
//Serial.printf("%lu: mSecSinceLastClockUpdate = %lu\n", millis(), (long int)mSecSinceLastClockUpdate);
}
As you can see the - does not draw in the rectangle returned, like the other two chars do:
Kurt,
Nice experiment! Any idea why the "-" character misbehaves like this?
TIA,
Frank
Kurt,
Hmm, I was able to center the '-' character by using the horizontal character extent, but ignoring the vertical extent, as shown in the code snippet below.
MinusBox.Draw(&tft);
Serial.printf("In ShowAdjButtons after MinuBox.Draw()\n");
int16_t x1 = 0;
int16_t y1 = 0;
uint16_t w = 0;
uint16_t h = 0;
tft.setFont(Arial_40);
tft.getTextBounds("-", MINUSBOX_X, MINUSBOX_Y, &x1, &y1, &w, &h);
Serial.printf("In ShowAdjButtons: getTextBounds shows %d,%d,%d,%d\n", x1, y1, w, h);
int chr_x = MINUSBOX_X + MINUSBOX_WIDTH / 2 - w / 2 ;
int chr_y = MINUSBOX_Y;
Serial.printf("Printing char at %d,%d\n", chr_x, chr_y);
tft.setCursor(chr_x, chr_y);
tft.setTextColor(ILI9341_BLACK);
tft.print("-");
Then I had a thought that maybe the '-' (dash, or minus) character may actually be the ' ' (underscore) character! This would explain the results we are seeing perfectly. Unfortunately when I actually replaced '-' with ' ' the displayed character was considerably lower and slightly more to the right - bummer!
So, there is still some unknown error in the getTextBounds() function that gets excited when dealing with a character with a very small vertical extent, but it may not be worth the time to figure it out. I can get what I want by using getTextBounds() manually as I did above ;-)
It's a mystery!
Frank
@paynterf @mjs513 Yes that may be true, that it is unclear if we should address it or not: I instrumented up the call to get the bounds
void ILI9341_t3n::charBounds(char c, int16_t *x, int16_t *y, int16_t *minx,
int16_t *miny, int16_t *maxx, int16_t *maxy) {
// BUGBUG:: Not handling offset/clip
if (font) {
if (c == '\n') { // Newline?
*x = 0; // Reset x to zero, advance y by one line
*y += font->line_space;
} else if (c != '\r') { // Not a carriage return; is normal char
uint32_t bitoffset;
const uint8_t *data;
if (c >= font->index1_first && c <= font->index1_last) {
bitoffset = c - font->index1_first;
bitoffset *= font->bits_index;
} else if (c >= font->index2_first && c <= font->index2_last) {
bitoffset =
c - font->index2_first + font->index1_last - font->index1_first + 1;
bitoffset *= font->bits_index;
} else if (font->unicode) {
return; // TODO: implement sparse unicode
} else {
return;
}
Serial.printf(" char = %c index = %d\n", c, fetchbits_unsigned(font->index,
bitoffset, font->bits_index));
data = font->data +
fetchbits_unsigned(font->index, bitoffset, font->bits_index);
uint32_t encoding = fetchbits_unsigned(data, 0, 3);
if (encoding != 0)
return;
uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
bitoffset = font->bits_width + 3;
uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
bitoffset += font->bits_height;
Serial.printf(" size = %d,%d\n", width, height);
Serial.printf(" line space = %d\n", font->line_space);
int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
bitoffset += font->bits_xoffset;
int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
bitoffset += font->bits_yoffset;
Serial.printf(" offsets = x:%d y:%d\n", xoffset, yoffset);
uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
bitoffset += font->bits_delta;
int16_t x1 = *x + xoffset, y1 = *y + yoffset, x2 = x1 + width,
y2 = y1 + height;
if (wrap && (x2 > _width)) {
*x = 0; // Reset x to zero, advance y by one line
*y += font->line_space;
x1 = *x + xoffset, y1 = *y + yoffset, x2 = x1 + width, y2 = y1 + height;
}
if (x1 < *minx)
*minx = x1;
if (y1 < *miny)
*miny = y1;
if (x2 > *maxx)
*maxx = x2;
if (y2 > *maxy)
*maxy = y2;
*x += delta; // ? guessing here...
}
}
Also output stuff in the function that called this:
while ((c = *str++)) {
charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
Serial.printf("%c %d %d - %d %d %d %d\n", c, x, y, minx, miny, maxx, maxy);
}
And debug output shows:
Teensy 3.2 TFT Clock Program
Initializing TFT display
char = - index = 837
size = 16,5
line space = 61
offsets = x:1 y:12
- 69 20 - 51 32 67 37
char = + index = 803
size = 27,27
line space = 61
offsets = x:3 y:6
+ 133 20 - 103 26 130 53
char = X index = 4921
size = 37,40
line space = 61
offsets = x:0 y:0
X 187 20 - 150 20 187 60
So my guess is that y size being much smaller than the line spacing is not properly handling the y offset... Will take a quick look to see what the difference in the handling of these values are versus when we actually draw the text with them.
Kurt, Yeah, I'm not sure it's "worth the candle" either, as it seems to only affect single characters with small vertical extents. FWIW, I manually centered the '+' and '-' signs on my boxes, using the following code:
void ShowAdjButtons()
{
Serial.printf("In ShowAdjButtons\n");
HideButtons();
//03/13/21 have to center plus (+) & minus sign (-) manually
//can't use getTextBounds() at all for '+' sign centering
PlusBox.Draw(&tft); //draw rectangle with no text
int chr_x = PLUSBOX_X + PLUSBOX_WIDTH / 2 - 16;
int chr_y = PLUSBOX_Y + PLUSBOX_HEIGHT / 2 - 20;
tft.setFont(Arial_40);
tft.setCursor(chr_x, chr_y);
tft.setTextColor(ILI9341_BLACK);
tft.print("+");
//for '-' sign, get text bounds, but ignore the vertical extent
MinusBox.Draw(&tft); //draw rectangle with no text
int16_t x1 = 0;
int16_t y1 = 0;
uint16_t w = 0;
uint16_t h = 0;
tft.setFont(Arial_40);
tft.getTextBounds("-", MINUSBOX_X, MINUSBOX_Y, &x1, &y1, &w, &h);
chr_x = MINUSBOX_X + MINUSBOX_WIDTH / 2 - w / 2 ;
chr_y = MINUSBOX_Y; //ignore getTextBounds() vertical extent
tft.setCursor(chr_x, chr_y);
tft.setTextColor(ILI9341_BLACK);
tft.print("-");
//03/13/21 centering feature works OK with regular text
NextBox.Draw(&tft, "NEXT", ILI9341_BLACK, Arial_20, true);
}
This resulted in the '+' & '-' signs being exactly (as closely as I could measure using a digital caliper) centered in my 9x9mm boxes. Interestingly enough, the vertical and horizontal extents reported by getTextExtents() for the '+' was 28x28, which should have meant that a negative offset of w/2 and h/2 from center should have put the '+' sign in the center of the box, but I actually needed a negative offset of 16 horizontally (2 more than it should have required) and 20 vertically (6 more than it should have required). For the '-' sign I used the horizontal extent w/o modification, and ignored the vertical extent entirely.
I think I pushed up a fix to this.
Let me know if works for you
WOW - Perfectly centered! You are a magician!
Frank
I have a clock project using the ILI9341 display, and I use the touch sensitive feature of the display to enable a 'clock setting' mode where the user has "+", "-", and "NEXT" buttons available to facilitate setting the time and date.
The "+", "-", and "NEXT" buttons are simple colored rectangles, with '+', '-' and 'NEXT' centered within the rectangles. However, I have found that even using the new centering version of the 'setCursor()' function, the single-character text isn't properly centered in the relevant rectangles, but the multi-character string "NEXT" does seem to be properly centered.
I have attached a photo showing the issue:
Here is the code used to produce this result (.ino file and required CustomBox.h)
And the required 'CustomBox.h' file: