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, "",
|
||||
LOG_STR_ARG(display::text_align_to_string(this->text_align_)));
|
||||
ESP_LOGCONFIG(TAG, "%*sText Runs: %i", indent_depth, "", this->text_runs_.size());
|
||||
for (TextRun *run : this->text_runs_) {
|
||||
std::string text = run->text_.value();
|
||||
for (TextRunBase *run : this->text_runs_) {
|
||||
std::string text = run->get_text();
|
||||
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 line_number = 0;
|
||||
|
||||
for (TextRun *run : this->text_runs_) {
|
||||
for (TextRunBase *run : this->text_runs_) {
|
||||
int x1;
|
||||
int width;
|
||||
int height;
|
||||
int baseline;
|
||||
std::string text = run->text_.value();
|
||||
std::string text = run->get_text();
|
||||
|
||||
run->font_->measure(text.c_str(), &width, &x1, &baseline, &height);
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "esphome/components/graphical_layout/graphical_layout.h"
|
||||
#include "esphome/components/font/font.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace graphical_layout {
|
||||
|
@ -25,25 +29,85 @@ struct CanWrapAtCharacterArguments {
|
|||
char character;
|
||||
};
|
||||
|
||||
class TextRun {
|
||||
class TextRunBase {
|
||||
public:
|
||||
TextRun(TemplatableValue<std::string> text, display::BaseFont *font) {
|
||||
this->text_ = std::move(text);
|
||||
TextRunBase(display::BaseFont *font) {
|
||||
this->font_ = font;
|
||||
}
|
||||
|
||||
void set_foreground_color(Color foreground_color) { this->foreground_color_ = foreground_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};
|
||||
Color foreground_color_{COLOR_ON};
|
||||
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 {
|
||||
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->text_ = std::move(text);
|
||||
this->bounds = bounds;
|
||||
|
@ -53,7 +117,7 @@ class CalculatedTextRun {
|
|||
|
||||
std::string text_;
|
||||
display::Rect bounds;
|
||||
TextRun *run;
|
||||
TextRunBase *run;
|
||||
int16_t line_number_;
|
||||
int16_t baseline;
|
||||
};
|
||||
|
@ -81,14 +145,14 @@ class TextRunPanel : public LayoutItem {
|
|||
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_min_width(int min_width) { this->min_width_ = min_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; };
|
||||
|
||||
protected:
|
||||
std::vector<TextRun *> text_runs_;
|
||||
std::vector<TextRunBase *> text_runs_;
|
||||
display::TextAlign text_align_{display::TextAlign::TOP_LEFT};
|
||||
int min_width_{0};
|
||||
int max_width_{0};
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import esphome.codegen as cg
|
||||
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.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")
|
||||
TextRunPanel = graphical_layout_ns.class_("TextRunPanel")
|
||||
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")
|
||||
CanWrapAtCharacterArgumentsConstRef = CanWrapAtCharacterArguments.operator(
|
||||
"const"
|
||||
|
@ -22,6 +25,8 @@ CONF_MIN_WIDTH = "min_width"
|
|||
CONF_RUNS = "runs"
|
||||
CONF_CAN_WRAP_AT_CHARACTER = "can_wrap_at_character"
|
||||
CONF_DEBUG_OUTLINE_RUNS = "debug_outline_runs"
|
||||
CONF_TEXT_SENSOR = "text_sensor"
|
||||
CONF_TEXT_FORMATTER = "text_formatter"
|
||||
|
||||
TEXT_ALIGN = {
|
||||
"TOP_LEFT": TextAlign.TOP_LEFT,
|
||||
|
@ -38,16 +43,44 @@ TEXT_ALIGN = {
|
|||
"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.Optional(CONF_FOREGROUND_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):
|
||||
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))
|
||||
|
||||
for run_config in item_config[CONF_RUNS]:
|
||||
run_text = await cg.templatable(
|
||||
run_config[CONF_TEXT], args=[], output_type=cg.std_string
|
||||
)
|
||||
run = None
|
||||
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):
|
||||
run_background_color = await cg.get_variable(run_background_color_config)
|
||||
|
|
Loading…
Reference in a new issue