diff --git a/box.py b/box.py index ea0ad1f..7beb394 100644 --- a/box.py +++ b/box.py @@ -19,82 +19,82 @@ class Box(Layout): **kwargs ): super().__init__(**kwargs) - self._title = title - self._title_font = title_font - self._title_color = title_color - self._title_anchor = title_anchor - self._title_position = title_position - self._title_padding = title_padding - self._content = content + self.title = title + self.title_font = title_font + self.title_color = title_color + self.title_anchor = title_anchor + self.title_position = title_position + self.title_padding = title_padding + self.content = content - def _children(self): - if self._content is not None: - return [self._content] + def children(self): + if self.content is not None: + return [self.content] else: return [] - def _get_title_font(self): - if self._title_font is not None: - return self._title_font + def get_title_font(self): + if self.title_font is not None: + return self.title_font else: return self.get_font() - def _get_title_color(self): - if self._title_color is not None: - return self._title_color + def get_title_color(self): + if self.title_color is not None: + return self.title_color else: return self.get_fg_color() def get_min_inner_width(self, max_height=None): - if self._content is None: + if self.content is None: return 0 else: - return self._content.get_min_outer_width(max_height) + return self.content.get_min_outer_width(max_height) def get_min_inner_height(self, max_width=None): - if self._content is None: + if self.content is None: return 0 else: - return self._content.get_min_outer_height(max_width) + return self.content.get_min_outer_height(max_width) def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): - if self._content is None: + if self.content is None: return 0, 0 else: - return self._content.get_ideal_outer_dimensions(min_width, min_height, available_width, available_height) + return self.content.get_ideal_outer_dimensions(min_width, min_height, available_width, available_height) def render_content(self, rect): - if self._content is None: + if self.content is None: return self.make_canvas() else: - return self._content.render(rect) + return self.content.render(rect) - def _title_pos(self, rect): - left, top, right, bottom = self._get_title_font().getbbox(self._title) + def title_pos(self, rect): + left, top, right, bottom = self.get_title_font().getbbox(self.title) height = bottom - top width = right - left - border_radius = self.border_radius() + border_radius = self.get_border_radius() available_width = rect[2] - rect[0] + 1 - border_radius[1] - border_radius[0] - pos_x = rect[0] + border_radius[0] + self._title_position - if self._title_anchor == BoxTitleAnchor.LEFT: + pos_x = rect[0] + border_radius[0] + self.title_position + if self.title_anchor == BoxTitleAnchor.LEFT: pos_x += 0 - elif self._title_anchor == BoxTitleAnchor.CENTER: + elif self.title_anchor == BoxTitleAnchor.CENTER: pos_x += (available_width - width) / 2 - elif self._title_anchor == BoxTitleAnchor.RIGHT: + elif self.title_anchor == BoxTitleAnchor.RIGHT: pos_x += available_width - width pos_y = rect[1] - height / 2 - return (pos_x, pos_y), (left - self._title_padding, top, right + self._title_padding, bottom) + return (pos_x, pos_y), (left - self.title_padding, top, right + self.title_padding, bottom) def modify_border_mask(self, border_mask, rect): - if self._title is None: + if self.title is None: return - (x, y), (left, top, right, bottom) = self._title_pos(rect) + (x, y), (left, top, right, bottom) = self.title_pos(rect) d = ImageDraw.Draw(border_mask) d.rectangle((x + left, y + top, x + right, y + bottom), fill=0) def render_after_border(self, image, rect): - if self._title is None: + if self.title is None: return - (x, y), _ = self._title_pos(rect) + (x, y), _ = self.title_pos(rect) d = ImageDraw.Draw(image) - d.text((x, y), self._title, font=self._get_title_font(), fill=self._get_title_color()) + d.text((x, y), self.title, font=self.get_title_font(), fill=self.get_title_color()) diff --git a/container.py b/container.py index b775f49..c66d591 100644 --- a/container.py +++ b/container.py @@ -17,20 +17,20 @@ class Container(Layout): contents = [] self._contents = contents - def _children(self): + def children(self): return self._contents def get_min_inner_width(self, max_height=None): min_width = 0 for c in self._contents: width = c.get_min_outer_width(max_height) - if c._left is not None: - width += c._left - if c._right is not None: - width += c._right + if c.left is not None: + width += c.left + if c.right is not None: + width += c.right min_width = max(min_width, width) - if self._min_width is not None: - min_width = max(min_width, self._min_width) + if self.min_width is not None: + min_width = max(min_width, self.min_width) return min_width def get_min_inner_height(self, max_width=None): @@ -38,17 +38,17 @@ class Container(Layout): min_height_absolute = 0 for c in self._contents: height = c.get_min_outer_height(max_width) - if c._top is None and c._bottom is None and c._left is None and c._right is None: + if c.top is None and c.bottom is None and c.left is None and c.right is None: min_height_automatic += height else: - if c._top is not None: - height += c._top - if c._bottom is not None: - height += c._bottom + if c.top is not None: + height += c.top + if c.bottom is not None: + height += c.bottom min_height_absolute = max(min_height_absolute, height) min_height = max(min_height_automatic, min_height_absolute) - if self._min_height is not None: - min_height = max(min_height, self._min_height) + if self.min_height is not None: + min_height = max(min_height, self.min_height) return min_height def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): @@ -56,24 +56,24 @@ class Container(Layout): for c in self._contents: w, h = c.get_ideal_outer_dimensions(min_width, min_height, available_width, available_height) - if c._left is not None: - w += c._left - if c._right is not None: - w += c._right - if c._top is not None: - h += c._top - if c._bottom is not None: - h += c._bottom + if c.left is not None: + w += c.left + if c.right is not None: + w += c.right + if c.top is not None: + h += c.top + if c.bottom is not None: + h += c.bottom width = max(width, w) - if c._top is None and c._bottom is None and c._left is None and c._right is None: + if c.top is None and c.bottom is None and c.left is None and c.right is None: height_automatic += h else: height_absolute = max(height_absolute, h) height = max(height_automatic, height_absolute) - if self._width is not None: - width = self._width - if self._height is not None: - height = self._height + if self.width is not None: + width = self.width + if self.height is not None: + height = self.height return width, height def render_content(self, rect): @@ -83,29 +83,29 @@ class Container(Layout): for c in self._contents: soft_max_width, soft_max_height = x2 - x1 + 1, y2 - y1 + 1 - is_absolute = not (c._top is None and c._bottom is None and c._left is None and c._right is None) + is_absolute = not (c.top is None and c.bottom is None and c.left is None and c.right is None) - if c._left is not None: - soft_max_width -= c._left - if c._right is not None: - soft_max_width -= c._right - if c._top is not None: - soft_max_height -= c._top - if c._bottom is not None: - soft_max_height -= c._bottom + if c.left is not None: + soft_max_width -= c.left + if c.right is not None: + soft_max_width -= c.right + if c.top is not None: + soft_max_height -= c.top + if c.bottom is not None: + soft_max_height -= c.bottom - hard_max_width, hard_max_height = c._max_width, c._max_height - if c._left is not None and c._right is not None: - hard_max_width = min_with_none(hard_max_width, x2 - x1 + 1 - c._left - c._right) - if c._top is not None and c._bottom is not None: - hard_max_height = min_with_none(hard_max_height, y2 - y1 + 1 - c._top - c._bottom) + hard_max_width, hard_max_height = c.max_width, c.max_height + if c.left is not None and c.right is not None: + hard_max_width = min_with_none(hard_max_width, x2 - x1 + 1 - c.left - c.right) + if c.top is not None and c.bottom is not None: + hard_max_height = min_with_none(hard_max_height, y2 - y1 + 1 - c.top - c.bottom) width, height = c.get_ideal_outer_dimensions(available_width=soft_max_width, available_height=soft_max_height) - if c._left is not None and c._right is not None: - width = (x2 - c._right) - (x1 + c._left) + 1 - if c._top is not None and c._bottom is not None: - height = (y2 - c._bottom) - (y1 + c._top) + 1 + if c.left is not None and c.right is not None: + width = (x2 - c.right) - (x1 + c.left) + 1 + if c.top is not None and c.bottom is not None: + height = (y2 - c.bottom) - (y1 + c.top) + 1 min_width, min_height = c.get_min_outer_width(hard_max_height), c.get_min_outer_height(hard_max_width) width = max_with_none(width, min_width) @@ -115,26 +115,26 @@ class Container(Layout): height = min_with_none(height, hard_max_height) if is_absolute: - if c._left is None: - if c._right is None: + if c.left is None: + if c.right is None: cx1 = x1 cx2 = cx1 + width - 1 else: - cx2 = x2 - c._right + cx2 = x2 - c.right cx1 = cx2 - width + 1 else: - cx1 = x1 + c._left + cx1 = x1 + c.left cx2 = cx1 + width - 1 - if c._top is None: - if c._bottom is None: + if c.top is None: + if c.bottom is None: cy1 = y1 cy2 = cy1 + height - 1 else: - cy2 = y2 - c._bottom + cy2 = y2 - c.bottom cy1 = cy2 - height + 1 else: - cy1 = y1 + c._top + cy1 = y1 + c.top cy2 = cy1 + height - 1 else: cx1 = x1 diff --git a/document.py b/document.py index 1bf6e15..c60ef33 100644 --- a/document.py +++ b/document.py @@ -14,67 +14,67 @@ class Document(Layout): **kwargs ): super().__init__(**kwargs) - if self._overflow is None: - self._overflow = True - if self._font is None: - self._font = ImageFont.load_default() - self._content = content - self._actual_size = None + if self.overflow is None: + self.overflow = True + if self.font is None: + self.font = ImageFont.load_default() + self.content = content + self.actual_size = None self.complete_init(None) - def _children(self): - if self._content is not None: - return [self._content] + def children(self): + if self.content is not None: + return [self.content] else: return [] def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): - if self._content is None: + if self.content is None: return 0,0 else: - return self._content.get_ideal_outer_dimensions(min_width, min_height, available_width, available_height) + return self.content.get_ideal_outer_dimensions(min_width, min_height, available_width, available_height) def get_min_inner_height(self, max_width=None): - if self._content is None: + if self.content is None: return 0 else: - return self._content.get_min_outer_height(max_width) + return self.content.get_min_outer_height(max_width) def get_min_inner_width(self, max_height=None): - if self._content is None: + if self.content is None: return 0 else: - return self._content.get_min_outer_width(max_height) + return self.content.get_min_outer_width(max_height) def render_content(self, rect): image = self.make_canvas() - if self._content is not None: - content_image = self._content.render(rect) + if self.content is not None: + content_image = self.content.render(rect) image.alpha_composite(content_image) return image def get_image(self): - min_width = max_with_none(self._width, self._min_width) - min_height = max_with_none(self._height, self._min_height) - max_width = min_with_none(self._width, self._max_width) - max_height = min_with_none(self._height, self._max_height) + min_width = max_with_none(self.width, self.min_width) + min_height = max_with_none(self.height, self.min_height) + max_width = min_with_none(self.width, self.max_width) + max_height = min_with_none(self.height, self.max_height) width, height = self.get_ideal_outer_dimensions(min_width=min_width, min_height=min_height, available_width=max_width, available_height=max_height) - if self._width is not None: - width = self._width + if self.width is not None: + width = self.width else: - width = min_with_none(max_with_none(width, self._min_width), self._max_width) - if self._height is not None: - height = self._height + width = min_with_none(max_with_none(width, self.min_width), self.max_width) + if self.height is not None: + height = self.height else: - height = min_with_none(max_with_none(height, self._min_height), self._max_height) + height = min_with_none(max_with_none(height, self.min_height), self.max_height) - self._actual_size = (width, height) + self.actual_size = (width, height) - background = Image.new('RGBA', (width, height), self._bg_color) + background = Image.new('RGBA', (width, height), self.bg_color) content = self.render((0, 0, width - 1, height - 1)) return Image.alpha_composite(background, content) diff --git a/flex.py b/flex.py index ab45cdd..9a204e2 100644 --- a/flex.py +++ b/flex.py @@ -21,43 +21,43 @@ class Flex(Layout): super().__init__(**kwargs) if contents is None: contents = [] - self._direction = direction - self._wrap = wrap - self._justify = justify - self._align_items = align_items - self._align_content = align_content - self._gap = gap - self._contents = contents - self._flex_layouter = FlexLayouter(contents, gap, direction, wrap, justify, align_content, align_items) + self.direction = direction + self.wrap = wrap + self.justify = justify + self.align_items = align_items + self.align_content = align_content + self.gap = gap + self.contents = contents + self.flex_layouter = FlexLayouter(contents, gap, direction, wrap, justify, align_content, align_items) - def _children(self): - return self._contents + def children(self): + return self.contents def get_min_inner_width(self, max_height=None): - max_width = min_with_none(self._max_width, 0) - width, _ = self._flex_layouter.get_dimensions(self._min_width, self._min_height, max_width, - min_with_none(self._max_height, max_height)) + max_width = min_with_none(self.max_width, 0) + width, _ = self.flex_layouter.get_dimensions(self.min_width, self.min_height, max_width, + min_with_none(self.max_height, max_height)) return width def get_min_inner_height(self, max_width=None): - max_height = min_with_none(self._min_height, 0) - _, height = self._flex_layouter.get_dimensions(self._min_width, self._min_height, - min_with_none(self._max_width, max_width), max_height) + max_height = min_with_none(self.min_height, 0) + _, height = self.flex_layouter.get_dimensions(self.min_width, self.min_height, + min_with_none(self.max_width, max_width), max_height) return height def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): - min_width = max_with_none(min_width, self._min_width) - min_height = max_with_none(min_height, self._min_height) - available_width = min_with_none(available_width, self._max_width, self._width) - available_height = min_with_none(available_height, self._max_height, self._height) - return self._flex_layouter.get_dimensions(min_width, min_height, available_width, available_height) + min_width = max_with_none(min_width, self.min_width) + min_height = max_with_none(min_height, self.min_height) + available_width = min_with_none(available_width, self.max_width, self.width) + available_height = min_with_none(available_height, self.max_height, self.height) + return self.flex_layouter.get_dimensions(min_width, min_height, available_width, available_height) def render_content(self, rect): image = self.make_canvas() x1, y1, x2, y2 = rect width = x2 - x1 + 1 height = y2 - y1 + 1 - contents = self._flex_layouter.arrange(self._min_width, self._min_height, width, height) + contents = self.flex_layouter.arrange(self.min_width, self.min_height, width, height) for (cx1, cy1, cx2, cy2), content in contents: content_image = content.render((cx1 + x1, cy1 + y1, cx2 + x1, cy2 + y1)) image.alpha_composite(content_image) diff --git a/image.py b/image.py index c9fa15b..651a8c0 100644 --- a/image.py +++ b/image.py @@ -19,69 +19,69 @@ class Image(Layout): **kwargs ): super().__init__(**kwargs) - self._image = image - self._mode = mode - self._scale = scale - self._position = position - self._offset_x = offset_x - self._offset_y = offset_y + self.image = image + self.mode = mode + self.scale = scale + self.position = position + self.offset_x = offset_x + self.offset_y = offset_y - def scale(self): - if isinstance(self._scale, (tuple, list)): - if len(self._scale) == 0: + def get_scale(self): + if isinstance(self.scale, (tuple, list)): + if len(self.scale) == 0: return 1, 1 - elif len(self._scale) == 1: - return self._scale[0], self._scale[0] + elif len(self.scale) == 1: + return self.scale[0], self.scale[0] else: - return self._scale[0], self._scale[1] - elif isinstance(self._scale, (int, float)): - return self._scale, self._scale + return self.scale[0], self.scale[1] + elif isinstance(self.scale, (int, float)): + return self.scale, self.scale else: return 1, 1 - def _get_image_width(self): - if self._image is None: + def get_image_width(self): + if self.image is None: return 0 - return self._image.size[0] + return self.image.size[0] - def _get_image_height(self): - if self._image is None: + def get_image_height(self): + if self.image is None: return 0 - return self._image.size[1] + return self.image.size[1] def get_min_inner_width(self, max_height=None): - if self._mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_Y, ImageMode.STRETCH_Y): - width = self._get_image_width() + if self.mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_Y, ImageMode.STRETCH_Y): + width = self.get_image_width() else: width = 0 - return max_with_none(width, self._min_width) + return max_with_none(width, self.min_width) def get_min_inner_height(self, max_width=None): - if self._mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_X, ImageMode.STRETCH_X): - height = self._get_image_height() + if self.mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_X, ImageMode.STRETCH_X): + height = self.get_image_height() else: height = 0 - return max_with_none(height, self._min_height) + return max_with_none(height, self.min_height) def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): width, height = 0, 0 - if self._mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_Y, ImageMode.STRETCH_Y): - width = self._get_image_width() - if self._mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_X, ImageMode.STRETCH_X): - height = self._get_image_height() - if self._width is not None: - width = self._width - if self._height is not None: - height = self._height - width = min_with_none(width, available_width, self._max_width) - height = min_with_none(height, available_height, self._max_height) - width = max_with_none(width, min_width, self._min_width) - height = max_with_none(height, min_height, self._min_height) + if self.mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_Y, ImageMode.STRETCH_Y): + width = self.get_image_width() + if self.mode in (ImageMode.ORIGINAL, ImageMode.REPEAT_X, ImageMode.STRETCH_X): + height = self.get_image_height() + if self.width is not None: + width = self.width + if self.height is not None: + height = self.height + width = min_with_none(width, available_width, self.max_width) + height = min_with_none(height, available_height, self.max_height) + width = max_with_none(width, min_width, self.min_width) + height = max_with_none(height, min_height, self.min_height) return width, height def render_content(self, rect): image = self.make_canvas() - if self._image is None: + if self.image is None: return image x1, y1, x2, y2 = rect @@ -91,24 +91,24 @@ class Image(Layout): if width == 0 or height == 0: return image - image_width = int(self._image.size[0] * self.scale()[0]) - image_height = int(self._image.size[1] * self.scale()[1]) + image_width = int(self.image.size[0] * self.get_scale()[0]) + image_height = int(self.image.size[1] * self.get_scale()[1]) - offset_x = self._offset_x - offset_y = self._offset_y + offset_x = self.offset_x + offset_y = self.offset_y - if self._mode == ImageMode.ORIGINAL: - if image_width != self._image.size[0] or image_height != self._image.size[1]: - img = self._image.resize((image_width, image_height), reducing_gap=3.0) + if self.mode == ImageMode.ORIGINAL: + if image_width != self.image.size[0] or image_height != self.image.size[1]: + img = self.image.resize((image_width, image_height), reducing_gap=3.0) else: - img = self._image - elif self._mode == ImageMode.STRETCH: - img = self._image.resize((width, height), reducing_gap=3.0) - elif self._mode == ImageMode.STRETCH_X: - img = self._image.resize((width, image_height), reducing_gap=3.0) - elif self._mode == ImageMode.STRETCH_Y: - img = self._image.resize((image_width, height), reducing_gap=3.0) - elif self._mode == ImageMode.CONTAIN: + img = self.image + elif self.mode == ImageMode.STRETCH: + img = self.image.resize((width, height), reducing_gap=3.0) + elif self.mode == ImageMode.STRETCH_X: + img = self.image.resize((width, image_height), reducing_gap=3.0) + elif self.mode == ImageMode.STRETCH_Y: + img = self.image.resize((image_width, height), reducing_gap=3.0) + elif self.mode == ImageMode.CONTAIN: ratio_width = width / image_width ratio_height = height / image_height if ratio_width < ratio_height: @@ -120,8 +120,8 @@ class Image(Layout): else: w = width h = height - img = self._image.resize((w, h), reducing_gap=3.0) - elif self._mode == ImageMode.COVER: + img = self.image.resize((w, h), reducing_gap=3.0) + elif self.mode == ImageMode.COVER: ratio_width = width / image_width ratio_height = height / image_height if ratio_width > ratio_height: @@ -133,42 +133,42 @@ class Image(Layout): else: w = width h = height - img = self._image.resize((w, h), reducing_gap=3.0) + img = self.image.resize((w, h), reducing_gap=3.0) - if self._mode == ImageMode.REPEAT_X_FILL: + if self.mode == ImageMode.REPEAT_X_FILL: repeat_width = int(image_width * height / image_height) repeat_height = height - elif self._mode == ImageMode.REPEAT_Y_FILL: + elif self.mode == ImageMode.REPEAT_Y_FILL: repeat_width = width repeat_height = int(image_height * width / image_width) else: repeat_width = image_width repeat_height = image_height - if self._mode in (ImageMode.REPEAT, ImageMode.REPEAT_X, ImageMode.REPEAT_X_FILL, ImageMode.REPEAT_X_STRETCH): - if self._position in (ImageAnchor.TOP_LEFT, ImageAnchor.MIDDLE_LEFT, ImageAnchor.BOTTOM_LEFT): + if self.mode in (ImageMode.REPEAT, ImageMode.REPEAT_X, ImageMode.REPEAT_X_FILL, ImageMode.REPEAT_X_STRETCH): + if self.position in (ImageAnchor.TOP_LEFT, ImageAnchor.MIDDLE_LEFT, ImageAnchor.BOTTOM_LEFT): repeat_offset_x = offset_x - elif self._position in (ImageAnchor.TOP_CENTER, ImageAnchor.MIDDLE_CENTER, ImageAnchor.BOTTOM_CENTER): + elif self.position in (ImageAnchor.TOP_CENTER, ImageAnchor.MIDDLE_CENTER, ImageAnchor.BOTTOM_CENTER): repeat_offset_x = (width // 2) - repeat_width // 2 + offset_x - elif self._position in (ImageAnchor.TOP_RIGHT, ImageAnchor.MIDDLE_RIGHT, ImageAnchor.BOTTOM_RIGHT): + elif self.position in (ImageAnchor.TOP_RIGHT, ImageAnchor.MIDDLE_RIGHT, ImageAnchor.BOTTOM_RIGHT): repeat_offset_x = width - repeat_width + offset_x else: raise Exception('invalid image position') - if self._mode in (ImageMode.REPEAT, ImageMode.REPEAT_Y, ImageMode.REPEAT_Y_FILL, ImageMode.REPEAT_Y_STRETCH): - if self._position in (ImageAnchor.TOP_LEFT, ImageAnchor.TOP_CENTER, ImageAnchor.TOP_RIGHT): + if self.mode in (ImageMode.REPEAT, ImageMode.REPEAT_Y, ImageMode.REPEAT_Y_FILL, ImageMode.REPEAT_Y_STRETCH): + if self.position in (ImageAnchor.TOP_LEFT, ImageAnchor.TOP_CENTER, ImageAnchor.TOP_RIGHT): repeat_offset_y = offset_y - elif self._position in (ImageAnchor.MIDDLE_LEFT, ImageAnchor.MIDDLE_CENTER, ImageAnchor.MIDDLE_RIGHT): + elif self.position in (ImageAnchor.MIDDLE_LEFT, ImageAnchor.MIDDLE_CENTER, ImageAnchor.MIDDLE_RIGHT): repeat_offset_y = (height // 2) - repeat_height // 2 + offset_y - elif self._position in (ImageAnchor.BOTTOM_LEFT, ImageAnchor.BOTTOM_CENTER, ImageAnchor.BOTTOM_RIGHT): + elif self.position in (ImageAnchor.BOTTOM_LEFT, ImageAnchor.BOTTOM_CENTER, ImageAnchor.BOTTOM_RIGHT): repeat_offset_y = height - repeat_height + offset_y else: raise Exception('invalid image position') - if self._mode == ImageMode.REPEAT: - if repeat_width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((repeat_width, repeat_height), reducing_gap=3.0) + if self.mode == ImageMode.REPEAT: + if repeat_width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((repeat_width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, height), (0,0,0,0)) num_x = width // repeat_width + 1 num_y = height // repeat_height + 1 @@ -179,66 +179,66 @@ class Image(Layout): img.paste(img_part, (i * repeat_width + ox, j * repeat_height + oy)) offset_x = 0 offset_y = 0 - elif self._mode == ImageMode.REPEAT_X: - if repeat_width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((repeat_width, repeat_height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_X: + if repeat_width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((repeat_width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, repeat_height), (0,0,0,0)) num_x = width // repeat_width + 1 ox = repeat_offset_x % (repeat_width if repeat_offset_x >= 0 else -repeat_width) for i in range(-1, num_x): img.paste(img_part, (i * repeat_width + ox, 0)) offset_x = 0 - elif self._mode == ImageMode.REPEAT_Y: - if repeat_width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((repeat_width, repeat_height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_Y: + if repeat_width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((repeat_width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (repeat_width, height), (0,0,0,0)) num_y = height // repeat_height + 1 oy = repeat_offset_y % (repeat_height if repeat_offset_y >= 0 else -repeat_height) for i in range(-1, num_y): img.paste(img_part, (0, i * repeat_height + oy)) offset_y = 0 - elif self._mode == ImageMode.REPEAT_X_STRETCH: - if repeat_width != self._image.size[0] or height != self._image.size[1]: - img_part = self._image.resize((repeat_width, height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_X_STRETCH: + if repeat_width != self.image.size[0] or height != self.image.size[1]: + img_part = self.image.resize((repeat_width, height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, height), (0,0,0,0)) num_x = width // repeat_width + 1 ox = repeat_offset_x % (repeat_width if repeat_offset_x >= 0 else -repeat_width) for i in range(-1, num_x): img.paste(img_part, (i * repeat_width + ox, 0)) offset_x = 0 - elif self._mode == ImageMode.REPEAT_Y_STRETCH: - if width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((width, repeat_height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_Y_STRETCH: + if width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, height), (0,0,0,0)) num_y = height // repeat_height + 1 oy = repeat_offset_y % (repeat_height if repeat_offset_y >= 0 else -repeat_height) for i in range(-1, num_y): img.paste(img_part, (0, i * repeat_height + oy)) offset_y = 0 - elif self._mode == ImageMode.REPEAT_X_FILL: - if repeat_width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((repeat_width, repeat_height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_X_FILL: + if repeat_width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((repeat_width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, height), (0,0,0,0)) num_x = width // repeat_width + 1 ox = repeat_offset_x % (repeat_width if repeat_offset_x >= 0 else -w) for i in range(-1, num_x): img.paste(img_part, (i * repeat_width + ox, 0)) offset_x = 0 - elif self._mode == ImageMode.REPEAT_Y_FILL: - if repeat_width != self._image.size[0] or repeat_height != self._image.size[1]: - img_part = self._image.resize((repeat_width, repeat_height), reducing_gap=3.0) + elif self.mode == ImageMode.REPEAT_Y_FILL: + if repeat_width != self.image.size[0] or repeat_height != self.image.size[1]: + img_part = self.image.resize((repeat_width, repeat_height), reducing_gap=3.0) else: - img_part = self._image + img_part = self.image img = PilImage.new('RGBA', (width, height), (0,0,0,0)) num_y = height // repeat_height + 1 oy = repeat_offset_y % (repeat_height if repeat_offset_y >= 0 else -repeat_height) @@ -246,19 +246,19 @@ class Image(Layout): img.paste(img_part, (0, i * repeat_height + oy)) offset_y = 0 - if self._position in (ImageAnchor.TOP_LEFT, ImageAnchor.MIDDLE_LEFT, ImageAnchor.BOTTOM_LEFT): + if self.position in (ImageAnchor.TOP_LEFT, ImageAnchor.MIDDLE_LEFT, ImageAnchor.BOTTOM_LEFT): x = x1 + offset_x - elif self._position in (ImageAnchor.TOP_CENTER, ImageAnchor.MIDDLE_CENTER, ImageAnchor.BOTTOM_CENTER): + elif self.position in (ImageAnchor.TOP_CENTER, ImageAnchor.MIDDLE_CENTER, ImageAnchor.BOTTOM_CENTER): x = x1 + (width // 2) - img.size[0] // 2 + offset_x - elif self._position in (ImageAnchor.TOP_RIGHT, ImageAnchor.MIDDLE_RIGHT, ImageAnchor.BOTTOM_RIGHT): + elif self.position in (ImageAnchor.TOP_RIGHT, ImageAnchor.MIDDLE_RIGHT, ImageAnchor.BOTTOM_RIGHT): x = x1 + width - img.size[0] + offset_x else: raise Exception('invalid image position') - if self._position in (ImageAnchor.TOP_LEFT, ImageAnchor.TOP_CENTER, ImageAnchor.TOP_RIGHT): + if self.position in (ImageAnchor.TOP_LEFT, ImageAnchor.TOP_CENTER, ImageAnchor.TOP_RIGHT): y = y1 + offset_y - elif self._position in (ImageAnchor.MIDDLE_LEFT, ImageAnchor.MIDDLE_CENTER, ImageAnchor.MIDDLE_RIGHT): + elif self.position in (ImageAnchor.MIDDLE_LEFT, ImageAnchor.MIDDLE_CENTER, ImageAnchor.MIDDLE_RIGHT): y = y1 + (height // 2) - img.size[1] // 2 + offset_y - elif self._position in (ImageAnchor.BOTTOM_LEFT, ImageAnchor.BOTTOM_CENTER, ImageAnchor.BOTTOM_RIGHT): + elif self.position in (ImageAnchor.BOTTOM_LEFT, ImageAnchor.BOTTOM_CENTER, ImageAnchor.BOTTOM_RIGHT): y = y1 + height - img.size[1] + offset_y else: raise Exception('invalid image position') diff --git a/internal/flexlayouter.py b/internal/flexlayouter.py index 76abf34..3062216 100644 --- a/internal/flexlayouter.py +++ b/internal/flexlayouter.py @@ -2,7 +2,7 @@ from ..enums import FlexDirection, FlexWrap, FlexJustify, FlexAlignItems, FlexAl from .helpers import min_with_none, max_with_none -class FlexLineItem(): +class FlexLineItem: def __init__(self, content, max_width, max_height, direction): self.__content = content self.__max_width = max_width @@ -20,14 +20,14 @@ class FlexLineItem(): def base_size(self): if self.__direction in (FlexDirection.ROW, FlexDirection.ROW_REVERSE): - if self.__content._width is not None: - return self.__content._width + if self.__content.width is not None: + return self.__content.width else: return self.__content.get_ideal_outer_dimensions(available_width=self.__max_width, available_height=self.__max_height)[0] else: - if self.__content._height is not None: - return self.__content._height + if self.__content.height is not None: + return self.__content.height else: return self.__content.get_ideal_outer_dimensions(available_width=self.__max_width, available_height=self.__max_height)[1] @@ -46,15 +46,15 @@ class FlexLineItem(): def max_main_size(self): if self.__direction in (FlexDirection.ROW, FlexDirection.ROW_REVERSE): - return self.__content._max_width + return self.__content.max_width else: - return self.__content._max_height + return self.__content.max_height def max_cross_size(self): if self.__direction in (FlexDirection.ROW, FlexDirection.ROW_REVERSE): - return self.__content._max_height + return self.__content.max_height else: - return self.__content._max_width + return self.__content.max_width def hypothetical_main_size(self): return min_with_none(self.max_main_size(), max_with_none(self.min_main_size(), self.base_size())) @@ -81,10 +81,10 @@ class FlexLineItem(): return self.__cross_pos def grow_factor(self): - return self.__content._flex_grow + return self.__content.flex_grow def shrink_factor(self): - return self.__content._flex_shrink + return self.__content.flex_shrink def scaled_shrink_factor(self): return self.shrink_factor() * self.base_size() diff --git a/layout.py b/layout.py index bb42f85..3f728d6 100644 --- a/layout.py +++ b/layout.py @@ -32,68 +32,68 @@ class Layout: flex_shrink=0, debug_layout=False, ): - self._width = width - self._height = height - self._min_width = min_width - self._min_height = min_height - self._max_width = max_width - self._max_height = max_height - self._fg_color = fg_color - self._bg_color = bg_color - self._border_color = border_color - self._border_width = border_width - self._border_radius = border_radius - self._padding = padding - self._font = font - self._overflow = overflow - self._left = left - self._top = top - self._right = right - self._bottom = bottom - self._flex_grow = flex_grow - self._flex_shrink = flex_shrink - self._debug_layout = debug_layout - self._container = None + self.width = width + self.height = height + self.min_width = min_width + self.min_height = min_height + self.max_width = max_width + self.max_height = max_height + self.fg_color = fg_color + self.bg_color = bg_color + self.border_color = border_color + self.border_width = border_width + self.border_radius = border_radius + self.padding = padding + self.font = font + self.overflow = overflow + self.left = left + self.top = top + self.right = right + self.bottom = bottom + self.flex_grow = flex_grow + self.flex_shrink = flex_shrink + self.debug_layout = debug_layout + self.container = None def complete_init(self, container): - self._container = container - for c in self._children(): + self.container = container + for c in self.children(): c.complete_init(self) - def _children(self): + def children(self): return [] def get_document_size(self): if isinstance(self, layout.Document): - return self._actual_size + return self.actual_size else: - return self._container.get_document_size() + return self.container.get_document_size() def get_fg_color(self): - if self._fg_color is not None: - return self._fg_color - elif self._container is not None: - return self._container.get_fg_color() + if self.fg_color is not None: + return self.fg_color + elif self.container is not None: + return self.container.get_fg_color() else: return None def get_font(self): - if self._font is not None: - return self._font - elif self._container is not None: - return self._container.get_font() + if self.font is not None: + return self.font + elif self.container is not None: + return self.container.get_font() else: raise Exception('no font defined in {0}'.format(self.__class__)) def get_overflow(self): - if self._overflow is not None: - return self._overflow - elif self._container is not None: - return self._container.get_overflow() + if self.overflow is not None: + return self.overflow + elif self.container is not None: + return self.container.get_overflow() else: return None - def _get_tuple_property(self, name, default, allow_tuple=True): + def get_tuple_property(self, name, default, allow_tuple=True): value = getattr(self, name) if isinstance(value, list) or (allow_tuple and isinstance(value, tuple)): if len(value) == 0: @@ -111,33 +111,33 @@ class Layout: else: return value, value, value, value - def padding(self): - return self._get_tuple_property('_padding', 0) + def get_padding(self): + return self.get_tuple_property('padding', 0) - def border_width(self): - return self._get_tuple_property('_border_width', 0) + def get_border_width(self): + return self.get_tuple_property('border_width', 0) - def border_color(self): - return self._get_tuple_property('_border_color', None, False) + def get_border_color(self): + return self.get_tuple_property('border_color', None, False) - def border_radius(self): - return self._get_tuple_property('_border_radius', None) + def get_border_radius(self): + return self.get_tuple_property('border_radius', None) def get_min_inner_width(self, max_height=None): - return self._min_width + return self.min_width def get_min_inner_height(self, max_width=None): - return self._min_height + return self.min_height def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): - return self._width, self._height + return self.width, self.height def get_x_padding_border_size(self): - border, padding = self.border_width(), self.padding() + border, padding = self.get_border_width(), self.get_padding() return border[0] + border[2] + padding[0] + padding[2] def get_y_padding_border_size(self): - border, padding = self.border_width(), self.padding() + border, padding = self.get_border_width(), self.get_padding() return border[1] + border[3] + padding[1] + padding[3] def get_min_outer_width(self, max_outer_height=None): @@ -208,7 +208,7 @@ class Layout: def make_border_inside_mask(self, rect, border_radii): mask = Image.new('1', self.get_document_size(), 0) x1, y1, x2, y2 = rect - width_left, width_top, width_right, width_bottom = self.border_width() + width_left, width_top, width_right, width_bottom = self.get_border_width() radius_top_left, radius_top_right, radius_bottom_right, radius_bottom_left = border_radii inner_rect = (x1 + width_left, y1 + width_top, x2 - width_right, y2 - width_bottom) @@ -236,8 +236,8 @@ class Layout: def make_border_color_image(self, rect, border_radii): x1, y1, x2, y2 = rect - color_left, color_top, color_right, color_bottom = self.border_color() - width_left, width_top, width_right, width_bottom = self.border_width() + color_left, color_top, color_right, color_bottom = self.get_border_color() + width_left, width_top, width_right, width_bottom = self.get_border_width() radius_top_left, radius_top_right, radius_bottom_right, radius_bottom_left = border_radii image = self.make_canvas() @@ -297,7 +297,7 @@ class Layout: x1, y1, x2, y2 = rect width, height = x2 - x1 + 1, y2 - y1 + 1 - border_radii = self.border_radius() + border_radii = self.get_border_radius() radius_sum_top = border_radii[0] + border_radii[1] radius_sum_right = border_radii[1] + border_radii[2] radius_sum_bottom = border_radii[2] + border_radii[3] @@ -354,8 +354,8 @@ class Layout: self.modify_inside_mask(inside_mask, rect) self.modify_border_mask(border_mask, rect) - if self._bg_color is not None: - image.paste(self._bg_color, mask=outside_mask) + if self.bg_color is not None: + image.paste(self.bg_color, mask=outside_mask) self.render_after_background(image, rect) border_color = self.make_border_color_image(rect, border_radii) @@ -365,8 +365,8 @@ class Layout: image.alpha_composite(border_image) self.render_after_border(image, rect) - border_width = self.border_width() - padding = self.padding() + border_width = self.get_border_width() + padding = self.get_padding() content_x1 = rect[0] + border_width[0] + padding[0] content_y1 = rect[1] + border_width[1] + padding[1] content_x2 = rect[2] - border_width[2] - padding[2] @@ -380,7 +380,7 @@ class Layout: image.alpha_composite(content_image) self.render_after_content(image, rect) - if self._debug_layout: + if self.debug_layout: dc = Image.new('RGBA', image.size, (0, 0, 0, 0)) d = ImageDraw.Draw(dc) diff --git a/readme.md b/readme.md index 4d6f6b9..2c9b22f 100644 --- a/readme.md +++ b/readme.md @@ -485,7 +485,11 @@ Where the image is anchored for positioning with `offset_x` and `offset_y`. #### ImageAnchor.BOTTOM_RIGHT -#### +# custom layouts + +A layout should extend the `Layout` class and implement the following methods: + + # possible future features diff --git a/text.py b/text.py index 0ad03f5..f318ffa 100644 --- a/text.py +++ b/text.py @@ -18,65 +18,65 @@ class Text(Layout): **kwargs ): super().__init__(**kwargs) - self._text_layouter = None - self._text = text - self._text_align = text_align - self._vertical_text_align = vertical_text_align - self._text_wrap = text_wrap - self._line_spacing = line_spacing + self.text_layouter = None + self.text = text + self.text_align = text_align + self.vertical_text_align = vertical_text_align + self.text_wrap = text_wrap + self.line_spacing = line_spacing def complete_init(self, container): super().complete_init(container) - if self._is_empty(): + if self.is_empty(): lines = [] - elif isinstance(self._text, list): - lines = self._text + elif isinstance(self.text, list): + lines = self.text else: - lines = self._text.splitlines() - self._text_layouter = TextLayouter(lines=lines, - align=self._text_align, - vertical_align=self._vertical_text_align, - wrap=self._text_wrap, - font=self.get_font(), - line_height=self._get_line_height_with_spacing()) + lines = self.text.splitlines() + self.text_layouter = TextLayouter(lines=lines, + align=self.text_align, + vertical_align=self.vertical_text_align, + wrap=self.text_wrap, + font=self.get_font(), + line_height=self.get_line_height_with_spacing()) - def _is_empty(self): - return self._text is None or self._text == '' or (isinstance(self._text, list) - and len(self._text) == 0) + def is_empty(self): + return self.text is None or self.text == '' or (isinstance(self.text, list) + and len(self.text) == 0) def get_min_inner_width(self, max_height=None): - if self._is_empty(): + if self.is_empty(): width = 0 else: if max_height is not None: - max_height += self._line_spacing - width = self._text_layouter.get_dimensions(0, max_height)[0] - return max_with_none(width, self._min_width) + max_height += self.line_spacing + width = self.text_layouter.get_dimensions(0, max_height)[0] + return max_with_none(width, self.min_width) def get_min_inner_height(self, max_width=None): - if self._is_empty(): + if self.is_empty(): height = 0 else: # no spacing after the last line - height = self._text_layouter.get_dimensions(max_width, 0)[1] - self._line_spacing - return max_with_none(height, self._min_height) + height = self.text_layouter.get_dimensions(max_width, 0)[1] - self.line_spacing + return max_with_none(height, self.min_height) def get_ideal_inner_dimensions(self, min_width=None, min_height=None, available_width=None, available_height=None): - available_width = min_with_none(available_width, self._width) - available_height = min_with_none(available_height, self._height) + available_width = min_with_none(available_width, self.width) + available_height = min_with_none(available_height, self.height) - width, height = self._text_layouter.get_dimensions(available_width, available_height) - height -= self._line_spacing # no spacing after the last line + width, height = self.text_layouter.get_dimensions(available_width, available_height) + height -= self.line_spacing # no spacing after the last line - if self._width is not None: - width = self._width - if self._height is not None: - height = self._height + if self.width is not None: + width = self.width + if self.height is not None: + height = self.height - width = max_with_none(width, self._min_width) - height = max_with_none(height, self._min_height) - width = min_with_none(width, self._max_width) - height = min_with_none(height, self._max_height) + width = max_with_none(width, self.min_width) + height = max_with_none(height, self.min_height) + width = min_with_none(width, self.max_width) + height = min_with_none(height, self.max_height) return width, height @@ -86,21 +86,21 @@ class Text(Layout): x1, y1, x2, y2 = rect width, height = x2 - x1 + 1, y2 - y1 + 1 - if self._max_width is not None: - width = min(width, self._max_width) - if self._min_width is not None: - width = max(width, self._min_width) - if self._max_height is not None: - height = min(height, self._max_height) - if self._min_height is not None: - height = max(height, self._min_height) + if self.max_width is not None: + width = min(width, self.max_width) + if self.min_width is not None: + width = max(width, self.min_width) + if self.max_height is not None: + height = min(height, self.max_height) + if self.min_height is not None: + height = max(height, self.min_height) - lines = self._text_layouter.get_lines(width, height) + lines = self.text_layouter.get_lines(width, height) color = self.get_fg_color() font = self.get_font() for posx, posy, text in lines: d.text((x1 + posx, y1 + posy), text, font=font, fill=color) return image - def _get_line_height_with_spacing(self): - return get_line_height(self.get_font()) + self._line_spacing + def get_line_height_with_spacing(self): + return get_line_height(self.get_font()) + self.line_spacing