Add ability for FixedDimensionPanel to operate in one of three modes; display dimension, child dimension, or fixed.

- Display dimensions use the width/height of the display (minus margin, border, and padding) for the dimension
- Child dimensions fix the dimension to that of the child
- Fixed dimension uses a specified pixel value (or lambda returning pixel value)
This commit is contained in:
Michael Davidson 2023-12-31 09:54:07 +11:00
parent fed36a0af5
commit cbd4515900
No known key found for this signature in database
GPG Key ID: B8D1A99712B8B0EB
3 changed files with 78 additions and 22 deletions

View File

@ -11,28 +11,53 @@ static const char *const TAG = "fixeddimensionpanel";
void FixedDimensionPanel::dump_config(int indent_depth, int additional_level_depth) {
this->dump_config_base_properties(TAG, indent_depth);
YESNO(this->width_.value() < 1));
ESP_LOGCONFIG(TAG, "%*sHeight: %i (Will use display height: %s)", indent_depth, "", this->height_.value(),
YESNO(this->height_.value() < 1));
if (this->width_.value() < 0) {
ESP_LOGCONFIG(TAG, "%*sWidth: UNSET (Will use %s's width)", indent_depth, "",
this->unset_width_uses_display_width_ ? "DISPLAY" : "CHILD");
} else {
ESP_LOGCONFIG(TAG, "%*sWidth: %i", indent_depth, "", this->width_.value());
}
if (this->height_.value() < 0) {
ESP_LOGCONFIG(TAG, "%*sHeight: UNSET (Will use %s's height)", indent_depth, "",
this->unset_height_uses_display_height_ ? "DISPLAY" : "CHILD");
} else {
ESP_LOGCONFIG(TAG, "%*sHeight: %i", indent_depth, "", this->height_.value());
}
this->child_->dump_config(indent_depth + additional_level_depth, additional_level_depth);
}
display::Rect FixedDimensionPanel::measure_item_internal(display::Display *display) {
// Call measure_child so they can do any measurements
display::Rect child_size = this->child_->measure_item(display);
display::Rect rect(0, 0, this->width_.value(), this->height_.value());
if (rect.w < 1) {
if (rect.w < 0) {
if (this->unset_width_uses_display_width_) {
rect.w = display->get_width();
// We need to account for our own padding + margin + border
rect.w -= (this->margin_ + this->border_ + this->padding_) * 2;
} else {
rect.w = child_size.w;
}
if (rect.h < 1) {
}
if (rect.h < 0) {
if (this->unset_height_uses_display_height_) {
rect.h = display->get_height();
// We need to account for our own padding + margin + border
rect.h -= (this->margin_ + this->border_ + this->padding_) * 2;
} else {
rect.h = child_size.h;
}
}
// Call measure_child just so they can do any measurements
this->child_->measure_item(display);
return rect;
}
void FixedDimensionPanel::render_internal(display::Display *display, display::Rect bounds) {
this->child_->render_internal(display, bounds);
this->child_->render(display, bounds);
}
} // namespace graphical_layout

View File

@ -19,10 +19,19 @@ class FixedDimensionPanel : public LayoutItem {
template<typename V> void set_width(V width) { this->width_ = width; };
template<typename V> void set_height(V height) { this->height_ = height; }
void set_unset_width_uses_display_width(bool use_display) {
this->unset_width_uses_display_width_ = use_display;
}
void set_unset_height_uses_display_height(bool use_display) {
this->unset_height_uses_display_height_ = use_display;
}
protected:
LayoutItem *child_{nullptr};
TemplatableValue<int> width_{0};
TemplatableValue<int> height_{0};
TemplatableValue<int> width_{-1};
TemplatableValue<int> height_{-1};
bool unset_width_uses_display_width_{false};
bool unset_height_uses_display_height_{false};
};
} // namespace graphical_layout

View File

@ -5,19 +5,25 @@ from esphome.const import CONF_TYPE, CONF_WIDTH, CONF_HEIGHT
graphical_layout_ns = cg.esphome_ns.namespace("graphical_layout")
FixedDimensionPanel = graphical_layout_ns.class_("FixedDimensionPanel")
CONF_ITEM_PADDING = "item_padding"
CONF_FIXED_DIMENSION_PANEL = "fixed_dimension_panel"
CONF_CHILD = "child"
UNSET_DIMENSION_MODE = ["CHILD", "DISPLAY"]
def get_config_schema(base_item_schema, item_type_schema):
return base_item_schema.extend(
{
cv.GenerateID(): cv.declare_id(FixedDimensionPanel),
cv.Optional(CONF_ITEM_PADDING, default=0): cv.int_,
cv.Required(CONF_CHILD): item_type_schema,
cv.Optional(CONF_WIDTH, default=-1): cv.templatable(cv.int_range(min=-1)),
cv.Optional(CONF_HEIGHT, default=-1): cv.templatable(cv.int_range(min=-1)),
cv.Optional(CONF_WIDTH, default=-1): cv.Any(
cv.one_of(*UNSET_DIMENSION_MODE, upper=True),
cv.templatable(cv.int_range(min=-1)),
),
cv.Optional(CONF_HEIGHT, default=-1): cv.Any(
cv.one_of(*UNSET_DIMENSION_MODE, upper=True),
cv.templatable(cv.int_range(min=-1)),
),
}
)
@ -25,9 +31,25 @@ def get_config_schema(base_item_schema, item_type_schema):
async def config_to_layout_item(pvariable_builder, item_config, child_item_builder):
var = await pvariable_builder(item_config)
width = await cg.templatable(item_config[CONF_WIDTH], args=[], output_type=cg.int_)
if width_config := item_config.get(CONF_WIDTH):
if width_config in UNSET_DIMENSION_MODE:
cg.add(
var.set_unset_width_uses_display_width(
width_config.upper() == "DISPLAY"
)
)
else:
width = await cg.templatable(width_config, args=[], output_type=cg.int_)
cg.add(var.set_width(width))
if height_config := item_config.get(CONF_HEIGHT):
if height_config in UNSET_DIMENSION_MODE:
cg.add(
var.set_unset_height_uses_display_height(
height_config.upper() == "DISPLAY"
)
)
else:
height = await cg.templatable(
item_config[CONF_HEIGHT], args=[], output_type=cg.int_
)