Compare commits

...

10 Commits

Author SHA1 Message Date
yumoqing
9e2b5db1a6 bugfix 2023-10-26 17:55:34 +08:00
yumoqing
01442309d9 bugfix 2023-10-13 15:53:33 +08:00
yumoqing
f1e493ca8e bugfix 2023-10-12 18:29:15 +08:00
yumoqing
313274b376 bugfix 2023-10-12 15:49:31 +08:00
yumoqing
9e60443e79 bugfix 2023-10-09 13:52:30 +08:00
yumoqing
263636779b bugfix 2022-12-16 18:14:59 +08:00
yumoqing
8e9719ac57 bugfix 2022-12-05 16:37:59 +08:00
yumoqing
2532efa9f2 bugfix 2022-11-26 15:16:43 +08:00
yumoqing
ef5c160c40 bugfix 2022-11-26 14:59:20 +08:00
yumoqing
c3ef3a99b3 bugfix 2022-11-26 13:31:13 +08:00
254 changed files with 1306 additions and 1516 deletions

0
README.md Normal file → Executable file
View File

0
docs/blocks.md Normal file → Executable file
View File

0
docs/changelog.md Normal file → Executable file
View File

0
docs/cn/binds.md Normal file → Executable file
View File

0
docs/cn/cdf.md Normal file → Executable file
View File

0
docs/cn/index.md Normal file → Executable file
View File

0
docs/cn/intro.md Normal file → Executable file
View File

0
docs/en/box.md Normal file → Executable file
View File

0
docs/imgs/hello_window.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

0
github-speed-up.md Normal file → Executable file
View File

0
kivyblocks/__init__.py Normal file → Executable file
View File

0
kivyblocks/android_rotation.py Normal file → Executable file
View File

0
kivyblocks/anz/__init__.py Normal file → Executable file
View File

0
kivyblocks/anz/bluetooth.py Normal file → Executable file
View File

0
kivyblocks/aplayer.py Normal file → Executable file
View File

0
kivyblocks/backendfunction.py Normal file → Executable file
View File

47
kivyblocks/baseWidget.py Normal file → Executable file
View File

@ -75,7 +75,7 @@ from .threadcall import HttpClient
from .i18n import I18n
from .widget_css import WidgetCSS
from .ready import WidgetReady
from .utils import CSize, SUPER
from .utils import CSize
from .swipebehavior import SwipeBehavior
from .widgetExt.inputext import MyDropDown
@ -89,16 +89,6 @@ font_names = {
'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':
from .widgetExt.phonebutton import PhoneButton
from .widgetExt.androidwebview import AWebView
@ -140,7 +130,7 @@ def ScatterBox(WidgetCSS, WidgetReady, ScatterLayout):
class Box(WidgetCSS, WidgetReady, BoxLayout):
def __init__(self, **kw):
try:
SUPER(Box, self, kw)
super(Box, self).__init__(**kw)
except Exception as e:
print('Box(',kw,') Error')
raise e
@ -157,17 +147,17 @@ class VBox(Box):
Box.__init__(self, **kw)
class SwipeBox(SwipeBehavior, Box):
def __init__(self, **kw):
SUPER(SwipeBox, self, kw)
pass
class Text(Label):
lang=StringProperty('')
otext = StringProperty('')
def __init__(self,i18n=False, texttype='text', wrap=False,
def __init__(self,i18n=False, texttype='text', wrap=False, rate=1,
fgcolor=None, **kw):
fontsize = font_sizes.get(texttype)
app = App.get_running_app()
self.rate = 1
fontsize = app.get_font_size(texttype) * self.rate
fontname = font_names.get(texttype)
self._i18n = i18n
self.i18n = I18n()
@ -182,7 +172,9 @@ class Text(Label):
if not kwargs.get('text'):
kwargs['text'] = kwargs.get('otext','')
SUPER(Text, self, kwargs)
super(Text, self).__init__(**kwargs)
app.bind(font_size=self.reset_font_size)
# self.bind(texture_size=self.setter('size'))
if self._i18n:
self.i18n.addI18nWidget(self)
if self.wrap:
@ -192,6 +184,9 @@ class Text(Label):
if self.bgcolor:
self.color = self.bgcolor
def reset_font_size(self, app, fsize):
self.font_size = fsize * self.rate
def resize(self, *args):
if not self.size_hint_y:
ps = [0,0,0,0]
@ -277,6 +272,7 @@ class Modal(VBox):
self._target = None
super(Modal, self).__init__(**kw)
self.set_size_position()
print('size_hint=', self.size_hint, kw)
self._target.bind(size=self.set_size_position)
self.register_event_type('on_open')
self.register_event_type('on_pre_open')
@ -299,7 +295,7 @@ class Modal(VBox):
return super().on_touch_down(touch)
def on_target(self):
def on_target(self, o, target):
w = Window
if self.target is not None:
w = Factory.Blocks.getWidgetById(self.target)
@ -324,9 +320,9 @@ class Modal(VBox):
self.width = self.size_hint_x * self._target.width
if self.size_hint_y:
self.height = self.size_hint_y * self._target.height
print(self.width, self.height,
self.size_hint_x, self.size_hint_y,
self._target.size
print("size with target:", self.width, self.height,
self.size_hint, self.size_hint,
"target size=", self._target.size
)
self.set_modal_position()
@ -343,7 +339,7 @@ class Modal(VBox):
x = 0
if yn == 'c':
y = (self._target.height - self.height) / 2
elif yn == 't':
elif yn == 'b':
y = self._target.height - self.height
if y < 0:
y = 0
@ -351,6 +347,9 @@ class Modal(VBox):
self.pos = x, y
else:
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):
if self.parent:
@ -389,7 +388,7 @@ class TimedModal(Modal):
show_time = NumericProperty(0)
def __init__(self, **kw):
self.time_task = None
SUPER(TimedModal, self, kw)
super(TimedModal, self).__init__(**kw)
def open(self, *args, **kw):
if self.time_task is not None:

0
kivyblocks/bgcolorbehavior.py Normal file → Executable file
View File

0
kivyblocks/block_test.py Normal file → Executable file
View File

25
kivyblocks/blocks.py Normal file → Executable file
View File

@ -204,7 +204,7 @@ x = ClassX{klass_cnt}()
return None
if url.startswith('file://'):
return self.script.dispatch(url, **params)
return self.script.dispatch(url, params)
elif url.startswith('http://') or url.startswith('https://'):
try:
hc = HttpClient()
@ -214,7 +214,14 @@ x = ClassX{klass_cnt}()
print_exc()
if errback:
return errback(None,e)
return None
return {
"widgettype":"Text",
"options":{
"text":f"{url=} error",
"wrap":True,
"halign":"left"
}
}
else:
config = getConfig()
url = config.uihome + url
@ -727,7 +734,7 @@ x = ClassX{klass_cnt}()
print('Block3: desc must be a dict object not None')
return None
w = doit(desc)
print('widgetBuild():w=', w)
# print('widgetBuild():w=', w)
return w
@classmethod
@ -781,8 +788,16 @@ x = ClassX{klass_cnt}()
return _find_widget(name,
from_widget=from_widget.parent,
dir=dir)
Logger.info('Block:_find_widget(), %s, %s %s return None',
name, from_widget.__class__.__name__, dir)
wid = None
if hasattr(from_widget, 'widget_id'):
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
def find_widget(step, from_widget):

51
kivyblocks/blocksapp.py Normal file → Executable file
View File

@ -12,6 +12,7 @@ from appPublic.folderUtils import ProgramPath
from appPublic.uniqueID import getID
from appPublic.rsawrap import RSA
from kivy.properties import NumericProperty
from kivy.factory import Factory
from kivy.metrics import sp,dp,mm
from kivy.core.window import WindowBase, Window
@ -48,6 +49,7 @@ signal.signal(signal.SIGINT, signal_handler)
class BlocksApp(App):
font_size = NumericProperty(24)
def get_rotation(self):
return get_rotation()
@ -60,10 +62,13 @@ class BlocksApp(App):
with codecs.open(config.css.css_filename, 'r', 'utf-8') as f:
d = json.load(f)
self.buildCsses(d)
if config.css.css_url:
hc = HttpClient()
d = hc.get(self.realurl(config.css.css_url))
self.buildCsses(d)
try:
if config.css.css_url:
hc = HttpClient()
d = hc.get(self.realurl(config.css.css_url))
self.buildCsses(d)
except:
pass
def on_rotate(self,*largs):
self.current_rotation = Window.rotation
@ -75,21 +80,47 @@ class BlocksApp(App):
if isinstance(v,dict):
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):
i18n = I18n()
tl = Label(text='test')
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.is_desktop = platform in ['win', 'linux', 'macosx']
config = getConfig()
self.default_params = {}
if config.default_params:
self.default_params.update(config.default_params)
self.public_headers = {
"client_uuid":getID(),
"platform":self.platform
}
# Window.borderless = True
print('Window.dpi=', Window.dpi, 'Metrics.dpi=', Metrics.dpi)
Window.bind(on_request_close=self.on_close)
Window.bind(on_rotate=self.on_rotate)
Window.bind(size=self.device_info)
self.workers = Workers(maxworkers=config.maxworkers or 80)
self.workers.start()
self.load_csses()
self.running = True
if config.root:
@ -163,7 +194,7 @@ class BlocksApp(App):
}
self.public_headers.update(device)
def on_close(self, *args):
def on_close(self, *args, **kwargs):
self.workers.running = False
return False

14
kivyblocks/boxViewer.py Normal file → Executable file
View File

@ -29,7 +29,7 @@ from kivy.graphics import Fbo, Color, Rectangle
from kivy.properties import NumericProperty, StringProperty, DictProperty
from .responsivelayout import VResponsiveLayout
from .toolbar import Toolbar
from .paging import Paging, RelatedLoader
from .paging import RelatedLoader
from .utils import CSize, SUPER
from .ready import WidgetReady
from .baseWidget import VBox
@ -122,15 +122,9 @@ class BoxViewer(VBox):
idx = data['idx']
widgets = data['widgets']
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:
self.showObject(widgets, r, index=idx)
with self.canvas:
self._fbo_rect = Rectangle(size=self.size,
texture=self._fbo.texture)
with self.fboContext():
for r in recs:
self.showObject(widgets, r, index=idx)
self.subwidgets += widgets

0
kivyblocks/circle_progress.py Normal file → Executable file
View File

41
kivyblocks/clickable.py Normal file → Executable file
View File

@ -3,6 +3,12 @@ from kivy.logger import Logger
from kivy.uix.behaviors import TouchRippleButtonBehavior
from kivy.graphics import Color, Rectangle
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.uix.image import AsyncImage
from kivy.properties import NumericProperty, DictProperty, \
@ -395,6 +401,34 @@ def build_cmdbox_view(desc, rec=None):
x.setValue(vd)
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('cmdbox', build_cmdbox_view, build_cmdbox_view)
@ -409,3 +443,10 @@ r('ToggleText',ToggleText)
r('ToggleIconText',ToggleIconText)
r('ClickableImage',ClickableImage)
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 Normal file → Executable file
View File

0
kivyblocks/colorcalc.py Normal file → Executable file
View File

0
kivyblocks/command_action.py Normal file → Executable file
View File

146
kivyblocks/container.py Normal file
View File

@ -0,0 +1,146 @@
# 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 Normal file → Executable file
View File

0
kivyblocks/date_picker.py Normal file → Executable file
View File

0
kivyblocks/dateinput.py Normal file → Executable file
View File

1
kivyblocks/defaultimage.py Normal file → Executable file
View File

@ -1,3 +1,4 @@
import os
from kivy.uix.image import AsyncImage
from kivy.factory import Factory
from kivy.properties import StringProperty

1282
kivyblocks/dg.py Normal file → Executable file

File diff suppressed because it is too large Load Diff

0
kivyblocks/download.py Normal file → Executable file
View File

View File

@ -0,0 +1,12 @@
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 Normal file → Executable file
View File

395
kivyblocks/ffpyplayer_video.py Normal file → Executable file
View File

@ -35,7 +35,6 @@ vhks = ['v_src',
]
class FFVideo(WidgetReady, VideoBehavior, BoxLayout):
# class FFVideo(VideoBehavior, BoxLayout):
def __init__(self, **kw):
kw1 = {k:v for k,v in kw.items() if k in vhks}
kw1['renderto'] = 'background'
@ -44,402 +43,8 @@ class FFVideo(WidgetReady, VideoBehavior, BoxLayout):
BoxLayout.__init__(self, **kw2)
VideoBehavior.__init__(self, **kw1)
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):
txt = f"size={d['size']}, vpos={d['pos']}, vsize={d['texture_size']}"
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 Normal file → Executable file
View File

1
kivyblocks/form.py Normal file → Executable file
View File

@ -32,6 +32,7 @@ form options
"method"
}
"cols":"1"
"inputwidth",
"labelwidth":
"textsize":
"inputheight":

0
kivyblocks/gps.py Normal file → Executable file
View File

0
kivyblocks/hack_ffpyplayer.py Normal file → Executable file
View File

0
kivyblocks/hierarchy.py Normal file → Executable file
View File

0
kivyblocks/hostimage.py Normal file → Executable file
View File

0
kivyblocks/httpvplayer.py Normal file → Executable file
View File

18
kivyblocks/i18n.py Normal file → Executable file
View File

@ -58,9 +58,12 @@ class I18n:
if config.i18n_url:
url = '%s%s' % (config.uihome, config.i18n_url)
hc = HttpClient()
d = hc.get(url)
if isinstance(d, list):
return d
try:
d = hc.get(url)
if isinstance(d, list):
return d
except:
pass
return []
def loadI18n(self,lang):
@ -74,9 +77,12 @@ class I18n:
if config.i18n_url:
url = '%s%s/%s' % (config.uihome, config.i18n_url, lang)
hc = HttpClient()
d = hc.get(url)
print('i18n() %s get data=' % url, d, type(d))
self.kvlang[lang] = d
try:
d = hc.get(url)
print('i18n() %s get data=' % url, d, type(d))
self.kvlang[lang] = d
except:
pass
def __call__(self,msg,lang=None):
if lang is None:

BIN
kivyblocks/imgs/.DS_Store vendored Executable file

Binary file not shown.

0
kivyblocks/imgs/Mute64x64.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

0
kivyblocks/imgs/Play64X64.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
kivyblocks/imgs/Sound64x64.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
kivyblocks/imgs/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

0
kivyblocks/imgs/backword.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

0
kivyblocks/imgs/broken.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

0
kivyblocks/imgs/bullet_arrow_down.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

0
kivyblocks/imgs/bullet_arrow_right.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 315 B

0
kivyblocks/imgs/cancel.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

0
kivyblocks/imgs/checkbox-off.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

0
kivyblocks/imgs/checkbox-on.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

0
kivyblocks/imgs/clear.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

0
kivyblocks/imgs/conform.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

0
kivyblocks/imgs/crud_add.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

0
kivyblocks/imgs/crud_browser.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

0
kivyblocks/imgs/crud_del.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
kivyblocks/imgs/crud_edit.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

0
kivyblocks/imgs/crud_filter.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

BIN
kivyblocks/imgs/deletex.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

0
kivyblocks/imgs/doing.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

0
kivyblocks/imgs/download.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

0
kivyblocks/imgs/error.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
kivyblocks/imgs/folder.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

0
kivyblocks/imgs/icon_view.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
kivyblocks/imgs/info.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

0
kivyblocks/imgs/kivymd_512.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

0
kivyblocks/imgs/kivymd_logo.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

BIN
kivyblocks/imgs/lensid.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

0
kivyblocks/imgs/list_view.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

0
kivyblocks/imgs/loading.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

0
kivyblocks/imgs/loading1.gif Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

0
kivyblocks/imgs/menu.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
kivyblocks/imgs/musictrack.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

0
kivyblocks/imgs/musictrack_d.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

0
kivyblocks/imgs/next.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

0
kivyblocks/imgs/next_d.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
kivyblocks/imgs/org_sound.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

0
kivyblocks/imgs/org_sound_d.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

0
kivyblocks/imgs/origin.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

0
kivyblocks/imgs/pause.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

0
kivyblocks/imgs/pause_d.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
kivyblocks/imgs/photo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

0
kivyblocks/imgs/picture_empty.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
kivyblocks/imgs/play.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

0
kivyblocks/imgs/play_d.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

0
kivyblocks/imgs/power64x64.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

0
kivyblocks/imgs/previous.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

0
kivyblocks/imgs/quad_shadow-0.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

0
kivyblocks/imgs/quad_shadow-1.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

0
kivyblocks/imgs/quad_shadow-2.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
kivyblocks/imgs/quad_shadow.atlas Normal file → Executable file
View File

0
kivyblocks/imgs/question.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

0
kivyblocks/imgs/rec_shadow-0.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Some files were not shown because too many files have changed in this diff Show More