diff --git a/esphome/components/sdl/display.py b/esphome/components/sdl/display.py index 78c180aa65..57266f33e2 100644 --- a/esphome/components/sdl/display.py +++ b/esphome/components/sdl/display.py @@ -20,6 +20,7 @@ Sdl = sdl_ns.class_("Sdl", display.Display, cg.Component) sdl_window_flags = cg.global_ns.enum("SDL_WindowFlags") +CONF_CENTERED_ON_DISPLAY = "centered_on_display" CONF_SDL_OPTIONS = "sdl_options" CONF_SDL_ID = "sdl_id" CONF_WINDOW_OPTIONS = "window_options" @@ -31,6 +32,8 @@ WINDOW_OPTIONS = ( "resizable", ) +SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000 + def get_sdl_options(value): if value != "": @@ -47,6 +50,20 @@ def get_window_options(): return {cv.Optional(option, default=False): cv.boolean for option in WINDOW_OPTIONS} +def _validate_position(config: dict) -> dict: + if CONF_CENTERED_ON_DISPLAY in config: + if CONF_X in config or CONF_Y in config: + raise cv.Invalid( + f"Cannot specify '{CONF_CENTERED_ON_DISPLAY}' with '{CONF_X}' and '{CONF_Y}' options" + ) + return config + if CONF_X in config and CONF_Y in config: + return config + if CONF_X in config or CONF_Y in config: + raise cv.Invalid(f"Must specify both '{CONF_X}' and '{CONF_Y}' options") + raise cv.Invalid("Must specify either 'x' and 'y' or 'centered_on_display'") + + CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( cv.Schema( @@ -66,10 +83,13 @@ CONFIG_SCHEMA = cv.All( { cv.Optional(CONF_POSITION): cv.Schema( { - cv.Required(CONF_X): cv.int_, - cv.Required(CONF_Y): cv.int_, + cv.Optional(CONF_X): cv.int_, + cv.Optional(CONF_Y): cv.int_, + cv.Optional(CONF_CENTERED_ON_DISPLAY): cv.int_range( + 0, 128 + ), } - ), + ).add_extra(_validate_position), **get_window_options(), } ), @@ -105,7 +125,15 @@ async def to_code(config): cg.add(var.set_window_options(create_flags)) if position := window_options.get(CONF_POSITION): - cg.add(var.set_position(position[CONF_X], position[CONF_Y])) + if (centered := position.get(CONF_CENTERED_ON_DISPLAY)) is not None: + cg.add( + var.set_position( + SDL_WINDOWPOS_CENTERED_MASK | centered, + SDL_WINDOWPOS_CENTERED_MASK | centered, + ) + ) + else: + cg.add(var.set_position(position[CONF_X], position[CONF_Y])) if lamb := config.get(CONF_LAMBDA): lambda_ = await cg.process_lambda( diff --git a/esphome/components/sdl/sdl_esphome.h b/esphome/components/sdl/sdl_esphome.h index 3f54b70560..a5ebf44c38 100644 --- a/esphome/components/sdl/sdl_esphome.h +++ b/esphome/components/sdl/sdl_esphome.h @@ -28,7 +28,7 @@ class Sdl : public display::Display { this->height_ = height; } void set_window_options(uint32_t window_options) { this->window_options_ = window_options; } - void set_position(uint16_t pos_x, uint16_t pos_y) { + void set_position(int32_t pos_x, int32_t pos_y) { this->pos_x_ = pos_x; this->pos_y_ = pos_y; } @@ -54,8 +54,8 @@ class Sdl : public display::Display { int width_{}; int height_{}; uint32_t window_options_{0}; - int pos_x_{SDL_WINDOWPOS_UNDEFINED}; - int pos_y_{SDL_WINDOWPOS_UNDEFINED}; + int32_t pos_x_{SDL_WINDOWPOS_UNDEFINED}; + int32_t pos_y_{SDL_WINDOWPOS_UNDEFINED}; SDL_Renderer *renderer_{}; SDL_Window *window_{}; SDL_Texture *texture_{}; diff --git a/tests/components/sdl/common.yaml b/tests/components/sdl/common.yaml index 66f93915b6..d3d3c9ee5e 100644 --- a/tests/components/sdl/common.yaml +++ b/tests/components/sdl/common.yaml @@ -10,6 +10,28 @@ display: dimensions: width: 450 height: 600 + window_options: + position: + x: 100 + y: 100 + + - platform: sdl + id: second_display + dimensions: + width: 450 + height: 600 + window_options: + position: + centered_on_display: 1 + + - platform: sdl + id: third_display + dimensions: + width: 450 + height: 600 + window_options: + position: + centered_on_display: 0 binary_sensor: - platform: sdl