Sideband/sbapp/kivymd/effects/fadingedge/fadingedge.py

198 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Effects/FadingEdgeEffect
========================
.. versionadded:: 1.0.0
The `FadingEdgeEffect` class implements a fade effect for `KivyMD` widgets:
.. code-block:: python
from kivy.lang import Builder
from kivy.uix.scrollview import ScrollView
from kivymd.app import MDApp
from kivymd.effects.fadingedge.fadingedge import FadingEdgeEffect
from kivymd.uix.list import OneLineListItem
KV = '''
MDScreen:
FadeScrollView:
fade_height: self.height / 2
fade_color: root.md_bg_color
MDList:
id: container
'''
class FadeScrollView(FadingEdgeEffect, ScrollView):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
for i in range(20):
self.root.ids.container.add_widget(
OneLineListItem(text=f"Single-line item {i}")
)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fading-edge-effect-white.gif
:align: center
.. note:: Use the same color value for the fade_color parameter as for the
parent widget.
"""
from typing import Union
from kivy.clock import Clock
from kivy.graphics.context_instructions import Color
from kivy.graphics.vertex_instructions import Rectangle
from kivy.metrics import dp
from kivy.properties import BooleanProperty, ColorProperty, NumericProperty
from kivymd.theming import ThemableBehavior
__all_ = ("FadingEdgeEffect",)
class FadingEdgeEffect(ThemableBehavior):
"""
The class implements the fade effect.
.. versionadded:: 1.0.0
"""
fade_color = ColorProperty(None)
"""
Fade color.
:attr:`fade_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
fade_height = NumericProperty(0)
"""
Fade height.
:attr:`fade_height` is an :class:`~kivy.properties.ColorProperty`
and defaults to `0`.
"""
edge_top = BooleanProperty(True)
"""
Display fade edge top.
:attr:`edge_top` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
edge_bottom = BooleanProperty(True)
"""
Display fade edge bottom.
:attr:`edge_bottom` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
_height_segment = 10
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.set_fade)
# TODO: Perhaps it would be better if we used a Shader for the fade effect.
# But, I think the canvas instructions shouldn't affect performance
def set_fade(self, interval: Union[int, float]) -> None:
"""Draws a bottom and top fade border on the canvas."""
fade_color = (
self.theme_cls.primary_color
if not self.fade_color
else self.fade_color
)
height_segment = (
self.fade_height if self.fade_height else dp(100)
) // self._height_segment
alpha = 1.1
with self.canvas:
for i in range(self._height_segment):
alpha -= 0.1
Color(rgba=(fade_color[:-1] + [round(alpha, 1)]))
rectangle_top = (
Rectangle(
pos=(self.x, self.height - (i * height_segment)),
size=(self.width, height_segment),
)
if self.edge_top
else None
)
rectangle_bottom = (
Rectangle(
pos=(self.x, i * height_segment),
size=(self.width, height_segment),
)
if self.edge_bottom
else None
)
# How I hate lambda functions because of their length :(
# But I dont want to call the arguments by short,
# incomprehensible names 'a', 'b', 'c'.
self.bind(
pos=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas(
instance_fadind_edge_effect,
window_size,
rectangle_top,
rectangle_bottom,
index,
),
size=lambda instance_fadind_edge_effect, window_size, rectangle_top=rectangle_top, rectangle_bottom=rectangle_bottom, index=i: self.update_canvas(
instance_fadind_edge_effect,
window_size,
rectangle_top,
rectangle_bottom,
index,
),
)
def update_canvas(
self,
instance_fadind_edge_effect,
size: list[int, int],
rectangle_top: Rectangle,
rectangle_bottom: Rectangle,
index: int,
) -> None:
"""
Updates the position and size of the fade border on the canvas.
Called when the application screen is resized.
"""
height_segment = (
self.fade_height if self.fade_height else dp(100)
) // self._height_segment
if rectangle_top:
rectangle_top.pos = (
instance_fadind_edge_effect.x,
size[1]
- (index * height_segment - instance_fadind_edge_effect.y),
)
rectangle_top.size = (size[0], height_segment)
if rectangle_bottom:
rectangle_bottom.pos = (
instance_fadind_edge_effect.x,
index * height_segment + instance_fadind_edge_effect.y,
)
rectangle_bottom.size = (size[0], height_segment)