Compare commits
No commits in common. "9e2b5db1a634b28fa8ea63cee917c96e4b7ea3ef" and "1c17b6165c5dd7b6bb992e816d07f897c4880e11" have entirely different histories.
9e2b5db1a6
...
1c17b6165c
0
docs/blocks.md
Executable file → Normal file
0
docs/changelog.md
Executable file → Normal file
0
docs/cn/binds.md
Executable file → Normal file
0
docs/cn/cdf.md
Executable file → Normal file
0
docs/cn/index.md
Executable file → Normal file
0
docs/cn/intro.md
Executable file → Normal file
0
docs/en/box.md
Executable file → Normal file
0
docs/imgs/hello_window.png
Executable file → Normal file
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
0
github-speed-up.md
Executable file → Normal file
0
kivyblocks/__init__.py
Executable file → Normal file
0
kivyblocks/android_rotation.py
Executable file → Normal file
0
kivyblocks/anz/__init__.py
Executable file → Normal file
0
kivyblocks/anz/bluetooth.py
Executable file → Normal file
0
kivyblocks/aplayer.py
Executable file → Normal file
0
kivyblocks/backendfunction.py
Executable file → Normal file
47
kivyblocks/baseWidget.py
Executable file → Normal file
@ -75,7 +75,7 @@ from .threadcall import HttpClient
|
|||||||
from .i18n import I18n
|
from .i18n import I18n
|
||||||
from .widget_css import WidgetCSS
|
from .widget_css import WidgetCSS
|
||||||
from .ready import WidgetReady
|
from .ready import WidgetReady
|
||||||
from .utils import CSize
|
from .utils import CSize, SUPER
|
||||||
from .swipebehavior import SwipeBehavior
|
from .swipebehavior import SwipeBehavior
|
||||||
from .widgetExt.inputext import MyDropDown
|
from .widgetExt.inputext import MyDropDown
|
||||||
|
|
||||||
@ -89,6 +89,16 @@ font_names = {
|
|||||||
'title1':resource_find('Alimama_ShuHeiTi_Bold.ttf')
|
'title1':resource_find('Alimama_ShuHeiTi_Bold.ttf')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
font_sizes = {
|
||||||
|
'text':CSize(1),
|
||||||
|
'title6':CSize(1.1),
|
||||||
|
'title5':CSize(1.3),
|
||||||
|
'title4':CSize(1.5),
|
||||||
|
'title3':CSize(1.7),
|
||||||
|
'title2':CSize(1.9),
|
||||||
|
'title1':CSize(2.1)
|
||||||
|
}
|
||||||
|
|
||||||
if platform == 'android':
|
if platform == 'android':
|
||||||
from .widgetExt.phonebutton import PhoneButton
|
from .widgetExt.phonebutton import PhoneButton
|
||||||
from .widgetExt.androidwebview import AWebView
|
from .widgetExt.androidwebview import AWebView
|
||||||
@ -130,7 +140,7 @@ def ScatterBox(WidgetCSS, WidgetReady, ScatterLayout):
|
|||||||
class Box(WidgetCSS, WidgetReady, BoxLayout):
|
class Box(WidgetCSS, WidgetReady, BoxLayout):
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
try:
|
try:
|
||||||
super(Box, self).__init__(**kw)
|
SUPER(Box, self, kw)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Box(',kw,') Error')
|
print('Box(',kw,') Error')
|
||||||
raise e
|
raise e
|
||||||
@ -147,17 +157,17 @@ class VBox(Box):
|
|||||||
Box.__init__(self, **kw)
|
Box.__init__(self, **kw)
|
||||||
|
|
||||||
class SwipeBox(SwipeBehavior, Box):
|
class SwipeBox(SwipeBehavior, Box):
|
||||||
pass
|
def __init__(self, **kw):
|
||||||
|
SUPER(SwipeBox, self, kw)
|
||||||
|
|
||||||
|
|
||||||
class Text(Label):
|
class Text(Label):
|
||||||
lang=StringProperty('')
|
lang=StringProperty('')
|
||||||
otext = StringProperty('')
|
otext = StringProperty('')
|
||||||
def __init__(self,i18n=False, texttype='text', wrap=False, rate=1,
|
def __init__(self,i18n=False, texttype='text', wrap=False,
|
||||||
fgcolor=None, **kw):
|
fgcolor=None, **kw):
|
||||||
|
|
||||||
app = App.get_running_app()
|
fontsize = font_sizes.get(texttype)
|
||||||
self.rate = 1
|
|
||||||
fontsize = app.get_font_size(texttype) * self.rate
|
|
||||||
fontname = font_names.get(texttype)
|
fontname = font_names.get(texttype)
|
||||||
self._i18n = i18n
|
self._i18n = i18n
|
||||||
self.i18n = I18n()
|
self.i18n = I18n()
|
||||||
@ -172,9 +182,7 @@ class Text(Label):
|
|||||||
if not kwargs.get('text'):
|
if not kwargs.get('text'):
|
||||||
kwargs['text'] = kwargs.get('otext','')
|
kwargs['text'] = kwargs.get('otext','')
|
||||||
|
|
||||||
super(Text, self).__init__(**kwargs)
|
SUPER(Text, self, kwargs)
|
||||||
app.bind(font_size=self.reset_font_size)
|
|
||||||
# self.bind(texture_size=self.setter('size'))
|
|
||||||
if self._i18n:
|
if self._i18n:
|
||||||
self.i18n.addI18nWidget(self)
|
self.i18n.addI18nWidget(self)
|
||||||
if self.wrap:
|
if self.wrap:
|
||||||
@ -184,9 +192,6 @@ class Text(Label):
|
|||||||
if self.bgcolor:
|
if self.bgcolor:
|
||||||
self.color = self.bgcolor
|
self.color = self.bgcolor
|
||||||
|
|
||||||
def reset_font_size(self, app, fsize):
|
|
||||||
self.font_size = fsize * self.rate
|
|
||||||
|
|
||||||
def resize(self, *args):
|
def resize(self, *args):
|
||||||
if not self.size_hint_y:
|
if not self.size_hint_y:
|
||||||
ps = [0,0,0,0]
|
ps = [0,0,0,0]
|
||||||
@ -272,7 +277,6 @@ class Modal(VBox):
|
|||||||
self._target = None
|
self._target = None
|
||||||
super(Modal, self).__init__(**kw)
|
super(Modal, self).__init__(**kw)
|
||||||
self.set_size_position()
|
self.set_size_position()
|
||||||
print('size_hint=', self.size_hint, kw)
|
|
||||||
self._target.bind(size=self.set_size_position)
|
self._target.bind(size=self.set_size_position)
|
||||||
self.register_event_type('on_open')
|
self.register_event_type('on_open')
|
||||||
self.register_event_type('on_pre_open')
|
self.register_event_type('on_pre_open')
|
||||||
@ -295,7 +299,7 @@ class Modal(VBox):
|
|||||||
|
|
||||||
return super().on_touch_down(touch)
|
return super().on_touch_down(touch)
|
||||||
|
|
||||||
def on_target(self, o, target):
|
def on_target(self):
|
||||||
w = Window
|
w = Window
|
||||||
if self.target is not None:
|
if self.target is not None:
|
||||||
w = Factory.Blocks.getWidgetById(self.target)
|
w = Factory.Blocks.getWidgetById(self.target)
|
||||||
@ -320,9 +324,9 @@ class Modal(VBox):
|
|||||||
self.width = self.size_hint_x * self._target.width
|
self.width = self.size_hint_x * self._target.width
|
||||||
if self.size_hint_y:
|
if self.size_hint_y:
|
||||||
self.height = self.size_hint_y * self._target.height
|
self.height = self.size_hint_y * self._target.height
|
||||||
print("size with target:", self.width, self.height,
|
print(self.width, self.height,
|
||||||
self.size_hint, self.size_hint,
|
self.size_hint_x, self.size_hint_y,
|
||||||
"target size=", self._target.size
|
self._target.size
|
||||||
)
|
)
|
||||||
self.set_modal_position()
|
self.set_modal_position()
|
||||||
|
|
||||||
@ -339,7 +343,7 @@ class Modal(VBox):
|
|||||||
x = 0
|
x = 0
|
||||||
if yn == 'c':
|
if yn == 'c':
|
||||||
y = (self._target.height - self.height) / 2
|
y = (self._target.height - self.height) / 2
|
||||||
elif yn == 'b':
|
elif yn == 't':
|
||||||
y = self._target.height - self.height
|
y = self._target.height - self.height
|
||||||
if y < 0:
|
if y < 0:
|
||||||
y = 0
|
y = 0
|
||||||
@ -347,9 +351,6 @@ class Modal(VBox):
|
|||||||
self.pos = x, y
|
self.pos = x, y
|
||||||
else:
|
else:
|
||||||
self.pos = self._target.pos[0] + x, self._target.pos[1] + y
|
self.pos = self._target.pos[0] + x, self._target.pos[1] + y
|
||||||
Mx = Window.width
|
|
||||||
My = Window.height
|
|
||||||
self.pos_hint = {'x':self.pos[0]/Mx, 'y':self.pos[1]/My}
|
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
if self.parent:
|
if self.parent:
|
||||||
@ -388,7 +389,7 @@ class TimedModal(Modal):
|
|||||||
show_time = NumericProperty(0)
|
show_time = NumericProperty(0)
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
self.time_task = None
|
self.time_task = None
|
||||||
super(TimedModal, self).__init__(**kw)
|
SUPER(TimedModal, self, kw)
|
||||||
|
|
||||||
def open(self, *args, **kw):
|
def open(self, *args, **kw):
|
||||||
if self.time_task is not None:
|
if self.time_task is not None:
|
||||||
|
0
kivyblocks/bgcolorbehavior.py
Executable file → Normal file
0
kivyblocks/block_test.py
Executable file → Normal file
25
kivyblocks/blocks.py
Executable file → Normal file
@ -204,7 +204,7 @@ x = ClassX{klass_cnt}()
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if url.startswith('file://'):
|
if url.startswith('file://'):
|
||||||
return self.script.dispatch(url, params)
|
return self.script.dispatch(url, **params)
|
||||||
elif url.startswith('http://') or url.startswith('https://'):
|
elif url.startswith('http://') or url.startswith('https://'):
|
||||||
try:
|
try:
|
||||||
hc = HttpClient()
|
hc = HttpClient()
|
||||||
@ -214,14 +214,7 @@ x = ClassX{klass_cnt}()
|
|||||||
print_exc()
|
print_exc()
|
||||||
if errback:
|
if errback:
|
||||||
return errback(None,e)
|
return errback(None,e)
|
||||||
return {
|
return None
|
||||||
"widgettype":"Text",
|
|
||||||
"options":{
|
|
||||||
"text":f"{url=} error",
|
|
||||||
"wrap":True,
|
|
||||||
"halign":"left"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
config = getConfig()
|
config = getConfig()
|
||||||
url = config.uihome + url
|
url = config.uihome + url
|
||||||
@ -734,7 +727,7 @@ x = ClassX{klass_cnt}()
|
|||||||
print('Block3: desc must be a dict object not None')
|
print('Block3: desc must be a dict object not None')
|
||||||
return None
|
return None
|
||||||
w = doit(desc)
|
w = doit(desc)
|
||||||
# print('widgetBuild():w=', w)
|
print('widgetBuild():w=', w)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -788,16 +781,8 @@ x = ClassX{klass_cnt}()
|
|||||||
return _find_widget(name,
|
return _find_widget(name,
|
||||||
from_widget=from_widget.parent,
|
from_widget=from_widget.parent,
|
||||||
dir=dir)
|
dir=dir)
|
||||||
wid = None
|
Logger.info('Block:_find_widget(), %s, %s %s return None',
|
||||||
if hasattr(from_widget, 'widget_id'):
|
name, from_widget.__class__.__name__, dir)
|
||||||
wid = getattr(from_widget, 'widget_id')
|
|
||||||
if wid == 'channel_list':
|
|
||||||
print('channel_list=', from_widget.__class__.__name__, 'children cnt=', len(from_widget.children))
|
|
||||||
for c in children:
|
|
||||||
cid = None
|
|
||||||
if hasattr(c, 'widget_id'):
|
|
||||||
cid = getattr(c, 'widget_id')
|
|
||||||
print('channel_list children:', c.__class__.__name__, cid)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def find_widget(step, from_widget):
|
def find_widget(step, from_widget):
|
||||||
|
51
kivyblocks/blocksapp.py
Executable file → Normal file
@ -12,7 +12,6 @@ from appPublic.folderUtils import ProgramPath
|
|||||||
from appPublic.uniqueID import getID
|
from appPublic.uniqueID import getID
|
||||||
from appPublic.rsawrap import RSA
|
from appPublic.rsawrap import RSA
|
||||||
|
|
||||||
from kivy.properties import NumericProperty
|
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from kivy.metrics import sp,dp,mm
|
from kivy.metrics import sp,dp,mm
|
||||||
from kivy.core.window import WindowBase, Window
|
from kivy.core.window import WindowBase, Window
|
||||||
@ -49,7 +48,6 @@ signal.signal(signal.SIGINT, signal_handler)
|
|||||||
|
|
||||||
|
|
||||||
class BlocksApp(App):
|
class BlocksApp(App):
|
||||||
font_size = NumericProperty(24)
|
|
||||||
def get_rotation(self):
|
def get_rotation(self):
|
||||||
return get_rotation()
|
return get_rotation()
|
||||||
|
|
||||||
@ -62,13 +60,10 @@ class BlocksApp(App):
|
|||||||
with codecs.open(config.css.css_filename, 'r', 'utf-8') as f:
|
with codecs.open(config.css.css_filename, 'r', 'utf-8') as f:
|
||||||
d = json.load(f)
|
d = json.load(f)
|
||||||
self.buildCsses(d)
|
self.buildCsses(d)
|
||||||
try:
|
if config.css.css_url:
|
||||||
if config.css.css_url:
|
hc = HttpClient()
|
||||||
hc = HttpClient()
|
d = hc.get(self.realurl(config.css.css_url))
|
||||||
d = hc.get(self.realurl(config.css.css_url))
|
self.buildCsses(d)
|
||||||
self.buildCsses(d)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_rotate(self,*largs):
|
def on_rotate(self,*largs):
|
||||||
self.current_rotation = Window.rotation
|
self.current_rotation = Window.rotation
|
||||||
@ -80,47 +75,21 @@ class BlocksApp(App):
|
|||||||
if isinstance(v,dict):
|
if isinstance(v,dict):
|
||||||
register_css(k,v)
|
register_css(k,v)
|
||||||
|
|
||||||
def set_fontsize(self, x):
|
|
||||||
self.font_size = x
|
|
||||||
|
|
||||||
def get_font_size(self, ttype='text'):
|
|
||||||
text_fontrates = {
|
|
||||||
'text':1,
|
|
||||||
'title6':1.1,
|
|
||||||
'title5':1.3,
|
|
||||||
'title4':1.5,
|
|
||||||
'title3':1.7,
|
|
||||||
'title2':1.9,
|
|
||||||
'title1':2.1
|
|
||||||
}
|
|
||||||
v = text_fontrates.get(ttype, 'text')
|
|
||||||
return v * self.font_size
|
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
tl = Label(text='test')
|
i18n = I18n()
|
||||||
self.font_size = tl.font_size
|
|
||||||
print('##################app_font_size=', self.font_size)
|
|
||||||
config = getConfig()
|
|
||||||
self.workers = Workers(maxworkers=config.maxworkers or 80)
|
|
||||||
self.workers.start()
|
|
||||||
try:
|
|
||||||
i18n = I18n()
|
|
||||||
except:
|
|
||||||
i18n = None
|
|
||||||
self.platform = platform
|
self.platform = platform
|
||||||
self.is_desktop = platform in ['win', 'linux', 'macosx']
|
self.is_desktop = platform in ['win', 'linux', 'macosx']
|
||||||
self.default_params = {}
|
config = getConfig()
|
||||||
if config.default_params:
|
|
||||||
self.default_params.update(config.default_params)
|
|
||||||
|
|
||||||
self.public_headers = {
|
self.public_headers = {
|
||||||
"client_uuid":getID(),
|
|
||||||
"platform":self.platform
|
"platform":self.platform
|
||||||
}
|
}
|
||||||
# Window.borderless = True
|
# Window.borderless = True
|
||||||
|
print('Window.dpi=', Window.dpi, 'Metrics.dpi=', Metrics.dpi)
|
||||||
Window.bind(on_request_close=self.on_close)
|
Window.bind(on_request_close=self.on_close)
|
||||||
Window.bind(on_rotate=self.on_rotate)
|
Window.bind(on_rotate=self.on_rotate)
|
||||||
Window.bind(size=self.device_info)
|
Window.bind(size=self.device_info)
|
||||||
|
self.workers = Workers(maxworkers=config.maxworkers or 80)
|
||||||
|
self.workers.start()
|
||||||
self.load_csses()
|
self.load_csses()
|
||||||
self.running = True
|
self.running = True
|
||||||
if config.root:
|
if config.root:
|
||||||
@ -194,7 +163,7 @@ class BlocksApp(App):
|
|||||||
}
|
}
|
||||||
self.public_headers.update(device)
|
self.public_headers.update(device)
|
||||||
|
|
||||||
def on_close(self, *args, **kwargs):
|
def on_close(self, *args):
|
||||||
self.workers.running = False
|
self.workers.running = False
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
14
kivyblocks/boxViewer.py
Executable file → Normal file
@ -29,7 +29,7 @@ from kivy.graphics import Fbo, Color, Rectangle
|
|||||||
from kivy.properties import NumericProperty, StringProperty, DictProperty
|
from kivy.properties import NumericProperty, StringProperty, DictProperty
|
||||||
from .responsivelayout import VResponsiveLayout
|
from .responsivelayout import VResponsiveLayout
|
||||||
from .toolbar import Toolbar
|
from .toolbar import Toolbar
|
||||||
from .paging import RelatedLoader
|
from .paging import Paging, RelatedLoader
|
||||||
from .utils import CSize, SUPER
|
from .utils import CSize, SUPER
|
||||||
from .ready import WidgetReady
|
from .ready import WidgetReady
|
||||||
from .baseWidget import VBox
|
from .baseWidget import VBox
|
||||||
@ -122,9 +122,15 @@ class BoxViewer(VBox):
|
|||||||
idx = data['idx']
|
idx = data['idx']
|
||||||
widgets = data['widgets']
|
widgets = data['widgets']
|
||||||
|
|
||||||
with self.fboContext():
|
self._fbo = Fbo(size=self.size)
|
||||||
for r in recs:
|
with self._fbo:
|
||||||
self.showObject(widgets, r, index=idx)
|
self._background_color = Color(0,0,0,1)
|
||||||
|
self._background_rect = Rectangle(size=self.size)
|
||||||
|
for r in recs:
|
||||||
|
self.showObject(widgets, r, index=idx)
|
||||||
|
with self.canvas:
|
||||||
|
self._fbo_rect = Rectangle(size=self.size,
|
||||||
|
texture=self._fbo.texture)
|
||||||
|
|
||||||
self.subwidgets += widgets
|
self.subwidgets += widgets
|
||||||
|
|
||||||
|
0
kivyblocks/circle_progress.py
Executable file → Normal file
41
kivyblocks/clickable.py
Executable file → Normal file
@ -3,12 +3,6 @@ from kivy.logger import Logger
|
|||||||
from kivy.uix.behaviors import TouchRippleButtonBehavior
|
from kivy.uix.behaviors import TouchRippleButtonBehavior
|
||||||
from kivy.graphics import Color, Rectangle
|
from kivy.graphics import Color, Rectangle
|
||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.anchorlayout import AnchorLayout
|
|
||||||
from kivy.uix.floatlayout import FloatLayout
|
|
||||||
from kivy.uix.relativelayout import RelativeLayout
|
|
||||||
from kivy.uix.gridlayout import GridLayout
|
|
||||||
from kivy.uix.scatterlayout import ScatterLayout
|
|
||||||
from kivy.uix.stacklayout import StackLayout
|
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from kivy.uix.image import AsyncImage
|
from kivy.uix.image import AsyncImage
|
||||||
from kivy.properties import NumericProperty, DictProperty, \
|
from kivy.properties import NumericProperty, DictProperty, \
|
||||||
@ -401,34 +395,6 @@ def build_cmdbox_view(desc, rec=None):
|
|||||||
x.setValue(vd)
|
x.setValue(vd)
|
||||||
return x
|
return x
|
||||||
|
|
||||||
class PressableAnchorLayout(TouchRippleButtonBehavior, AnchorLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableBoxLayout(TouchRippleButtonBehavior, BoxLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableFloatLayout(TouchRippleButtonBehavior, FloatLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableRelativeLayout(TouchRippleButtonBehavior, RelativeLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableGridLayout(TouchRippleButtonBehavior, GridLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableScatterLayout(TouchRippleButtonBehavior, ScatterLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class PressableStackLayout(TouchRippleButtonBehavior, StackLayout):
|
|
||||||
def on_press(self, o=None, d=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
UiFactory.register('checkbox', build_checkbox, build_checkbox)
|
UiFactory.register('checkbox', build_checkbox, build_checkbox)
|
||||||
UiFactory.register('cmdbox', build_cmdbox_view, build_cmdbox_view)
|
UiFactory.register('cmdbox', build_cmdbox_view, build_cmdbox_view)
|
||||||
|
|
||||||
@ -443,10 +409,3 @@ r('ToggleText',ToggleText)
|
|||||||
r('ToggleIconText',ToggleIconText)
|
r('ToggleIconText',ToggleIconText)
|
||||||
r('ClickableImage',ClickableImage)
|
r('ClickableImage',ClickableImage)
|
||||||
r('ToggleImage',ToggleImage)
|
r('ToggleImage',ToggleImage)
|
||||||
r('PressableAnchorLayout',PressableAnchorLayout)
|
|
||||||
r('PressableBoxLayout',PressableBoxLayout)
|
|
||||||
r('PressableFloatLayout',PressableFloatLayout)
|
|
||||||
r('PressableRelativeLayout',PressableRelativeLayout)
|
|
||||||
r('PressableGridLayout',PressableGridLayout)
|
|
||||||
r('PressableScatterLayout',PressableScatterLayout)
|
|
||||||
r('PressableStackLayout',PressableStackLayout)
|
|
||||||
|
0
kivyblocks/color_definitions.py
Executable file → Normal file
0
kivyblocks/colorcalc.py
Executable file → Normal file
0
kivyblocks/command_action.py
Executable file → Normal file
@ -1,146 +0,0 @@
|
|||||||
# container is ScrollView with a dataloader
|
|
||||||
import json
|
|
||||||
from appPublic.myTE import MyTemplateEngine
|
|
||||||
from kivy.uix.scrollview import ScrollView
|
|
||||||
from kivy.properties import DictProperty, ListProperty, BooleanProperty, StringProperty, NumericProperty
|
|
||||||
from kivy.clock import Clock
|
|
||||||
from kivyblocks.blocks import Blocks
|
|
||||||
from kivyblocks.paging import RelatedLoader
|
|
||||||
from kivyblocks.widget_css import WidgetCSS
|
|
||||||
|
|
||||||
class LayoutBuildFailed(Exception):
|
|
||||||
def __init__(self, desc):
|
|
||||||
self.desc = desc
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.desc)
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class Container(WidgetCSS, ScrollView):
|
|
||||||
"""
|
|
||||||
"loader":{
|
|
||||||
"page":1,
|
|
||||||
"rows":60,
|
|
||||||
"dataurl":"eeee",
|
|
||||||
"params":{
|
|
||||||
k:v
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"""
|
|
||||||
idField = StringProperty('id')
|
|
||||||
loader = DictProperty({})
|
|
||||||
data = ListProperty(None)
|
|
||||||
layout = DictProperty({})
|
|
||||||
viewer = DictProperty({})
|
|
||||||
min_threhold = NumericProperty(0.01)
|
|
||||||
max_htrehold = NumericProperty(0.99)
|
|
||||||
extend_x = BooleanProperty(False)
|
|
||||||
content = None
|
|
||||||
def __init__(self, **kw):
|
|
||||||
self.dataloader = None
|
|
||||||
self.engine = MyTemplateEngine('.')
|
|
||||||
self.id_widget = {}
|
|
||||||
super(Container, self).__init__(**kw)
|
|
||||||
self.content = Blocks().widgetBuild(self.layout)
|
|
||||||
if not self.content:
|
|
||||||
raise LayoutBuildFailed
|
|
||||||
if self.do_scroll_x:
|
|
||||||
self.content.bind(minimum_width=self.content.setter('width'))
|
|
||||||
if self.do_scroll_y:
|
|
||||||
self.content.bind(minimum_height=self.content.setter('height'))
|
|
||||||
self.add_widget(self.content)
|
|
||||||
self.viewer_tmpl = json.dumps(self.viewer)
|
|
||||||
self.bind(on_scroll_stop = self.on_scrollstop)
|
|
||||||
if self.data:
|
|
||||||
d = {
|
|
||||||
"dir":"down",
|
|
||||||
"rows":self.data,
|
|
||||||
"total":len(self.data)
|
|
||||||
}
|
|
||||||
self.add_page(d)
|
|
||||||
|
|
||||||
if self.loader:
|
|
||||||
self.dataloader = RelatedLoader(target=self, **self.loader)
|
|
||||||
self.dataloader.bind(on_deletepage=self.delete_page)
|
|
||||||
self.dataloader.bind(on_pageloaded=self.add_page)
|
|
||||||
self.dataloader.bind(on_newbegin=self.clear_records)
|
|
||||||
Clock.schedule_once(self.loadData, 0.5)
|
|
||||||
|
|
||||||
def print_info(self, *args):
|
|
||||||
print(f"{self.scroll_distance=}, {self.scroll_timeout=}, {self.do_scroll_x=} {self.do_scroll_y=}, {self.scroll_x=}, {self.scroll_y=}, {self.content.size=}")
|
|
||||||
|
|
||||||
def parse_viewer(self, rec):
|
|
||||||
return json.loads(self.engine.renders(self.viewer_tmpl, rec))
|
|
||||||
|
|
||||||
def loadData(self, *args, **kw):
|
|
||||||
kw['page'] = 1
|
|
||||||
self.dataloader.do_search(None,kw)
|
|
||||||
|
|
||||||
def add_record(self, rec, tail=True):
|
|
||||||
desc = self.parse_viewer(rec)
|
|
||||||
w = Blocks().widgetBuild(desc)
|
|
||||||
if w:
|
|
||||||
idx = 0
|
|
||||||
if not tail:
|
|
||||||
idx = -1
|
|
||||||
id = rec.get(self.idField)
|
|
||||||
self.id_widget[id] = w
|
|
||||||
self.content.add_widget(w, index=idx)
|
|
||||||
else:
|
|
||||||
print(f'create widget error {self.viewer_tmpl=}, {rec=}')
|
|
||||||
|
|
||||||
def delete_record(self, rec):
|
|
||||||
id = rec.get(self.idField)
|
|
||||||
w = self.id_widget.get(id)
|
|
||||||
if w:
|
|
||||||
self.content.remove_widget(w)
|
|
||||||
del self.id_widget[id]
|
|
||||||
|
|
||||||
def delete_page(self, o, d):
|
|
||||||
# print(f'delete_page():{o=}, {d=}')
|
|
||||||
for r in d:
|
|
||||||
self.delete_record(r)
|
|
||||||
|
|
||||||
def add_page(self, o, d):
|
|
||||||
# print(f'add_page():{o=},{d=}')
|
|
||||||
dir = d.get('dir', 'down')
|
|
||||||
recs = d.get('data', [])
|
|
||||||
tail = True
|
|
||||||
if dir != 'down':
|
|
||||||
tail = False
|
|
||||||
recs.reverse()
|
|
||||||
|
|
||||||
for r in recs:
|
|
||||||
self.add_record(r, tail=tail)
|
|
||||||
if self.extend_x:
|
|
||||||
self.scroll_x = d['locator']
|
|
||||||
else:
|
|
||||||
self.scroll_y = d['locator']
|
|
||||||
|
|
||||||
def clear_records(self, o):
|
|
||||||
# print(f'clear_records():{o=}')
|
|
||||||
self.content.clear_widgets()
|
|
||||||
self.id_Widget = {}
|
|
||||||
|
|
||||||
def on_scrollstop(self, o, d=None):
|
|
||||||
if self.dataloader is None:
|
|
||||||
return
|
|
||||||
if self.extend_x:
|
|
||||||
if self.scroll_x < self.min_threhold:
|
|
||||||
self.dataloader.loadNextPage()
|
|
||||||
if self.scroll_x > self.max_htrehold:
|
|
||||||
self.dataloader.loadPreviousPage()
|
|
||||||
print('return here ...')
|
|
||||||
return
|
|
||||||
if self.dataloader.loading:
|
|
||||||
print('loading is True')
|
|
||||||
return
|
|
||||||
if self.scroll_y < self.min_threhold:
|
|
||||||
print('load next page ...')
|
|
||||||
self.dataloader.loadNextPage()
|
|
||||||
if self.scroll_y > self.max_htrehold:
|
|
||||||
print('load previous page ...')
|
|
||||||
self.dataloader.loadPreviousPage()
|
|
||||||
|
|
0
kivyblocks/dataloader.py
Executable file → Normal file
0
kivyblocks/date_picker.py
Executable file → Normal file
0
kivyblocks/dateinput.py
Executable file → Normal file
1
kivyblocks/defaultimage.py
Executable file → Normal file
@ -1,4 +1,3 @@
|
|||||||
import os
|
|
||||||
from kivy.uix.image import AsyncImage
|
from kivy.uix.image import AsyncImage
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from kivy.properties import StringProperty
|
from kivy.properties import StringProperty
|
||||||
|
84
kivyblocks/dg.py
Executable file → Normal file
@ -10,6 +10,7 @@ from kivy.uix.gridlayout import GridLayout
|
|||||||
from kivy.uix.boxlayout import BoxLayout
|
from kivy.uix.boxlayout import BoxLayout
|
||||||
from kivy.uix.scrollview import ScrollView
|
from kivy.uix.scrollview import ScrollView
|
||||||
from kivy.uix.label import Label
|
from kivy.uix.label import Label
|
||||||
|
from kivy.graphics import Fbo
|
||||||
from kivy.uix.button import ButtonBehavior
|
from kivy.uix.button import ButtonBehavior
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.properties import BooleanProperty, StringProperty, \
|
from kivy.properties import BooleanProperty, StringProperty, \
|
||||||
@ -24,9 +25,9 @@ from appPublic.uniqueID import getID
|
|||||||
from appPublic.myTE import string_template_render
|
from appPublic.myTE import string_template_render
|
||||||
|
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .baseWidget import Text, HBox, VBox
|
from .baseWidget import Text, HBox, VBox, Running
|
||||||
from .scrollpanel import ScrollPanel
|
from .scrollpanel import ScrollPanel
|
||||||
from .paging import RelatedLoader
|
from .paging import Paging, RelatedLoader
|
||||||
from .ready import WidgetReady
|
from .ready import WidgetReady
|
||||||
from .toolbar import Toolbar
|
from .toolbar import Toolbar
|
||||||
from .bgcolorbehavior import BGColorBehavior
|
from .bgcolorbehavior import BGColorBehavior
|
||||||
@ -55,19 +56,17 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
|
|||||||
"""
|
"""
|
||||||
self.desc = desc
|
self.desc = desc
|
||||||
self.row = row
|
self.row = row
|
||||||
width = self.desc['width']
|
self.part = self.row.part
|
||||||
height = self.row.part.datagrid.rowHeight()
|
self.datagrid = self.part.datagrid
|
||||||
# print(f'Cell:{width=}, {height=},value={desc["value"]}')
|
|
||||||
super().__init__(size_hint=(None,None),
|
super().__init__(size_hint=(None,None),
|
||||||
width=width,
|
width = self.desc['width'],
|
||||||
bgcolor=[0.1,0.5,0.5],
|
height = self.row.part.datagrid.rowHeight()
|
||||||
height=height
|
|
||||||
)
|
)
|
||||||
self.csscls=self.row.part.datagrid.row_normal_css
|
self.csscls=self.row.part.datagrid.row_normal_css
|
||||||
if self.row.header:
|
if self.row.header:
|
||||||
self.csscls=self.row.part.datagrid.header_css
|
self.csscls=self.row.part.datagrid.header_css
|
||||||
if desc['header']:
|
if desc['header']:
|
||||||
bl = Text(i18n=True, text=str(desc['value']),
|
bl = Text(i18n=True, otext=str(desc['value']),
|
||||||
font_size=CSize(1),wrap=True,
|
font_size=CSize(1),wrap=True,
|
||||||
halign='left', valign='middle'
|
halign='left', valign='middle'
|
||||||
)
|
)
|
||||||
@ -75,6 +74,14 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
|
|||||||
else:
|
else:
|
||||||
self.cell_type = 'data'
|
self.cell_type = 'data'
|
||||||
bl = UiFactory.build_view_widget(desc,self.row.row_data)
|
bl = UiFactory.build_view_widget(desc,self.row.row_data)
|
||||||
|
if self.row.header and desc['name'] == '_checkable_action_':
|
||||||
|
id = self.row.row_data[idfield]
|
||||||
|
if self.row.part.datagrid.is_checked(id):
|
||||||
|
bl.setValue(True)
|
||||||
|
else:
|
||||||
|
bl.setValue(False)
|
||||||
|
bl.bind(select_state=self.row.checkable_action)
|
||||||
|
|
||||||
self.colume_name = desc['name']
|
self.colume_name = desc['name']
|
||||||
if bl:
|
if bl:
|
||||||
self.add_widget(bl)
|
self.add_widget(bl)
|
||||||
@ -92,6 +99,7 @@ class Row(BoxLayout):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.part = part
|
self.part = part
|
||||||
|
self.datagrid = self.part.datagrid
|
||||||
self.header = header
|
self.header = header
|
||||||
self.row_data = data
|
self.row_data = data
|
||||||
self.row_id = None
|
self.row_id = None
|
||||||
@ -106,6 +114,9 @@ class Row(BoxLayout):
|
|||||||
self.height = self.part.datagrid.rowHeight()
|
self.height = self.part.datagrid.rowHeight()
|
||||||
self.init(0)
|
self.init(0)
|
||||||
|
|
||||||
|
def checkable_action(self, o, *args):
|
||||||
|
self.datagrid.set_checked_rows(self.row_id, o.select_state)
|
||||||
|
|
||||||
def on_row_press(self, *args):
|
def on_row_press(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -151,7 +162,6 @@ class Header(WidgetReady, ScrollPanel):
|
|||||||
for i,f in enumerate(rd) ]
|
for i,f in enumerate(rd) ]
|
||||||
self.header = Row(self.part,rd,header=True)
|
self.header = Row(self.part,rd,header=True)
|
||||||
self.add_widget(self.header)
|
self.add_widget(self.header)
|
||||||
self.size_hint_y = None
|
|
||||||
self.height = self.header.height
|
self.height = self.header.height
|
||||||
|
|
||||||
class Body(WidgetReady, ScrollPanel):
|
class Body(WidgetReady, ScrollPanel):
|
||||||
@ -317,6 +327,7 @@ class DataGrid(VBox):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
checkable = BooleanProperty(False)
|
||||||
row_selected = BooleanProperty(False)
|
row_selected = BooleanProperty(False)
|
||||||
row_normal_css = StringProperty('default')
|
row_normal_css = StringProperty('default')
|
||||||
row_selected_css = StringProperty('default')
|
row_selected_css = StringProperty('default')
|
||||||
@ -330,6 +341,16 @@ class DataGrid(VBox):
|
|||||||
fields = ListProperty(None)
|
fields = ListProperty(None)
|
||||||
tailer = DictProperty(None)
|
tailer = DictProperty(None)
|
||||||
def __init__(self,**options):
|
def __init__(self,**options):
|
||||||
|
if self.checkable:
|
||||||
|
self.fields.insert(0, {
|
||||||
|
"name":"_checkable_action_",
|
||||||
|
"label":" ",
|
||||||
|
"type":"checkbox",
|
||||||
|
"width":CSize(2),
|
||||||
|
"freeze_flag":True
|
||||||
|
})
|
||||||
|
|
||||||
|
self.checked_rows = []
|
||||||
self.select_rowid = None
|
self.select_rowid = None
|
||||||
self.rowheight = None
|
self.rowheight = None
|
||||||
self.on_sizeTask = None
|
self.on_sizeTask = None
|
||||||
@ -367,11 +388,16 @@ class DataGrid(VBox):
|
|||||||
self.tailer_widgets = {}
|
self.tailer_widgets = {}
|
||||||
self.build_tailer(self.tailer)
|
self.build_tailer(self.tailer)
|
||||||
|
|
||||||
|
def set_checked_rows(self, rowid, flag):
|
||||||
|
if flag and rowid not in self.checked_ids:
|
||||||
|
self.checked_ids.append(rowid)
|
||||||
|
if not flag:
|
||||||
|
self.checked_ids = [ id for id in self.checked_ids if id !=rowid]
|
||||||
def on_rowpress(self, *args):
|
def on_rowpress(self, *args):
|
||||||
print('on_rowpress fire, args=', args)
|
print('on_rowpress fire, args=', args)
|
||||||
|
|
||||||
def on_cellpress(self, *args):
|
def on_cellpress(self, *args):
|
||||||
print('on_cellpress fire, args=', args)
|
print('on_cesspress fire, args=', args)
|
||||||
|
|
||||||
def on_headerpress(self, *args):
|
def on_headerpress(self, *args):
|
||||||
print('on_headerpress fire, args=', args)
|
print('on_headerpress fire, args=', args)
|
||||||
@ -436,7 +462,7 @@ class DataGrid(VBox):
|
|||||||
desc = {
|
desc = {
|
||||||
"widgettype":"Text",
|
"widgettype":"Text",
|
||||||
"options":{
|
"options":{
|
||||||
"text":n,
|
"otext":n,
|
||||||
"i18n":True,
|
"i18n":True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,9 +555,17 @@ class DataGrid(VBox):
|
|||||||
idx = -1
|
idx = -1
|
||||||
recs1 = recs[:self.show_rows]
|
recs1 = recs[:self.show_rows]
|
||||||
recs2 = recs[self.show_rows:]
|
recs2 = recs[self.show_rows:]
|
||||||
|
self._fbo = Fbo(size=self.size)
|
||||||
|
with self._fbo:
|
||||||
|
self._background_color = Color(0,0,0,1)
|
||||||
|
self._background_rect = Rectangle(size=self.size)
|
||||||
for r in recs1:
|
for r in recs1:
|
||||||
id = self.addRow(r,index=idx)
|
id = self.addRow(r,index=idx)
|
||||||
ids.append(id)
|
ids.append(id)
|
||||||
|
with self.canvas:
|
||||||
|
self._fbo_rect = Rectangle(size=self.size,
|
||||||
|
texture=self._fbo.texture)
|
||||||
|
|
||||||
data['idx'] = idx
|
data['idx'] = idx
|
||||||
data['ids'] = ids
|
data['ids'] = ids
|
||||||
data['data'] = recs2
|
data['data'] = recs2
|
||||||
@ -543,9 +577,16 @@ class DataGrid(VBox):
|
|||||||
page = data['page']
|
page = data['page']
|
||||||
idx = data['idx']
|
idx = data['idx']
|
||||||
ids = data['ids']
|
ids = data['ids']
|
||||||
|
self._fbo = Fbo(size=self.size)
|
||||||
|
with self._fbo:
|
||||||
|
self._background_color = Color(0,0,0,1)
|
||||||
|
self._background_rect = Rectangle(size=self.size)
|
||||||
for r in recs:
|
for r in recs:
|
||||||
id = self.addRow(r,index=idx)
|
id = self.addRow(r,index=idx)
|
||||||
ids.append(id)
|
ids.append(id)
|
||||||
|
with self.canvas:
|
||||||
|
self._fbo_rect = Rectangle(size=self.size,
|
||||||
|
texture=self._fbo.texture)
|
||||||
self._dataloader.bufferObjects(page,ids)
|
self._dataloader.bufferObjects(page,ids)
|
||||||
x = self._dataloader.getLocater()
|
x = self._dataloader.getLocater()
|
||||||
self.locater(x)
|
self.locater(x)
|
||||||
@ -555,13 +596,11 @@ class DataGrid(VBox):
|
|||||||
self.delRow(id)
|
self.delRow(id)
|
||||||
|
|
||||||
def addRow(self,data, **kw):
|
def addRow(self,data, **kw):
|
||||||
# print('#########addRow() ---------')
|
|
||||||
id = getID()
|
id = getID()
|
||||||
f_row = None
|
f_row = None
|
||||||
if self.freeze_part:
|
if self.freeze_part:
|
||||||
self.freeze_part.body.addRow(id, data, **kw)
|
self.freeze_part.body.addRow(id, data, **kw)
|
||||||
self.normal_part.body.addRow(id, data, **kw)
|
self.normal_part.body.addRow(id, data, **kw)
|
||||||
# print('#########addRow()==========')
|
|
||||||
return id
|
return id
|
||||||
|
|
||||||
def delRow(self,id,**kw):
|
def delRow(self,id,**kw):
|
||||||
@ -600,23 +639,6 @@ class DataGrid(VBox):
|
|||||||
fs.append(f)
|
fs.append(f)
|
||||||
return fs
|
return fs
|
||||||
|
|
||||||
def show_size(self, *args, **kw):
|
|
||||||
print(f'dg:{self.size}')
|
|
||||||
print(f'normal_part:{self.normal_part.size}')
|
|
||||||
print(f'body:{self.normal_part.body.size}')
|
|
||||||
print(f'row:{self.normal_part.body.children[0].size}')
|
|
||||||
print(f'row:{self.normal_part.body.children[0].size}')
|
|
||||||
sp = self.normal_part.body.children[0]
|
|
||||||
print(f'rows={len(sp.children) - 1}')
|
|
||||||
for i, r in enumerate(sp.children):
|
|
||||||
print(f'{i} {r.size=}')
|
|
||||||
if self.normal_part.parent.parent == self:
|
|
||||||
print('part ok')
|
|
||||||
else:
|
|
||||||
print('part parent=', self.normal_part.parent)
|
|
||||||
if self.normal_part.body.parent == self.normal_part:
|
|
||||||
print('body ok')
|
|
||||||
|
|
||||||
def get_selected_data(self):
|
def get_selected_data(self):
|
||||||
if not self.selected_rowid:
|
if not self.selected_rowid:
|
||||||
return {}
|
return {}
|
||||||
|
0
kivyblocks/download.py
Executable file → Normal file
@ -1,12 +0,0 @@
|
|||||||
import inspect
|
|
||||||
import asyncio
|
|
||||||
from functools import wraps
|
|
||||||
|
|
||||||
def eventhandler(func):
|
|
||||||
@wraps(func)
|
|
||||||
def wrapper_func(*args, **kw):
|
|
||||||
if inspect.iscoroutinefunction(func):
|
|
||||||
return asyncio.gather(func(*args, **kw))
|
|
||||||
return func(*args, **kw)
|
|
||||||
return wrapper_func
|
|
||||||
|
|
0
kivyblocks/externalwidgetmanager.py
Executable file → Normal file
395
kivyblocks/ffpyplayer_video.py
Executable file → Normal file
@ -35,6 +35,7 @@ vhks = ['v_src',
|
|||||||
]
|
]
|
||||||
|
|
||||||
class FFVideo(WidgetReady, VideoBehavior, BoxLayout):
|
class FFVideo(WidgetReady, VideoBehavior, BoxLayout):
|
||||||
|
# class FFVideo(VideoBehavior, BoxLayout):
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
kw1 = {k:v for k,v in kw.items() if k in vhks}
|
kw1 = {k:v for k,v in kw.items() if k in vhks}
|
||||||
kw1['renderto'] = 'background'
|
kw1['renderto'] = 'background'
|
||||||
@ -43,8 +44,402 @@ class FFVideo(WidgetReady, VideoBehavior, BoxLayout):
|
|||||||
BoxLayout.__init__(self, **kw2)
|
BoxLayout.__init__(self, **kw2)
|
||||||
VideoBehavior.__init__(self, **kw1)
|
VideoBehavior.__init__(self, **kw1)
|
||||||
WidgetReady.__init__(self)
|
WidgetReady.__init__(self)
|
||||||
|
# self.msg_w = Label(text='Hello')
|
||||||
|
# self.add_widget(self.msg_w)
|
||||||
|
# self.bind(on_frame=self.show_info)
|
||||||
|
|
||||||
def show_info(self, o, d):
|
def show_info(self, o, d):
|
||||||
txt = f"size={d['size']}, vpos={d['pos']}, vsize={d['texture_size']}"
|
txt = f"size={d['size']}, vpos={d['pos']}, vsize={d['texture_size']}"
|
||||||
self.msg_w.text = txt
|
self.msg_w.text = txt
|
||||||
|
|
||||||
|
"""
|
||||||
|
class FFVideo(WidgetReady, Image):
|
||||||
|
v_src = StringProperty(None)
|
||||||
|
status = OptionProperty('stop', \
|
||||||
|
options=['stop', 'play', 'pause'])
|
||||||
|
play_mode = OptionProperty('normal', \
|
||||||
|
options=['normal', 'preview', 'audioonly'])
|
||||||
|
header_callback = StringProperty(None)
|
||||||
|
audio_id = NumericProperty(None)
|
||||||
|
duration = NumericProperty(-1)
|
||||||
|
position = NumericProperty(-1)
|
||||||
|
volume = NumericProperty(-1)
|
||||||
|
timeout = NumericProperty(5)
|
||||||
|
in_center_focus = BooleanProperty(False)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self._player = None
|
||||||
|
self._update_task = None
|
||||||
|
self.running = None
|
||||||
|
self.vh_task = None
|
||||||
|
self.is_black = False
|
||||||
|
self.videosize = None
|
||||||
|
self.ff_opts = {
|
||||||
|
"framedrop":True
|
||||||
|
}
|
||||||
|
self.lib_opts = {}
|
||||||
|
self.headers_pattern = {}
|
||||||
|
super(FFVideo, self).__init__(**kwargs)
|
||||||
|
self.set_black()
|
||||||
|
self.start_task = None
|
||||||
|
self.block_task = None
|
||||||
|
self.register_event_type('on_frame')
|
||||||
|
self.register_event_type('on_open_failed')
|
||||||
|
self.register_event_type('on_leave_focus')
|
||||||
|
self.register_event_type('on_enter_focus')
|
||||||
|
self.register_event_type('on_load_success')
|
||||||
|
self.register_event_type('on_startplay')
|
||||||
|
|
||||||
|
def video_blocked(self, *args):
|
||||||
|
self._play_stop()
|
||||||
|
self.on_v_src(None, None)
|
||||||
|
|
||||||
|
def on_open_failed(self, source):
|
||||||
|
print(f'{source} open failed')
|
||||||
|
|
||||||
|
def on_load_success(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_enter_focus(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_leave_focus(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def check_focus(self,*args):
|
||||||
|
if not self.parent:
|
||||||
|
self.in_center_screen = False
|
||||||
|
return
|
||||||
|
if not self.get_root_window():
|
||||||
|
self.in_center_screen = False
|
||||||
|
|
||||||
|
w = self.parent
|
||||||
|
pos = w.to_widget(*Window.center)
|
||||||
|
if self.collide_point(*pos):
|
||||||
|
self.in_center_screen = True
|
||||||
|
else:
|
||||||
|
self.in_center_screen = False
|
||||||
|
|
||||||
|
def set_ff_opt(self, k,v):
|
||||||
|
self.ff_opts.update({k:v})
|
||||||
|
|
||||||
|
def set_lib_opt(self, k, v):
|
||||||
|
self.lib_opts.update({k:v})
|
||||||
|
|
||||||
|
def set_pattern_header(self, pattern, k,v):
|
||||||
|
dic = self.headers_pattern.get(pattern,{})
|
||||||
|
dic.update({k:v})
|
||||||
|
self.headers_pattern[pattern] = dic
|
||||||
|
|
||||||
|
def _get_spec_headers(self, filename):
|
||||||
|
for p in self.headers_pattern.keys():
|
||||||
|
if filename.startswith(p):
|
||||||
|
headers = self.headers_pattern[p]
|
||||||
|
headers_str = ''.join([f'{k}:{v}\r\n' for k,v in headers.items()])
|
||||||
|
return headers_str
|
||||||
|
return None
|
||||||
|
|
||||||
|
def on_volume(self, *args):
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._player.set_volume(self.volume)
|
||||||
|
|
||||||
|
def on_status(self, *args):
|
||||||
|
print('on_status called, ', self.status)
|
||||||
|
if self._player is None:
|
||||||
|
print('no _player, do nothing')
|
||||||
|
return
|
||||||
|
|
||||||
|
Window.allow_screensaver = True
|
||||||
|
if self.status == 'play':
|
||||||
|
Window.allow_screensaver = False
|
||||||
|
self._player.set_pause(False)
|
||||||
|
self.video_handle()
|
||||||
|
elif self.status == 'pause':
|
||||||
|
self._player.set_pause(True)
|
||||||
|
elif self.status == 'stop':
|
||||||
|
self._play_stop()
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_parent(self, *args):
|
||||||
|
if self.parent:
|
||||||
|
return
|
||||||
|
# self._play_stop()
|
||||||
|
print('on_parent() called -----------')
|
||||||
|
|
||||||
|
def on_startplay(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_frame(self, *args):
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if not self.playing:
|
||||||
|
self.dispatch('on_startplay')
|
||||||
|
self._player.request_channel( \
|
||||||
|
'audio', 'open', self.audio_id)
|
||||||
|
self.seek(self.position)
|
||||||
|
self.playing = True
|
||||||
|
if self.duration > 0:
|
||||||
|
p = self.position / self.duration * self.width
|
||||||
|
self.canvas.after.clear()
|
||||||
|
with self.canvas.after:
|
||||||
|
Color(1,1,1,1)
|
||||||
|
Line()
|
||||||
|
Line(points=[0, 0, self.width, 0], width=1)
|
||||||
|
Color(1,0,0,1)
|
||||||
|
Line(points=[0,1,p,1], width=1)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self._play_stop()
|
||||||
|
|
||||||
|
def set_volume(self, v):
|
||||||
|
if self.play_mode == 'preview':
|
||||||
|
return
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if self.status != 'play':
|
||||||
|
return
|
||||||
|
if v > 1.0:
|
||||||
|
v = 1.0
|
||||||
|
if v < 0.0:
|
||||||
|
v = 0.0
|
||||||
|
self.volume = v
|
||||||
|
|
||||||
|
def seek(self, pts):
|
||||||
|
self.vsync = False
|
||||||
|
if self.play_mode == 'preview':
|
||||||
|
return
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if self.status != 'play':
|
||||||
|
return
|
||||||
|
self._player.seek(pts, relative=False)
|
||||||
|
self.position = self._player.get_pts()
|
||||||
|
self.last_val = None
|
||||||
|
|
||||||
|
def mute(self, flag=None):
|
||||||
|
if self.play_mode == 'preview':
|
||||||
|
return
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if self.status != 'play':
|
||||||
|
return
|
||||||
|
x = self._player.get_mute()
|
||||||
|
print('Video(), mute=', x)
|
||||||
|
self._player.set_mute(not x)
|
||||||
|
|
||||||
|
def switch_audio(self):
|
||||||
|
if self.play_mode == 'preview':
|
||||||
|
return
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if self.status != 'play':
|
||||||
|
return
|
||||||
|
self._player.request_channel('audio', action='cycle')
|
||||||
|
|
||||||
|
def on_v_src(self, o, src):
|
||||||
|
# self.running = Running(self)
|
||||||
|
self.status = 'stop'
|
||||||
|
self.playing = False
|
||||||
|
|
||||||
|
ff_opts = {
|
||||||
|
'pause':False
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.play_mode == 'preview':
|
||||||
|
ff_opts['lowres'] = 2 # 1/4 size
|
||||||
|
ff_opts['an'] = True
|
||||||
|
elif self.play_mode == 'audioonly':
|
||||||
|
ff_opts['vn'] = True
|
||||||
|
ff_opts.update(self.ff_opts)
|
||||||
|
|
||||||
|
lib_opts = {
|
||||||
|
}
|
||||||
|
lib_opts.update(self.lib_opts)
|
||||||
|
heads = self._get_spec_headers(self.v_src)
|
||||||
|
if heads:
|
||||||
|
lib_opts.update({'headers':heads})
|
||||||
|
ff_opts.update({'headers':heads})
|
||||||
|
|
||||||
|
print('ff_opts=', ff_opts)
|
||||||
|
print('lib_opts=', lib_opts)
|
||||||
|
print('EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEe')
|
||||||
|
print_exc()
|
||||||
|
print('EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEe')
|
||||||
|
self._player = MediaPlayer(self.v_src, ff_opts=ff_opts, \
|
||||||
|
lib_opts=lib_opts)
|
||||||
|
# self._play_start()
|
||||||
|
self.status = 'play'
|
||||||
|
self.start_task = Clock.schedule_once(self.open_failed, self.timeout)
|
||||||
|
|
||||||
|
def open_failed(self, *args):
|
||||||
|
self.dispatch('on_open_failed', self.v_src)
|
||||||
|
|
||||||
|
def on_open_failed(self, source):
|
||||||
|
print(f'{source} open failed')
|
||||||
|
|
||||||
|
def file_opened(self, files):
|
||||||
|
self.v_src = files[0]
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
self.status = 'play'
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
# self._player.set_pause(True)
|
||||||
|
self.status = 'pause'
|
||||||
|
|
||||||
|
def _play_start(self):
|
||||||
|
self.last_frame = None
|
||||||
|
self.is_black = False
|
||||||
|
self.vsync = False
|
||||||
|
|
||||||
|
def _get_video_info(self):
|
||||||
|
if not self.playing:
|
||||||
|
self.playing = True
|
||||||
|
meta = self._player.get_metadata()
|
||||||
|
self.duration = meta['duration']
|
||||||
|
self._out_fmt = meta['src_pix_fmt']
|
||||||
|
self.frame_rate = meta['frame_rate']
|
||||||
|
self.videosize = meta['src_vid_size']
|
||||||
|
|
||||||
|
def _play_stop(self):
|
||||||
|
if self._player:
|
||||||
|
self._player.close_player()
|
||||||
|
self._player = None
|
||||||
|
if self._update_task:
|
||||||
|
self._update_task.cancel()
|
||||||
|
self._update_task = None
|
||||||
|
if self.vh_task:
|
||||||
|
self.vh_task.cancel()
|
||||||
|
self.vh_task = None
|
||||||
|
self.next_frame = None
|
||||||
|
self.duration = -1
|
||||||
|
self.position = 0
|
||||||
|
self.videosize = None
|
||||||
|
|
||||||
|
def on_size(self, *args):
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
if self.videosize == None:
|
||||||
|
return
|
||||||
|
w, h = self.videosize
|
||||||
|
r = w / h
|
||||||
|
r1 = self.width / self.height
|
||||||
|
if r1 >= r:
|
||||||
|
self._player.set_size(-1, self.height)
|
||||||
|
else:
|
||||||
|
self._player.set_size(self.width, -1)
|
||||||
|
|
||||||
|
def set_black(self):
|
||||||
|
if self.is_black:
|
||||||
|
return
|
||||||
|
image_texture = Texture.create(
|
||||||
|
size=self.size, colorfmt='rgb')
|
||||||
|
buf = b'\x00' * int(self.width * self.height * 3)
|
||||||
|
image_texture.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
|
||||||
|
self.texture = image_texture
|
||||||
|
self.is_black = True
|
||||||
|
|
||||||
|
def show_yuv420(self, img):
|
||||||
|
w, h = img.get_size()
|
||||||
|
w2 = int(w / 2)
|
||||||
|
h2 = int(h / 2)
|
||||||
|
self._tex_y = Texture.create(
|
||||||
|
size=(w, h), colorfmt='luminance')
|
||||||
|
self._tex_u = Texture.create(
|
||||||
|
size=(w2, h2), colorfmt='luminance')
|
||||||
|
self._tex_v = Texture.create(
|
||||||
|
size=(w2, h2), colorfmt='luminance')
|
||||||
|
self._fbo = fbo = Fbo(size=(w, h))
|
||||||
|
with fbo:
|
||||||
|
BindTexture(texture=self._tex_u, index=1)
|
||||||
|
BindTexture(texture=self._tex_v, index=2)
|
||||||
|
Rectangle(size=fbo.size, texture=self._tex_y)
|
||||||
|
fbo.shader.fs = VideoFFPy.YUV_RGB_FS
|
||||||
|
fbo['tex_y'] = 0
|
||||||
|
fbo['tex_u'] = 1
|
||||||
|
fbo['tex_v'] = 2
|
||||||
|
dy, du, dv, _ = img.to_memoryview()
|
||||||
|
if dy and du and dv:
|
||||||
|
self._tex_y.blit_buffer(dy, colorfmt='luminance')
|
||||||
|
self._tex_u.blit_buffer(du, colorfmt='luminance')
|
||||||
|
self._tex_v.blit_buffer(dv, colorfmt='luminance')
|
||||||
|
self._fbo.ask_update()
|
||||||
|
self._fbo.draw()
|
||||||
|
texture.flip_vertical()
|
||||||
|
self.texture = texture
|
||||||
|
|
||||||
|
def show_others(self, img):
|
||||||
|
w, h = img.get_size()
|
||||||
|
texture = Texture.create(size=(w, h), colorfmt='rgb')
|
||||||
|
texture.blit_buffer(
|
||||||
|
img.to_memoryview()[0], colorfmt='rgb',
|
||||||
|
bufferfmt='ubyte')
|
||||||
|
texture.flip_vertical()
|
||||||
|
self.texture = texture
|
||||||
|
# print('img_size=', w, h, 'window size=', self.size)
|
||||||
|
|
||||||
|
def video_handle(self, *args):
|
||||||
|
if self._update_task:
|
||||||
|
self._update_task.cancel()
|
||||||
|
self._update_task = None
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
|
frame, val = self._player.get_frame()
|
||||||
|
if val == 'eof':
|
||||||
|
self.status = 'stop'
|
||||||
|
self.set_black()
|
||||||
|
self.last_val = None
|
||||||
|
return
|
||||||
|
if val == 'pause':
|
||||||
|
self.status = 'pause'
|
||||||
|
self.last_val = None
|
||||||
|
return
|
||||||
|
if frame is None:
|
||||||
|
self.set_black()
|
||||||
|
self.last_val = None
|
||||||
|
self.vh_task = Clock.schedule_once(self.video_handle, 0.1)
|
||||||
|
return
|
||||||
|
|
||||||
|
self. _get_video_info()
|
||||||
|
self.last_frame = frame
|
||||||
|
self.video_ts = val
|
||||||
|
if self.last_val is None:
|
||||||
|
self.last_val = val
|
||||||
|
self._update_task = Clock.schedule_once(self.do_update, 0)
|
||||||
|
else:
|
||||||
|
t = val - self.last_val
|
||||||
|
if t > 0:
|
||||||
|
self._update_task = Clock.schedule_once(self.do_update, t)
|
||||||
|
else:
|
||||||
|
self._update_task = Clock.schedule_once(self.do_update, 0)
|
||||||
|
|
||||||
|
def do_update(self, *args):
|
||||||
|
if self.start_task:
|
||||||
|
self.start_task.cancel()
|
||||||
|
self.start_task = None
|
||||||
|
if self.block_task:
|
||||||
|
self.block_task.cancel()
|
||||||
|
# if self.running:
|
||||||
|
# print('runnung dismiss ........')
|
||||||
|
# self.running.dismiss()
|
||||||
|
# self.running = None
|
||||||
|
self.position = self._player.get_pts()
|
||||||
|
self.volume = self._player.get_volume()
|
||||||
|
img, t = self.last_frame
|
||||||
|
if self._out_fmt == 'yuv420p':
|
||||||
|
self.show_yuv420(img)
|
||||||
|
else:
|
||||||
|
self.show_others(img)
|
||||||
|
self.dispatch('on_frame', self.last_frame)
|
||||||
|
self.last_frame = None
|
||||||
|
self.vh_task = Clock.schedule_once(self.video_handle, 0)
|
||||||
|
self.block_task = Clock.schedule_once(self.video_blocked, self.timeout)
|
||||||
|
|
||||||
|
"""
|
||||||
|
0
kivyblocks/filebrowser.py
Executable file → Normal file
1
kivyblocks/form.py
Executable file → Normal file
@ -32,7 +32,6 @@ form options
|
|||||||
"method"
|
"method"
|
||||||
}
|
}
|
||||||
"cols":"1"
|
"cols":"1"
|
||||||
"inputwidth",
|
|
||||||
"labelwidth":
|
"labelwidth":
|
||||||
"textsize":
|
"textsize":
|
||||||
"inputheight":
|
"inputheight":
|
||||||
|
0
kivyblocks/gps.py
Executable file → Normal file
0
kivyblocks/hack_ffpyplayer.py
Executable file → Normal file
0
kivyblocks/hierarchy.py
Executable file → Normal file
0
kivyblocks/hostimage.py
Executable file → Normal file
0
kivyblocks/httpvplayer.py
Executable file → Normal file
18
kivyblocks/i18n.py
Executable file → Normal file
@ -58,12 +58,9 @@ class I18n:
|
|||||||
if config.i18n_url:
|
if config.i18n_url:
|
||||||
url = '%s%s' % (config.uihome, config.i18n_url)
|
url = '%s%s' % (config.uihome, config.i18n_url)
|
||||||
hc = HttpClient()
|
hc = HttpClient()
|
||||||
try:
|
d = hc.get(url)
|
||||||
d = hc.get(url)
|
if isinstance(d, list):
|
||||||
if isinstance(d, list):
|
return d
|
||||||
return d
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def loadI18n(self,lang):
|
def loadI18n(self,lang):
|
||||||
@ -77,12 +74,9 @@ class I18n:
|
|||||||
if config.i18n_url:
|
if config.i18n_url:
|
||||||
url = '%s%s/%s' % (config.uihome, config.i18n_url, lang)
|
url = '%s%s/%s' % (config.uihome, config.i18n_url, lang)
|
||||||
hc = HttpClient()
|
hc = HttpClient()
|
||||||
try:
|
d = hc.get(url)
|
||||||
d = hc.get(url)
|
print('i18n() %s get data=' % url, d, type(d))
|
||||||
print('i18n() %s get data=' % url, d, type(d))
|
self.kvlang[lang] = d
|
||||||
self.kvlang[lang] = d
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __call__(self,msg,lang=None):
|
def __call__(self,msg,lang=None):
|
||||||
if lang is None:
|
if lang is None:
|
||||||
|
BIN
kivyblocks/imgs/.DS_Store
vendored
0
kivyblocks/imgs/Mute64x64.png
Executable file → Normal file
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
0
kivyblocks/imgs/Play64X64.png
Executable file → Normal file
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
0
kivyblocks/imgs/Sound64x64.png
Executable file → Normal file
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 10 KiB |
0
kivyblocks/imgs/backword.png
Executable file → Normal file
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
0
kivyblocks/imgs/broken.png
Executable file → Normal file
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
0
kivyblocks/imgs/bullet_arrow_down.png
Executable file → Normal file
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
0
kivyblocks/imgs/bullet_arrow_right.png
Executable file → Normal file
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
0
kivyblocks/imgs/cancel.png
Executable file → Normal file
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
0
kivyblocks/imgs/checkbox-off.png
Executable file → Normal file
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
0
kivyblocks/imgs/checkbox-on.png
Executable file → Normal file
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
0
kivyblocks/imgs/clear.png
Executable file → Normal file
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
0
kivyblocks/imgs/conform.png
Executable file → Normal file
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
0
kivyblocks/imgs/crud_add.png
Executable file → Normal file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
kivyblocks/imgs/crud_browser.png
Executable file → Normal file
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
0
kivyblocks/imgs/crud_del.png
Executable file → Normal file
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
0
kivyblocks/imgs/crud_edit.png
Executable file → Normal file
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
0
kivyblocks/imgs/crud_filter.png
Executable file → Normal file
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
0
kivyblocks/imgs/doing.gif
Executable file → Normal file
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 171 KiB |
0
kivyblocks/imgs/download.png
Executable file → Normal file
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
0
kivyblocks/imgs/error.png
Executable file → Normal file
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
0
kivyblocks/imgs/folder.png
Executable file → Normal file
Before Width: | Height: | Size: 537 B After Width: | Height: | Size: 537 B |
0
kivyblocks/imgs/icon_view.png
Executable file → Normal file
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
0
kivyblocks/imgs/info.png
Executable file → Normal file
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
0
kivyblocks/imgs/kivymd_512.png
Executable file → Normal file
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
0
kivyblocks/imgs/kivymd_logo.png
Executable file → Normal file
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 17 KiB |
0
kivyblocks/imgs/list_view.png
Executable file → Normal file
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
0
kivyblocks/imgs/loading.gif
Executable file → Normal file
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
0
kivyblocks/imgs/loading1.gif
Executable file → Normal file
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
0
kivyblocks/imgs/menu.png
Executable file → Normal file
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
0
kivyblocks/imgs/musictrack.png
Executable file → Normal file
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
0
kivyblocks/imgs/musictrack_d.png
Executable file → Normal file
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
0
kivyblocks/imgs/next.png
Executable file → Normal file
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
0
kivyblocks/imgs/next_d.png
Executable file → Normal file
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
0
kivyblocks/imgs/org_sound.png
Executable file → Normal file
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
0
kivyblocks/imgs/org_sound_d.png
Executable file → Normal file
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
0
kivyblocks/imgs/origin.jpg
Executable file → Normal file
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
0
kivyblocks/imgs/pause.png
Executable file → Normal file
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
0
kivyblocks/imgs/pause_d.png
Executable file → Normal file
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 14 KiB |
0
kivyblocks/imgs/picture_empty.png
Executable file → Normal file
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
0
kivyblocks/imgs/play.png
Executable file → Normal file
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
0
kivyblocks/imgs/play_d.png
Executable file → Normal file
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
0
kivyblocks/imgs/power64x64.png
Executable file → Normal file
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
0
kivyblocks/imgs/previous.jpg
Executable file → Normal file
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
kivyblocks/imgs/quad_shadow-0.png
Executable file → Normal file
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
0
kivyblocks/imgs/quad_shadow-1.png
Executable file → Normal file
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
0
kivyblocks/imgs/quad_shadow-2.png
Executable file → Normal file
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
0
kivyblocks/imgs/quad_shadow.atlas
Executable file → Normal file
0
kivyblocks/imgs/question.png
Executable file → Normal file
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
0
kivyblocks/imgs/rec_shadow-0.png
Executable file → Normal file
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |