Exemplo n.º 1
0
 def resize(self, available: Size):
     """
     Sets the view's frame size, taking into account content size, padding, and borders.
     """
     available = self.env.constrain(available)
     max_w = 0
     max_h = 0
     inside = Size(
         max(0,
             available.w - self.env.padding.width - self.env.border.width),
         max(0, available.h - self.env.padding.height -
             self.env.border.height),
     )
     for view in self.subviews:
         view.resize(inside)
         max_w = max(max_w, view.frame.width)
         max_h = max(max_h, view.frame.height)
     size = self.content_size(inside)
     max_w = max(max_w, size.w)
     max_h = max(max_h, size.h)
     self.frame.size = Size(
         max_w + self.env.padding.width + self.env.border.width,
         max_h + self.env.padding.height + self.env.border.height,
     )
     return Size(max_w, max_h)
Exemplo n.º 2
0
 def test_rect_insets(self):
     r1 = Rect(origin=(100, 100), size=(150, 50))
     r2 = r1 + Insets(10)
     self.assertEqual(r2.origin, Point(90, 90))
     self.assertEqual(r2.size, Size(170, 70))
     r3 = r1 - Insets(10)
     self.assertEqual(r3.origin, Point(110, 110))
     self.assertEqual(r3.size, Size(130, 30))
Exemplo n.º 3
0
 def constrain(self, available=None):
     if available is None:
         available = self.image_size
     box = self.env.constrain(available,
                              self.image_size,
                              clamped=self.clamped)
     if self.stretch:
         return box
     pct_w = box.w / self.image_size.w
     pct_h = box.h / self.image_size.h
     if pct_w < pct_h:
         return Size(box.w, int(self.image_size.h * pct_w))
     else:
         return Size(int(self.image_size.w * pct_h), box.h)
Exemplo n.º 4
0
 def load_surface(self):
     if self._surface is None:
         if self.path:
             self._surface = IMG_Load(self.path.encode("utf-8"))
         else:
             self._surface = IMG_Load_RW(self.rw, 0)
         self._size = Size(self._surface.contents.w,
                           self._surface.contents.h)
Exemplo n.º 5
0
 def size(self, width=None, height=None):
     if isinstance(width, int):
         width = self.env.scaled(width)
     if isinstance(height, int):
         height = self.env.scaled(height)
     self.env.size = Size(width or self.env.size.w, height
                          or self.env.size.h)
     return self
Exemplo n.º 6
0
 def constrain(self, available, value=None, clamped=True):
     final = list(value or available)
     for a in Axis:
         v = self.size[a]
         if v:
             final[a] = v if isinstance(v, int) else int(v * available[a])
         if clamped:
             final[a] = clamp(final[a], 0, available[a])
     return Size(*final)
Exemplo n.º 7
0
 def content_size(self, available):
     if self.env.lines > 0:
         h = self._font.line_height * self.env.lines
     else:
         size = self._font.measure(self.text.value, width=available.w)
         h = max(size.h, available.h)
     # TODO: be smarter about when to invalidate this
     self._line_cache = None
     return Size(available.w, h)
Exemplo n.º 8
0
 def knob_size(self):
     return Size(
         max(self.track_size, int(self.frame.width * self.frame.width / self.scroll_size[Axis.HORIZONTAL]))
         if self.scroll_size[Axis.HORIZONTAL] > self.frame.width
         else 0,
         max(self.track_size, int(self.frame.height * self.frame.height / self.scroll_size[Axis.VERTICAL]))
         if self.scroll_size[Axis.VERTICAL] > self.frame.height
         else 0,
     )
Exemplo n.º 9
0
 def __init__(self, *contents, axis=Axis.VERTICAL, **options):
     super().__init__(*contents, **options)
     self.axis = Axis(axis) if axis is not None else None
     self.scroll_size = Size()
     self.scroll_interval = self.env.scaled(20)
     self.tracking = None
     self.offset = 0
     self.track_size = self.env.scaled(15)
     # Local state, not overwritten when re-using the view.
     self._position = Point()
Exemplo n.º 10
0
 def minimum_size(self):
     # Not sure a minimum size calculation is useful for this without knowing what's available.
     return Size()
     # Minimum size for a Grid is a single row/column (based on Axis).
     main = self.spacing[self.axis] * (len(self.subviews) - 1)
     cross = 0
     for view in self.subviews:
         min_size = view.minimum_size()
         main += min_size[self.axis] + view.env.padding[
             self.axis] + view.env.border[self.axis]
         cross = max(
             cross, min_size[self.cross] + view.env.padding[self.cross] +
             view.env.border[self.cross])
     return self.axis.size(main, cross)
Exemplo n.º 11
0
 def minimum_size(self):
     """
     Returns the minimum size in each dimension of this view's content, not including any padding or borders.
     """
     min_w = 0
     min_h = 0
     for view in self.subviews:
         m = view.minimum_size()
         min_w = max(
             m.w, min_w + view.env.padding[Axis.HORIZONTAL] +
             view.env.border[Axis.HORIZONTAL])
         min_h = max(
             m.h, min_h + view.env.padding[Axis.VERTICAL] +
             view.env.border[Axis.VERTICAL])
     return Size(min_w, min_h)
Exemplo n.º 12
0
 def resize(self, available: Size):
     available = self.env.constrain(available)
     # Need to account for scrollbars when resizing subviews.
     h = self.track_size if self.axis in (Axis.HORIZONTAL, None) else 0
     w = self.track_size if self.axis in (Axis.VERTICAL, None) else 0
     inside = Size(
         max(0, available.w - self.env.padding.width - self.env.border.width - w),
         max(0, available.h - self.env.padding.height - self.env.border.height - h),
     )
     self.scroll_size = super().resize(inside)
     self.frame.size = available
     # Clamp scroll positions when resizing.
     for axis in Axis:
         self.set_position(axis)
     return self.scroll_size
Exemplo n.º 13
0
 def load(self, class_name):
     for key, value in self.theme.env(class_name.lower()).items():
         if key in ("padding", "border"):
             value = Insets(*value).scaled(self.scale)
         elif key in ("color", "background", "border_color", "text_shadow"):
             value = sdl2.SDL_Color(*value)
         elif key == "priority":
             value = Priority[value.upper()]
         elif key == "position":
             value = Position[value.upper()]
         elif key == "alignment":
             value = Alignment[value.upper()]
         elif key == "spacing":
             value = self.scaled(value)
         elif key == "size":
             value = Size(self.scaled(value[0]), self.scaled(value[1]))
         elif key == "opacity":
             value = clamp(float(value), 0.0, 1.0)
         setattr(self, key, value)
Exemplo n.º 14
0
class Environment:
    theme = Env(inherit=True,
                default=Theme(os.path.join(BASE_DIR,
                                           "themes/dark/config.json")))
    scale = Env(inherit=True, default=1.0)

    font = Env(inherit=True, default="default")
    font_size = Env(inherit=True)
    text_shadow = Env(inherit=True)
    color = Env(default=sdl2.SDL_Color(230, 230, 230), inherit=True)
    background = Env()
    radius = Env(default=0)
    padding = Env(default=Insets(0))
    border = Env(default=Insets(0))
    border_color = Env()
    priority = Env(default=Priority.NORMAL)
    position = Env(default=Position.CENTER)
    alignment = Env(default=Alignment.CENTER)
    spacing = Env(default=0)
    size = Env(default=Size())
    opacity = Env(default=1.0, inherit=True)
    animation = Env(inherit=True)
    lines = Env(default=1)

    alpha = property(lambda self: round(self.opacity * 255))
    blended_color = property(
        lambda self: sdl2.SDL_Color(self.color.r, self.color.g, self.color.b,
                                    round((self.color.a * self.alpha) / 255)))

    def __init__(self, class_name=None, **overrides):
        self.parent = None
        if class_name:
            self.load(class_name)
        for key, value in overrides.items():
            setattr(self, key, value)

    def inherit(self, parent):
        self.parent = parent

    def scaled(self, value):
        if value is None:
            return None
        return value.__class__(value * self.scale)

    def constrain(self, available, value=None, clamped=True):
        final = list(value or available)
        for a in Axis:
            v = self.size[a]
            if v:
                final[a] = v if isinstance(v, int) else int(v * available[a])
            if clamped:
                final[a] = clamp(final[a], 0, available[a])
        return Size(*final)

    def load(self, class_name):
        for key, value in self.theme.env(class_name.lower()).items():
            if key in ("padding", "border"):
                value = Insets(*value).scaled(self.scale)
            elif key in ("color", "background", "border_color", "text_shadow"):
                value = sdl2.SDL_Color(*value)
            elif key == "priority":
                value = Priority[value.upper()]
            elif key == "position":
                value = Position[value.upper()]
            elif key == "alignment":
                value = Alignment[value.upper()]
            elif key == "spacing":
                value = self.scaled(value)
            elif key == "size":
                value = Size(self.scaled(value[0]), self.scaled(value[1]))
            elif key == "opacity":
                value = clamp(float(value), 0.0, 1.0)
            setattr(self, key, value)

    def draw(self, renderer, asset_name, rect, alpha=None):
        # Mostly lives here because it's where I have access to the theme and the scale, not because it's a good place
        # for it to live.
        asset = self.theme.load_asset(asset_name)
        if alpha is None:
            alpha = self.alpha
        asset.render(renderer, rect, alpha=alpha, scale=self.scale)
Exemplo n.º 15
0
 def minimum_size(self):
     return Size(self.track_size * 2, self.track_size * 2)
Exemplo n.º 16
0
 def content_size(self, available: Size):
     return self.env.constrain(Size(self.d, self.d))
Exemplo n.º 17
0
 def minimum_size(self):
     return Size(self.env.scaled(40), self.env.scaled(20))
Exemplo n.º 18
0
 def content_size(self, available):
     return Size(available.w, self.env.scaled(20))
Exemplo n.º 19
0
 def content_size(self, available: Size):
     return Size(available.w,
                 0) if self.parent.axis == Axis.HORIZONTAL else Size(
                     0, available.h)
Exemplo n.º 20
0
 def minimum_size(self):
     size = self._font.measure(self.placeholder)
     return Size(size.w, size.h * max(1, self.env.lines))