mirror of
https://github.com/esphome/esphome.git
synced 2024-12-12 08:24:55 +01:00
Add support for Text Run Panel grabbing run text from a Sensor or Text Sensor
This commit is contained in:
parent
4e37a09310
commit
c5ed675be5
3 changed files with 134 additions and 22 deletions
|
@ -19,8 +19,8 @@ void TextRunPanel::dump_config(int indent_depth, int additional_level_depth) {
|
||||||
ESP_LOGCONFIG(TAG, "%*sText Align: %s", indent_depth, "",
|
ESP_LOGCONFIG(TAG, "%*sText Align: %s", indent_depth, "",
|
||||||
LOG_STR_ARG(display::text_align_to_string(this->text_align_)));
|
LOG_STR_ARG(display::text_align_to_string(this->text_align_)));
|
||||||
ESP_LOGCONFIG(TAG, "%*sText Runs: %i", indent_depth, "", this->text_runs_.size());
|
ESP_LOGCONFIG(TAG, "%*sText Runs: %i", indent_depth, "", this->text_runs_.size());
|
||||||
for (TextRun *run : this->text_runs_) {
|
for (TextRunBase *run : this->text_runs_) {
|
||||||
std::string text = run->text_.value();
|
std::string text = run->get_text();
|
||||||
ESP_LOGCONFIG(TAG, "%*sText: %s", indent_depth + additional_level_depth, "", text.c_str());
|
ESP_LOGCONFIG(TAG, "%*sText: %s", indent_depth + additional_level_depth, "", text.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,12 +72,12 @@ CalculatedLayout TextRunPanel::determine_layout(display::Display *display, displ
|
||||||
int widest_line = 0;
|
int widest_line = 0;
|
||||||
int line_number = 0;
|
int line_number = 0;
|
||||||
|
|
||||||
for (TextRun *run : this->text_runs_) {
|
for (TextRunBase *run : this->text_runs_) {
|
||||||
int x1;
|
int x1;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int baseline;
|
int baseline;
|
||||||
std::string text = run->text_.value();
|
std::string text = run->get_text();
|
||||||
|
|
||||||
run->font_->measure(text.c_str(), &width, &x1, &baseline, &height);
|
run->font_->measure(text.c_str(), &width, &x1, &baseline, &height);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "esphome/components/graphical_layout/graphical_layout.h"
|
#include "esphome/components/graphical_layout/graphical_layout.h"
|
||||||
#include "esphome/components/font/font.h"
|
#include "esphome/components/font/font.h"
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/text_sensor/text_sensor.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace graphical_layout {
|
namespace graphical_layout {
|
||||||
|
@ -25,25 +29,85 @@ struct CanWrapAtCharacterArguments {
|
||||||
char character;
|
char character;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextRun {
|
class TextRunBase {
|
||||||
public:
|
public:
|
||||||
TextRun(TemplatableValue<std::string> text, display::BaseFont *font) {
|
TextRunBase(display::BaseFont *font) {
|
||||||
this->text_ = std::move(text);
|
|
||||||
this->font_ = font;
|
this->font_ = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_foreground_color(Color foreground_color) { this->foreground_color_ = foreground_color; }
|
void set_foreground_color(Color foreground_color) { this->foreground_color_ = foreground_color; }
|
||||||
void set_background_color(Color background_color) { this->background_color_ = background_color; }
|
void set_background_color(Color background_color) { this->background_color_ = background_color; }
|
||||||
|
virtual std::string get_text() = 0;
|
||||||
|
|
||||||
|
|
||||||
TemplatableValue<std::string> text_{};
|
|
||||||
display::BaseFont *font_{nullptr};
|
display::BaseFont *font_{nullptr};
|
||||||
Color foreground_color_{COLOR_ON};
|
Color foreground_color_{COLOR_ON};
|
||||||
Color background_color_{COLOR_OFF};
|
Color background_color_{COLOR_OFF};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FormattableTextRun {
|
||||||
|
public:
|
||||||
|
template<typename V> void set_text_formatter(V text_formatter) { this->text_formatter_ = text_formatter; };
|
||||||
|
|
||||||
|
std::string format_text(std::string string) {
|
||||||
|
if (this->text_formatter_.has_value()) {
|
||||||
|
return this->text_formatter_.value(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TemplatableValue<std::string, const std::string> text_formatter_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextRun : public TextRunBase, public FormattableTextRun {
|
||||||
|
public:
|
||||||
|
TextRun(TemplatableValue<std::string> text, display::BaseFont *font) : TextRunBase(font) {
|
||||||
|
this->text_ = std::move(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_text() override {
|
||||||
|
return this->format_text(text_.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TemplatableValue<std::string> text_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class SensorTextRun : public TextRunBase, public FormattableTextRun {
|
||||||
|
public:
|
||||||
|
SensorTextRun(sensor::Sensor *sensor, display::BaseFont *font) : TextRunBase(font) {
|
||||||
|
this->sensor_ = sensor;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_text() override {
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << std::fixed << std::setprecision(this->sensor_->get_accuracy_decimals()) << this->sensor_->get_state();
|
||||||
|
return this->format_text(stream.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sensor::Sensor *sensor_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextSensorTextRun : public TextRunBase, public FormattableTextRun {
|
||||||
|
public:
|
||||||
|
TextSensorTextRun(text_sensor::TextSensor *text_sensor, display::BaseFont *font) : TextRunBase(font) {
|
||||||
|
this->text_sensor_ = text_sensor;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_text() override {
|
||||||
|
return this->format_text(this->text_sensor_->get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
text_sensor::TextSensor *text_sensor_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
class CalculatedTextRun {
|
class CalculatedTextRun {
|
||||||
public:
|
public:
|
||||||
CalculatedTextRun(TextRun *run, std::string text, display::Rect bounds, int16_t baseline, int16_t line_number) {
|
CalculatedTextRun(TextRunBase *run, std::string text, display::Rect bounds, int16_t baseline, int16_t line_number) {
|
||||||
this->run = run;
|
this->run = run;
|
||||||
this->text_ = std::move(text);
|
this->text_ = std::move(text);
|
||||||
this->bounds = bounds;
|
this->bounds = bounds;
|
||||||
|
@ -53,7 +117,7 @@ class CalculatedTextRun {
|
||||||
|
|
||||||
std::string text_;
|
std::string text_;
|
||||||
display::Rect bounds;
|
display::Rect bounds;
|
||||||
TextRun *run;
|
TextRunBase *run;
|
||||||
int16_t line_number_;
|
int16_t line_number_;
|
||||||
int16_t baseline;
|
int16_t baseline;
|
||||||
};
|
};
|
||||||
|
@ -81,14 +145,14 @@ class TextRunPanel : public LayoutItem {
|
||||||
this->can_wrap_at_character_ = can_wrap_at_character;
|
this->can_wrap_at_character_ = can_wrap_at_character;
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_text_run(TextRun *text_run) { this->text_runs_.push_back(text_run); };
|
void add_text_run(TextRunBase *text_run) { this->text_runs_.push_back(text_run); };
|
||||||
void set_text_align(display::TextAlign text_align) { this->text_align_ = text_align; };
|
void set_text_align(display::TextAlign text_align) { this->text_align_ = text_align; };
|
||||||
void set_min_width(int min_width) { this->min_width_ = min_width; };
|
void set_min_width(int min_width) { this->min_width_ = min_width; };
|
||||||
void set_max_width(int max_width) { this->max_width_ = max_width; };
|
void set_max_width(int max_width) { this->max_width_ = max_width; };
|
||||||
void set_debug_outline_runs(bool debug_outline_runs) { this->debug_outline_runs_ = debug_outline_runs; };
|
void set_debug_outline_runs(bool debug_outline_runs) { this->debug_outline_runs_ = debug_outline_runs; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<TextRun *> text_runs_;
|
std::vector<TextRunBase *> text_runs_;
|
||||||
display::TextAlign text_align_{display::TextAlign::TOP_LEFT};
|
display::TextAlign text_align_{display::TextAlign::TOP_LEFT};
|
||||||
int min_width_{0};
|
int min_width_{0};
|
||||||
int max_width_{0};
|
int max_width_{0};
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.components import font, color
|
from esphome.components import font, color, sensor, text_sensor
|
||||||
from esphome.components.display import display_ns
|
from esphome.components.display import display_ns
|
||||||
from esphome.const import CONF_ID, CONF_FOREGROUND_COLOR, CONF_BACKGROUND_COLOR
|
from esphome.const import CONF_ID, CONF_FOREGROUND_COLOR, CONF_BACKGROUND_COLOR, CONF_SENSOR
|
||||||
|
|
||||||
graphical_layout_ns = cg.esphome_ns.namespace("graphical_layout")
|
graphical_layout_ns = cg.esphome_ns.namespace("graphical_layout")
|
||||||
TextRunPanel = graphical_layout_ns.class_("TextRunPanel")
|
TextRunPanel = graphical_layout_ns.class_("TextRunPanel")
|
||||||
TextAlign = display_ns.enum("TextAlign", is_class=True)
|
TextAlign = display_ns.enum("TextAlign", is_class=True)
|
||||||
TextRun = graphical_layout_ns.class_("TextRun")
|
TextRunBase = graphical_layout_ns.class_("TextRunBase")
|
||||||
|
TextRun = graphical_layout_ns.class_("TextRun", TextRunBase)
|
||||||
|
SensorTextRun = graphical_layout_ns.class_("SensorTextRun", TextRunBase)
|
||||||
|
TextSensorTextRun = graphical_layout_ns.class_("TextSensorTextRun", TextRunBase)
|
||||||
CanWrapAtCharacterArguments = graphical_layout_ns.struct("CanWrapAtCharacterArguments")
|
CanWrapAtCharacterArguments = graphical_layout_ns.struct("CanWrapAtCharacterArguments")
|
||||||
CanWrapAtCharacterArgumentsConstRef = CanWrapAtCharacterArguments.operator(
|
CanWrapAtCharacterArgumentsConstRef = CanWrapAtCharacterArguments.operator(
|
||||||
"const"
|
"const"
|
||||||
|
@ -22,6 +25,8 @@ CONF_MIN_WIDTH = "min_width"
|
||||||
CONF_RUNS = "runs"
|
CONF_RUNS = "runs"
|
||||||
CONF_CAN_WRAP_AT_CHARACTER = "can_wrap_at_character"
|
CONF_CAN_WRAP_AT_CHARACTER = "can_wrap_at_character"
|
||||||
CONF_DEBUG_OUTLINE_RUNS = "debug_outline_runs"
|
CONF_DEBUG_OUTLINE_RUNS = "debug_outline_runs"
|
||||||
|
CONF_TEXT_SENSOR = "text_sensor"
|
||||||
|
CONF_TEXT_FORMATTER = "text_formatter"
|
||||||
|
|
||||||
TEXT_ALIGN = {
|
TEXT_ALIGN = {
|
||||||
"TOP_LEFT": TextAlign.TOP_LEFT,
|
"TOP_LEFT": TextAlign.TOP_LEFT,
|
||||||
|
@ -38,16 +43,44 @@ TEXT_ALIGN = {
|
||||||
"BOTTOM_RIGHT": TextAlign.BOTTOM_RIGHT,
|
"BOTTOM_RIGHT": TextAlign.BOTTOM_RIGHT,
|
||||||
}
|
}
|
||||||
|
|
||||||
RUN_SCHEMA = cv.Schema(
|
BASE_RUN_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(TextRun),
|
|
||||||
cv.Required(CONF_FONT): cv.use_id(font.Font),
|
cv.Required(CONF_FONT): cv.use_id(font.Font),
|
||||||
cv.Optional(CONF_FOREGROUND_COLOR): cv.use_id(color.ColorStruct),
|
cv.Optional(CONF_FOREGROUND_COLOR): cv.use_id(color.ColorStruct),
|
||||||
cv.Optional(CONF_BACKGROUND_COLOR): cv.use_id(color.ColorStruct),
|
cv.Optional(CONF_BACKGROUND_COLOR): cv.use_id(color.ColorStruct),
|
||||||
cv.Required(CONF_TEXT): cv.templatable(cv.string),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SENSOR_TEXT_RUN_SCHEMA = BASE_RUN_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(SensorTextRun),
|
||||||
|
cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
||||||
|
cv.Optional(CONF_TEXT_FORMATTER): cv.returning_lambda,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
TEXT_RUN_SCHEMA = BASE_RUN_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TextRun),
|
||||||
|
cv.Required(CONF_TEXT): cv.templatable(cv.string),
|
||||||
|
cv.Optional(CONF_TEXT_FORMATTER): cv.returning_lambda,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
TEXT_SENSOR_TEXT_RUN_SCHEMA = BASE_RUN_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TextSensorTextRun),
|
||||||
|
cv.Required(CONF_TEXT_SENSOR): cv.use_id(text_sensor.TextSensor),
|
||||||
|
cv.Optional(CONF_TEXT_FORMATTER): cv.returning_lambda,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
RUN_SCHEMA = cv.Any(
|
||||||
|
SENSOR_TEXT_RUN_SCHEMA,
|
||||||
|
TEXT_RUN_SCHEMA,
|
||||||
|
TEXT_SENSOR_TEXT_RUN_SCHEMA,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_config_schema(base_item_schema, item_type_schema):
|
def get_config_schema(base_item_schema, item_type_schema):
|
||||||
return base_item_schema.extend(
|
return base_item_schema.extend(
|
||||||
|
@ -90,12 +123,27 @@ async def config_to_layout_item(pvariable_builder, item_config, child_item_build
|
||||||
cg.add(var.set_debug_outline_runs(debug_outline_runs))
|
cg.add(var.set_debug_outline_runs(debug_outline_runs))
|
||||||
|
|
||||||
for run_config in item_config[CONF_RUNS]:
|
for run_config in item_config[CONF_RUNS]:
|
||||||
run_text = await cg.templatable(
|
run = None
|
||||||
run_config[CONF_TEXT], args=[], output_type=cg.std_string
|
|
||||||
)
|
|
||||||
run_font = await cg.get_variable(run_config[CONF_FONT])
|
run_font = await cg.get_variable(run_config[CONF_FONT])
|
||||||
|
if run_sensor_config := run_config.get(CONF_SENSOR):
|
||||||
|
sens = await cg.get_variable(run_sensor_config)
|
||||||
|
run = cg.new_Pvariable(run_config[CONF_ID], sens, run_font)
|
||||||
|
elif run_text_sensor_config := run_config.get(CONF_TEXT_SENSOR):
|
||||||
|
text_sens = await cg.get_variable(run_text_sensor_config)
|
||||||
|
run = cg.new_Pvariable(run_config[CONF_ID], text_sens, run_font)
|
||||||
|
else:
|
||||||
|
run_text = await cg.templatable(
|
||||||
|
run_config[CONF_TEXT], args=[], output_type=cg.std_string
|
||||||
|
)
|
||||||
|
run = cg.new_Pvariable(run_config[CONF_ID], run_text, run_font)
|
||||||
|
|
||||||
run = cg.new_Pvariable(run_config[CONF_ID], run_text, run_font)
|
if run_text_formatter_config := run_config.get(CONF_TEXT_FORMATTER):
|
||||||
|
run_text_formatter = await cg.process_lambda(
|
||||||
|
run_text_formatter_config,
|
||||||
|
[(cg.std_string, "it")],
|
||||||
|
return_type=cg.std_string,
|
||||||
|
)
|
||||||
|
cg.add(run.set_text_formatter(run_text_formatter))
|
||||||
|
|
||||||
if run_background_color_config := run_config.get(CONF_BACKGROUND_COLOR):
|
if run_background_color_config := run_config.get(CONF_BACKGROUND_COLOR):
|
||||||
run_background_color = await cg.get_variable(run_background_color_config)
|
run_background_color = await cg.get_variable(run_background_color_config)
|
||||||
|
|
Loading…
Reference in a new issue