Highly optimized ILI9341 (320x240 TFT color display) library

KurtE, et All:
Is there a function call to determine the font size (X,Y) in pixels of the ILI fonts? I am writing a Buttons class and have not been able to determine the actual size in pixels of the font Arial 16.

Thanks,
Ed
 
Is there a function call to determine the font size (X,Y) in pixels of the ILI fonts? I am writing a Buttons class and have not been able to determine the actual size in pixels of the font Arial 16.
As @thebigg mentioned, the Font is proportional.

You can however find out the size of a text string. That is, suppose your button has the text, "Ok"
you can do something like:
Code:
int16_t x, y;
uint16_t w, h;
getTextBounds("Ok", 0, 0, &x, &y, &w, &h);

The code says tell me the bounds of this text, if I start drawing it position 0, 0.
Note: the returned x and y, could be positive or negative. For example with some GFX fonts, they text will extend
beyond the actual bounds, of the start of where you started. The w, and h will also be filled in with the width and height
 
Kurt:
I tried using the getTextBounds() sub, but it does not work correctly on the RA8276 7" display.

Regards,
Ed
 
Kurt:
I tried using the getTextBounds() sub, but it does not work correctly on the RA8276 7" display.

Regards,
Ed
Which display? RA8276? Is that the RA8876? or something different? if RA8876 You might want to mention which library you are using...
 
Kurt:
Sorry for not being more specific.
I am using the RA8876 7 inch display using the only library I know of for that part:
"name": "Ra8876LiteTeensy",
"frameworks": "Arduino",
"platforms": "Teensy 3.6 - T4",
"keywords": "Ra8876_Lite",
"description": "wwatson Ra8876LiteTeensy Library",
"version": "1.0.0",
"authors":
{ "name": "Warren Watson",
"maintainer": true
}

Regards,
Ed
 
There is the other recent thread on the RA8876 where @wwatson and @mjs513 and I have been playing with a different
version of the library, which supports both parallel and SPI interfaces.

Which is now 3 libraries:
https://github.com/wwatson4506/TeensyRA8876-GFX-Common - common for both SPI and Parallel

To use with SPI: https://github.com/wwatson4506/TeensyRA8876-SPI

To use with Parallel 8080: https://github.com/wwatson4506/TeensyRA8876-SPI

Not sure if it has been fully tested on all of the different Teensy boards yet? But it is what I am playing with...
 
Kurt:
Yes, I have been watching the discussion going on in that thread, however I have not seen any mention of changes to the old existing code for SPI, this problem is very specific because it only applies to the size of characters using ILI9341 fonts which are proportional. I simply draw a box on the TFT and try to center a text string in the box, but when I ask for the x and y size using getTextBounds() it returns a bogus value for both x and y size.
The code looks like this:
Code:
tft.getTextBounds(newString[0], 0, 0, &_externalFontYPosition, &_externalFontXPosition, &_externalFontHeight, &_externalFontWidth);  // Need to switch X and Y as we are in Landscape mode.
_currentXCursorPosition = ( (uint16_t)(_XCenterPosition -  ( ( (_externalFontWidth - 6) * (_numberOfCharacters / 2.0f) ) ) ) );
_currentYCursorPosition = ( (uint16_t)(_YCenterPosition - ( ( _externalFontHeight / 2.0f ) *  _numberOfTextLines  ) ) );

Actually I watch all the threads on this forum multiple times a day.
 
Kurt:
Yes, I have been watching the discussion going on in that thread, however I have not seen any mention of changes to the old existing code for SPI, this problem is very specific because it only applies to the size of characters using ILI9341 fonts which are proportional. I simply draw a box on the TFT and try to center a text string in the box, but when I ask for the x and y size using getTextBounds() it returns a bogus value for both x and y size.
The code looks like this:
Code:
tft.getTextBounds(newString[0], 0, 0, &_externalFontYPosition, &_externalFontXPosition, &_externalFontHeight, &_externalFontWidth);  // Need to switch X and Y as we are in Landscape mode.
_currentXCursorPosition = ( (uint16_t)(_XCenterPosition -  ( ( (_externalFontWidth - 6) * (_numberOfCharacters / 2.0f) ) ) ) );
_currentYCursorPosition = ( (uint16_t)(_YCenterPosition - ( ( _externalFontHeight / 2.0f ) *  _numberOfTextLines  ) ) );

Actually I watch all the threads on this forum multiple times a day.
Which font and size are you using. Likewise rotation of screen.

we have example sketch with the different libraries that tries to display several fonts including showing bounding …
Example of text you are displaying...
IMG_0681.jpeg
 
Kurt:
I am using Arial 16, the rotation is like your picture accept rotated 180 degrees.
When the touch screen is touched, it displays a menu with 6 boxes spaced equidistant in two rows (2 rows of 3 rectangles). In each rectangle this is the text:
Set Time Preferences in box top left.
Set Rain Preferences in box top middle.
Set TempSensors Preferences in box top right.
TFT Settings in box bottom left.
Reset Master in box bottom middle.
Reset Slave in box bottom right.

Each group of characters is separated at the space to produce, for example in box top left 3 lines of text centered left to right.

I hope this info helps,
Ed
 
Something like this:
C++:
#include "Arduino.h"
#include <Adafruit_GFX.h>
#include <RA8876_t3.h>

// SPI hardware settings
#define USE_SPI  // Needed for writeRect() in RA8876_GFX
#define RA8876_CS 30
#define RA8876_RESET 28
#define BACKLITE 29  // Kurt's DB5 shield


RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET);  //Using standard SPI pins

#include <SPI.h>
#include "font_Arial.h"

uint8_t test_screen_rotation = 0;

void setup() {
    //I'm guessing most copies of this display are using external PWM
    //backlight control instead of the internal RA8876 PWM.
    //Connect a Teensy pin to pin 14 on the display.
    //Can use analogWrite() but I suggest you increase the PWM frequency first so it doesn't sing.
#if defined(BACKLITE)  // Defined in RA8876_Config.h.
    pinMode(BACKLITE, OUTPUT);
    digitalWrite(BACKLITE, HIGH);
#endif

    Serial.begin(115200);
    while (!Serial && millis() < 1000) {}  //wait for Serial Monitor

    tft.begin();  // default SPI clock speed is 30000000 MHz
#if defined(BACKLITE)
    tft.backlight(true);
    pinMode(BACKLITE, OUTPUT);
    digitalWrite(BACKLITE, HIGH);
#endif

    long unsigned debug_start = millis();
    while (!Serial && ((millis() - debug_start) <= 5000))
        ;
    Serial.println("Setup");
    tft.setRotation(2);
    tft.fillScreen(RED);
    delay(500);
    tft.fillScreen(GREEN);
    delay(500);
    tft.fillScreen(BLUE);
    delay(500);
    displayStuff();
}

uint8_t rotation = 2;
void loop() {
    nextPage();
    rotation = (rotation + 2) & 2;
    Serial.printf("Rotation = %u\n", rotation);
    tft.setRotation(rotation);
    tft.fillScreen(BLACK);
    displayStuff();
}



void displayStuff() {
    int16_t xT, yT;
    uint16_t wT, hT;

    tft.setTextColor(WHITE);
    tft.setFont(Arial_16);

    tft.getTextBounds("Set Time Preferences", 0, 0, &xT, &yT, &wT, &hT);
    int16_t xOrigin = 0;
    int16_t yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("Set Time Preferences");

    tft.getTextBounds("Set Rain Preferences", 0, 0, &xT, &yT, &wT, &hT);
    xOrigin = (tft.width() - (wT + 4)) / 2;
    yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("Set Rain Preferences");

    tft.getTextBounds("Set TempSensors Preferences", 0, 0, &xT, &yT, &wT, &hT);
    xOrigin = tft.width() - (wT + 4);
    yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("Set TempSensors Preferences");


    tft.getTextBounds("TFT Settings", 0, 0, &xT, &yT, &wT, &hT);
    xOrigin = 0;
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("TFT Settings");

    tft.getTextBounds("Reset Master", 0, 0, &xT, &yT, &wT, &hT);
    xOrigin = (tft.width() - (wT + 4)) / 2;
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("Reset Master");

    tft.getTextBounds("Reset Slave", 0, 0, &xT, &yT, &wT, &hT);
    xOrigin = tft.width() - (wT + 4);
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    tft.setCursor(xOrigin + 2 - xT, yOrigin + 2 - yT);
    tft.print("Reset Slave");
}



void nextPage() {
    Serial.println("Press anykey to continue");
    while (Serial.read() == -1)
        ;
    while (Serial.read() != -1)
        ;

    tft.fillScreen(BLACK);
    tft.setCursor(0, 0);
}

IMG_0686.jpeg


code is quick and dirty would not hard code strings like this…

EDIT: should mention if you try this, entering something in the keyboard monitor will alternate between rotation 0 and rotation 2...
 
Kurt:
Close, but no cigar. This is a button class that creates touch buttons.
It should look like this:
 

Attachments

  • Button Class.jpg
    Button Class.jpg
    337.8 KB · Views: 39
I am still having problems centering both horizontally and vertically.
What library are you using? Perhaps I am using a very old or out of date library.

Regards,
Ed
 
Here is the code in setup:
Code:
/// I'm guessing most copies of this display are using external PWM
    /// backlight control instead of the internal RA8876 PWM.
    /// Connect a Teensy pin to pin 14 on the display.
    /// Can use analogWrite() but I suggest you increase the PWM frequency first so it doesn't sing.
    pinMode(BACKLITE, OUTPUT);
    digitalWrite(BACKLITE, HIGH);

    #if defined(DEBUG)
        Serial.println(F("\nInitializing the TFT..."));
    #endif
    
    //    tft.begin(20000000);
    if (!tft.begin(20000000UL))  // Set the SPI speed to 20MHz.
        {
            #if defined(DEBUG)
                Serial.println(F("- TFT Inialization failed, setting noTFT = true"));
            #endif
            noTFT = true;
            
        }
    else
        {
            noTFT = false;  // TFT is present.
        }

    #if defined(DEBUG)
        Serial.println(F("- Setting up the graphic Mode, the Font, text color, and rotation of the screen..."));
    #endif

    tft.graphicMode(true);
    tft.setTextCursor(0,0);
    //tft.setFontSize(2);  // Set internal font size to 2 (16W x 32H)
    tft.setFont(Arial_16);
    externalFont = true;
    externalFontWidth = 16;
    externalFontHeight = 32;

    tft.setTextColor( WHITE);
  
    tft.setRotation(0);
    w = tft.width() - 1;
    h = tft.height() - 1;
    fontXsize = tft.getFontWidth();  // This only works on the internal font.
    fontYsize = tft.getFontHeight();  // This only works on the internal font.

    #if defined(DEBUG)
        Serial.printf("- TFT Screen Width is: %d\n", w);
        Serial.printf("- TFT Screen Height is: %d\n", h);
        Serial.println(F("- The Font is Arial_16..."));
        Serial.printf("- TFT The internal Font Width is: %u\n", tft.getFontWidth());  // This only works on the internal font.
        Serial.printf("- TFT The internal Font Height is: %u\n", tft.getFontHeight());  // This only works on the internal font.
        Serial.printf("");
        
        Serial.printf("- TFT The External font Width is: %d\n", externalFontWidth);  // This only works on the internal font.
        Serial.printf("- TFT The External Font Height is: %d\n", externalFontHeight);  // This only works on the internal font.
    #endif

    #if defined(DEBUG)
        Serial.println(F("- Filling the TFT screen with all black (clear screen)..."));
    #endif

    tft.fillScreen(BLACK);

I have not finished with the button class, I still have a lot of work to do, but the RoundRectangle is sort of working except for the centering of the text in the box.
Attached is the button class:
 

Attachments

  • Buttons.cpp
    149.6 KB · Views: 38
  • Buttons.h
    51.6 KB · Views: 37
No clue if this sketch is correct but this is what I came up with for a rounded rect:

Code:
#include "Arduino.h"
#include <Adafruit_GFX.h>
#include <RA8876_t3.h>
#include "Buttons.h"

RA8876_t3 tft = RA8876_t3(10, 8); //Using standard SPI pins

#include "font_Arial.h"
#include "font_ArialBold.h"

#define DEBUG
boolean noTFT, externalFont;
uint16_t externalFontWidth, externalFontHeight, w, h, fontXsize,fontYsize;

char p[] = "TEST";
RndRectangle Rrect(p, 12, true, WHITE, 1, 100, 100, 200, 100, 20, 20, BLUE, RED);

void setup() {

  Serial.begin(115200);
  while (!Serial && millis() < 1000) {} //wait for Serial Monitor

#if defined(USE_SPI_47000000)
  tft.begin(47000000); // Max is 47000000 MHz (using short 3" wires)
#else
  tft.begin(); // default SPI clock speed is 30000000 MHz
#endif
/// I'm guessing most copies of this display are using external PWM
    /// backlight control instead of the internal RA8876 PWM.
    /// Connect a Teensy pin to pin 14 on the display.
    /// Can use analogWrite() but I suggest you increase the PWM frequency first so it doesn't sing.
    //pinMode(BACKLITE, OUTPUT);
    //digitalWrite(BACKLITE, HIGH);

    #if defined(DEBUG)
        Serial.println(F("\nInitializing the TFT..."));
    #endif
   
    //    tft.begin(20000000);
    if (!tft.begin(20000000UL))  // Set the SPI speed to 20MHz.
        {
            #if defined(DEBUG)
                Serial.println(F("- TFT Inialization failed, setting noTFT = true"));
            #endif
            noTFT = true;
           
        }
    else
        {
            noTFT = false;  // TFT is present.
        }

    #if defined(DEBUG)
        Serial.println(F("- Setting up the graphic Mode, the Font, text color, and rotation of the screen..."));
    #endif

    tft.graphicMode(true);
    tft.setTextCursor(0,0);
    //tft.setFontSize(2);  // Set internal font size to 2 (16W x 32H)
    tft.setFont(Arial_16);
    externalFont = true;
    externalFontWidth = 16;
    externalFontHeight = 32;

    tft.setTextColor( WHITE);
 
    tft.setRotation(0);
    w = tft.width() - 1;
    h = tft.height() - 1;
    fontXsize = tft.getFontWidth();  // This only works on the internal font.
    fontYsize = tft.getFontHeight();  // This only works on the internal font.

    #if defined(DEBUG)
        Serial.printf("- TFT Screen Width is: %d\n", w);
        Serial.printf("- TFT Screen Height is: %d\n", h);
        Serial.println(F("- The Font is Arial_16..."));
        Serial.printf("- TFT The internal Font Width is: %u\n", tft.getFontWidth());  // This only works on the internal font.
        Serial.printf("- TFT The internal Font Height is: %u\n", tft.getFontHeight());  // This only works on the internal font.
        Serial.printf("");
       
        Serial.printf("- TFT The External font Width is: %d\n", externalFontWidth);  // This only works on the internal font.
        Serial.printf("- TFT The External Font Height is: %d\n", externalFontHeight);  // This only works on the internal font.
    #endif

    #if defined(DEBUG)
        Serial.println(F("- Filling the TFT screen with all black (clear screen)..."));
    #endif

    tft.fillScreen(BLACK);

    //RndRectangle(p, 12, 100, 100, true, WHITE, 1, 200, 100, 10, 10, BLACK, RED);
    Rrect.draw();
}

void loop() {
  // put your main code here, to run repeatedly:

}

Always better to start with 1 to debug. This is the output:

Code:
Initializing the TFT...
- Setting up the graphic Mode, the Font, text color, and rotation of the screen...
- TFT Screen Width is: 1023
- TFT Screen Height is: 599
- The Font is Arial_16...
- TFT The internal Font Width is: 8
- TFT The internal Font Height is: 16
- TFT The External font Width is: 16
- TFT The External Font Height is: 32
- Filling the TFT screen with all black (clear screen)...
 ----- RndRectangle::draw function ****************************** Begin RndRectangle Draw ***********************************

 ----- The is the X-Y Position of the RndRectangle to be drawn: 100, 100
 ----- The is the Width & Height of the RndRectangle to be drawn: 200, 100
 ----- The is the xradius, and yradius of the RndRectangle corners to be drawn: 20, 20
 ----- The is the border color of the RndRectangle to be drawn: F800
 ----- The is the fill color of the RndRectangle to be drawn: 1F
 ----- The is the text color of the Rectangle to be drawn: FFFF
 ----- This is the number of lines of Text to be drawn in the Rectangle Vertically: 1
 ----- This is the size of the character array to be drawn in the Rectangle: 4
 ----- This is the Text to be drawn in the Button: TEST

 ----- RndRectangle::draw function - Filling RndRectangle...
 ----- RndRectangle::draw function - Drawing RndRectangle with colored border...
 ----- RndRectangle::draw function - Do You see a colored round rectangle border on the TFT?, Waiting for you to touch any key...
 ----- RndRectangle::draw function - Begin drawing the text in the Button...

 ----- RndRectangle::draw function ...
 ----- _XCenterPosition: 200
 ----- _YCenterPosition: 150

 ----- Now checking for the number of lines of text: 1


 ----- RndRectangle::draw function - External Font in Use...
 ----- This is the returned data from getTextBounds, _externalFontXPosition: 0, _externalFontYPosition: 0
 ----- This is the _XCenterPosition: 200, This is the _ExternalfontWidth: 0, This is the _numberOfCharacters: 4
 ----- This is quotient of (uint16_t)( ( _ExternalfontWidth * (_numberOfCharacters / 2) ) ): 0
 ----- This is the _YCenterPosition: 150, This is the _ExternalfontHeight: 0, This is the _numberOfCharacters: 1
 ----- This is quotient of (uint16_t)( ( (_externalFontHeight / 2 ) * _numberOfTextLines ): 0
 ----- This is the Calculated X cursor position: 212 , This is the Calculated Y cursor Position: 150
 ----- RndRectangle::draw function - Do You see the text in the colored round rectangle on the TFT?, Waiting for you to touch any key...
 ----- ****************************** End of RndRectangle Draw ***********************************

With the following screen image:
IMG_1419.png


Not sure yet if issue is with textbounds or the draw code - have to debug in the morning. A couple of things that I notice is that (1) you don't get a complete rnd rect fill and (2) the centering looks like its in the right half of the rnd rect? Its late now so tomorrow hopefully.

EDIT: Here is the whole sketch if interested
 

Attachments

  • Buttons_class_debug-240804a.zip
    20.8 KB · Views: 36
@sbfreddie
Been playing with your button class and beginning to understand what you did. I have been primarily looking at Single Line of text for the rnd rectange.

A couple of things I noticed is that you shouldnt have to swap x,y since its already done for you. Also, when you call
Code:
getTextBounds
you aren't getting the fontwidth/fonthHeight you are the the width and height of the string. So for the case of
Code:
if (_numberOfTextLines == 1 )
the code should be changed to:
Code:
                else 
                    {  /// TODO: Fix this to include the amout of offset returned from the externalfontXPosition, and the externalFontYPosition.
                        tft.getTextBounds(_text, 0, 0, &_externalFontXPosition, &_externalFontYPosition, &_externalFontWidth, &_externalFontHeight);  // Need to switch X and Y as we are in Landscape mode.
                        _currentXCursorPosition = ( (uint16_t)(_XCenterPosition  ) - (_externalFontWidth / 2 ) );
                        _currentYCursorPosition = ( (uint16_t)(_YCenterPosition - ( ( _externalFontHeight / 2 ) ) ) );

                        #if defined(DEBUG_RNDRECTANGLE_DRAW)
                            Serial.println(F("\n ----- RndRectangle::draw function - External Font in Use..."));
                            Serial.printf(" ----- This is the returned data from getTextBounds, _externalFontXPosition: %d, _externalFontYPosition: %d\n", _externalFontXPosition, _externalFontYPosition);
                            Serial.printf(" ----- This is the _XCenterPosition: %d, This is the _ExternalfontWidth: %d, This is the _numberOfCharacters: %d\n", _XCenterPosition, _externalFontWidth, _numberOfCharacters);
                            Serial.printf(" ----- This is quotient of (uint16_t)( ( _ExternalfontWidth * (_numberOfCharacters / 2) ) ): %d\n", ((uint16_t)( ( (_externalFontWidth / 2) * _numberOfCharacters ) )));
                            Serial.printf(" ----- This is the _YCenterPosition: %d, This is the _ExternalfontHeight: %d, This is the _numberOfCharacters: %d\n", _YCenterPosition, _externalFontHeight, _numberOfTextLines);
                            Serial.printf(" ----- This is quotient of (uint16_t)( ( (_externalFontHeight / 2 ) * _numberOfTextLines ): %d\n", ((uint16_t)( ( (_externalFontHeight / 2) * _numberOfTextLines ) )));
                            Serial.printf(" ----- This is the Calculated X cursor position: %d , This is the Calculated Y cursor Position: %d\n", _currentXCursorPosition, _currentYCursorPosition);
                        #endif
                    }

Also note in the line for getTextBounds you were telling it get the string length of newString[0] which is null in case so I changed it to _text. Doing this gives an output of:
Code:
----- RndRectangle::draw function - External Font in Use...
 ----- This is the returned data from getTextBounds, _externalFontXPosition: 1, _externalFontYPosition: 0
 ----- This is the _XCenterPosition: 200, This is the _ExternalfontWidth: 210, This is the _numberOfCharacters: 20
 ----- This is quotient of (uint16_t)( ( _ExternalfontWidth * (_numberOfCharacters / 2) ) ): 2100
 ----- This is the _YCenterPosition: 150, This is the _ExternalfontHeight: 17, This is the _numberOfCharacters: 1
 ----- This is quotient of (uint16_t)( ( (_externalFontHeight / 2 ) * _numberOfTextLines ): 8
 ----- This is the Calculated X cursor position: 95 , This is the Calculated Y cursor Position: 142

with the corressponding image of:
IMG_1420.png
 
Here is a real hacked up version of my earlier sketch:
C++:
#include "Arduino.h"
#include <Adafruit_GFX.h>
#include <RA8876_t3.h>

// SPI hardware settings
#define USE_SPI  // Needed for writeRect() in RA8876_GFX
#define RA8876_CS 30
#define RA8876_RESET 28
#define BACKLITE 29  // Kurt's DB5 shield


RA8876_t3 tft = RA8876_t3(RA8876_CS, RA8876_RESET);  //Using standard SPI pins

#include <SPI.h>
#include "font_Arial.h"

uint8_t test_screen_rotation = 0;

void setup() {
    //I'm guessing most copies of this display are using external PWM
    //backlight control instead of the internal RA8876 PWM.
    //Connect a Teensy pin to pin 14 on the display.
    //Can use analogWrite() but I suggest you increase the PWM frequency first so it doesn't sing.
#if defined(BACKLITE)  // Defined in RA8876_Config.h.
    pinMode(BACKLITE, OUTPUT);
    digitalWrite(BACKLITE, HIGH);
#endif

    Serial.begin(115200);
    while (!Serial && millis() < 1000) {}  //wait for Serial Monitor

    tft.begin();  // default SPI clock speed is 30000000 MHz
#if defined(BACKLITE)
    tft.backlight(true);
    pinMode(BACKLITE, OUTPUT);
    digitalWrite(BACKLITE, HIGH);
#endif

    long unsigned debug_start = millis();
    while (!Serial && ((millis() - debug_start) <= 5000))
        ;
    Serial.println("Setup");
    tft.setRotation(2);
    tft.fillScreen(RED);
    delay(500);
    tft.fillScreen(GREEN);
    delay(500);
    tft.fillScreen(BLUE);
    delay(500);
    displayStuff(&Arial_16);
}

uint8_t rotation = 2;
void loop() {
    nextPage();
    rotation = (rotation + 2) & 2;
    Serial.printf("Rotation = %u\n", rotation);
    tft.setRotation(rotation);
    tft.fillScreen(BLACK);
    displayStuff(&Arial_16);
}


void getCenteredTextBounds(const char *label, const ILI9341_t3_font_t *font, int16_t &xMin, int16_t &yMin, uint16_t &width, uint16_t &height) {
    xMin = 0;
    yMin = 0;
    width = 0;
    height = 0;
    const char *szStart = label;
    const char *sz = label;

    int16_t x, y;
    uint16_t w, h;

    for (;;) {
        while ((*sz != ' ') && (*sz != 0)) sz++;
        tft.getTextBounds((const uint8_t *)szStart, (uint16_t)(sz - szStart), 0, height, &x, &y, &w, &h);
        if (x < xMin) xMin = x;
        if (w > width) width = w;

        if (height == 0) yMin = y;
        if (*sz == 0) {
            height += h;
            break;
        }
        height += font->line_space;
        sz++;
        szStart = sz;
    }
}

void drawCenteredTextLines(const char *label, const ILI9341_t3_font_t *font, int16_t xb, int16_t yb, uint16_t wb, uint16_t hb) {
    const char *szStart = label;
    const char *sz = label;

    int16_t x, y;
    uint16_t w, h;

    for (;;) {
        while ((*sz != ' ') && (*sz != 0)) sz++;
        tft.getTextBounds((const uint8_t *)szStart, (uint16_t)(sz - szStart), 0, 0, &x, &y, &w, &h);
        tft.setCursor(xb + (wb - w) / 2, yb);
        tft.write(szStart, (uint16_t)(sz - szStart));
        if (*sz == 0) {
            break;
        }
        yb += font->line_space;
        sz++;
        szStart = sz;
    }
}


void displayStuff(const ILI9341_t3_font_t *font) {
    int16_t xT, yT;
    uint16_t wT, hT;

    tft.setTextColor(WHITE);
    tft.setFont(*font);

    const char *szTitle = "Set Time Preferences";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    int16_t xOrigin = 0;
    int16_t yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);

    szTitle = "Set Rain Preferences";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    xOrigin = (tft.width() - (wT + 4)) / 2;
    yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);

    szTitle = "Set TempSensors Preferences";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    xOrigin = tft.width() - (wT + 4);
    yOrigin = 0;
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);


    szTitle = "TFT Settings";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    xOrigin = 0;
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);

    szTitle = "Reset Master";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    xOrigin = (tft.width() - (wT + 4)) / 2;
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);

    szTitle = "Reset Slave";
    getCenteredTextBounds(szTitle, font, xT, yT, wT, hT);
    xOrigin = tft.width() - (wT + 4);
    yOrigin = tft.height() - (hT + 4);
    Serial.printf("TB: %d, %d, %u %, %d %d\n", xT, yT, wT, hT, xOrigin, yOrigin);
    tft.drawRect(xOrigin, yOrigin, wT + 4, hT + 4, RED);
    drawCenteredTextLines(szTitle, font, xOrigin + 2, yOrigin + 2, wT - 4, yT - 4);
}



void nextPage() {
    Serial.println("Press anykey to continue");
    while (Serial.read() == -1)
        ;
    while (Serial.read() != -1)
        ;

    tft.fillScreen(BLACK);
    tft.setCursor(0, 0);
}

IMG_0688.jpeg
 
Ok last update.
Note to get Font Size you would use getFontHeight and getFontWidth. But besides that I changed your multiline code to read:

Code:
                            {   // TODO: Fix this to include the amout of offset returned from the externalfontXPosition, and the externalFontYPosition.
                                tft.getTextBounds(newString[0], 0, 0, &_externalFontXPosition, &_externalFontYPosition, &_externalFontWidth, &_externalFontHeight);  // Need to switch X and Y as we are in Landscape mode.
                                _currentXCursorPosition =  (uint16_t)((float)_XCenterPosition - ( ((float)(_numberOfCharacters  * tft.getFontWidth() / 2.0f ) + 6 ) ) );
                                _currentYCursorPosition = ( (uint16_t)((float)_YCenterPosition - ( ( (float)_externalFontHeight / 2.0f ) * (float)_numberOfTextLines ) ) + ((float)_externalFontHeight * i) );
and seems to work better.

heres the whole sketch. THink you can take it from here:
 

Attachments

  • Buttons_class_debug-240805a.zip
    20.8 KB · Views: 34
Back
Top