mirror of
https://github.com/esphome/esphome.git
synced 2024-12-12 08:24:55 +01:00
Make margin, borders, and padding individually settable (top vs left vs bottom vs right)
Can still take an int to set all the properties equally
This commit is contained in:
parent
feef234ddd
commit
b18e217313
4 changed files with 143 additions and 39 deletions
|
@ -24,13 +24,32 @@ CONF_LAYOUT = "layout"
|
|||
CONF_MARGIN = "margin"
|
||||
CONF_PADDING = "padding"
|
||||
CONF_BORDER_COLOR = "border_color"
|
||||
CONF_LEFT = "left"
|
||||
CONF_TOP = "top"
|
||||
CONF_RIGHT = "right"
|
||||
CONF_BOTTOM = "bottom"
|
||||
|
||||
DIMENSION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_LEFT, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_TOP, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_RIGHT, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_BOTTOM, default=0): cv.int_range(min=0),
|
||||
}
|
||||
)
|
||||
|
||||
BASE_ITEM_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_MARGIN, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_BORDER, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_MARGIN, default=0): cv.Any(
|
||||
DIMENSION_SCHEMA, cv.int_range(min=0)
|
||||
),
|
||||
cv.Optional(CONF_BORDER, default=0): cv.Any(
|
||||
DIMENSION_SCHEMA, cv.int_range(min=0)
|
||||
),
|
||||
cv.Optional(CONF_BORDER_COLOR): cv.use_id(color.ColorStruct),
|
||||
cv.Optional(CONF_PADDING, default=0): cv.int_range(min=0),
|
||||
cv.Optional(CONF_PADDING, default=0): cv.Any(
|
||||
DIMENSION_SCHEMA, cv.int_range(min=0)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -79,22 +98,52 @@ CONFIG_SCHEMA = cv.Schema(
|
|||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def extract_dimension_expression(value_config, individual_set, single_set):
|
||||
if value_config is not None:
|
||||
if not isinstance(value_config, int):
|
||||
# Handle individual dimensions
|
||||
left = value_config.get(CONF_LEFT)
|
||||
top = value_config.get(CONF_TOP)
|
||||
right = value_config.get(CONF_RIGHT)
|
||||
bottom = value_config.get(CONF_BOTTOM)
|
||||
|
||||
individual_set(left, top, right, bottom)
|
||||
else:
|
||||
template = await cg.templatable(value_config, args=[], output_type=int)
|
||||
single_set(template)
|
||||
|
||||
|
||||
async def build_layout_item_pvariable(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
||||
margin = await cg.templatable(config[CONF_MARGIN], args=[], output_type=int)
|
||||
cg.add(var.set_margin(margin))
|
||||
await extract_dimension_expression(
|
||||
config.get(CONF_MARGIN),
|
||||
lambda left, top, right, bottom: cg.add(
|
||||
var.set_margin(left, top, right, bottom)
|
||||
),
|
||||
lambda margin: cg.add(var.set_margin(margin)),
|
||||
)
|
||||
|
||||
border = await cg.templatable(config[CONF_BORDER], args=[], output_type=int)
|
||||
cg.add(var.set_border(border))
|
||||
await extract_dimension_expression(
|
||||
config.get(CONF_BORDER),
|
||||
lambda left, top, right, bottom: cg.add(
|
||||
var.set_border(left, top, right, bottom)
|
||||
),
|
||||
lambda border: cg.add(var.set_border(border)),
|
||||
)
|
||||
|
||||
await extract_dimension_expression(
|
||||
config.get(CONF_PADDING),
|
||||
lambda left, top, right, bottom: cg.add(
|
||||
var.set_padding(left, top, right, bottom)
|
||||
),
|
||||
lambda padding: cg.add(var.set_padding(padding)),
|
||||
)
|
||||
|
||||
if border_color_config := config.get(CONF_BORDER_COLOR):
|
||||
border_color = await cg.get_variable(border_color_config)
|
||||
cg.add(var.set_border_color(border_color))
|
||||
|
||||
padding = await cg.templatable(config[CONF_PADDING], args=[], output_type=int)
|
||||
cg.add(var.set_padding(padding))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ display::Rect FixedDimensionPanel::measure_item_internal(display::Display *displ
|
|||
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;
|
||||
rect.w -= this->margin_.horizontal() + this->border_.horizontal() + this->padding_.horizontal();
|
||||
} else {
|
||||
rect.w = child_size.w;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ display::Rect FixedDimensionPanel::measure_item_internal(display::Display *displ
|
|||
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;
|
||||
rect.h -= this->margin_.vertical() + this->border_.vertical() + this->padding_.vertical();
|
||||
} else {
|
||||
rect.h = child_size.h;
|
||||
}
|
||||
|
|
|
@ -13,38 +13,43 @@ const Color COLOR_ON(255, 255, 255, 255);
|
|||
|
||||
display::Rect LayoutItem::measure_item(display::Display *display) {
|
||||
display::Rect inner_size = this->measure_item_internal(display);
|
||||
int margin_border_padding = this->margin_ + this->border_ + this->padding_;
|
||||
|
||||
return display::Rect(0, 0, (margin_border_padding * 2) + inner_size.w, (margin_border_padding * 2) + inner_size.h);
|
||||
return display::Rect(0, 0, this->margin_.horizontal() + this->border_.horizontal() + this->padding_.horizontal() + inner_size.w, this->margin_.vertical() + this->border_.vertical() + this->padding_.vertical() + inner_size.h);
|
||||
}
|
||||
|
||||
void LayoutItem::render(display::Display *display, display::Rect bounds) {
|
||||
// Margin
|
||||
display->set_local_coordinates_relative_to_current(this->margin_, this->margin_);
|
||||
display->set_local_coordinates_relative_to_current(this->margin_.left, this->margin_.top);
|
||||
|
||||
// Border
|
||||
if (this->border_ > 0) {
|
||||
display::Rect border_bounds(0, 0, bounds.w - (this->margin_ * 2), bounds.h - (this->margin_ * 2));
|
||||
if (this->border_ == 1) {
|
||||
if (this->border_.any()) {
|
||||
display::Rect border_bounds(0, 0, bounds.w - this->margin_.horizontal(), bounds.h - this->margin_.vertical());
|
||||
if (this->border_.equals(1)) {
|
||||
// Single pixel border use the native function
|
||||
display->rectangle(0, 0, border_bounds.w, border_bounds.h, this->border_color_);
|
||||
} else {
|
||||
// Thicker border need to do mutiple filled rects
|
||||
// Top rectangle
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.y, border_bounds.w, this->border_);
|
||||
// Bottom rectangle
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.h - this->border_, border_bounds.w, this->border_);
|
||||
// Left rectangle
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.y, this->border_, border_bounds.h);
|
||||
// Right rectangle
|
||||
display->filled_rectangle(border_bounds.w - this->border_, border_bounds.y, this->border_, border_bounds.h);
|
||||
// Top Rectangle
|
||||
if (this->border_.top > 0) {
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.y, border_bounds.w, this->border_.top);
|
||||
}
|
||||
// Left Rectangle
|
||||
if (this->border_.left > 0) {
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.y + this->border_.top, this->border_.left, border_bounds.h - this->border_.bottom - this->border_.top);
|
||||
}
|
||||
// Bottom Rectangle
|
||||
if (this->border_.bottom > 0) {
|
||||
display->filled_rectangle(border_bounds.x, border_bounds.h - this->border_.bottom, border_bounds.w, this->border_.bottom);
|
||||
}
|
||||
// Right Rectangle
|
||||
if (this->border_.right > 0) {
|
||||
display->filled_rectangle(border_bounds.w - this->border_.right, border_bounds.y + this->border_.top, this->border_.right, border_bounds.h - this->border_.bottom - this->border_.top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Padding
|
||||
display->set_local_coordinates_relative_to_current(this->border_ + this->padding_, this->border_ + this->padding_);
|
||||
int margin_border_padding_offset = (this->margin_ + this->border_ + this->padding_) * 2;
|
||||
display::Rect internal_bounds(0, 0, bounds.w - margin_border_padding_offset, bounds.h - margin_border_padding_offset);
|
||||
display->set_local_coordinates_relative_to_current(this->border_.left + this->padding_.left, this->border_.top + this->padding_.top);
|
||||
display::Rect internal_bounds(0, 0, bounds.w - this->margin_.horizontal() - this->border_.horizontal() - this->padding_.horizontal(), bounds.h - this->margin_.vertical() - this->border_.vertical() - this->padding_.vertical());
|
||||
|
||||
// Rendering
|
||||
this->render_internal(display, internal_bounds);
|
||||
|
@ -59,11 +64,14 @@ void LayoutItem::render(display::Display *display, display::Rect bounds) {
|
|||
}
|
||||
|
||||
void LayoutItem::dump_config_base_properties(const char *tag, int indent_depth) {
|
||||
ESP_LOGCONFIG(tag, "%*sMargin: %i", indent_depth, "", this->margin_);
|
||||
ESP_LOGCONFIG(tag, "%*sBorder: %i", indent_depth, "", this->border_);
|
||||
ESP_LOGCONFIG(tag, "%*sMargin: : (L: %i, T: %i, R: %i, B: %i)", indent_depth, "", this->margin_.left,
|
||||
this->margin_.top, this->margin_.right, this->margin_.bottom);
|
||||
ESP_LOGCONFIG(tag, "%*sBorder: (L: %i, T: %i, R: %i, B: %i)", indent_depth, "", this->border_.left,
|
||||
this->border_.top, this->border_.right, this->border_.bottom);
|
||||
ESP_LOGCONFIG(tag, "%*sBorder Color: (R: %i, G: %i, B: %i)", indent_depth, "", this->border_color_.r,
|
||||
this->border_color_.g, this->border_color_.b);
|
||||
ESP_LOGCONFIG(tag, "%*sPadding: %i", indent_depth, "", this->padding_);
|
||||
ESP_LOGCONFIG(tag, "%*sPadding: : (L: %i, T: %i, R: %i, B: %i)", indent_depth, "", this->padding_.left,
|
||||
this->padding_.top, this->padding_.right, this->padding_.bottom);
|
||||
}
|
||||
|
||||
const LogString *horizontal_child_align_to_string(HorizontalChildAlign align) {
|
||||
|
|
|
@ -44,6 +44,43 @@ enum class VerticalChildAlign {
|
|||
STRETCH_TO_FIT_HEIGHT = 0x03
|
||||
};
|
||||
|
||||
struct Dimension {
|
||||
Dimension() {};
|
||||
Dimension(int16_t padding) {
|
||||
this->left = padding;
|
||||
this->top = padding;
|
||||
this->right = padding;
|
||||
this->bottom = padding;
|
||||
}
|
||||
Dimension(int16_t left, int16_t top, int16_t right, int16_t bottom) {
|
||||
this->left = left;
|
||||
this->top = top;
|
||||
this->right = right;
|
||||
this->bottom = bottom;
|
||||
}
|
||||
|
||||
/* Gets the total padding for the horizontal direction (left + right) */
|
||||
inline int16_t horizontal() const { return this->left + this->right; };
|
||||
/* Gets the total padding for the vertical direction (top + bottom) */
|
||||
inline int16_t vertical() const { return this->top + this->bottom; };
|
||||
|
||||
/* Returns true if any value is set to a non-zero value*/
|
||||
inline bool any() const {
|
||||
return this->left > 0 || this->top > 0 || this->right > 0 || this->bottom > 0;
|
||||
};
|
||||
|
||||
/* Returns true if all dimensions are equal to the value */
|
||||
inline bool equals(int16_t value) const {
|
||||
return this->left == value && this->top == value && this->right == value
|
||||
&& this->bottom == value;
|
||||
}
|
||||
|
||||
int16_t left{0};
|
||||
int16_t top{0};
|
||||
int16_t right{0};
|
||||
int16_t bottom{0};
|
||||
};
|
||||
|
||||
/** LayoutItem is the base from which all items derive from*/
|
||||
class LayoutItem {
|
||||
public:
|
||||
|
@ -99,15 +136,25 @@ class LayoutItem {
|
|||
*/
|
||||
virtual void setup_complete(){};
|
||||
|
||||
void set_margin(int margin) { this->margin_ = margin; };
|
||||
void set_padding(int padding) { this->padding_ = padding; };
|
||||
void set_border(int border) { this->border_ = border; };
|
||||
void set_margin(int margin) { this->margin_ = Dimension(margin); };
|
||||
void set_margin(int left, int top, int right, int bottom) {
|
||||
this->margin_ = Dimension(left, top, right, bottom);
|
||||
}
|
||||
void set_padding(int padding) { this->padding_ = Dimension(padding); };
|
||||
void set_padding(int left, int top, int right, int bottom) {
|
||||
this->padding_ = Dimension(left, top, right, bottom);
|
||||
}
|
||||
void set_border(int border) { this->border_ = Dimension(border); };
|
||||
void set_border(int left, int top, int right, int bottom) {
|
||||
this->border_ = Dimension(left, top, right, bottom);
|
||||
}
|
||||
void set_border_color(Color color) { this->border_color_ = color; };
|
||||
|
||||
|
||||
protected:
|
||||
int margin_{0};
|
||||
int padding_{0};
|
||||
int border_{0};
|
||||
Dimension margin_{};
|
||||
Dimension padding_{};
|
||||
Dimension border_{};
|
||||
Color border_color_{COLOR_ON};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue