bugfix
This commit is contained in:
commit
d65729b431
@ -5,3 +5,5 @@ add script to support local .tmpl and .dspy file translation. it can build dynam
|
|||||||
|
|
||||||
## version 0.3.1
|
## version 0.3.1
|
||||||
* uses weakref to collect all the i18n widgets in i18n.py
|
* uses weakref to collect all the i18n widgets in i18n.py
|
||||||
|
* show video play position
|
||||||
|
|
||||||
|
0
kivyblocks/anz/__init__.py
Normal file
0
kivyblocks/anz/__init__.py
Normal file
46
kivyblocks/anz/bluetooth.py
Normal file
46
kivyblocks/anz/bluetooth.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from kivy.app import App
|
||||||
|
|
||||||
|
from jnius import autoclass
|
||||||
|
import kivy
|
||||||
|
from android.broadcast import BroadcastReceiver
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from kivyblocks.baseWidget import VBox
|
||||||
|
|
||||||
|
BluetoothManager = autoclass('android.bluetooth.BluetoothManager')
|
||||||
|
BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
|
||||||
|
BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
|
||||||
|
|
||||||
|
class BluetoothFinder(VBox):
|
||||||
|
data = ListProperty([])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
super().__init__(**kw)
|
||||||
|
arg = context.getSystemService(context.BLUETOOTH_SERVICE)
|
||||||
|
self.bt_manager = BluetoothManager(arg)
|
||||||
|
self.bt_adapter = self.bt_manager.getAdaper()
|
||||||
|
self.unpairedBT()
|
||||||
|
|
||||||
|
def get_paired_bt(self):
|
||||||
|
return self.bt_adapter.getBondedDevice()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.adapter.cancelDiscovery()
|
||||||
|
|
||||||
|
def unpairedBT(self):
|
||||||
|
self.adapter = BluetoothAdapter.getDefaultAdapter()
|
||||||
|
# Search foir unpaired devices
|
||||||
|
print("Unpaired devices")
|
||||||
|
self.data=[{"text": "Unpaired Devices"}]
|
||||||
|
myReceiver = BroadcastReceiver(self.onReceive, actions = [BluetoothDevice.ACTION_FOUND, BluetoothAdapter.ACTION_DISCOVERY_STARTED, BluetoothAdapter.ACTION_DISCOVERY_FINISHED])
|
||||||
|
myReceiver.start()
|
||||||
|
self.adapter.startDiscovery()
|
||||||
|
|
||||||
|
# Called by Broadcastreceiver
|
||||||
|
def onReceive(self, context, intent):
|
||||||
|
print(f"*BT* On receive context{context}", flush = True)
|
||||||
|
print(f"*BT* On receive intent {intent}", flush = True)
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
self.myData.append({"text": f"Context {context}, intent {intent}"})
|
||||||
|
self.layout.data = [item for item in self.myData]
|
||||||
|
|
@ -2,6 +2,7 @@ import sys
|
|||||||
import math
|
import math
|
||||||
from traceback import print_exc
|
from traceback import print_exc
|
||||||
|
|
||||||
|
from kivy.resources import resource_find
|
||||||
from kivy.properties import ObjectProperty, StringProperty, \
|
from kivy.properties import ObjectProperty, StringProperty, \
|
||||||
NumericProperty, BooleanProperty, OptionProperty
|
NumericProperty, BooleanProperty, OptionProperty
|
||||||
from kivy.properties import DictProperty
|
from kivy.properties import DictProperty
|
||||||
@ -67,7 +68,7 @@ from .widgetExt.inputext import FloatInput,IntegerInput, \
|
|||||||
StrInput,SelectInput, BoolInput, Password
|
StrInput,SelectInput, BoolInput, Password
|
||||||
from .widgetExt.messager import Messager
|
from .widgetExt.messager import Messager
|
||||||
from .bgcolorbehavior import BGColorBehavior
|
from .bgcolorbehavior import BGColorBehavior
|
||||||
from .utils import NeedLogin, InsufficientPrivilege, HTTPError
|
from .utils import NeedLogin, InsufficientPrivilege, HTTPError, blockImage
|
||||||
from .login import LoginForm
|
from .login import LoginForm
|
||||||
from .tab import TabsPanel
|
from .tab import TabsPanel
|
||||||
from .threadcall import HttpClient
|
from .threadcall import HttpClient
|
||||||
@ -76,6 +77,27 @@ from .widget_css import WidgetCSS
|
|||||||
from .ready import WidgetReady
|
from .ready import WidgetReady
|
||||||
from .utils import CSize, SUPER
|
from .utils import CSize, SUPER
|
||||||
from .swipebehavior import SwipeBehavior
|
from .swipebehavior import SwipeBehavior
|
||||||
|
from .widgetExt.inputext import MyDropDown
|
||||||
|
|
||||||
|
font_names = {
|
||||||
|
'text':resource_find('DroidSansFallback.ttf'),
|
||||||
|
'title6':resource_find('TsangerYuYangT_W01_W01.ttf'),
|
||||||
|
'title5':resource_find('TsangerYuYangT_W01_W02.ttf'),
|
||||||
|
'title4':resource_find('TsangerYuYangT_W01_W03.ttf'),
|
||||||
|
'title3':resource_find('TsangerYuYangT_W01_W04.ttf'),
|
||||||
|
'title2':resource_find('TsangerYuYangT_W01_W05.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
|
||||||
@ -145,33 +167,23 @@ class Text(Label):
|
|||||||
def __init__(self,i18n=False, texttype='text', wrap=False,
|
def __init__(self,i18n=False, texttype='text', wrap=False,
|
||||||
fgcolor=None, **kw):
|
fgcolor=None, **kw):
|
||||||
|
|
||||||
fontsize={'font_size':CSize(1)}
|
fontsize = font_sizes.get(texttype)
|
||||||
offset={
|
fontname = font_names.get(texttype)
|
||||||
'text':0,
|
|
||||||
'title1':CSize(0.6),
|
|
||||||
'title2':CSize(0.5),
|
|
||||||
'title3':CSize(0.4),
|
|
||||||
'title4':CSize(0.3),
|
|
||||||
'title5':CSize(0.2),
|
|
||||||
'title6':CSize(0.1),
|
|
||||||
}
|
|
||||||
fontsize = {'font_size': CSize(1) + offset.get(texttype,0)}
|
|
||||||
self._i18n = i18n
|
self._i18n = i18n
|
||||||
self.i18n = I18n()
|
self.i18n = I18n()
|
||||||
self.bgcolor = fgcolor
|
self.bgcolor = fgcolor
|
||||||
kwargs = kw.copy()
|
kwargs = kw.copy()
|
||||||
config = getConfig()
|
config = getConfig()
|
||||||
self.wrap = wrap
|
self.wrap = wrap
|
||||||
if kwargs.get('font_size') and texttype=='text':
|
kwargs.update({
|
||||||
pass
|
'font_size':fontsize,
|
||||||
else:
|
'font_name':fontname
|
||||||
kwargs.update(fontsize)
|
})
|
||||||
if not kwargs.get('text'):
|
if not kwargs.get('text'):
|
||||||
kwargs['text'] = kwargs.get('otext','')
|
kwargs['text'] = kwargs.get('otext','')
|
||||||
|
|
||||||
SUPER(Text, self, kwargs)
|
SUPER(Text, self, kwargs)
|
||||||
if self._i18n:
|
if self._i18n:
|
||||||
self.i18n = I18n()
|
|
||||||
self.i18n.addI18nWidget(self)
|
self.i18n.addI18nWidget(self)
|
||||||
if self.wrap:
|
if self.wrap:
|
||||||
self.size_hint_y = None
|
self.size_hint_y = None
|
||||||
@ -220,6 +232,7 @@ class Text(Label):
|
|||||||
self.lang = lang
|
self.lang = lang
|
||||||
|
|
||||||
def on_lang(self,o,lang):
|
def on_lang(self,o,lang):
|
||||||
|
if self._i18n and self.otext:
|
||||||
self.text = self.i18n(self.otext)
|
self.text = self.i18n(self.otext)
|
||||||
|
|
||||||
class Title1(Text):
|
class Title1(Text):
|
||||||
@ -256,12 +269,19 @@ class Modal(VBox):
|
|||||||
content = DictProperty(None)
|
content = DictProperty(None)
|
||||||
auto_open = BooleanProperty(True)
|
auto_open = BooleanProperty(True)
|
||||||
auto_dismiss = BooleanProperty(True)
|
auto_dismiss = BooleanProperty(True)
|
||||||
position = OptionProperty('tc',options=['tl', 'tc', 'tr',
|
target = StringProperty(None)
|
||||||
|
position = OptionProperty('cc',options=['tl', 'tc', 'tr',
|
||||||
'cl', 'cc', 'cr',
|
'cl', 'cc', 'cr',
|
||||||
'bl', 'bc', 'br'])
|
'bl', 'bc', 'br'])
|
||||||
|
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
SUPER(Modal, self, kw)
|
self._target = None
|
||||||
|
super(Modal, self).__init__(**kw)
|
||||||
|
self.set_size_position()
|
||||||
|
self._target.bind(size=self.set_size_position)
|
||||||
|
self.register_event_type('on_open')
|
||||||
|
self.register_event_type('on_pre_open')
|
||||||
|
self.register_event_type('on_pre_dismiss')
|
||||||
|
self.register_event_type('on_dismiss')
|
||||||
if self.content:
|
if self.content:
|
||||||
blocks = Factory.Blocks()
|
blocks = Factory.Blocks()
|
||||||
self.content_w = blocks.widgetBuild(self.content)
|
self.content_w = blocks.widgetBuild(self.content)
|
||||||
@ -269,10 +289,6 @@ class Modal(VBox):
|
|||||||
self.add_widget(self.content_w)
|
self.add_widget(self.content_w)
|
||||||
else:
|
else:
|
||||||
print(content,':cannot build widget')
|
print(content,':cannot build widget')
|
||||||
self.register_event_type('on_open')
|
|
||||||
self.register_event_type('on_pre_open')
|
|
||||||
self.register_event_type('on_pre_dismiss')
|
|
||||||
self.register_event_type('on_dismiss')
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
if not self.collide_point(touch.x, touch.y):
|
if not self.collide_point(touch.x, touch.y):
|
||||||
@ -283,41 +299,74 @@ class Modal(VBox):
|
|||||||
|
|
||||||
return super().on_touch_down(touch)
|
return super().on_touch_down(touch)
|
||||||
|
|
||||||
def set_modal_position(self, w):
|
def on_target(self):
|
||||||
|
w = Window
|
||||||
|
if self.target is not None:
|
||||||
|
w = Factory.Blocks.getWidgetById(self.target)
|
||||||
|
if w is None:
|
||||||
|
w = Window
|
||||||
|
if w != self._target:
|
||||||
|
self._target = w
|
||||||
|
|
||||||
|
def set_target(self):
|
||||||
|
if self._target is None:
|
||||||
|
if self.target is None:
|
||||||
|
w = Window
|
||||||
|
else:
|
||||||
|
w = Factory.Blocks.getWidgetById(self.target)
|
||||||
|
if w is None:
|
||||||
|
w = Window
|
||||||
|
self._target = w
|
||||||
|
|
||||||
|
def set_size_position(self, *args):
|
||||||
|
self.set_target()
|
||||||
|
if self.size_hint_x:
|
||||||
|
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
|
||||||
|
)
|
||||||
|
self.set_modal_position()
|
||||||
|
|
||||||
|
def set_modal_position(self):
|
||||||
|
self.set_target()
|
||||||
xn = self.position[1]
|
xn = self.position[1]
|
||||||
yn = self.position[0]
|
yn = self.position[0]
|
||||||
x, y = 0, 0
|
x, y = 0, 0
|
||||||
if xn == 'c':
|
if xn == 'c':
|
||||||
x = (w.width - self.width) / 2
|
x = (self._target.width - self.width) / 2
|
||||||
elif xn == 'r':
|
elif xn == 'r':
|
||||||
x = w.width - self.width
|
x = self._target.width - self.width
|
||||||
if x < 0:
|
if x < 0:
|
||||||
x = 0
|
x = 0
|
||||||
if yn == 'c':
|
if yn == 'c':
|
||||||
y = (w.height - self.height) / 2
|
y = (self._target.height - self.height) / 2
|
||||||
elif yn == 'b':
|
elif yn == 't':
|
||||||
y = w.height - self.height
|
y = self._target.height - self.height
|
||||||
if y < 0:
|
if y < 0:
|
||||||
y = 0
|
y = 0
|
||||||
if w == Window:
|
if self._target == Window:
|
||||||
self.pos = x, y
|
self.pos = x, y
|
||||||
else:
|
else:
|
||||||
self.pos = w.pos[0] + x, w.pos[1] + y
|
self.pos = self._target.pos[0] + x, self._target.pos[1] + y
|
||||||
|
|
||||||
def open(self, widget=None):
|
def open(self):
|
||||||
if self.parent:
|
if self.parent:
|
||||||
return
|
self.parent.remove_widget(self)
|
||||||
self.dispatch('on_pre_open')
|
self.dispatch('on_pre_open')
|
||||||
if widget is None:
|
|
||||||
widget = Window
|
|
||||||
self.set_modal_position(widget)
|
|
||||||
Window.add_widget(self)
|
Window.add_widget(self)
|
||||||
self.dispatch('on_open')
|
self.dispatch('on_open')
|
||||||
|
if self._target != Window:
|
||||||
|
self._target.disabled = True
|
||||||
|
|
||||||
def dismiss(self, *args):
|
def dismiss(self, *args):
|
||||||
self.dispatch('on_pre_dismiss')
|
self.dispatch('on_pre_dismiss')
|
||||||
self.dispatch('on_dismiss')
|
self.dispatch('on_dismiss')
|
||||||
Window.remove_widget(self)
|
Window.remove_widget(self)
|
||||||
|
if self._target != Window:
|
||||||
|
self._target.enabled = False
|
||||||
|
|
||||||
def on_open(self, *args):
|
def on_open(self, *args):
|
||||||
pass
|
pass
|
||||||
@ -333,7 +382,6 @@ class Modal(VBox):
|
|||||||
|
|
||||||
def add_widget(self, w, *args, **kw):
|
def add_widget(self, w, *args, **kw):
|
||||||
super().add_widget(w, *args, **kw)
|
super().add_widget(w, *args, **kw)
|
||||||
# super().add_widget(Label(text='1111'))
|
|
||||||
if self.auto_open:
|
if self.auto_open:
|
||||||
self.open()
|
self.open()
|
||||||
|
|
||||||
@ -358,6 +406,32 @@ class TimedModal(Modal):
|
|||||||
self.time_task = None
|
self.time_task = None
|
||||||
super().dismiss()
|
super().dismiss()
|
||||||
|
|
||||||
|
class Running(AsyncImage):
|
||||||
|
def __init__(self, widget, **kw):
|
||||||
|
super().__init__(**kw)
|
||||||
|
self.host_widget = widget
|
||||||
|
self.source = blockImage('running.gif')
|
||||||
|
self.host_widget.bind(size=self.set_size)
|
||||||
|
self.set_size()
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
if self.parent:
|
||||||
|
self.parent.remove_widget(self)
|
||||||
|
Window.add_widget(self)
|
||||||
|
self.host_widget.disabled = True
|
||||||
|
|
||||||
|
def dismiss(self):
|
||||||
|
if self.parent:
|
||||||
|
self.parent.remove_widget(self)
|
||||||
|
self.host_widget.disabled = False
|
||||||
|
|
||||||
|
def set_size(self, *args):
|
||||||
|
self.size_hint = (None, None)
|
||||||
|
self.width = CSize(2)
|
||||||
|
self.height = CSize(2)
|
||||||
|
self.center = self.host_widget.center
|
||||||
|
|
||||||
class PressableImage(ButtonBehavior,AsyncImage):
|
class PressableImage(ButtonBehavior,AsyncImage):
|
||||||
def on_press(self):
|
def on_press(self):
|
||||||
pass
|
pass
|
||||||
@ -366,6 +440,10 @@ class PressableLabel(ButtonBehavior, Text):
|
|||||||
def on_press(self):
|
def on_press(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class PressableText(ButtonBehavior, Text):
|
||||||
|
def on_press(self):
|
||||||
|
pass
|
||||||
|
|
||||||
class FILEDataHandler(EventDispatcher):
|
class FILEDataHandler(EventDispatcher):
|
||||||
def __init__(self, url, suffixs=[],params={}):
|
def __init__(self, url, suffixs=[],params={}):
|
||||||
self.url = url
|
self.url = url
|
||||||
@ -566,3 +644,29 @@ class Slider(Carousel):
|
|||||||
w = bk.widgetBuild(desc)
|
w = bk.widgetBuild(desc)
|
||||||
self.add_widget(w)
|
self.add_widget(w)
|
||||||
|
|
||||||
|
class I18nWidget(PressableText):
|
||||||
|
lang = StringProperty(None)
|
||||||
|
def __init__(self, **kw):
|
||||||
|
super().__init__(**kw)
|
||||||
|
i18n = I18n()
|
||||||
|
self.lang = i18n.lang
|
||||||
|
|
||||||
|
def on_lang(self, *args):
|
||||||
|
self.otext = self.lang
|
||||||
|
|
||||||
|
def on_press(self, *args):
|
||||||
|
i18n = I18n()
|
||||||
|
langs = i18n.get_languages()
|
||||||
|
data = [ {'lang':l} for l in langs ]
|
||||||
|
mdd = MyDropDown(textField='lang', valueField='lang',
|
||||||
|
value=self.lang,
|
||||||
|
data=data)
|
||||||
|
mdd.bind(on_select=self.selected_lang)
|
||||||
|
mdd.showme(self)
|
||||||
|
|
||||||
|
def selected_lang(self, o, v):
|
||||||
|
lang = v[0]
|
||||||
|
self.lang = lang
|
||||||
|
i18n = I18n()
|
||||||
|
i18n.changeLang(self.lang)
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import codecs
|
import codecs
|
||||||
@ -818,3 +819,822 @@ class {{ classname }}({% for b in bases -%}{{b}}{% endfor %})
|
|||||||
Factory.register('Blocks',Blocks)
|
Factory.register('Blocks',Blocks)
|
||||||
Factory.register('Video',Video)
|
Factory.register('Video',Video)
|
||||||
Factory.register('OrientationLayout', OrientationLayout)
|
Factory.register('OrientationLayout', OrientationLayout)
|
||||||
|
=======
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import codecs
|
||||||
|
# import ujson as json
|
||||||
|
try:
|
||||||
|
import ujson as json
|
||||||
|
except:
|
||||||
|
import json
|
||||||
|
from traceback import print_exc
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
from appPublic.dictExt import dictExtend
|
||||||
|
from appPublic.folderUtils import ProgramPath
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
from appPublic.Singleton import SingletonDecorator, GlobalEnv
|
||||||
|
from appPublic.datamapping import keyMapping
|
||||||
|
from appPublic.registerfunction import RegisterFunction
|
||||||
|
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.config import Config
|
||||||
|
from kivy.metrics import sp,dp,mm
|
||||||
|
from kivy.core.window import WindowBase, Window
|
||||||
|
from kivy.properties import BooleanProperty
|
||||||
|
from kivy.uix.widget import Widget
|
||||||
|
from kivy.clock import mainthread
|
||||||
|
from kivy.uix.modalview import ModalView
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.factory import Factory
|
||||||
|
from kivy.uix.video import Video
|
||||||
|
from .utils import *
|
||||||
|
from .newvideo import Video
|
||||||
|
from .orientationlayout import OrientationLayout
|
||||||
|
from .threadcall import HttpClient
|
||||||
|
from .register import *
|
||||||
|
from .script import Script, set_script_env
|
||||||
|
|
||||||
|
class WidgetNotFoundById(Exception):
|
||||||
|
def __init__(self, id):
|
||||||
|
super().__init__()
|
||||||
|
self.idstr = id
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Widget not found by id:" + self.idstr + ':'
|
||||||
|
|
||||||
|
def __expr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
class ClassMethodNotFound(Exception):
|
||||||
|
def __init__(self,k,m):
|
||||||
|
super().__init__()
|
||||||
|
self.kname = k
|
||||||
|
self.mname = m
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'Method(%s) not found in class(%s)' % (self.mname,
|
||||||
|
str(self.kname.__classname__))
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __expr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
|
||||||
|
class NotExistsObject(Exception):
|
||||||
|
def __init__(self,name):
|
||||||
|
super().__init__()
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'not exists widget(%s)' % self.name
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __expr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
class ArgumentError(Exception):
|
||||||
|
def __init__(self,argument,desc):
|
||||||
|
super().__init__()
|
||||||
|
self.argument = argument
|
||||||
|
self.desc = desc
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'argument(%s) missed:%s' % (self.argument,self.desc)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __expr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
|
||||||
|
class NotRegistedWidget(Exception):
|
||||||
|
def __init__(self, name:str):
|
||||||
|
super().__init__()
|
||||||
|
self.widget_name = name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'not reigsted widget(%s)' % self.name
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __expr__(self):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
|
def registerWidget(name:str,widget):
|
||||||
|
globals()[name] = widget
|
||||||
|
|
||||||
|
|
||||||
|
class Blocks(EventDispatcher):
|
||||||
|
def __init__(self):
|
||||||
|
EventDispatcher.__init__(self)
|
||||||
|
self.action_id = 0
|
||||||
|
self.register_event_type('on_built')
|
||||||
|
self.register_event_type('on_failed')
|
||||||
|
self.env = GlobalEnv()
|
||||||
|
config = getConfig()
|
||||||
|
self.script = Script()
|
||||||
|
|
||||||
|
def set(self, k:str, v):
|
||||||
|
self.env[k] = v
|
||||||
|
|
||||||
|
def register_widget(self, name:str, widget:Widget):
|
||||||
|
globals()[name] = widget
|
||||||
|
|
||||||
|
def buildAction(self, widget:Widget, desc):
|
||||||
|
conform_desc = desc.get('conform')
|
||||||
|
blocks = Blocks()
|
||||||
|
if not conform_desc:
|
||||||
|
return partial(blocks.uniaction, widget, desc)
|
||||||
|
func =partial(blocks.conform_action,widget, desc)
|
||||||
|
return func
|
||||||
|
|
||||||
|
def eval(self, s:str, l:dict):
|
||||||
|
g = {}
|
||||||
|
forbidens = [
|
||||||
|
"os",
|
||||||
|
"sys",
|
||||||
|
"codecs",
|
||||||
|
"json",
|
||||||
|
]
|
||||||
|
|
||||||
|
for k,v in globals().copy().items():
|
||||||
|
if k not in forbidens:
|
||||||
|
g[k] = v
|
||||||
|
|
||||||
|
"""
|
||||||
|
g['__builtins__'] = globals()['__builtins__']
|
||||||
|
g['__builtins__']['__import__'] = None
|
||||||
|
g['__builtins__']['__loader__'] = None
|
||||||
|
g['__builtins__']['open'] = None
|
||||||
|
"""
|
||||||
|
g.update(self.env)
|
||||||
|
return eval(s,g,l)
|
||||||
|
|
||||||
|
def getUrlData(self, url:str, method:str='GET',
|
||||||
|
params:dict={}, files:dict={},
|
||||||
|
callback=None,
|
||||||
|
errback=None,**kw):
|
||||||
|
|
||||||
|
if url is None:
|
||||||
|
if errback:
|
||||||
|
errback(None,Exception('url is None'))
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if url.startswith('file://'):
|
||||||
|
return self.script.dispatch(url, **params)
|
||||||
|
elif url.startswith('http://') or url.startswith('https://'):
|
||||||
|
try:
|
||||||
|
hc = HttpClient()
|
||||||
|
resp=hc(url,method=method,params=params,files=files)
|
||||||
|
# print('Blocks.py :resp=',resp)
|
||||||
|
return resp
|
||||||
|
except Exception as e:
|
||||||
|
print_exc()
|
||||||
|
if errback:
|
||||||
|
return errback(None,e)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
config = getConfig()
|
||||||
|
url = config.uihome + url
|
||||||
|
return self.getUrlData(url,method=method,
|
||||||
|
params=params,
|
||||||
|
files=files,
|
||||||
|
**kw)
|
||||||
|
|
||||||
|
def strValueExpr(self,s:str,localnamespace:dict={}):
|
||||||
|
if not s.startswith('py::'):
|
||||||
|
return s
|
||||||
|
s = s[4:]
|
||||||
|
try:
|
||||||
|
v = self.eval(s,localnamespace)
|
||||||
|
return v
|
||||||
|
except Exception as e:
|
||||||
|
print('Exception .... ',e,'script=',s)
|
||||||
|
print_exc()
|
||||||
|
return s
|
||||||
|
|
||||||
|
def arrayValueExpr(self,arr:list,localnamespace:dict={}) -> list:
|
||||||
|
d = []
|
||||||
|
for v in arr:
|
||||||
|
if type(v) == type(''):
|
||||||
|
d.append(self.strValueExpr(v,localnamespace))
|
||||||
|
continue
|
||||||
|
if type(v) == type([]):
|
||||||
|
d.append(self.arrayValueExpr(v,localnamespace))
|
||||||
|
continue
|
||||||
|
if type(v) == type({}):
|
||||||
|
d.append(self.dictValueExpr(v,localnamespace))
|
||||||
|
continue
|
||||||
|
if type(v) == type(DictObject):
|
||||||
|
d.append(self.dictValueExpr(v,localnamespace))
|
||||||
|
continue
|
||||||
|
d.append(v)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def dictValueExpr(self,dic:dict,localnamespace:dict={}) -> dict:
|
||||||
|
d = {}
|
||||||
|
for k,v in dic.items():
|
||||||
|
if type(v) == type(''):
|
||||||
|
d[k] = self.strValueExpr(v,localnamespace)
|
||||||
|
continue
|
||||||
|
if type(v) == type([]):
|
||||||
|
d[k] = self.arrayValueExpr(v,localnamespace)
|
||||||
|
continue
|
||||||
|
if type(v) == type({}):
|
||||||
|
d[k] = self.dictValueExpr(v,localnamespace)
|
||||||
|
continue
|
||||||
|
if type(v) == type(DictObject):
|
||||||
|
d[k] = self.dictValueExpr(v,localnamespace)
|
||||||
|
continue
|
||||||
|
d[k] = v
|
||||||
|
return d
|
||||||
|
def valueExpr(self,obj,localnamespace:dict={}):
|
||||||
|
if type(obj) == type(''):
|
||||||
|
return self.strValueExpr(obj,localnamespace)
|
||||||
|
if type(obj) == type([]):
|
||||||
|
return self.arrayValueExpr(obj,localnamespace)
|
||||||
|
if type(obj) == type({}):
|
||||||
|
return self.dictValueExpr(obj,localnamespace)
|
||||||
|
if isinstance(obj,DictObject):
|
||||||
|
return self.dictValueExpr(obj,localnamespace)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def w_build(self,desc) -> Widget:
|
||||||
|
widgetClass = desc.get('widgettype',None)
|
||||||
|
if not widgetClass:
|
||||||
|
Logger.info("Block: w_build(), desc invalid", desc)
|
||||||
|
raise Exception(desc)
|
||||||
|
|
||||||
|
widgetClass = desc['widgettype']
|
||||||
|
opts = self.valueExpr(desc.get('options',{}).copy())
|
||||||
|
widget = None
|
||||||
|
try:
|
||||||
|
klass = Factory.get(widgetClass)
|
||||||
|
widget = klass(**opts)
|
||||||
|
except Exception as e:
|
||||||
|
print('Error:',widgetClass,'contructon error')
|
||||||
|
print_exc()
|
||||||
|
raise NotExistsObject(widgetClass)
|
||||||
|
|
||||||
|
if desc.get('id'):
|
||||||
|
id = desc.get('id')
|
||||||
|
if id.startswith('app.'):
|
||||||
|
app = App.get_running_app()
|
||||||
|
id = id[4:]
|
||||||
|
setattr(app, id, widget)
|
||||||
|
if id.startswith('root.'):
|
||||||
|
app = App.get_running_app()
|
||||||
|
id = id[5:]
|
||||||
|
setattr(app.root, id, widget)
|
||||||
|
|
||||||
|
if '.' in id:
|
||||||
|
Logger.info('widget id(%s) can not contain "."', id)
|
||||||
|
else:
|
||||||
|
widget.widget_id = id
|
||||||
|
|
||||||
|
widget.build_desc = desc
|
||||||
|
self.build_attributes(widget, desc)
|
||||||
|
self.build_rest(widget, desc)
|
||||||
|
self.buildBinds(widget, desc)
|
||||||
|
return widget
|
||||||
|
|
||||||
|
def build_attributes(self, widget:Widget,desc,t=None):
|
||||||
|
excludes = ['widgettype','options','subwidgets','binds']
|
||||||
|
for k,v in [(k,v) for k,v in desc.items() if k not in excludes]:
|
||||||
|
if isinstance(v,dict) and v.get('widgettype'):
|
||||||
|
b = Blocks()
|
||||||
|
v = self.valueExpr(v, localnamespace={'self':widget})
|
||||||
|
w = b.widgetBuild(v)
|
||||||
|
if hasattr(widget,k):
|
||||||
|
aw = getattr(widget,k)
|
||||||
|
if isinstance(aw,Layout):
|
||||||
|
aw.add_widget(w)
|
||||||
|
continue
|
||||||
|
setattr(widget,k,w)
|
||||||
|
continue
|
||||||
|
setattr(widget,k,self.valueExpr(v,\
|
||||||
|
localnamespace={'self':widget}))
|
||||||
|
|
||||||
|
def build_rest(self, widget:Widget,desc,t=None):
|
||||||
|
self.subwidget_total = len(desc.get('subwidgets',[]))
|
||||||
|
self.subwidgets = [ None for i in range(self.subwidget_total)]
|
||||||
|
pos = 0
|
||||||
|
for pos,sw in enumerate(desc.get('subwidgets',[])):
|
||||||
|
b = Blocks()
|
||||||
|
if isinstance(sw, str):
|
||||||
|
# w = Blocks.getWidgetById(sw, from_widget=widget)
|
||||||
|
w = Blocks.findWidget(sw, from_widget=widget)
|
||||||
|
if w:
|
||||||
|
widget.add_widget(w)
|
||||||
|
continue
|
||||||
|
|
||||||
|
kw = self.valueExpr(sw.copy(),
|
||||||
|
localnamespace={'self':widget})
|
||||||
|
w = b.widgetBuild(kw)
|
||||||
|
if w:
|
||||||
|
widget.add_widget(w)
|
||||||
|
|
||||||
|
|
||||||
|
def buildBinds(self, widget:Widget, desc:dict):
|
||||||
|
for b in desc.get('binds',[]):
|
||||||
|
kw = self.valueExpr(b.copy(), \
|
||||||
|
localnamespace={'self':widget})
|
||||||
|
self.buildBind(widget,kw)
|
||||||
|
|
||||||
|
def buildBind(self, widget:Widget, desc:dict):
|
||||||
|
wid = desc.get('wid','self')
|
||||||
|
# w = Blocks.getWidgetById(desc.get('wid','self'),from_widget=widget)
|
||||||
|
w = Blocks.findWidget(desc.get('wid','self'),from_widget=widget)
|
||||||
|
if not w:
|
||||||
|
Logger.info('Block: id(%s) %s',desc.get('wid','self'),
|
||||||
|
'not found via Blocks.getWidgetById()')
|
||||||
|
return
|
||||||
|
event = desc.get('event')
|
||||||
|
if event is None:
|
||||||
|
Logger.info('Block: binds desc miss event, desc=%s',str(desc))
|
||||||
|
return
|
||||||
|
f = self.buildAction(widget,desc)
|
||||||
|
if f is None:
|
||||||
|
Logger.info('Block: get a null function,%s',str(desc))
|
||||||
|
return
|
||||||
|
w.bind(**{event:f})
|
||||||
|
|
||||||
|
def multipleAction(self, widget:Widget, desc, *args):
|
||||||
|
desc1 = {k:v for k, v in desc.items() if k != 'actions'}
|
||||||
|
mydesc = desc1.copy()
|
||||||
|
for a in desc['actions']:
|
||||||
|
new_desc = mydesc.copy()
|
||||||
|
new_desc.update(a)
|
||||||
|
self.uniaction(widget,new_desc, *args)
|
||||||
|
|
||||||
|
def conform_action(self, widget:Widget, desc, *args):
|
||||||
|
conform_desc = desc.get('conform')
|
||||||
|
blocks = Blocks()
|
||||||
|
if not conform_desc:
|
||||||
|
blocks.uniaction(widget, desc,*args, **kw)
|
||||||
|
return
|
||||||
|
w = blocks.widgetBuild({
|
||||||
|
"widgettype":"Conform",
|
||||||
|
"options":conform_desc
|
||||||
|
})
|
||||||
|
w.bind(on_conform=partial(blocks.uniaction, widget, desc))
|
||||||
|
w.open()
|
||||||
|
|
||||||
|
def uniaction(self, widget:Widget, desc, *args):
|
||||||
|
acttype = desc.get('actiontype')
|
||||||
|
if acttype=='blocks':
|
||||||
|
return self.blocksAction(widget,desc, *args)
|
||||||
|
if acttype=='urlwidget':
|
||||||
|
return self.urlwidgetAction(widget,desc, *args)
|
||||||
|
if acttype == 'registedfunction':
|
||||||
|
return self.registedfunctionAction(widget,desc, *args)
|
||||||
|
if acttype == 'script':
|
||||||
|
return self.scriptAction(widget, desc, *args)
|
||||||
|
if acttype == 'method':
|
||||||
|
return self.methodAction(widget, desc, *args)
|
||||||
|
if acttype == 'event':
|
||||||
|
return self.eventAction(widget, desc, *args)
|
||||||
|
if acttype == 'multiple':
|
||||||
|
return self.multipleAction(widget, desc, *args)
|
||||||
|
|
||||||
|
alert("actiontype(%s) invalid" % acttype,title='error')
|
||||||
|
|
||||||
|
def eventAction(self, widget:Widget, desc, *args):
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
event = desc.get('dispatch_event')
|
||||||
|
if not event:
|
||||||
|
Logger.info('Block: eventAction():desc(%s) miss dispatch_event',
|
||||||
|
str(desc))
|
||||||
|
return
|
||||||
|
params = desc.get('params',{})
|
||||||
|
d = self.getActionData(widget,desc, *args)
|
||||||
|
if d:
|
||||||
|
params.update(d)
|
||||||
|
try:
|
||||||
|
target.dispatch(event, params)
|
||||||
|
except Exception as e:
|
||||||
|
Logger.info(f'Block: eventAction():dispatch {event} error')
|
||||||
|
print_exc()
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_target(self, widget:Widget, desc):
|
||||||
|
if not desc.get('target'):
|
||||||
|
return None
|
||||||
|
# return Blocks.getWidgetById(desc.get('target'),from_widget=widget)
|
||||||
|
return Blocks.findWidget(desc.get('target'),from_widget=widget)
|
||||||
|
|
||||||
|
def blocksAction(self, widget:Widget, desc, *args):
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
add_mode = desc.get('mode','replace')
|
||||||
|
opts = desc.get('options').copy()
|
||||||
|
d = self.getActionData(widget,desc, *args)
|
||||||
|
p = opts.get('options',{}).copy()
|
||||||
|
if d:
|
||||||
|
p.update(d)
|
||||||
|
opts['options'] = p
|
||||||
|
def doit(target:Widget, add_mode:str, o, w:Widget):
|
||||||
|
if isinstance(w, Modal):
|
||||||
|
return
|
||||||
|
|
||||||
|
if target and not w.parent:
|
||||||
|
if add_mode == 'replace':
|
||||||
|
target.clear_widgets()
|
||||||
|
target.add_widget(w)
|
||||||
|
|
||||||
|
def doerr(o,e):
|
||||||
|
Logger.info('Block: blocksAction(): desc=%s widgetBuild error'
|
||||||
|
,str(desc))
|
||||||
|
raise e
|
||||||
|
|
||||||
|
b = Blocks()
|
||||||
|
b.bind(on_built=partial(doit,target,add_mode))
|
||||||
|
b.bind(on_failed=doerr)
|
||||||
|
b.widgetBuild(opts)
|
||||||
|
|
||||||
|
def urlwidgetAction(self, widget:Widget, desc, *args):
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
add_mode = desc.get('mode','replace')
|
||||||
|
opts = desc.get('options', {}).copy()
|
||||||
|
p1 = opts.get('params',{})
|
||||||
|
p = {}
|
||||||
|
if p1:
|
||||||
|
p.update(p1)
|
||||||
|
if len(args) >= 1 and isinstance(args[0],dict):
|
||||||
|
p.update(args[0])
|
||||||
|
d = self.getActionData(widget, desc, *args)
|
||||||
|
if d:
|
||||||
|
p.update(d)
|
||||||
|
opts['params'] = p
|
||||||
|
d = {
|
||||||
|
'widgettype' : 'urlwidget',
|
||||||
|
'options': opts
|
||||||
|
}
|
||||||
|
|
||||||
|
def doit(target:Widget, add_mode:str, o, w:Widget):
|
||||||
|
if isinstance(w, ModalView):
|
||||||
|
return
|
||||||
|
|
||||||
|
if target and not w.parent:
|
||||||
|
if add_mode == 'replace':
|
||||||
|
target.clear_widgets()
|
||||||
|
target.add_widget(w)
|
||||||
|
|
||||||
|
def doerr(o,e):
|
||||||
|
Logger.info('Block: urlwidgetAction(): desc=%s widgetBuild error'
|
||||||
|
,str(desc))
|
||||||
|
|
||||||
|
b = Blocks()
|
||||||
|
b.bind(on_built=partial(doit,target,add_mode))
|
||||||
|
b.bind(on_failed=doerr)
|
||||||
|
b.widgetBuild(d)
|
||||||
|
|
||||||
|
def getActionData(self, widget:Widget, desc, *args):
|
||||||
|
data = {}
|
||||||
|
rtdesc = self.build_rtdesc(desc)
|
||||||
|
if rtdesc:
|
||||||
|
rt = self.get_rtdata(widget, rtdesc, *args)
|
||||||
|
if rt:
|
||||||
|
data.update(rt)
|
||||||
|
if desc.get('keymapping'):
|
||||||
|
data = keyMapping(data, desc.get('keymapping'))
|
||||||
|
Logger.info('getActionData():rtdesc=%s, data=%s', rtdesc, data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def registedfunctionAction(self, widget:Widget, desc, *args):
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
rf = RegisterFunction()
|
||||||
|
name = desc.get('rfname')
|
||||||
|
func = rf.get(name)
|
||||||
|
if func is None:
|
||||||
|
Logger.info('Block: desc=%s rfname(%s) not found',
|
||||||
|
str(desc), name)
|
||||||
|
raise Exception('rfname(%s) not found' % name)
|
||||||
|
|
||||||
|
params = desc.get('params',{}).copy()
|
||||||
|
d = self.getActionData(widget,desc, *args)
|
||||||
|
if d:
|
||||||
|
params.update(d)
|
||||||
|
func(target, *args, **params)
|
||||||
|
|
||||||
|
def scriptAction(self, widget:Widget, desc, *args):
|
||||||
|
script = desc.get('script')
|
||||||
|
if not script:
|
||||||
|
Logger.info('Block: scriptAction():desc(%s) target not found',
|
||||||
|
str(desc))
|
||||||
|
return
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
d = self.getActionData(widget,desc, *args)
|
||||||
|
ns = {
|
||||||
|
"self":target,
|
||||||
|
"args":args,
|
||||||
|
"kwargs":d
|
||||||
|
}
|
||||||
|
if d:
|
||||||
|
ns.update(d)
|
||||||
|
try:
|
||||||
|
self.eval(script, ns)
|
||||||
|
except Exception as e:
|
||||||
|
print_exc()
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
def build_rtdesc(self, desc):
|
||||||
|
rtdesc = desc.get('rtdata')
|
||||||
|
if not rtdesc:
|
||||||
|
if desc.get('datawidget'):
|
||||||
|
rtdesc = {}
|
||||||
|
rtdesc['target'] = desc['datawidget']
|
||||||
|
if desc.get('datascript'):
|
||||||
|
rtdesc['script'] = desc.get('datacript')
|
||||||
|
else:
|
||||||
|
rtdesc['method'] = desc.get('datamethod', 'getValue')
|
||||||
|
rtdesc['kwargs'] = desc.get('datakwargs', {})
|
||||||
|
return rtdesc
|
||||||
|
|
||||||
|
def get_rtdata(self, widget:Widget, desc, *args):
|
||||||
|
"""
|
||||||
|
desc descript follow attributes
|
||||||
|
{
|
||||||
|
"target", a target name from widget
|
||||||
|
"method", a method name, default is 'getValue',
|
||||||
|
"script", script to handle the data
|
||||||
|
"kwargs":" a dict arguments, default is {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
if desc is None or desc == {}:
|
||||||
|
print('get_rtdata():desc is None')
|
||||||
|
return {}
|
||||||
|
kwargs = desc.get('kwargs', {})
|
||||||
|
if not isinstance(kwargs, dict):
|
||||||
|
kwargs = {}
|
||||||
|
w = None
|
||||||
|
if len(args) > 0:
|
||||||
|
w = args[0]
|
||||||
|
target = desc.get('target')
|
||||||
|
if target:
|
||||||
|
# w = Blocks.getWidgetById(target, from_widget=widget)
|
||||||
|
w = Blocks.findWidget(target, from_widget=widget)
|
||||||
|
if w is None:
|
||||||
|
print('get_rtdata():w is None', desc)
|
||||||
|
return {}
|
||||||
|
script = desc.get('script')
|
||||||
|
if script:
|
||||||
|
ns = {
|
||||||
|
"self":w,
|
||||||
|
"args":args,
|
||||||
|
"kwargs":kwargs
|
||||||
|
}
|
||||||
|
d = self.eval(script, ns)
|
||||||
|
return d
|
||||||
|
|
||||||
|
method = desc.get('method', 'getValue')
|
||||||
|
if not hasattr(w, method):
|
||||||
|
print('get_rtdata():method is None', desc, type(w))
|
||||||
|
return {}
|
||||||
|
f = getattr(w, method)
|
||||||
|
try:
|
||||||
|
r = f(**kwargs)
|
||||||
|
if isinstance(r, dict):
|
||||||
|
return r
|
||||||
|
if isinstance(r, DictObject):
|
||||||
|
return r.to_dict()
|
||||||
|
print('get_rtdata():method return is not dict', desc, 'ret=', r, type(r))
|
||||||
|
return {}
|
||||||
|
except:
|
||||||
|
print_exc()
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def methodAction(self, widget:Widget, desc, *args):
|
||||||
|
method = desc.get('method')
|
||||||
|
target = self.get_target(widget, desc)
|
||||||
|
if target is None:
|
||||||
|
Logger.info('Block: methodAction():desc(%s) target not found',
|
||||||
|
str(desc))
|
||||||
|
return
|
||||||
|
if method is None:
|
||||||
|
Logger.info('Block: methodAction():desc(%s) method not found',
|
||||||
|
str(desc))
|
||||||
|
return
|
||||||
|
if hasattr(target,method):
|
||||||
|
f = getattr(target, method)
|
||||||
|
kwargs = desc.get('options',{}).copy()
|
||||||
|
d = self.getActionData(widget,desc, *args)
|
||||||
|
if d:
|
||||||
|
kwargs.update(d)
|
||||||
|
f(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
alert('%s method not found' % method)
|
||||||
|
|
||||||
|
def widgetBuild(self, desc):
|
||||||
|
"""
|
||||||
|
desc format:
|
||||||
|
{
|
||||||
|
widgettype:<registered widget>,
|
||||||
|
id:widget id,
|
||||||
|
options:{}
|
||||||
|
subwidgets:[
|
||||||
|
]
|
||||||
|
binds:[
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
def doit(desc):
|
||||||
|
if isinstance(desc,DictObject):
|
||||||
|
desc = desc.to_dict()
|
||||||
|
if not isinstance(desc,dict):
|
||||||
|
Logger.info('Block: desc(%s) must be a dict object(%s)',
|
||||||
|
desc,type(desc))
|
||||||
|
return None
|
||||||
|
|
||||||
|
# desc = self.valueExpr(desc)
|
||||||
|
try:
|
||||||
|
widget = self.w_build(desc)
|
||||||
|
self.dispatch('on_built',widget)
|
||||||
|
if hasattr(widget,'ready'):
|
||||||
|
widget.ready = True
|
||||||
|
return widget
|
||||||
|
except Exception as e:
|
||||||
|
print_exc()
|
||||||
|
self.dispatch('on_failed',e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(desc,DictObject):
|
||||||
|
desc = desc.to_dict()
|
||||||
|
if not isinstance(desc, dict):
|
||||||
|
print('widgetBuild1: desc must be a dict object',
|
||||||
|
desc,type(desc))
|
||||||
|
self.dispatch('on_failed',Exception('miss url'))
|
||||||
|
return
|
||||||
|
|
||||||
|
widgettype = desc.get('widgettype')
|
||||||
|
while widgettype == "urlwidget":
|
||||||
|
opts = desc.get('options',{}).copy()
|
||||||
|
extend = desc.get('extend')
|
||||||
|
addon = None
|
||||||
|
if desc.get('extend'):
|
||||||
|
addon = desc.get('extend').copy()
|
||||||
|
url = opts.get('url')
|
||||||
|
if url is None:
|
||||||
|
self.dispatch('on_failed',Exception('miss url'))
|
||||||
|
return
|
||||||
|
|
||||||
|
if opts.get('url'):
|
||||||
|
del opts['url']
|
||||||
|
rtdesc = self.build_rtdesc(opts)
|
||||||
|
if rtdesc:
|
||||||
|
rtdata = self.get_rtdata(None, rtdesc)
|
||||||
|
params = opts.get('params', {})
|
||||||
|
params.update(rtdata)
|
||||||
|
opts['params'] = params
|
||||||
|
|
||||||
|
desc = self.getUrlData(url,**opts)
|
||||||
|
if not (isinstance(desc, DictObject) or \
|
||||||
|
isinstance(desc, dict)):
|
||||||
|
print('Block2: desc must be a dict object',
|
||||||
|
desc,type(desc))
|
||||||
|
self.dispatch('on_failed',Exception('miss url'))
|
||||||
|
return
|
||||||
|
|
||||||
|
if addon:
|
||||||
|
desc = dictExtend(desc,addon)
|
||||||
|
widgettype = desc.get('widgettype')
|
||||||
|
if widgettype is None:
|
||||||
|
print('Block3: desc must be a dict object not None')
|
||||||
|
return None
|
||||||
|
return doit(desc)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def findWidget(self, id:str, from_widget:Widget=None) -> Widget:
|
||||||
|
"""
|
||||||
|
-:find up direct, find widget in ancestor
|
||||||
|
+ or empty: find down direct, find widget in descendant
|
||||||
|
@:find widget by class
|
||||||
|
$ or empty:find widget by id
|
||||||
|
.:more than one step.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def find_widget_by_id(id, from_widget):
|
||||||
|
if id=='self':
|
||||||
|
return from_widget
|
||||||
|
if hasattr(from_widget,'widget_id'):
|
||||||
|
if from_widget.widget_id == id:
|
||||||
|
return from_widget
|
||||||
|
if hasattr(from_widget, id):
|
||||||
|
w = getattr(from_widget,id)
|
||||||
|
return w
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_widget_by_class(klass, from_widget):
|
||||||
|
if from_widget.__class__.__name__ == klass:
|
||||||
|
return from_widget
|
||||||
|
for k, v in from_widget.__dict__.items():
|
||||||
|
if isinstance(v, Widget):
|
||||||
|
if v.__class__.__name__ == klass:
|
||||||
|
return v
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _find_widget(name, from_widget, dir='down',
|
||||||
|
find_func=find_widget_by_id):
|
||||||
|
w = find_func(name, from_widget)
|
||||||
|
if w:
|
||||||
|
return w
|
||||||
|
if dir == 'down':
|
||||||
|
children = [i for i in from_widget.children]
|
||||||
|
if hasattr(from_widget, 'get_subwidgets'):
|
||||||
|
children = from_widget.get_subwidgets()
|
||||||
|
# Logger.info('children=%s', str(children))
|
||||||
|
for c in children:
|
||||||
|
ret = _find_widget(name, from_widget=c, dir=dir)
|
||||||
|
if ret:
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
if isinstance(from_widget, WindowBase):
|
||||||
|
return None
|
||||||
|
if from_widget.parent:
|
||||||
|
return _find_widget(name,
|
||||||
|
from_widget=from_widget.parent,
|
||||||
|
dir=dir)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_widget(step, from_widget):
|
||||||
|
dir = 'down'
|
||||||
|
if step[0:1] == '-':
|
||||||
|
dir = 'up'
|
||||||
|
step = step[1:]
|
||||||
|
find_func = find_widget_by_id
|
||||||
|
if step[0:1] == '@':
|
||||||
|
step = step[1:]
|
||||||
|
find_func = find_widget_by_class
|
||||||
|
return _find_widget(step, from_widget=from_widget,
|
||||||
|
dir=dir, find_func=find_func)
|
||||||
|
|
||||||
|
steps = id.split('.')
|
||||||
|
w = from_widget
|
||||||
|
for i, s in enumerate(steps):
|
||||||
|
if i==0:
|
||||||
|
app = App.get_running_app()
|
||||||
|
fid = s
|
||||||
|
if fid == '/self' or fid == 'root':
|
||||||
|
w = app.root
|
||||||
|
if len(steps) == 1:
|
||||||
|
return from_widget
|
||||||
|
continue
|
||||||
|
if fid == 'Window':
|
||||||
|
w = Window
|
||||||
|
if len(steps) == 1:
|
||||||
|
return w
|
||||||
|
continue
|
||||||
|
if fid == 'app':
|
||||||
|
return app
|
||||||
|
|
||||||
|
w = find_widget(s, w)
|
||||||
|
if not w:
|
||||||
|
return None
|
||||||
|
return w
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getWidgetById(self, id:str, from_widget:Widget=None) -> Widget:
|
||||||
|
return Blocks.findWidget(id, from_widget=from_widget)
|
||||||
|
|
||||||
|
def on_built(self,v=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def on_failed(self,e=None):
|
||||||
|
return
|
||||||
|
|
||||||
|
def buildKlass(self, desc):
|
||||||
|
"""
|
||||||
|
desc = {
|
||||||
|
"classname":"MyClass",
|
||||||
|
"base":["Box", "WidgetReady"],
|
||||||
|
"properties":[
|
||||||
|
{
|
||||||
|
"name":"aaa",
|
||||||
|
"type":"str",
|
||||||
|
"default":1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"subwidgets":[
|
||||||
|
],
|
||||||
|
|
||||||
|
"""
|
||||||
|
codes = """
|
||||||
|
{% for b in bases %}
|
||||||
|
{{b}} = Factory.{{b}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
class {{ classname }}({% for b in bases -%}{{b}}{% endfor %})
|
||||||
|
{% for p in properties %}
|
||||||
|
{{p.name}} {{p.type}}({{p.default}})
|
||||||
|
{% endfor %}
|
||||||
|
def __init__(self, **kw):
|
||||||
|
super({{classname}}, self).__init__(**kw)
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
Factory.register('Blocks',Blocks)
|
||||||
|
Factory.register('Video',Video)
|
||||||
|
Factory.register('OrientationLayout', OrientationLayout)
|
||||||
|
>>>>>>> cab6a2818466e5d32880a6a01e7afe16ad192675
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from kivy.resources import resource_add_path
|
from kivy.resources import resource_add_path
|
||||||
from kivy.config import Config
|
|
||||||
resource_add_path(os.path.join(os.path.dirname(__file__),'./ttf'))
|
|
||||||
Config.set('kivy', 'default_font', [
|
|
||||||
'msgothic',
|
|
||||||
'DroidSansFallback.ttf'])
|
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
import codecs
|
import codecs
|
||||||
import json
|
import json
|
||||||
@ -23,6 +17,7 @@ from kivy.core.window import WindowBase, Window
|
|||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.logger import Logger
|
from kivy.logger import Logger
|
||||||
from kivy.utils import platform
|
from kivy.utils import platform
|
||||||
|
from kivy.metrics import Metrics
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
|
|
||||||
import plyer
|
import plyer
|
||||||
@ -31,20 +26,25 @@ from .register import *
|
|||||||
from .threadcall import HttpClient,Workers
|
from .threadcall import HttpClient,Workers
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .widget_css import register_css
|
from .widget_css import register_css
|
||||||
|
from .version import __version__
|
||||||
|
|
||||||
if platform == 'android':
|
if platform == 'android':
|
||||||
|
from android.storage import app_storage_path
|
||||||
from jnius import autoclass
|
from jnius import autoclass
|
||||||
|
from .android_rotation import get_rotation
|
||||||
|
|
||||||
from .android_rotation import get_rotation
|
Logger.info(f'KivyBlocks:version={__version__}')
|
||||||
|
|
||||||
def signal_handler(signal, frame):
|
def signal_handler(signal, frame):
|
||||||
app = App.get_running_app()
|
app = App.get_running_app()
|
||||||
|
if app is None:
|
||||||
|
return
|
||||||
app.workers.running = False
|
app.workers.running = False
|
||||||
app.stop()
|
app.stop()
|
||||||
print('Singal handled .........')
|
print('Singal handled .........')
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
|
|
||||||
class BlocksApp(App):
|
class BlocksApp(App):
|
||||||
def get_rotation(self):
|
def get_rotation(self):
|
||||||
return get_rotation()
|
return get_rotation()
|
||||||
@ -80,6 +80,8 @@ class BlocksApp(App):
|
|||||||
self.public_headers = {
|
self.public_headers = {
|
||||||
"platform":self.platform
|
"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_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)
|
||||||
@ -104,23 +106,19 @@ class BlocksApp(App):
|
|||||||
|
|
||||||
def get_user_data_path(self):
|
def get_user_data_path(self):
|
||||||
if platform == 'android':
|
if platform == 'android':
|
||||||
Environment = autoclass('android.os.Environment')
|
# Environment = autoclass('android.os.Environment')
|
||||||
sdpath = Environment.getExternalStorageDirectory()
|
# sdpath = Environment.getExternalStorageDirectory()
|
||||||
return str(sdpath)
|
# return str(sdpath)
|
||||||
|
return str(app_storage_path())
|
||||||
sdpath = App.get_running_app().user_data_dir
|
sdpath = App.get_running_app().user_data_dir
|
||||||
return str(sdpath)
|
return str(sdpath)
|
||||||
|
|
||||||
def get_profile_name(self):
|
def get_profile_name(self):
|
||||||
fname = os.path.join(self.user_data_dir,'.profile.json')
|
fname = os.path.join(self.get_user_data_path(),'.profile.json')
|
||||||
print('profile_path=', fname)
|
print('profile_path=', fname)
|
||||||
return fname
|
return fname
|
||||||
|
|
||||||
def write_profile(self, dic):
|
def default_profile(self):
|
||||||
fname = self.get_profile_name()
|
|
||||||
with codecs.open(fname,'w','utf-8') as f:
|
|
||||||
json.dump(dic,f)
|
|
||||||
|
|
||||||
def write_default_profile(self):
|
|
||||||
device_id = getID()
|
device_id = getID()
|
||||||
try:
|
try:
|
||||||
device_id = plyer.uniqueid.id
|
device_id = plyer.uniqueid.id
|
||||||
@ -132,6 +130,15 @@ class BlocksApp(App):
|
|||||||
d = {
|
d = {
|
||||||
'device_id': device_id
|
'device_id': device_id
|
||||||
}
|
}
|
||||||
|
return d
|
||||||
|
|
||||||
|
def write_profile(self, dic):
|
||||||
|
fname = self.get_profile_name()
|
||||||
|
with codecs.open(fname,'w','utf-8') as f:
|
||||||
|
json.dump(dic,f)
|
||||||
|
|
||||||
|
def write_default_profile(self):
|
||||||
|
d = self.default_profile()
|
||||||
self.write_profile(d)
|
self.write_profile(d)
|
||||||
|
|
||||||
def read_profile(self):
|
def read_profile(self):
|
||||||
|
@ -16,6 +16,11 @@ from kivyblocks.widget_css import WidgetCSS
|
|||||||
from .uitype.factory import UiFactory, get_value
|
from .uitype.factory import UiFactory, get_value
|
||||||
from .command_action import cmd_action
|
from .command_action import cmd_action
|
||||||
|
|
||||||
|
def on_disabled(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
TouchRippleButtonBehavior.on_disabled = on_disabled
|
||||||
|
|
||||||
class TinyText(Text):
|
class TinyText(Text):
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
SUPER(TinyText, self, kw)
|
SUPER(TinyText, self, kw)
|
||||||
@ -26,6 +31,46 @@ class TinyText(Text):
|
|||||||
self.texture_update()
|
self.texture_update()
|
||||||
self.size = self.texture_size
|
self.size = self.texture_size
|
||||||
|
|
||||||
|
class PressableBox(TouchRippleButtonBehavior, Box):
|
||||||
|
normal_css = StringProperty("default")
|
||||||
|
actived_css = StringProperty("default")
|
||||||
|
box_actived = BooleanProperty(False)
|
||||||
|
def __init__(self,
|
||||||
|
border_width=1,
|
||||||
|
user_data=None,
|
||||||
|
radius=[],
|
||||||
|
**kw):
|
||||||
|
super(PressableBox, self).__init__(
|
||||||
|
padding=[border_width,
|
||||||
|
border_width,
|
||||||
|
border_width,
|
||||||
|
border_width],
|
||||||
|
radius=radius,
|
||||||
|
**kw)
|
||||||
|
self.border_width = border_width
|
||||||
|
self.user_data = user_data
|
||||||
|
self.actived = False
|
||||||
|
self.csscls = self.normal_css
|
||||||
|
|
||||||
|
def active(self, flag):
|
||||||
|
self.box_actived = flag
|
||||||
|
|
||||||
|
def on_box_actived(self, o, v):
|
||||||
|
if self.box_actived:
|
||||||
|
self.csscls = self.actived_css
|
||||||
|
else:
|
||||||
|
self.csscls = self.normal_css
|
||||||
|
|
||||||
|
def on_press(self,o=None):
|
||||||
|
self.box_actived = True
|
||||||
|
|
||||||
|
|
||||||
|
def setValue(self,d):
|
||||||
|
self.user_data = d
|
||||||
|
|
||||||
|
def getValue(self):
|
||||||
|
return self.user_data
|
||||||
|
|
||||||
class ClickableBox(TouchRippleButtonBehavior, Box):
|
class ClickableBox(TouchRippleButtonBehavior, Box):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
border_width=1,
|
border_width=1,
|
||||||
|
@ -15,7 +15,6 @@ def get_cmd_desc(cmd_desc):
|
|||||||
desc['datamethod'] = v['datamethod']
|
desc['datamethod'] = v['datamethod']
|
||||||
keys = v.keys()
|
keys = v.keys()
|
||||||
if 'url' in keys:
|
if 'url' in keys:
|
||||||
Logger.info('get_cmd_desc():cmd_desc=%s', cmd_desc)
|
|
||||||
desc['actiontype'] = 'urlwidget'
|
desc['actiontype'] = 'urlwidget'
|
||||||
desc['mode'] = 'replace'
|
desc['mode'] = 'replace'
|
||||||
options = {
|
options = {
|
||||||
@ -24,18 +23,22 @@ def get_cmd_desc(cmd_desc):
|
|||||||
}
|
}
|
||||||
desc['options'] = options
|
desc['options'] = options
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
if 'rfname' in keys:
|
if 'rfname' in keys:
|
||||||
desc['actiontype'] = 'registedfunction'
|
desc['actiontype'] = 'registedfunction'
|
||||||
desc['params'] = v.get('params',{})
|
desc['params'] = v.get('params',{})
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
if 'script' in keys:
|
if 'script' in keys:
|
||||||
desc['actiontype'] = 'script'
|
desc['actiontype'] = 'script'
|
||||||
desc['script'] = v.get('script')
|
desc['script'] = v.get('script')
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
if 'method' in keys:
|
if 'method' in keys:
|
||||||
desc['actiontype'] = 'method'
|
desc['actiontype'] = 'method'
|
||||||
desc['method'] = v.get('method')
|
desc['method'] = v.get('method')
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
if 'actions' in keys:
|
if 'actions' in keys:
|
||||||
desc['actiontype'] = 'multiple'
|
desc['actiontype'] = 'multiple'
|
||||||
desc['actions'] = v.get('actions')
|
desc['actions'] = v.get('actions')
|
||||||
@ -61,6 +64,6 @@ def cmd_action(cmd_desc, widget):
|
|||||||
})
|
})
|
||||||
w.bind(on_conform=partial(blocks.uniaction, widget, desc))
|
w.bind(on_conform=partial(blocks.uniaction, widget, desc))
|
||||||
w.open()
|
w.open()
|
||||||
Logger.info('cmd_action():desc=%s, conform and action', desc)
|
print('cmd_action():desc=', desc, ' conform and action', desc)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
from kivy.event import EventDispatcher
|
from kivy.event import EventDispatcher
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
@ -191,3 +192,187 @@ class RegisterFunctionDataLoader(DataLoader):
|
|||||||
self.dispatch('on_error', e)
|
self.dispatch('on_error', e)
|
||||||
|
|
||||||
|
|
||||||
|
=======
|
||||||
|
|
||||||
|
from kivy.event import EventDispatcher
|
||||||
|
from kivy.app import App
|
||||||
|
from kivy.factory import Factory
|
||||||
|
from .threadcall import HttpClient
|
||||||
|
from .utils import absurl
|
||||||
|
from appPublic.registerfunction import RegisterFunction
|
||||||
|
|
||||||
|
class DataGraber(EventDispatcher):
|
||||||
|
"""
|
||||||
|
Graber format
|
||||||
|
{
|
||||||
|
"widgettype":"DataGraber",
|
||||||
|
"options":{
|
||||||
|
"dataurl":"first",
|
||||||
|
"datarfname":"second",
|
||||||
|
"target":"third",
|
||||||
|
"params":
|
||||||
|
"method":
|
||||||
|
"pagging":"default false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dataurl present, the DataGraber using this dataurl to get and
|
||||||
|
return data
|
||||||
|
else if datarfname present, it find a registered function named
|
||||||
|
by 'datarfname' to return data
|
||||||
|
else if datatarget present, it find the widget and uses target
|
||||||
|
method(default is 'getValue') to return data
|
||||||
|
else it return None
|
||||||
|
"""
|
||||||
|
def __init__(self, **kw):
|
||||||
|
super().__init__()
|
||||||
|
self.options = kw
|
||||||
|
self.register_event_type('on_success')
|
||||||
|
self.register_event_type('on_error')
|
||||||
|
|
||||||
|
def load(self, *args, **kw):
|
||||||
|
ret = None
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
dataurl = self.options.get('dataurl')
|
||||||
|
if dataurl:
|
||||||
|
ret = self.loadUrlData(*args, **kw)
|
||||||
|
break
|
||||||
|
|
||||||
|
rfname = self.options.get('datarfname')
|
||||||
|
if rfname:
|
||||||
|
ret = self.loadRFData(*args, **kw)
|
||||||
|
break
|
||||||
|
target = self.options.get('datatarget')
|
||||||
|
if target:
|
||||||
|
ret = self.loadTargetData(*args, **kw)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
self.dispatch('on_error', e)
|
||||||
|
return
|
||||||
|
if ret:
|
||||||
|
self.dispatch('on_success',ret)
|
||||||
|
else:
|
||||||
|
e = Exception('Not method to do load')
|
||||||
|
self.dispatch('on_error', e)
|
||||||
|
|
||||||
|
def loadUrlData(self, *args, **kw):
|
||||||
|
dataurl = self.options.get('dataurl')
|
||||||
|
hc = HttpClient()
|
||||||
|
params = self.options.get('params',{}).copy()
|
||||||
|
params.update(kw)
|
||||||
|
method = self.options.get('method','GET')
|
||||||
|
d = hc(dataurl, params=params,method=method)
|
||||||
|
return d
|
||||||
|
|
||||||
|
def loadRFData(self, *args, **kw):
|
||||||
|
rfname = self.options.get('datarfname')
|
||||||
|
rf = RegisterFunction()
|
||||||
|
f = rf.get(rfname)
|
||||||
|
if not f:
|
||||||
|
return None
|
||||||
|
params = self.options.get('params',{}).copy()
|
||||||
|
params.update(kw)
|
||||||
|
try:
|
||||||
|
d = f(**params)
|
||||||
|
return d
|
||||||
|
except Exception as e:
|
||||||
|
Logger.info('blocks : Exception:%s',e)
|
||||||
|
print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def loadTargetData(self, *args, **kw):
|
||||||
|
target = self.options.get('datatarget')
|
||||||
|
w = Factory.Blocks.getWidgetById(target)
|
||||||
|
if not w:
|
||||||
|
return None
|
||||||
|
params = self.options.get('params',{}).copy()
|
||||||
|
params.update(kw)
|
||||||
|
method = params.get('method', 'getValue')
|
||||||
|
if not has(w, method):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
f = getattr(w, method)
|
||||||
|
d = f()
|
||||||
|
return d
|
||||||
|
except Exception as e:
|
||||||
|
Logger.info('blocks : Exception %s', e)
|
||||||
|
print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def on_success(self,d):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_error(self,e):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DataLoader(EventDispatcher):
|
||||||
|
def __init__(self,data_user):
|
||||||
|
self.data_user = data_user
|
||||||
|
EventDispatcher.__init__(self)
|
||||||
|
self.register_event_type('on_success')
|
||||||
|
self.register_event_type('on_error')
|
||||||
|
|
||||||
|
def on_success(self,d):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_error(self,e):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class HttpDataLoader(DataLoader):
|
||||||
|
def load(self, *args, **kw):
|
||||||
|
app = App.get_running_app()
|
||||||
|
url = self.data_user.url
|
||||||
|
method = self.data_user.method
|
||||||
|
params = self.data_user.params.copy()
|
||||||
|
params.update({
|
||||||
|
"page":self.data_user.curpage,
|
||||||
|
"rows":self.data_user.page_rows
|
||||||
|
})
|
||||||
|
hc = HttpClient()
|
||||||
|
try:
|
||||||
|
r = hc(url, method=method, params=params)
|
||||||
|
self.dispatch('on_success', r)
|
||||||
|
return r
|
||||||
|
except Exception as e:
|
||||||
|
self.dispatch('on_error', e)
|
||||||
|
|
||||||
|
|
||||||
|
class ListDataLoader(DataLoader):
|
||||||
|
def load(self, *args, **kw):
|
||||||
|
p = self.data_user.curpage
|
||||||
|
r = self.data_user.page_rows
|
||||||
|
try:
|
||||||
|
s = self.data_user.data[(p-1)*r:p*r]
|
||||||
|
d = {
|
||||||
|
"total":len(self.data_user.data),
|
||||||
|
"rows":s
|
||||||
|
}
|
||||||
|
self.dispatch('on_success', d)
|
||||||
|
return d
|
||||||
|
except Exception as e:
|
||||||
|
self.dispatch('on_error', e)
|
||||||
|
|
||||||
|
class RegisterFunctionDataLoader(DataLoader):
|
||||||
|
def load(self, *args, **kw):
|
||||||
|
rf = RegisterFunction()
|
||||||
|
try:
|
||||||
|
rfname = self.data_user.rfname
|
||||||
|
func = rf.get(rfname)
|
||||||
|
if func is None:
|
||||||
|
raise Exception('%s is not a registerfunction' % rfname)
|
||||||
|
params = {k:v for k,v in self.user_data.params.items()}
|
||||||
|
params.update({
|
||||||
|
"page":self.data_user.curpage,
|
||||||
|
"rows":self.data_user.page_rows
|
||||||
|
})
|
||||||
|
s = func(**params)
|
||||||
|
self.dispatch('on_success', s)
|
||||||
|
return s
|
||||||
|
except Exception as e:
|
||||||
|
self.dispatch('on_error', e)
|
||||||
|
|
||||||
|
|
||||||
|
>>>>>>> cab6a2818466e5d32880a6a01e7afe16ad192675
|
||||||
|
@ -25,7 +25,7 @@ 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 Paging, RelatedLoader
|
from .paging import Paging, RelatedLoader
|
||||||
from .ready import WidgetReady
|
from .ready import WidgetReady
|
||||||
@ -64,7 +64,7 @@ class Cell(ButtonBehavior, WidgetCSS, BoxLayout):
|
|||||||
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'
|
||||||
)
|
)
|
||||||
@ -432,7 +432,7 @@ class DataGrid(VBox):
|
|||||||
desc = {
|
desc = {
|
||||||
"widgettype":"Text",
|
"widgettype":"Text",
|
||||||
"options":{
|
"options":{
|
||||||
"text":n,
|
"otext":n,
|
||||||
"i18n":True,
|
"i18n":True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
kivyblocks/download.py
Normal file
7
kivyblocks/download.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from kivy.properties import StringProperty
|
||||||
|
|
||||||
|
class DownloadFile(ClickableIconText):
|
||||||
|
def __init__(self, **kw):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
@ -6,12 +6,14 @@ from ffpyplayer.tools import set_log_callback
|
|||||||
|
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
|
from kivy.core.window import Window
|
||||||
from kivy.uix.image import Image
|
from kivy.uix.image import Image
|
||||||
from kivy.uix.widget import Widget
|
from kivy.uix.widget import Widget
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
from kivy.properties import StringProperty, BooleanProperty, \
|
from kivy.properties import StringProperty, BooleanProperty, \
|
||||||
OptionProperty, NumericProperty
|
OptionProperty, NumericProperty
|
||||||
from kivy.graphics.texture import Texture
|
from kivy.graphics.texture import Texture
|
||||||
|
from kivy.graphics import Color, Line
|
||||||
from kivyblocks.ready import WidgetReady
|
from kivyblocks.ready import WidgetReady
|
||||||
|
|
||||||
|
|
||||||
@ -26,17 +28,17 @@ class FFVideo(WidgetReady, Image):
|
|||||||
duration = NumericProperty(-1)
|
duration = NumericProperty(-1)
|
||||||
position = NumericProperty(-1)
|
position = NumericProperty(-1)
|
||||||
volume = NumericProperty(-1)
|
volume = NumericProperty(-1)
|
||||||
framerate = NumericProperty(180)
|
|
||||||
in_center_focus = BooleanProperty(False)
|
in_center_focus = BooleanProperty(False)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self._player = None
|
self._player = None
|
||||||
self._update_task = None
|
self._update_task = None
|
||||||
self._texture = None
|
self.vh_task = None
|
||||||
self.is_black = False
|
self.is_black = False
|
||||||
self.videosize = None
|
self.videosize = None
|
||||||
self.timeperiod = 1.0 / self.framerate
|
self.ff_opts = {
|
||||||
self.ff_opts = {}
|
"framedrop":True
|
||||||
|
}
|
||||||
self.lib_opts = {}
|
self.lib_opts = {}
|
||||||
self.headers_pattern = {}
|
self.headers_pattern = {}
|
||||||
super(FFVideo, self).__init__(**kwargs)
|
super(FFVideo, self).__init__(**kwargs)
|
||||||
@ -46,6 +48,7 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self.register_event_type('on_leave_focus')
|
self.register_event_type('on_leave_focus')
|
||||||
self.register_event_type('on_enter_focus')
|
self.register_event_type('on_enter_focus')
|
||||||
self.register_event_type('on_load_success')
|
self.register_event_type('on_load_success')
|
||||||
|
self.register_event_type('on_startplay')
|
||||||
|
|
||||||
def on_open_failed(self, *args):
|
def on_open_failed(self, *args):
|
||||||
pass
|
pass
|
||||||
@ -101,10 +104,14 @@ class FFVideo(WidgetReady, Image):
|
|||||||
def on_status(self, *args):
|
def on_status(self, *args):
|
||||||
print('on_status called, ', self.status)
|
print('on_status called, ', self.status)
|
||||||
if self._player is None:
|
if self._player is None:
|
||||||
|
print('no _player, do nothing')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Window.allow_screensaver = True
|
||||||
if self.status == 'play':
|
if self.status == 'play':
|
||||||
|
Window.allow_screensaver = False
|
||||||
self._player.set_pause(False)
|
self._player.set_pause(False)
|
||||||
|
self.video_handle()
|
||||||
elif self.status == 'pause':
|
elif self.status == 'pause':
|
||||||
self._player.set_pause(True)
|
self._player.set_pause(True)
|
||||||
elif self.status == 'stop':
|
elif self.status == 'stop':
|
||||||
@ -112,20 +119,35 @@ class FFVideo(WidgetReady, Image):
|
|||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def on_parent(self, *args):
|
||||||
|
if self.parent:
|
||||||
|
return
|
||||||
|
self._play_stop()
|
||||||
|
|
||||||
|
def on_startplay(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
def on_frame(self, *args):
|
def on_frame(self, *args):
|
||||||
if self._player is None:
|
if self._player is None:
|
||||||
return
|
return
|
||||||
if self.audio_id is None:
|
if not self.playing:
|
||||||
return
|
self.dispatch('on_startplay')
|
||||||
self._player.request_channel(self, 'audio', 'open', self.audio_id)
|
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):
|
def __del__(self):
|
||||||
if self._update_task:
|
self._play_stop()
|
||||||
self._update_task.cancel()
|
|
||||||
self._update_task = None
|
|
||||||
if self._player:
|
|
||||||
self._player.close_player()
|
|
||||||
self._player = None
|
|
||||||
|
|
||||||
def set_volume(self, v):
|
def set_volume(self, v):
|
||||||
if self.play_mode == 'preview':
|
if self.play_mode == 'preview':
|
||||||
@ -141,23 +163,27 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self.volume = v
|
self.volume = v
|
||||||
|
|
||||||
def seek(self, pts):
|
def seek(self, pts):
|
||||||
|
self.vsync = False
|
||||||
if self.play_mode == 'preview':
|
if self.play_mode == 'preview':
|
||||||
return
|
return
|
||||||
if self._player is None:
|
if self._player is None:
|
||||||
return
|
return
|
||||||
if self.status != 'play':
|
if self.status != 'play':
|
||||||
return
|
return
|
||||||
self._player.seek(pts)
|
self._player.seek(pts, relative=False)
|
||||||
self.position = self._player.get_pts()
|
self.position = self._player.get_pts()
|
||||||
|
self.last_val = None
|
||||||
|
|
||||||
def mute(self, flag):
|
def mute(self, flag=None):
|
||||||
if self.play_mode == 'preview':
|
if self.play_mode == 'preview':
|
||||||
return
|
return
|
||||||
if self._player is None:
|
if self._player is None:
|
||||||
return
|
return
|
||||||
if self.status != 'play':
|
if self.status != 'play':
|
||||||
return
|
return
|
||||||
self._player.set_mute(flag)
|
x = self._player.get_mute()
|
||||||
|
print('Video(), mute=', x)
|
||||||
|
self._player.set_mute(not x)
|
||||||
|
|
||||||
def switch_audio(self):
|
def switch_audio(self):
|
||||||
if self.play_mode == 'preview':
|
if self.play_mode == 'preview':
|
||||||
@ -169,7 +195,9 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self._player.request_channel('audio', action='cycle')
|
self._player.request_channel('audio', action='cycle')
|
||||||
|
|
||||||
def on_v_src(self, o, src):
|
def on_v_src(self, o, src):
|
||||||
self._play_stop()
|
self.status = 'stop'
|
||||||
|
self.playing = False
|
||||||
|
|
||||||
ff_opts = {
|
ff_opts = {
|
||||||
'pause':False
|
'pause':False
|
||||||
}
|
}
|
||||||
@ -194,7 +222,8 @@ class FFVideo(WidgetReady, Image):
|
|||||||
# self._player = MediaPlayer(self.v_src)
|
# self._player = MediaPlayer(self.v_src)
|
||||||
self._player = MediaPlayer(self.v_src, ff_opts=ff_opts, \
|
self._player = MediaPlayer(self.v_src, ff_opts=ff_opts, \
|
||||||
lib_opts=lib_opts)
|
lib_opts=lib_opts)
|
||||||
self._play_start()
|
# self._play_start()
|
||||||
|
self.status = 'play'
|
||||||
|
|
||||||
def file_opened(self, files):
|
def file_opened(self, files):
|
||||||
self.v_src = files[0]
|
self.v_src = files[0]
|
||||||
@ -202,7 +231,6 @@ class FFVideo(WidgetReady, Image):
|
|||||||
def play(self):
|
def play(self):
|
||||||
if self._player is None:
|
if self._player is None:
|
||||||
return
|
return
|
||||||
# self._player.set_pause(False)
|
|
||||||
self.status = 'play'
|
self.status = 'play'
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
@ -212,33 +240,32 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self.status = 'pause'
|
self.status = 'pause'
|
||||||
|
|
||||||
def _play_start(self):
|
def _play_start(self):
|
||||||
self.timepass = 0.0
|
|
||||||
self.last_frame = None
|
self.last_frame = None
|
||||||
self.is_black = False
|
self.is_black = False
|
||||||
self.first_play = True
|
self.vsync = False
|
||||||
self._update_task = Clock.schedule_interval(self._update, self.timeperiod)
|
|
||||||
|
|
||||||
def _get_video_info(self):
|
def _get_video_info(self):
|
||||||
if self.first_play:
|
if not self.playing:
|
||||||
|
self.playing = True
|
||||||
meta = self._player.get_metadata()
|
meta = self._player.get_metadata()
|
||||||
self.duration = meta['duration']
|
self.duration = meta['duration']
|
||||||
self.position = 0
|
|
||||||
self._out_fmt = meta['src_pix_fmt']
|
self._out_fmt = meta['src_pix_fmt']
|
||||||
self.frame_rate = meta['frame_rate']
|
self.frame_rate = meta['frame_rate']
|
||||||
self.videosize = meta['src_vid_size']
|
self.videosize = meta['src_vid_size']
|
||||||
|
|
||||||
def _play_stop(self):
|
def _play_stop(self):
|
||||||
if self._player is None:
|
if self._player:
|
||||||
return
|
|
||||||
self._update_task.cancel()
|
|
||||||
self._update_task = None
|
|
||||||
self._player.close_player()
|
self._player.close_player()
|
||||||
self._player = None
|
self._player = None
|
||||||
self.timepass = 0
|
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.next_frame = None
|
||||||
self.duration = -1
|
self.duration = -1
|
||||||
self.position = -1
|
self.position = 0
|
||||||
self.frame_rate = None
|
|
||||||
self.videosize = None
|
self.videosize = None
|
||||||
|
|
||||||
def on_size(self, *args):
|
def on_size(self, *args):
|
||||||
@ -283,7 +310,6 @@ class FFVideo(WidgetReady, Image):
|
|||||||
fbo['tex_y'] = 0
|
fbo['tex_y'] = 0
|
||||||
fbo['tex_u'] = 1
|
fbo['tex_u'] = 1
|
||||||
fbo['tex_v'] = 2
|
fbo['tex_v'] = 2
|
||||||
self._texture = fbo.texture
|
|
||||||
dy, du, dv, _ = img.to_memoryview()
|
dy, du, dv, _ = img.to_memoryview()
|
||||||
if dy and du and dv:
|
if dy and du and dv:
|
||||||
self._tex_y.blit_buffer(dy, colorfmt='luminance')
|
self._tex_y.blit_buffer(dy, colorfmt='luminance')
|
||||||
@ -304,35 +330,44 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self.texture = texture
|
self.texture = texture
|
||||||
# print('img_size=', w, h, 'window size=', self.size)
|
# print('img_size=', w, h, 'window size=', self.size)
|
||||||
|
|
||||||
def _update(self, dt):
|
def video_handle(self, *args):
|
||||||
if self.last_frame is None:
|
if self._update_task:
|
||||||
|
self._update_task.cancel()
|
||||||
|
self._update_task = None
|
||||||
|
if self._player is None:
|
||||||
|
return
|
||||||
frame, val = self._player.get_frame()
|
frame, val = self._player.get_frame()
|
||||||
if val == 'eof':
|
if val == 'eof':
|
||||||
print('*****EOF******')
|
|
||||||
self.status = 'stop'
|
self.status = 'stop'
|
||||||
self.set_black()
|
self.set_black()
|
||||||
|
self.last_val = None
|
||||||
return
|
return
|
||||||
if val == 'pause':
|
if val == 'pause':
|
||||||
self.status = 'pause'
|
self.status = 'pause'
|
||||||
|
self.last_val = None
|
||||||
return
|
return
|
||||||
if frame is None:
|
if frame is None:
|
||||||
# print('video null', time.time())
|
|
||||||
self.set_black()
|
self.set_black()
|
||||||
|
self.last_val = None
|
||||||
|
self.vh_task = Clock.schedule_once(self.video_handle, 0.1)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self. _get_video_info()
|
||||||
self.last_frame = frame
|
self.last_frame = frame
|
||||||
self.video_ts = val
|
self.video_ts = val
|
||||||
self._get_video_info()
|
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)
|
||||||
|
|
||||||
self.timepass += self.timeperiod
|
def do_update(self, *args):
|
||||||
self.position = self._player.get_pts()
|
self.position = self._player.get_pts()
|
||||||
if self.timepass < self.video_ts:
|
self.volume = self._player.get_volume()
|
||||||
return
|
|
||||||
|
|
||||||
if self.timepass > self.video_ts +0.2:
|
|
||||||
self.last_frame = None
|
|
||||||
return
|
|
||||||
|
|
||||||
self.status = 'play'
|
|
||||||
img, t = self.last_frame
|
img, t = self.last_frame
|
||||||
if self._out_fmt == 'yuv420p':
|
if self._out_fmt == 'yuv420p':
|
||||||
self.show_yuv420(img)
|
self.show_yuv420(img)
|
||||||
@ -340,5 +375,5 @@ class FFVideo(WidgetReady, Image):
|
|||||||
self.show_others(img)
|
self.show_others(img)
|
||||||
self.dispatch('on_frame', self.last_frame)
|
self.dispatch('on_frame', self.last_frame)
|
||||||
self.last_frame = None
|
self.last_frame = None
|
||||||
|
self.vh_task = Clock.schedule_once(self.video_handle, 0)
|
||||||
|
|
||||||
Factory.register('FFVideo', FFVideo)
|
|
||||||
|
@ -13,31 +13,34 @@ from .scrollpanel import ScrollPanel
|
|||||||
from .clickable import SingleCheckBox
|
from .clickable import SingleCheckBox
|
||||||
from .baseWidget import Text
|
from .baseWidget import Text
|
||||||
from .utils import CSize
|
from .utils import CSize
|
||||||
|
from .command_action import cmd_action
|
||||||
|
|
||||||
from appPublic.registerfunction import getRegisterFunctionByName
|
from appPublic.registerfunction import getRegisterFunctionByName
|
||||||
|
|
||||||
class TreeViewComplexNode(BoxLayout, TreeViewLabel):
|
class TreeViewComplexNode(BoxLayout, TreeViewNode):
|
||||||
otext = StringProperty(None)
|
otext = StringProperty(None)
|
||||||
|
font_size_c = NumericProperty(1)
|
||||||
|
node_height = NumericProperty(2)
|
||||||
checkbox = BooleanProperty(False)
|
checkbox = BooleanProperty(False)
|
||||||
icon = StringProperty(None)
|
icon = StringProperty(None)
|
||||||
data = DictProperty(None)
|
data = DictProperty(None)
|
||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
super(TreeViewComplexNode, self).__init__(**kw)
|
super(TreeViewComplexNode, self).__init__(**kw)
|
||||||
self.orientation = 'horizontal'
|
self.orientation = 'horizontal'
|
||||||
self.size_hint_x = None
|
|
||||||
if self.checkbox:
|
if self.checkbox:
|
||||||
cb = SingleCheckBox(size_hint=(None,None))
|
cb = SingleCheckBox(size_hint=(None,None))
|
||||||
cb.bind(on_press=self.set_checked)
|
cb.bind(on_press=self.set_checked)
|
||||||
self.add_widget(cb)
|
self.add_widget(cb)
|
||||||
if self.icon:
|
if self.icon:
|
||||||
img = AsyncImage(source=self.icon, size_hint=(None,None))
|
img = AsyncImage(source=self.icon, size_hint=(None,None))
|
||||||
img.size = CSize(1,1)
|
img.size = CSize(self.font_size_c,self.font_size_c)
|
||||||
self.add_widget(img)
|
self.add_widget(img)
|
||||||
txt = Text(otext=self.otext, i18n=True)
|
txt = Text(otext=self.otext, i18n=True, wrap=True,
|
||||||
txt.texture_update()
|
font_size=CSize(self.font_size_c),halign='left')
|
||||||
txt.size_hint = (None, None)
|
|
||||||
txt.size = txt.texture_size
|
|
||||||
self.add_widget(txt)
|
self.add_widget(txt)
|
||||||
|
self.size_hint_x = 1
|
||||||
|
self.size_hint_y = None
|
||||||
|
self.height = CSize(self.node_height)
|
||||||
|
|
||||||
def set_checked(self, o):
|
def set_checked(self, o):
|
||||||
if not self.data:
|
if not self.data:
|
||||||
@ -52,6 +55,8 @@ class Hierarchy(ScrollPanel):
|
|||||||
params = DictProperty(None)
|
params = DictProperty(None)
|
||||||
method = StringProperty('get')
|
method = StringProperty('get')
|
||||||
idField = StringProperty(None)
|
idField = StringProperty(None)
|
||||||
|
node_height = NumericProperty(2)
|
||||||
|
font_size_c = NumericProperty(1)
|
||||||
textField = StringProperty(None)
|
textField = StringProperty(None)
|
||||||
data = ListProperty(None)
|
data = ListProperty(None)
|
||||||
checkbox = BooleanProperty(False)
|
checkbox = BooleanProperty(False)
|
||||||
@ -60,13 +65,17 @@ class Hierarchy(ScrollPanel):
|
|||||||
def __init__(self, **kw):
|
def __init__(self, **kw):
|
||||||
self.register_event_type('on_press')
|
self.register_event_type('on_press')
|
||||||
self.tree = TreeView(hide_root=True)
|
self.tree = TreeView(hide_root=True)
|
||||||
self.tree.size_hint = (None, None)
|
self.tree.size_hint = (1, None)
|
||||||
self.tree.bind(on_node_expand=self.check_load_subnodes)
|
self.tree.bind(on_node_expand=self.check_load_subnodes)
|
||||||
self.tree.bind(selected_node=self.node_selected)
|
self.tree.bind(selected_node=self.node_selected)
|
||||||
super(Hierarchy, self).__init__(inner=self.tree, **kw)
|
super(Hierarchy, self).__init__(inner=self.tree, **kw)
|
||||||
if self.url:
|
if self.url:
|
||||||
self.data = self.get_remote_data()
|
self.data = self.get_remote_data()
|
||||||
|
|
||||||
|
def on_size(self, *args):
|
||||||
|
self.tree.size_hint_x = 1
|
||||||
|
self.tree.width = self.width
|
||||||
|
|
||||||
def on_press(self, node):
|
def on_press(self, node):
|
||||||
print('selected node=', node)
|
print('selected node=', node)
|
||||||
|
|
||||||
@ -95,12 +104,14 @@ class Hierarchy(ScrollPanel):
|
|||||||
def create_new_node(self, data, node=None):
|
def create_new_node(self, data, node=None):
|
||||||
n = TreeViewComplexNode(otext=data[self.textField],
|
n = TreeViewComplexNode(otext=data[self.textField],
|
||||||
checkbox=self.checkbox,
|
checkbox=self.checkbox,
|
||||||
|
node_height=self.node_height,
|
||||||
|
font_size_c=self.font_size_c,
|
||||||
icon=data.get('icon') or self.icon
|
icon=data.get('icon') or self.icon
|
||||||
)
|
)
|
||||||
n.data = data
|
n.data = data
|
||||||
n.width = self.tree.indent_start + \
|
# n.width = self.tree.indent_start + \
|
||||||
self.tree.indent_level * n.level \
|
# self.tree.indent_level * n.level \
|
||||||
+ sum([i.width for i in n.children])
|
# + sum([i.width for i in n.children])
|
||||||
if node:
|
if node:
|
||||||
self.tree.add_node(n, node)
|
self.tree.add_node(n, node)
|
||||||
else:
|
else:
|
||||||
@ -148,50 +159,10 @@ class Menu(Hierarchy):
|
|||||||
def on_press(self, node):
|
def on_press(self, node):
|
||||||
self.tree.deselect_node()
|
self.tree.deselect_node()
|
||||||
data = {}
|
data = {}
|
||||||
dw = node.data.get('datawidget')
|
data = node.data.copy()
|
||||||
if dw:
|
if self.target and data.get('target') is None:
|
||||||
data_widget = Factory.Blocks.getWidgetById(dw)
|
data['target'] = self.target
|
||||||
if data_widget:
|
return cmd_action(data, self)
|
||||||
vn = node.data.get('datamethod', 'getValue')
|
|
||||||
if hasattr(data_widget, vn):
|
|
||||||
f = getattr(data_widget, vn)
|
|
||||||
data = f()
|
|
||||||
if not isinstance(data, dict):
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
url = node.data.get('url')
|
|
||||||
target = Factory.Blocks.getWidgetById(node.data.get('target',self.target),self)
|
|
||||||
if url:
|
|
||||||
params = node.data.get('params',{})
|
|
||||||
params.update(data)
|
|
||||||
blocks = Factory.Blocks()
|
|
||||||
desc = {
|
|
||||||
"widgettype":"urlwidget",
|
|
||||||
"options":{
|
|
||||||
"url":url,
|
|
||||||
"params":params
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w = blocks.widgetBuild(desc)
|
|
||||||
if w and target:
|
|
||||||
target.add_widget(w)
|
|
||||||
return
|
|
||||||
|
|
||||||
rfname = node.data.get('rfname')
|
|
||||||
if rfname:
|
|
||||||
f = getRegisterFunctionByName(rfname)
|
|
||||||
if f:
|
|
||||||
f(self, **data)
|
|
||||||
return
|
|
||||||
|
|
||||||
script = node.data.get('script')
|
|
||||||
if script:
|
|
||||||
target_name = node.data.get('target', self.target)
|
|
||||||
target = Factory.Blocks.getWidgetById(target_name, self)
|
|
||||||
data.update({'self':target})
|
|
||||||
if target:
|
|
||||||
eval(script,data)
|
|
||||||
return
|
|
||||||
|
|
||||||
Factory.register('Hierarchy', Hierarchy)
|
Factory.register('Hierarchy', Hierarchy)
|
||||||
Factory.register('Menu', Menu)
|
Factory.register('Menu', Menu)
|
||||||
|
@ -14,6 +14,9 @@ class I18n:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.kvlang={}
|
self.kvlang={}
|
||||||
self.lang = locale.getdefaultlocale()[0]
|
self.lang = locale.getdefaultlocale()[0]
|
||||||
|
if self.lang is None:
|
||||||
|
self.lang = 'en_US'
|
||||||
|
self.languages = None
|
||||||
self.loadI18n(self.lang)
|
self.loadI18n(self.lang)
|
||||||
self.i18nWidgets = []
|
self.i18nWidgets = []
|
||||||
|
|
||||||
@ -21,8 +24,9 @@ class I18n:
|
|||||||
self.i18nWidgets.append(ref(w))
|
self.i18nWidgets.append(ref(w))
|
||||||
|
|
||||||
def loadI18nFromI18nFolder(self, lang):
|
def loadI18nFromI18nFolder(self, lang):
|
||||||
config = gtConfig()
|
config = getConfig()
|
||||||
fpath = os.path.join(config.i18n_folder,lang,'msg.txt')
|
fpath = os.path.join(config.i18n_folder,lang,'msg.txt')
|
||||||
|
print('fpath=', fpath, type(fpath))
|
||||||
with codecs.open(fpath,'r','utf-8') as f:
|
with codecs.open(fpath,'r','utf-8') as f:
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
d = {}
|
d = {}
|
||||||
@ -32,15 +36,39 @@ class I18n:
|
|||||||
continue
|
continue
|
||||||
k,v = line.split(':',1)
|
k,v = line.split(':',1)
|
||||||
d.update({k:v})
|
d.update({k:v})
|
||||||
line = readline()
|
line = f.readline()
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def get_languages(self):
|
||||||
|
if self.languages:
|
||||||
|
return self.languages
|
||||||
|
self.languages = self.getLanguages()
|
||||||
|
return self.languages
|
||||||
|
|
||||||
|
def getLanguages(self):
|
||||||
|
config = getConfig()
|
||||||
|
if config.i18n_folder:
|
||||||
|
langs = []
|
||||||
|
for f in os.listdir(config.i18n_folder):
|
||||||
|
p = os.path.join(config.i18n_folder, f)
|
||||||
|
if os.path.isdir(p):
|
||||||
|
langs.append(os.path.basename(f))
|
||||||
|
return langs
|
||||||
|
|
||||||
|
if config.i18n_url:
|
||||||
|
url = '%s%s' % (config.uihome, config.i18n_url)
|
||||||
|
hc = HttpClient()
|
||||||
|
d = hc.get(url)
|
||||||
|
if isinstance(d, list):
|
||||||
|
return d
|
||||||
|
return []
|
||||||
|
|
||||||
def loadI18n(self,lang):
|
def loadI18n(self,lang):
|
||||||
app = App.get_running_app()
|
app = App.get_running_app()
|
||||||
config = getConfig()
|
config = getConfig()
|
||||||
self.kvlang[lang] = {}
|
self.kvlang[lang] = {}
|
||||||
if config.i18n_folder:
|
if config.i18n_folder:
|
||||||
self.kvlang[lang] = self.loadI18nFromFolder(lang)
|
self.kvlang[lang] = self.loadI18nFromI18nFolder(lang)
|
||||||
return
|
return
|
||||||
|
|
||||||
if config.i18n_url:
|
if config.i18n_url:
|
||||||
@ -63,8 +91,8 @@ class I18n:
|
|||||||
if not d:
|
if not d:
|
||||||
self.loadI18n(lang)
|
self.loadI18n(lang)
|
||||||
self.lang = lang
|
self.lang = lang
|
||||||
ws = [ w for w in self.i18nWidgets if w is not None ]
|
ws = [ w for w in self.i18nWidgets if w() is not None ]
|
||||||
|
for w in ws:
|
||||||
|
w().changeLang(lang)
|
||||||
self.i18nWidgets = ws
|
self.i18nWidgets = ws
|
||||||
for w in self.i18nWidgets:
|
|
||||||
w.changeLang(lang)
|
|
||||||
|
|
||||||
|
BIN
kivyblocks/imgs/download.png
Normal file
BIN
kivyblocks/imgs/download.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
BIN
kivyblocks/imgs/upload.png
Normal file
BIN
kivyblocks/imgs/upload.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -191,7 +191,7 @@ class MarkdownBody(VBox):
|
|||||||
self.md_obj = md_obj
|
self.md_obj = md_obj
|
||||||
super().__init__(**kw)
|
super().__init__(**kw)
|
||||||
self.padding=padding
|
self.padding=padding
|
||||||
self.size_hint = None,None
|
self.size_hint = 1,None
|
||||||
self.bind(parent=self.resize)
|
self.bind(parent=self.resize)
|
||||||
self.resize()
|
self.resize()
|
||||||
|
|
||||||
@ -205,6 +205,7 @@ class MarkdownBody(VBox):
|
|||||||
f(v)
|
f(v)
|
||||||
|
|
||||||
def resize(self, *args):
|
def resize(self, *args):
|
||||||
|
return
|
||||||
Logger.info('MDBody:resize called')
|
Logger.info('MDBody:resize called')
|
||||||
if self.parent:
|
if self.parent:
|
||||||
ps = [0,0,0,0]
|
ps = [0,0,0,0]
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.uix.widget import Widget
|
from kivy.uix.widget import Widget
|
||||||
from kivy.app import App
|
from kivy.app import App
|
||||||
|
from kivy.clock import Clock
|
||||||
from kivy.factory import Factory
|
from kivy.factory import Factory
|
||||||
from .baseWidget import VBox, HBox
|
from kivy.utils import platform
|
||||||
|
from .baseWidget import VBox, HBox, I18nWidget
|
||||||
from .toggleitems import PressableBox
|
from .toggleitems import PressableBox
|
||||||
from .utils import *
|
from .utils import *
|
||||||
from .swipebehavior import SwipeBehavior
|
from .swipebehavior import SwipeBehavior
|
||||||
@ -56,8 +58,10 @@ in control bar, there is a optional left menu icon, page title, right menu icon,
|
|||||||
PagePanel description file format
|
PagePanel description file format
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
|
"bar_autohide": true when page is idle
|
||||||
"bar_size": bar size in CSize unit
|
"bar_size": bar size in CSize unit
|
||||||
"bar_at": "top" or "bottom"
|
"bar_at": "top" or "bottom"
|
||||||
|
"i18n": true of false
|
||||||
"bar_css":
|
"bar_css":
|
||||||
"panel_css":
|
"panel_css":
|
||||||
"left_menu": if defined, it must be a widget instance or a dict
|
"left_menu": if defined, it must be a widget instance or a dict
|
||||||
@ -133,16 +137,24 @@ sub-widget's description file format
|
|||||||
"""
|
"""
|
||||||
def __init__(self, bar_size=2,
|
def __init__(self, bar_size=2,
|
||||||
bar_css='default',
|
bar_css='default',
|
||||||
|
i18n=False,
|
||||||
csscls='default',
|
csscls='default',
|
||||||
singlepage=False,
|
singlepage=False,
|
||||||
fixed_before=None,
|
fixed_before=None,
|
||||||
|
bar_autohide=False,
|
||||||
fixed_after=None,
|
fixed_after=None,
|
||||||
bar_at='top',
|
bar_at='top',
|
||||||
enable_on_close=False,
|
enable_on_close=False,
|
||||||
left_menu=None, **kw):
|
left_menu=None, **kw):
|
||||||
self.bar_size = bar_size
|
self.bar_size = bar_size
|
||||||
|
self.bar_autohide = bar_autohide
|
||||||
self.bar_at = bar_at
|
self.bar_at = bar_at
|
||||||
|
self.i18n = i18n
|
||||||
self.singlepage = singlepage
|
self.singlepage = singlepage
|
||||||
|
self.idle_status = False
|
||||||
|
self.idle_threshold = 10
|
||||||
|
self.bar_show = True
|
||||||
|
self.idle_task = None
|
||||||
self.swipe_buffer = []
|
self.swipe_buffer = []
|
||||||
self.swipe_right = False
|
self.swipe_right = False
|
||||||
self.fixed_before = None
|
self.fixed_before = None
|
||||||
@ -209,6 +221,10 @@ sub-widget's description file format
|
|||||||
})
|
})
|
||||||
self.bar.add_widget(self.bar_left_menu)
|
self.bar.add_widget(self.bar_left_menu)
|
||||||
self.bar_left_menu.bind(on_press=self.show_left_menu)
|
self.bar_left_menu.bind(on_press=self.show_left_menu)
|
||||||
|
if self.i18n:
|
||||||
|
self.i18n_w = I18nWidget(size_hint_x=None, width=CSize(5))
|
||||||
|
self.bar.add_widget(self.i18n_w)
|
||||||
|
|
||||||
self.bar_title = HBox(csscls=bar_css)
|
self.bar_title = HBox(csscls=bar_css)
|
||||||
self.bar.add_widget(self.bar_title)
|
self.bar.add_widget(self.bar_title)
|
||||||
self.bar_right_menu = VBox(size_hint=(None,None),size=CSize(bcsize,bcsize))
|
self.bar_right_menu = VBox(size_hint=(None,None),size=CSize(bcsize,bcsize))
|
||||||
@ -229,15 +245,47 @@ sub-widget's description file format
|
|||||||
})
|
})
|
||||||
self.bar.add_widget(self.bar_right_menu)
|
self.bar.add_widget(self.bar_right_menu)
|
||||||
self.bar_right_menu_w.bind(on_press=self.show_right_menu)
|
self.bar_right_menu_w.bind(on_press=self.show_right_menu)
|
||||||
|
self.construct()
|
||||||
|
if self.bar_autohide:
|
||||||
|
Window.bind(on_touch_down=self.set_normal_bar)
|
||||||
|
self.idle_task = Clock.schedule_once(self.set_idle_bar, \
|
||||||
|
self.idle_threshold)
|
||||||
|
|
||||||
if bar_at == 'top':
|
def set_idle_bar(self, *args):
|
||||||
|
if not self.bar_show:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.bar_pos = self.children.index(self.bar)
|
||||||
|
print('self.bar_pos=', self.bar_pos, '......................')
|
||||||
|
super().remove_widget(self.bar)
|
||||||
|
if platform in ['win', 'macosx','linux']:
|
||||||
|
Window.borderless = True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.bar_show = False
|
||||||
|
|
||||||
|
def set_normal_bar(self, *args):
|
||||||
|
if self.idle_task:
|
||||||
|
self.idle_task.cancel()
|
||||||
|
self.idle_task = Clock.schedule_once(self.set_idle_bar, \
|
||||||
|
self.idle_threshold)
|
||||||
|
if self.bar_show:
|
||||||
|
return
|
||||||
|
super().add_widget(self.bar, index=self.bar_pos)
|
||||||
|
if platform in ['win', 'macosx','linux']:
|
||||||
|
Window.borderless = False
|
||||||
|
self.bar_show = True
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.clear_widgets()
|
||||||
|
if self.bar_show and self.bar_at == 'top':
|
||||||
super().add_widget(self.bar)
|
super().add_widget(self.bar)
|
||||||
if self.fixed_before:
|
if self.fixed_before:
|
||||||
super().add_widget(self.fixed_before)
|
super().add_widget(self.fixed_before)
|
||||||
super().add_widget(self.content)
|
super().add_widget(self.content)
|
||||||
if self.fixed_after:
|
if self.fixed_after:
|
||||||
super().add_widget(self.fixed_after)
|
super().add_widget(self.fixed_after)
|
||||||
if bar_at != 'top':
|
if self.bar_show and self.bar_at != 'top':
|
||||||
super().add_widget(self.bar)
|
super().add_widget(self.bar)
|
||||||
self.left_menu_showed = False
|
self.left_menu_showed = False
|
||||||
self.right_menu_showed = False
|
self.right_menu_showed = False
|
||||||
|
@ -42,10 +42,13 @@ from .block_test import BlockTest
|
|||||||
from .hierarchy import Hierarchy
|
from .hierarchy import Hierarchy
|
||||||
from .price import PriceView
|
from .price import PriceView
|
||||||
from .ffpyplayer_video import FFVideo
|
from .ffpyplayer_video import FFVideo
|
||||||
|
from .upload import UploadFile
|
||||||
|
|
||||||
r = Factory.register
|
r = Factory.register
|
||||||
# if kivy.platform in ['win','linux', 'macosx']:
|
# if kivy.platform in ['win','linux', 'macosx']:
|
||||||
# r('ScreenWithMic', ScreenWithMic)
|
# r('ScreenWithMic', ScreenWithMic)
|
||||||
|
r('UploadFile', UploadFile)
|
||||||
|
r('FFVideo', FFVideo)
|
||||||
r('AnchorBox', AnchorBox)
|
r('AnchorBox', AnchorBox)
|
||||||
r('FloatBox', FloatBox)
|
r('FloatBox', FloatBox)
|
||||||
r('RelativeBox', RelativeBox)
|
r('RelativeBox', RelativeBox)
|
||||||
@ -144,4 +147,3 @@ def register_blocks(name, value):
|
|||||||
except:
|
except:
|
||||||
Logger.info(f'plugin : register_blocks():{name} register error')
|
Logger.info(f'plugin : register_blocks():{name} register error')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import os
|
||||||
|
import traceback
|
||||||
try:
|
try:
|
||||||
import ujson as json
|
import ujson as json
|
||||||
except:
|
except:
|
||||||
@ -9,6 +11,9 @@ from appPublic.myTE import MyTemplateEngine
|
|||||||
from appPublic.Singleton import SingletonDecorator
|
from appPublic.Singleton import SingletonDecorator
|
||||||
from appPublic.dictObject import DictObject
|
from appPublic.dictObject import DictObject
|
||||||
|
|
||||||
|
from kivy.logger import Logger
|
||||||
|
from kivy.utils import platform
|
||||||
|
|
||||||
@SingletonDecorator
|
@SingletonDecorator
|
||||||
class ScriptEnv(DictObject):
|
class ScriptEnv(DictObject):
|
||||||
pass
|
pass
|
||||||
@ -18,8 +23,10 @@ def set_script_env(n,v):
|
|||||||
env.update({n:v})
|
env.update({n:v})
|
||||||
|
|
||||||
class Script:
|
class Script:
|
||||||
def __init__(self, root):
|
def __init__(self):
|
||||||
self.root = root
|
config = getConfig()
|
||||||
|
self.root = config.script_root
|
||||||
|
# print('Script.root=', self.root)
|
||||||
self.env = {}
|
self.env = {}
|
||||||
self.handlers = {}
|
self.handlers = {}
|
||||||
self.register('.tmpl', TemplateHandler)
|
self.register('.tmpl', TemplateHandler)
|
||||||
@ -31,6 +38,20 @@ class Script:
|
|||||||
url = url[7:]
|
url = url[7:]
|
||||||
return join(self.root, *url.split('/'))
|
return join(self.root, *url.split('/'))
|
||||||
|
|
||||||
|
def show_info(self, env):
|
||||||
|
workdir = env['workdir']
|
||||||
|
sfile = env['filepath']
|
||||||
|
url = env['url']
|
||||||
|
print(f'script:workdir={workdir}')
|
||||||
|
print(f'script:script_file={sfile}')
|
||||||
|
print(f'script:url={url}')
|
||||||
|
sdir = os.path.join(workdir, 'scripts')
|
||||||
|
sf_exists = os.path.isdir(sdir)
|
||||||
|
conf_f = os.path.join(workdir, 'conf', 'config.json')
|
||||||
|
conf_exists = os.path.isfile(conf_f)
|
||||||
|
print(f'script:script exists {sf_exists}')
|
||||||
|
print(f'script:config.json exists {conf_exists}')
|
||||||
|
|
||||||
def dispatch(self, url, **kw):
|
def dispatch(self, url, **kw):
|
||||||
filepath = self.url2filepath(url)
|
filepath = self.url2filepath(url)
|
||||||
for suffix, handler in self.handlers.items():
|
for suffix, handler in self.handlers.items():
|
||||||
@ -41,6 +62,10 @@ class Script:
|
|||||||
env['root_path'] = self.root
|
env['root_path'] = self.root
|
||||||
env['url'] = url
|
env['url'] = url
|
||||||
env['filepath'] = filepath
|
env['filepath'] = filepath
|
||||||
|
# print(f"workdir={env['workdir']}--------")
|
||||||
|
# if platform == 'android':
|
||||||
|
# self.show_info(env)
|
||||||
|
|
||||||
h = handler(env)
|
h = handler(env)
|
||||||
d = h.render()
|
d = h.render()
|
||||||
try:
|
try:
|
||||||
@ -90,7 +115,12 @@ class TemplateHandler(BaseHandler):
|
|||||||
self.engine = MyTemplateEngine(paths)
|
self.engine = MyTemplateEngine(paths)
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
|
try:
|
||||||
return self.engine.render(self.templ_file, self.env)
|
return self.engine.render(self.templ_file, self.env)
|
||||||
|
except Exception as e:
|
||||||
|
print('Exception:', str(e))
|
||||||
|
print('filename=', self.env['filepath'])
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
class DspyHandler(BaseHandler):
|
class DspyHandler(BaseHandler):
|
||||||
def __init__(self, env):
|
def __init__(self, env):
|
||||||
@ -107,9 +137,15 @@ class DspyHandler(BaseHandler):
|
|||||||
return txt
|
return txt
|
||||||
|
|
||||||
def render(self, params={}):
|
def render(self, params={}):
|
||||||
|
try:
|
||||||
lenv = self.env.copy()
|
lenv = self.env.copy()
|
||||||
lenv.update(params)
|
lenv.update(params)
|
||||||
txt = self.loadScript(self.env['filepath'])
|
txt = self.loadScript(self.env['filepath'])
|
||||||
exec(txt,lenv,lenv)
|
exec(txt,lenv,lenv)
|
||||||
func = lenv['myfunc']
|
func = lenv['myfunc']
|
||||||
return func(self.env, **lenv)
|
return func(self.env, **lenv)
|
||||||
|
except Exception as e:
|
||||||
|
print('Exception:', str(e))
|
||||||
|
print('filename=', self.env['filepath'])
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
@ -121,18 +121,18 @@ class HttpClient(Http_Client):
|
|||||||
|
|
||||||
self.workers.add(self.webcall,callback,errback,kwargs=kwargs)
|
self.workers.add(self.webcall,callback,errback,kwargs=kwargs)
|
||||||
|
|
||||||
def get(self, url, params={}, headers={}, callback=None, errback=None):
|
def get(self, url, params={}, headers={}, stream=False, callback=None, errback=None):
|
||||||
return self.__call__(url,method='GET',params=params,
|
return self.__call__(url,method='GET',params=params,
|
||||||
headers=headers, callback=callback,
|
headers=headers, stream=stream, callback=callback,
|
||||||
errback=errback)
|
errback=errback)
|
||||||
def post(self, url, params={}, headers={}, files={}, callback=None, errback=None):
|
def post(self, url, params={}, headers={}, files={}, stream=False, callback=None, errback=None):
|
||||||
return self.__call__(url,method='POST',params=params, files=files,
|
return self.__call__(url,method='POST',params=params, files=files,
|
||||||
headers=headers, callback=callback,
|
headers=headers, stream=stream, callback=callback,
|
||||||
errback=errback)
|
errback=errback)
|
||||||
|
|
||||||
def put(self, url, params={}, headers={}, callback=None, errback=None):
|
def put(self, url, params={}, headers={}, stream=False, callback=None, errback=None):
|
||||||
return self.__call__(url,method='PUT',params=params,
|
return self.__call__(url,method='PUT',params=params,
|
||||||
headers=headers, callback=callback,
|
headers=headers, stream=stream, callback=callback,
|
||||||
errback=errback)
|
errback=errback)
|
||||||
|
|
||||||
def delete(self, url, params={}, headers={}, callback=None, errback=None):
|
def delete(self, url, params={}, headers={}, callback=None, errback=None):
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from kivy.logger import Logger
|
from kivy.logger import Logger
|
||||||
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.factory import Factory
|
from kivy.factory import Factory
|
||||||
@ -11,46 +10,7 @@ from kivyblocks.bgcolorbehavior import BGColorBehavior
|
|||||||
from kivyblocks.utils import CSize
|
from kivyblocks.utils import CSize
|
||||||
from kivyblocks.baseWidget import Box
|
from kivyblocks.baseWidget import Box
|
||||||
from kivyblocks.widget_css import WidgetCSS
|
from kivyblocks.widget_css import WidgetCSS
|
||||||
|
from kivyblocks.clickable import PressableBox
|
||||||
class PressableBox(TouchRippleButtonBehavior, Box):
|
|
||||||
normal_css = StringProperty("default")
|
|
||||||
actived_css = StringProperty("default")
|
|
||||||
box_actived = BooleanProperty(False)
|
|
||||||
def __init__(self,
|
|
||||||
border_width=1,
|
|
||||||
user_data=None,
|
|
||||||
radius=[],
|
|
||||||
**kw):
|
|
||||||
super(PressableBox, self).__init__(
|
|
||||||
padding=[border_width,
|
|
||||||
border_width,
|
|
||||||
border_width,
|
|
||||||
border_width],
|
|
||||||
radius=radius,
|
|
||||||
**kw)
|
|
||||||
self.border_width = border_width
|
|
||||||
self.user_data = user_data
|
|
||||||
self.actived = False
|
|
||||||
self.csscls = self.normal_css
|
|
||||||
|
|
||||||
def active(self, flag):
|
|
||||||
self.box_actived = flag
|
|
||||||
|
|
||||||
def on_box_actived(self, o, v):
|
|
||||||
if self.box_actived:
|
|
||||||
self.csscls = self.actived_css
|
|
||||||
else:
|
|
||||||
self.csscls = self.normal_css
|
|
||||||
|
|
||||||
def on_press(self,o=None):
|
|
||||||
self.box_actived = True
|
|
||||||
|
|
||||||
|
|
||||||
def setValue(self,d):
|
|
||||||
self.user_data = d
|
|
||||||
|
|
||||||
def getValue(self):
|
|
||||||
return self.user_data
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ToggleItems format:
|
ToggleItems format:
|
||||||
|
@ -67,16 +67,22 @@ class Toolbar(ScrollPanel):
|
|||||||
self.register_event_type('on_delete_tool')
|
self.register_event_type('on_delete_tool')
|
||||||
if self.toolbar_orient == 'H':
|
if self.toolbar_orient == 'H':
|
||||||
self._inner.orientation = 'horizontal'
|
self._inner.orientation = 'horizontal'
|
||||||
|
self.size_hint_x = 1
|
||||||
else:
|
else:
|
||||||
self._inner.orientation = 'vertical'
|
self._inner.orientation = 'vertical'
|
||||||
|
self.size_hint_y = 1
|
||||||
self.clear_widgets()
|
self.clear_widgets()
|
||||||
for t in self.tools:
|
for t in self.tools:
|
||||||
self.add_tool(t)
|
self.add_tool(t)
|
||||||
|
|
||||||
self.bar_width = 0
|
self.bar_width = 0
|
||||||
if self.toolbar_orient == 'H':
|
if self.toolbar_orient == 'H':
|
||||||
|
self.size_hint_y = None
|
||||||
|
self.height = self._inner.height * 1.6
|
||||||
self.do_scroll_y = False
|
self.do_scroll_y = False
|
||||||
else:
|
else:
|
||||||
|
self.size_hint_x = None
|
||||||
|
self.width = self._inner.width * 1.6
|
||||||
self.do_scroll_x = False
|
self.do_scroll_x = False
|
||||||
|
|
||||||
def on_children_size(self, o, size):
|
def on_children_size(self, o, size):
|
||||||
|
BIN
kivyblocks/ttf/Alimama_ShuHeiTi_Bold.ttf
Normal file
BIN
kivyblocks/ttf/Alimama_ShuHeiTi_Bold.ttf
Normal file
Binary file not shown.
BIN
kivyblocks/ttf/TsangerYuYangT_W01_W01.ttf
Normal file
BIN
kivyblocks/ttf/TsangerYuYangT_W01_W01.ttf
Normal file
Binary file not shown.
BIN
kivyblocks/ttf/TsangerYuYangT_W02_W02.ttf
Normal file
BIN
kivyblocks/ttf/TsangerYuYangT_W02_W02.ttf
Normal file
Binary file not shown.
BIN
kivyblocks/ttf/TsangerYuYangT_W03_W03.ttf
Normal file
BIN
kivyblocks/ttf/TsangerYuYangT_W03_W03.ttf
Normal file
Binary file not shown.
BIN
kivyblocks/ttf/TsangerYuYangT_W04_W04.ttf
Normal file
BIN
kivyblocks/ttf/TsangerYuYangT_W04_W04.ttf
Normal file
Binary file not shown.
BIN
kivyblocks/ttf/TsangerYuYangT_W05_W05.ttf
Normal file
BIN
kivyblocks/ttf/TsangerYuYangT_W05_W05.ttf
Normal file
Binary file not shown.
57
kivyblocks/upload.py
Normal file
57
kivyblocks/upload.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import os
|
||||||
|
from kivy.properties import StringProperty, ListProperty
|
||||||
|
from kivyblocks.utils import blockImage, CSize
|
||||||
|
import requests
|
||||||
|
from plyer import filechooser
|
||||||
|
from .i18n import I18n
|
||||||
|
from .clickable import ClickableIconText
|
||||||
|
from .baseWidget import Running
|
||||||
|
from .message import Error
|
||||||
|
|
||||||
|
class UploadFile(ClickableIconText):
|
||||||
|
upload_url = StringProperty(None)
|
||||||
|
name = StringProperty('upfile')
|
||||||
|
# suffixes = ListProperty([])
|
||||||
|
def __init__(self, **kw):
|
||||||
|
super().__init__(**kw)
|
||||||
|
self.otext = 'please select file'
|
||||||
|
self.img_kw = {
|
||||||
|
"size_hint":[None, None],
|
||||||
|
"width":CSize(1),
|
||||||
|
"height":CSize(1)
|
||||||
|
}
|
||||||
|
self.source = blockImage('upload.png')
|
||||||
|
self.file_url = None
|
||||||
|
self.running = None
|
||||||
|
|
||||||
|
def getValue(self):
|
||||||
|
return {
|
||||||
|
self.name:self.file_url
|
||||||
|
}
|
||||||
|
|
||||||
|
def on_press(self, *args):
|
||||||
|
i18n = I18n()
|
||||||
|
filechooser.open_file(title=i18n('open file'),
|
||||||
|
on_selection=self.file_selected)
|
||||||
|
|
||||||
|
def file_selected(self, files):
|
||||||
|
running = Running(self)
|
||||||
|
def readfile(f):
|
||||||
|
with open(f, 'rb') as o:
|
||||||
|
d = o.read(102400)
|
||||||
|
if not d:
|
||||||
|
return
|
||||||
|
yield d
|
||||||
|
fpath = files[0]
|
||||||
|
fn = os.path.basename(fpath)
|
||||||
|
print('fn=', fn)
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/octet-stream',
|
||||||
|
'Content-Disposition':'attachments;filename={}'.format(fn)
|
||||||
|
}
|
||||||
|
r = requests.post(self.upload_url,
|
||||||
|
data=readfile(files[0]),
|
||||||
|
headers=headers
|
||||||
|
)
|
||||||
|
running.dismiss()
|
||||||
|
|
@ -1 +1 @@
|
|||||||
__version__ = '0.3.0'
|
__version__ = '0.4.1'
|
||||||
|
Loading…
Reference in New Issue
Block a user