Skip to content

Commit

Permalink
Kivy/Android Version
Browse files Browse the repository at this point in the history
- MfxCanvas implemented with new base class LImage
- MfxCanvas background updates adapted
- Screen rotation lock change: locks on card selection, i.e.
  when the user plays, unlocks on menu selection or pause.
- animations callback implemented in MfxCanvasGroup (mainly for
  mahjongg games) in order to have correct placments with undo
  when animation is enabled
- animation scheduling implemented on a tasking basis. New
  module LTaskQ added.
- refactorings and clean ups
  • Loading branch information
lufebe16 committed Nov 26, 2023
1 parent 069c8e8 commit 492acd6
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 360 deletions.
8 changes: 5 additions & 3 deletions fastlane/metadata/android/en-US/changelogs/102122100.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Android specific:
- Temporary screen orientation lock added. Long tap (3 seconds) to the
playground locks screen rotation, pause unlocks.
- Toolbar: configuration of displayed toolbar buttons added to the options menu.
- Temporary screen orientation lock added. While playing a game screen
rotation is locked with the first card move, unlocked when selecting
menu or pause.
- Toolbar: configuration of displayed toolbar buttons added to the options
menu.
- Toolbar: dynamic updates on Toolbar and Options settings.
- Toolbar buttons for 'new deal' and 'restart' now display a
toast. Tap to it to accept.
Expand Down
8 changes: 3 additions & 5 deletions pysollib/game/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1452,16 +1452,14 @@ def animatedMoveTo(self, from_stack, to_stack, cards, x, y,
return

if TOOLKIT == 'kivy':
if tkraise:
for card in cards:
card.tkraise()
c0 = cards[0]
dx, dy = (x - c0.x), (y - c0.y)
base = float(self.app.opt.animations)
duration = base*base/5.0/10.0
duration = base*base/40.0 + 0.05
for card in cards:
card.animatedMove(dx, dy, duration)
self.top.waitAnimation(swallow=True, pickup=True)
# self.top.waitAnimation(swallow=True, pickup=True)
# synchronise: ev. per option ?
return

# init timer - need a high resolution for this to work
Expand Down
152 changes: 75 additions & 77 deletions pysollib/kivy/LApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from kivy.utils import platform

from pysollib.kivy.LBase import LBase
from pysollib.kivy.LTask import LTask, LTaskQ
from pysollib.kivy.androidperms import requestStoragePerm
from pysollib.kivy.androidrot import AndroidScreenRotation
from pysollib.resource import CSI
Expand Down Expand Up @@ -113,38 +114,51 @@ def pop(self):
# =============================================================================


class LAnimationTask(LTask, LBase):
def __init__(self, anim, spos, widget, delay):
super(LAnimationTask, self).__init__(widget.card)
self.anim = anim
self.spos = spos
self.widget = widget
print(self.widget.card)
self.delay = delay

def start(self):
super(LAnimationTask, self).start()
self.widget.pos = self.spos
self.anim.bind(on_complete=self.stop)
self.anim.start(self.widget)

# =============================================================================


class LAnimationMgr(object):
def __init__(self, **kw):
super(LAnimationMgr, self).__init__()
self.animations = []
self.widgets = {}
self.callbacks = []
self.taskQ = LTaskQ()

def checkRunning(self):
return len(self.animations) > 0

def addEndCallback(self, cb):
self.callbacks.append(cb)
# print('len of callbacks', len(self.callbacks))

def animEnd(self, anim, widget):
# print('LAnimationMgr: animEnd = %s.%s' % (anim, widget))

self.widgets[widget] = self.widgets[widget][1:]
self.animations.remove(anim)
if len(self.widgets[widget]) > 0:
# start next animation on widget
nanim = self.widgets[widget][0]
self.animations.append(nanim)
print('LAnimationMgr: animEnd, append = %s' % (nanim))
nanim.start(widget)
else:
# no further animations for widget so stop
del self.widgets[widget]

# print('Clock.get_fps() ->', Clock.get_fps())

def makeAnimStart(self, anim, spos, widget):
def animStart(dt):
widget.pos = spos
# print('LAnimationMgr: animStart = %s ... %s' % (anim, dt))
anim.start(widget)
return animStart
if not self.checkRunning():
# print('LAnimationMgr: animEnd -> do callbacks')
for cb in self.callbacks:
cb()
print('LAnimationMgr: animEnd -> callbacks done')
self.callbacks = []

def checkRunning(self):
return len(self.animations) > 0
print('Clock.get_fps() ->', Clock.get_fps())

def create(self, spos, widget, **kw):
x = 0.0
Expand All @@ -166,22 +180,11 @@ def create(self, spos, widget, **kw):
anim.bind(on_complete=kw['bindE'])
if 'bindS' in kw:
anim.bind(on_start=kw['bindS'])
self.animations.append(anim)

offset = duration / 3.0
# offset = duration*1.2
timedelay = offset * len(self.animations)
# print('offset = %s'% offset)
# print('LAnimationMgr: timedelay = %s' % timedelay)

if widget in self.widgets:
# append additional animation to widget
self.widgets[widget].append(anim)
else:
# setup first animation for widget
self.animations.append(anim)
self.widgets[widget] = [anim]
Clock.schedule_once(self.makeAnimStart(
anim, spos, widget), timedelay)
animTask = LAnimationTask(anim, spos, widget, offset)
Clock.schedule_once(lambda dt: self.taskQ.taskInsert(animTask), 0.016)


LAnimationManager = LAnimationMgr()
Expand Down Expand Up @@ -673,7 +676,8 @@ def on_touch_up(self, touch):
# =============================================================================
# Represents a Card as Kivy Window. Will contain an LImage item as child.
# Images are managed in cards.py according to the cards state. Processes
# Events/Action on the card.
# Events/Action on the card or other images, as LImage is designed to not
# process events. Should not take more than one child (LImage) at a time.


class LImageItem(BoxLayout, LBase):
Expand Down Expand Up @@ -719,29 +723,28 @@ def send_event_pressed(self, touch, event):

def on_touch_down(self, touch):

print('LCardImage: size = %s' % self.size)
# print('LCardImage: size = %s' % self.size)
if self.collide_point(*touch.pos):

for c in self.children:
# print('child at %s' % c)
if (c.on_touch_down(touch) and self.game):
for stack in self.game.allstacks:
for i in range(len(stack.cards)):
if stack.cards[i] == self.card:
print('LCardImage: stack = %s' % stack)
print('LCardImage: touch = %s' % str(touch))
print('grab')
# grab the touch!
touch.grab(self)
ppos, psize = self.game.canvas.KivyToCore(
touch.pos, self.size)
event = LEvent()
event.x = ppos[0]
event.y = ppos[1]
self.dragstart = touch.pos
event.cardid = i
self.send_event_pressed(touch, event)
return True
if (self.game):
for stack in self.game.allstacks:
for i in range(len(stack.cards)):
if stack.cards[i] == self.card:
print('LCardImage: stack = %s' % stack)
print('LCardImage: touch = %s' % str(touch))
print('grab')
# grab the touch!
touch.grab(self)
ppos, psize = self.game.canvas.KivyToCore(
touch.pos, self.size)
event = LEvent()
event.x = ppos[0]
event.y = ppos[1]
self.dragstart = touch.pos
event.cardid = i
self.send_event_pressed(touch, event)
AndroidScreenRotation.lock(toaster=False)
return True

if self.group is not None:
print('LCardImage: self=%s group=%s' % (self, self.group))
Expand Down Expand Up @@ -775,22 +778,19 @@ def on_touch_up(self, touch):

if self.collide_point(*touch.pos):

for c in self.children:
# print('child at %s' % c)

if (c.on_touch_up(touch) and self.game):
for stack in self.game.allstacks:
for i in range(len(stack.cards)):
if stack.cards[i] == self.card:
print('LCardImage: stack = %s' % stack)
ppos, psize = self.game.canvas.KivyToCore(
touch.pos, self.size)
event = LEvent()
event.x = ppos[0]
event.y = ppos[1]
event.cardid = i
self.send_event_released_1(event)
return True
if (self.game):
for stack in self.game.allstacks:
for i in range(len(stack.cards)):
if stack.cards[i] == self.card:
print('LCardImage: stack = %s' % stack)
ppos, psize = self.game.canvas.KivyToCore(
touch.pos, self.size)
event = LEvent()
event.x = ppos[0]
event.y = ppos[1]
event.cardid = i
self.send_event_released_1(event)
return True

if self.group is not None:
print('LCardImage: self=%s group=%s' % (self, self.group))
Expand Down Expand Up @@ -1266,7 +1266,7 @@ def setSubMenu(self, submenu):
pass

def setCommand(self, cmd):
# print('LMenuItem: setCommand')
print('LMenuItem: setCommand')
self.bind(on_release=cmd)

# def __str__(self):
Expand Down Expand Up @@ -1575,7 +1575,6 @@ def on_motion(self, m):

def on_touch_down(self, touch):
ret = False

if super().on_touch_down(touch):
return True

Expand Down Expand Up @@ -1655,7 +1654,6 @@ def on_touch_up(self, touch):

def on_longPress(self, instance, timestamp):
print('longPressed at {time}'.format(time=timestamp))
AndroidScreenRotation.lock()

# Menubar:

Expand Down Expand Up @@ -1889,7 +1887,7 @@ def on_resume(self):
if app is None:
return

AndroidScreenRotation.unlock()
AndroidScreenRotation.unlock(toaster=False)

so = get_screen_ori()
go = so # flake8: F841 nonsense!
Expand Down
30 changes: 5 additions & 25 deletions pysollib/kivy/LImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class LImage(Widget, LBase):
COVER = 2
SCALE_DOWN = 3
TILING = 4
fit_mode = StringProperty("fill")
fit_mode = StringProperty("contain")
texture = ObjectProperty(None, allownone=True)

def make_scale_down(self, s, p):
Expand Down Expand Up @@ -63,12 +63,9 @@ def make_contain(self, s, p):
def make_cover(self, s, p):
aspect = self.texture.size[0]/self.texture.size[1]
waspect = self.size[0]/self.size[1]
print ('aspect: ', aspect) # noqa
print ('waspect: ', waspect) # noqa

# 'clamp_to_edge','repeat','mirrored_repeat'
self.texture.wrap = 'repeat'
print ('wrap: ',self.texture.wrap) # noqa

# set rect size/pos to window
self.rect.size = s
Expand Down Expand Up @@ -172,7 +169,8 @@ def __init__(self, **kwargs):
self.tex_coord_update(self.texture)

# initial size is the natural size of the image.
self.size = self.texture.size
if self.texture is not None:
self.size = self.texture.size

def tex_coord_update(self, texture):
if hasattr(self, "rect"):
Expand Down Expand Up @@ -202,10 +200,12 @@ def on_pos(self, a, p):
self.make_format(self.size, p)

def on_fit_mode(self, a, m):
print('on_fit_mode', m)
self.fit_num_update(self.fit_mode)
self.make_format(self.size, self.pos)

def on_texture(self, a, texture):
print('on_texture', texture)
self.tex_coord_update(self.texture)
self.make_format(self.size, self.pos)

Expand All @@ -221,24 +221,4 @@ def getWidth(self):
def subsample(self, r):
return LImage(texture=self.texture)

def on_touch_down(self, touch):
# print('LImage: touch_down on %s' % str(touch.pos))
if self.collide_point(*touch.pos):
if (self.source is not None):
print('LImage match %s' % self.source)
else:
print('LImage match with texture')
return True
return False

def on_touch_up(self, touch):
# print('LImage: touch_up on %s' % str(touch.pos))
if self.collide_point(*touch.pos):
if (self.source is not None):
print('LImage match %s' % self.source)
else:
print('LImage match with texture')
return True
return False

# =============================================================================
Loading

0 comments on commit 492acd6

Please sign in to comment.