Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
T-Dynamos committed May 21, 2024
1 parent fc49b0e commit 2499bda
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 30 deletions.
Empty file added examples/material_motion.py
Empty file.
5 changes: 2 additions & 3 deletions examples/md_axis_transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
text:root.subtext
font_style:"Label"
role:"large"
theme_text_color:"Custom"
text_color:app.theme_cls.surfaceContainerLowestColor[:-1] + [0.5]
text_color:app.theme_cls.onSurfaceVariantColor
<SettingsScreen@MDScreen>:
name:"main"
Expand Down Expand Up @@ -96,7 +95,7 @@
font_style:"Body"
role:"large"
theme_text_color:"Custom"
text_color:app.theme_cls.surfaceContainerLowestColor[:-1] + [0.5]
text_color:app.theme_cls.onSurfaceVariantColor
Image:
size_hint_y:1
source:app.image_path
Expand Down
1 change: 1 addition & 0 deletions kivymd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@

import kivymd.factory_registers # NOQA
import kivymd.font_definitions # NOQA
import kivymd.motion # NOQA
from kivymd.tools.packaging.pyinstaller import hooks_path # NOQA
56 changes: 33 additions & 23 deletions kivymd/motion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
"""

import math
import kivy.animation

float_epsilon = 8.3446500e-7


class CubicBezier:
"""Ported from Android source code"""

p0 = 0
p1 = 0
p2 = 0
p3 = 0

def __init__(self, *args):
self.p0, self.p1, self.p2, self.p3 = args

def evaluate_cubic(self, p1, p2, t):
a = 1.0 / 3.0 + (p1 - p2)
b = p2 - 2.0 * p1
Expand All @@ -37,13 +41,12 @@ def clamp_range(self, r):

def close_to(self, x, y):
return abs(x - y) < float_epsilon

def find_first_cubic_root(self, p0, p1, p2, p3):
a = 3.0 * (p0 - 2.0 * p1 + p2)
b = 3.0 * (p1 - p0)
c = p0
d = -p0 + 3.0 * (p1 - p2) + p3

if self.close_to(d, 0.0):
if self.close_to(a, 0.0):
if self.close_to(b, 0.0):
Expand All @@ -52,21 +55,18 @@ def find_first_cubic_root(self, p0, p1, p2, p3):
else:
q = math.sqrt(b * b - 4.0 * a * c)
a2 = 2.0 * a

root = self.clamp_range((q - b) / a2)
if not math.isnan(root):
return root

return self.clamp_range((-b - q) / a2)

a /= d
b /= d
c /= d
o3 = (3.0 * b - a * a) / 9.0
q2 = (2.0 * a * a * a - 9.0 * a * b + 27.0 * c) / 54.0
discriminant = q2 * q2 + o3 * o3 * o3
a3 = a / 3.0

if discriminant < 0.0:
mp33 = -(o3 * o3 * o3)
r = math.sqrt(mp33)
Expand All @@ -77,12 +77,16 @@ def find_first_cubic_root(self, p0, p1, p2, p3):
root = self.clamp_range(t1 * math.cos(phi / 3.0) - a3)
if not math.isnan(root):
return root
root = self.clamp_range(t1 * math.cos((phi + 2.0 * math.pi) / 3.0) - a3)
root = self.clamp_range(
t1 * math.cos((phi + 2.0 * math.pi) / 3.0) - a3
)
if not math.isnan(root):
return root
return self.clamp_range(t1 * math.cos((phi + 4.0 * math.pi) / 3.0) - a3)
return self.clamp_range(
t1 * math.cos((phi + 4.0 * math.pi) / 3.0) - a3
)

elif self.close_to(discriminant, 0.0):
elif self.close_to(discriminant, 0.0):
u1 = -math.cbrt(q2)
root = self.clamp_range(2.0 * u1 - a3)
if not math.isnan(root):
Expand All @@ -94,24 +98,30 @@ def find_first_cubic_root(self, p0, p1, p2, p3):
v1 = math.cbrt(q2 + sd)
return self.clamp_range(u1 - v1 - a3)

def transform(self, value: float):
def t(self, value: float):
return self.evaluate_cubic(
self.p1, self.p3, self.find_first_cubic_root(
self.p1,
self.p3,
self.find_first_cubic_root(
-value,
self.p0 - value,
self.p2 - value,
1.0 - value,
)
),
)


class MaterialMotion:
class MaterialMotion(kivy.animation.AnimationTransition):
"""KivyMD's equivalent of kivy's `AnimationTransition`"""

easing_standard = CubicBezier(0.4, 0.0, 0.2, 1.0)
easing_decelerated = CubicBezier(0.0, 0.0, 0.2, 1.0)
easing_accelerated = CubicBezier(0.4, 0.0, 1.0, 1.0)
easing_linear = CubicBezier(0.0, 0.0, 1.0, 1.0)

# TODO: add `easing_emphasized` here
# it's defination is
# path(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1)
easing_standard = CubicBezier(0.4, 0.0, 0.2, 1.0).t
easing_decelerated = CubicBezier(0.0, 0.0, 0.2, 1.0).t
easing_accelerated = CubicBezier(0.4, 0.0, 1.0, 1.0).t
easing_linear = CubicBezier(0.0, 0.0, 1.0, 1.0).t

# TODO: add `easing_emphasized` here
# it's defination is
# path(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1)

# Monkey patch kivy's animation module
kivy.animation.AnimationTransition = MaterialMotion
6 changes: 2 additions & 4 deletions kivymd/uix/transition/transition.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def start(self, manager):
# Save hash of the objects
self.ih = hash(self.screen_in)
self.oh = hash(self.screen_out)

# Init pos
self.screen_in.pos = manager.pos
self.screen_out.pos = manager.pos
Expand Down Expand Up @@ -439,9 +439,7 @@ def start(self, manager):

def on_progress(self, progress):
# This code could be simplyfied with setattr, but it's slow
progress = getattr(MaterialMotion, self.switch_animation).transform(
progress
)
progress = getattr(MaterialMotion, self.switch_animation)(progress)
progress_i = progress - 1
progress_d = progress * 2
# first half
Expand Down
77 changes: 77 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.metrics import dp
from kivy.properties import ListProperty

from kivymd.app import MDApp


class AnimBox(BoxLayout):
obj_pos = ListProperty([0, 0])


UI = """
<AnimBox>:
transition:"in_out_bounce"
size_hint_y:None
height:dp(100)
obj_pos:[dp(40), self.pos[-1] + dp(40)]
canvas:
Color:
rgba:app.theme_cls.primaryContainerColor
Rectangle:
size:[self.size[0], dp(5)]
pos:self.pos[0], self.pos[-1] + dp(50)
Color:
rgba:app.theme_cls.primaryColor
Rectangle:
size:[dp(30)] * 2
pos:root.obj_pos
MDLabel:
adaptive_height:True
text:root.transition
padding:[dp(10), 0]
halign:"center"
MDGridLayout:
orientation:"lr-tb"
cols:1
md_bg_color:app.theme_cls.backgroundColor
spacing:dp(10)
"""


class MotionApp(MDApp):

def build(self):
return Builder.load_string(UI)

def on_start(self):
for transition in [
"easing_linear",
"easing_accelerated",
"easing_decelerated",
"easing_standard",
"in_out_cubic"
]: # Add more here for comparison
print(transition)
widget = AnimBox()
widget.transition = transition
self.root.add_widget(widget)
Clock.schedule_once(self.run_animation, 1)

_inverse = True

def run_animation(self, dt):
x = (self.root.children[0].width - dp(30)) if self._inverse else 0
for widget in self.root.children:
Animation(
obj_pos=[x, widget.obj_pos[-1]], t=widget.transition, d=3
).start(widget)
self._inverse = not self._inverse
Clock.schedule_once(self.run_animation, 3.1)


MotionApp().run()

0 comments on commit 2499bda

Please sign in to comment.