Source code for todays_paper_web.widgets.core.layout

from typing import Optional

from PIL import Image
from pydantic import Field

from todays_paper_web.widgets import registerView, View
from todays_paper_web.widgets.view import ViewParams


[docs] class BoxParams(ViewParams): width: Optional[int] = Field( None, description="Fixes the box's rendered width; auto-computed from children if unset." ) height: Optional[int] = Field( None, description="Fixes the box's rendered height; auto-computed from children if unset." )
@registerView("box") class BoxView(View): Params = BoxParams def render(self): width, height = 0, 0 imgs = [] # Loop all children to get total width and height of the box for child in self.children: childImg = child.render() if not childImg: continue x = child.params.x or 0 y = child.params.y or 0 align = child.params.align or "left" valign = child.params.valign or "top" if child.params.x is not None: # Only align x here if we have x attribute if align == "right": x -= childImg.width elif align == "center": x -= int(childImg.width / 2.0) if child.params.y is not None: # Only align y here if we have y attribute if valign == "bottom": y -= childImg.height elif valign in ["middle", "center"]: y -= int(childImg.height / 2.0) width = max(width, childImg.width + x) height = max(height, childImg.height + y) imgs.append((childImg, x, y, align, valign)) if self.params.width is not None: width = self.params.width if self.params.height is not None: height = self.params.height img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) # Now we have the box width and height, loop all and render them for childImg, x, y, align, valign in imgs: if x == 0: # Do alignment here if no x attribute are set if align == "right": x = width - childImg.width elif align == "center": x = int((width - childImg.width) / 2.0) if y == 0: # Do alignment here if no y attribute are set if valign == "bottom": y = height - childImg.height elif valign in ["middle", "center"]: y = int((height - childImg.height) / 2.0) self.paste(img, childImg, (x, y)) return img
[docs] class ColumnParams(ViewParams): """No attributes of its own - `<column>` only reads a child's `x` (see `ViewParams`), inherited rather than redeclared."""
@registerView("column") class ColumnView(View): Params = ColumnParams def render(self): width, height = 0, 0 imgs = [] for child in self.children: childImg = child.render() x = child.params.x or 0 width = max(width, childImg.width + x) height += childImg.height imgs.append((childImg, x)) y = 0 img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) for childImg, x in imgs: ColumnView.paste(img, childImg, (x, y)) y += childImg.height return img
[docs] class RowParams(ViewParams): valign: str = Field( "top", description="Default vertical alignment for a child that doesn't set its own `y`: `top`, " "`middle`/`center`, or `bottom`.", )
@registerView("row") class RowView(View): Params = RowParams def render(self): width, height = 0, 0 imgs = [] for child in self.children: childImg = child.render() y = child.params.y or 0 height = max(height, childImg.height + y) width += childImg.width imgs.append((childImg, y)) x = 0 img = Image.new("RGBA", (width, height), (0, 0, 0, 0)) for childImg, y in imgs: if not y: if self.params.valign == "bottom": y = height - childImg.height elif self.params.valign in ["middle", "center"]: y = int((height - int(childImg.height)) / 2.0) self.paste(img, childImg, (x, y)) x += childImg.width return img