mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	[lvgl] Allow linear positioning of grid cells (#9196)
This commit is contained in:
		| @@ -466,7 +466,7 @@ LVGL_SCHEMA = cv.All( | |||||||
|                 ): lvalid.lv_color, |                 ): lvalid.lv_color, | ||||||
|                 cv.Optional(df.CONF_THEME): cv.Schema( |                 cv.Optional(df.CONF_THEME): cv.Schema( | ||||||
|                     { |                     { | ||||||
|                         cv.Optional(name): obj_schema(w) |                         cv.Optional(name): obj_schema(w).extend(FULL_STYLE_SCHEMA) | ||||||
|                         for name, w in WIDGET_TYPES.items() |                         for name, w in WIDGET_TYPES.items() | ||||||
|                     } |                     } | ||||||
|                 ), |                 ), | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ from esphome.core.config import StartupTrigger | |||||||
| from esphome.schema_extractors import SCHEMA_EXTRACT | from esphome.schema_extractors import SCHEMA_EXTRACT | ||||||
|  |  | ||||||
| from . import defines as df, lv_validation as lvalid | from . import defines as df, lv_validation as lvalid | ||||||
| from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR | from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR, TYPE_GRID | ||||||
| from .helpers import add_lv_use, requires_component, validate_printf | from .helpers import add_lv_use, requires_component, validate_printf | ||||||
| from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity | from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity | ||||||
| from .lvcode import LvglComponent, lv_event_t_ptr | from .lvcode import LvglComponent, lv_event_t_ptr | ||||||
| @@ -349,7 +349,60 @@ def obj_schema(widget_type: WidgetType): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _validate_grid_layout(config): | ||||||
|  |     layout = config[df.CONF_LAYOUT] | ||||||
|  |     rows = len(layout[df.CONF_GRID_ROWS]) | ||||||
|  |     columns = len(layout[df.CONF_GRID_COLUMNS]) | ||||||
|  |     used_cells = [[None] * columns for _ in range(rows)] | ||||||
|  |     for index, widget in enumerate(config[df.CONF_WIDGETS]): | ||||||
|  |         _, w = next(iter(widget.items())) | ||||||
|  |         if (df.CONF_GRID_CELL_COLUMN_POS in w) != (df.CONF_GRID_CELL_ROW_POS in w): | ||||||
|  |             # pylint: disable=raise-missing-from | ||||||
|  |             raise cv.Invalid( | ||||||
|  |                 "Both row and column positions must be specified, or both omitted", | ||||||
|  |                 [df.CONF_WIDGETS, index], | ||||||
|  |             ) | ||||||
|  |         if df.CONF_GRID_CELL_ROW_POS in w: | ||||||
|  |             row = w[df.CONF_GRID_CELL_ROW_POS] | ||||||
|  |             column = w[df.CONF_GRID_CELL_COLUMN_POS] | ||||||
|  |         else: | ||||||
|  |             try: | ||||||
|  |                 row, column = next( | ||||||
|  |                     (r_idx, c_idx) | ||||||
|  |                     for r_idx, row in enumerate(used_cells) | ||||||
|  |                     for c_idx, value in enumerate(row) | ||||||
|  |                     if value is None | ||||||
|  |                 ) | ||||||
|  |             except StopIteration: | ||||||
|  |                 # pylint: disable=raise-missing-from | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     "No free cells available in grid layout", [df.CONF_WIDGETS, index] | ||||||
|  |                 ) | ||||||
|  |             w[df.CONF_GRID_CELL_ROW_POS] = row | ||||||
|  |             w[df.CONF_GRID_CELL_COLUMN_POS] = column | ||||||
|  |  | ||||||
|  |         for i in range(w[df.CONF_GRID_CELL_ROW_SPAN]): | ||||||
|  |             for j in range(w[df.CONF_GRID_CELL_COLUMN_SPAN]): | ||||||
|  |                 if row + i >= rows or column + j >= columns: | ||||||
|  |                     # pylint: disable=raise-missing-from | ||||||
|  |                     raise cv.Invalid( | ||||||
|  |                         f"Cell at {row}/{column} span {w[df.CONF_GRID_CELL_ROW_SPAN]}x{w[df.CONF_GRID_CELL_COLUMN_SPAN]} " | ||||||
|  |                         f"exceeds grid size {rows}x{columns}", | ||||||
|  |                         [df.CONF_WIDGETS, index], | ||||||
|  |                     ) | ||||||
|  |                 if used_cells[row + i][column + j] is not None: | ||||||
|  |                     # pylint: disable=raise-missing-from | ||||||
|  |                     raise cv.Invalid( | ||||||
|  |                         f"Cell span {row + i}/{column + j} already occupied by widget at index {used_cells[row + i][column + j]}", | ||||||
|  |                         [df.CONF_WIDGETS, index], | ||||||
|  |                     ) | ||||||
|  |                 used_cells[row + i][column + j] = index | ||||||
|  |  | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
| LAYOUT_SCHEMAS = {} | LAYOUT_SCHEMAS = {} | ||||||
|  | LAYOUT_VALIDATORS = {TYPE_GRID: _validate_grid_layout} | ||||||
|  |  | ||||||
| ALIGN_TO_SCHEMA = { | ALIGN_TO_SCHEMA = { | ||||||
|     cv.Optional(df.CONF_ALIGN_TO): cv.Schema( |     cv.Optional(df.CONF_ALIGN_TO): cv.Schema( | ||||||
| @@ -402,8 +455,8 @@ LAYOUT_SCHEMA = { | |||||||
| } | } | ||||||
|  |  | ||||||
| GRID_CELL_SCHEMA = { | GRID_CELL_SCHEMA = { | ||||||
|     cv.Required(df.CONF_GRID_CELL_ROW_POS): cv.positive_int, |     cv.Optional(df.CONF_GRID_CELL_ROW_POS): cv.positive_int, | ||||||
|     cv.Required(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int, |     cv.Optional(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int, | ||||||
|     cv.Optional(df.CONF_GRID_CELL_ROW_SPAN, default=1): cv.positive_int, |     cv.Optional(df.CONF_GRID_CELL_ROW_SPAN, default=1): cv.positive_int, | ||||||
|     cv.Optional(df.CONF_GRID_CELL_COLUMN_SPAN, default=1): cv.positive_int, |     cv.Optional(df.CONF_GRID_CELL_COLUMN_SPAN, default=1): cv.positive_int, | ||||||
|     cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, |     cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments, | ||||||
| @@ -474,7 +527,10 @@ def container_validator(schema, widget_type: WidgetType): | |||||||
|         result = result.extend( |         result = result.extend( | ||||||
|             LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE]) |             LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE]) | ||||||
|         ) |         ) | ||||||
|         return result(value) |         value = result(value) | ||||||
|  |         if layout_validator := LAYOUT_VALIDATORS.get(ltype): | ||||||
|  |             value = layout_validator(value) | ||||||
|  |         return value | ||||||
|  |  | ||||||
|     return validator |     return validator | ||||||
|  |  | ||||||
|   | |||||||
| @@ -839,9 +839,7 @@ lvgl: | |||||||
|                       styles: bdr_style |                       styles: bdr_style | ||||||
|                       grid_cell_x_align: center |                       grid_cell_x_align: center | ||||||
|                       grid_cell_y_align: stretch |                       grid_cell_y_align: stretch | ||||||
|                       grid_cell_row_pos: 0 |                       grid_cell_column_span: 2 | ||||||
|                       grid_cell_column_pos: 1 |  | ||||||
|                       grid_cell_column_span: 1 |  | ||||||
|                       text: "Grid cell 0/1" |                       text: "Grid cell 0/1" | ||||||
|                   - label: |                   - label: | ||||||
|                       grid_cell_x_align: end |                       grid_cell_x_align: end | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user