Skip to content

Instantly share code, notes, and snippets.

@alvesvaren
Created January 29, 2024 13:36
Show Gist options
  • Save alvesvaren/767d9585f0ecbef18ef1c7c0492c4332 to your computer and use it in GitHub Desktop.
Save alvesvaren/767d9585f0ecbef18ef1c7c0492c4332 to your computer and use it in GitHub Desktop.
Text wrapping for the esphome display api
#include <vector>
#include <string>
#include <sstream>
#include "esphome/components/display/display_buffer.h"
#include "text_wrap.h"
using namespace esphome;
using namespace esphome::display;
void wrap_text(DisplayBuffer* it, int x, int y, const char* text, Font* font, TextAlign align, float line_height) {
// Calculate the bounds of a single space character
int space_x1, space_y1, space_width, space_height;
it->get_text_bounds(x, y, " ", font, align, &space_x1, &space_y1, &space_width, &space_height);
// Break text into words
std::vector<std::string> words;
std::stringstream ss(text);
std::string word;
while (std::getline(ss, word, ' ')) {
words.push_back(word);
}
// Initialize variables for the wrapped text
int line_x = x;
int line_y = y;
int word_x1, word_y1, word_width, word_height;
std::string line;
// Iterate through the words and wrap them
for (const auto& w : words) {
it->get_text_bounds(line_x, line_y, w.c_str(), font, align, &word_x1, &word_y1, &word_width, &word_height);
if (line_x + word_width >= it->get_width()) {
// Print the current line and move to the next line
it->printf(x, line_y, font, align, "%s", line.c_str());
line_y += static_cast<int>(word_height * line_height);
line_x = x;
// Clear the line buffer
line.clear();
}
// Add the word to the line buffer and move the cursor
line += w;
line_x += word_width + space_width;
// If it's not the last word, add a space
if (!line.empty() && &w != &words.back()) {
line += " ";
}
}
// Print the last line
if (!line.empty()) {
it->printf(x, line_y, font, align, "%s", line.c_str());
}
}
#pragma once
#include "esphome/components/display/display_buffer.h"
void wrap_text(
esphome::display::DisplayBuffer* it, int x, int y,
const char* text, esphome::display::Font* font,
esphome::display::TextAlign align, float line_height
);
@alvesvaren
Copy link
Author

Put the files in the esphome folder of your home assistant configuration.

Usage in yaml:

esphome:
  # ...
  includes:
    - text_wrap.h
    - text_wrap.cpp


display:
  - platform: waveshare_epaper  # or any other display platform
    # ...
    lambda: |-
      wrap_text(&it, 8, 80, "Long text here that needs wrapping", id(fontId), TextAlign::TOP_LEFT, 1);

@azcoov
Copy link

azcoov commented Jun 5, 2024

Thanks for this, it was very helpful. I had an urgent priority to add dad jokes to my e-paper display, least I die of boredom.

Note, I had to add #include esphome/components/font/font.h to text_wrap.cpp because it would error out on lack of reference to Font. I also needed to change Font* font to esphome::display::BaseFont* font on the wrap_text function for the same reason.

Perhaps you have a reference to Font somewhere else in your ESPHome config?

Anyway, it works like a charm! Thanks again.

@davet2001
Copy link

This is great @alvesvaren. I have built on what you wrote, to make a printf format compatible version, that also allows you to specify a box anywhere on the screen (not just wrapping at the screen edge). Would you be willing for this to be added to the official esphome distribution?

If so, I am happy to create the pull request.

@alvesvaren
Copy link
Author

@davet2001 Sure, go for it! I just put this together pretty quickly for a project I had but it would be great to have it in esphome directly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment