This commit is contained in:
yumoqing 2021-12-27 13:54:00 +08:00
parent 51033259b7
commit 5317227fbd
8 changed files with 191 additions and 109 deletions

Binary file not shown.

View File

@ -10,13 +10,14 @@ from kivy.properties import NumericProperty, DictProperty, \
from kivyblocks.ready import WidgetReady from kivyblocks.ready import WidgetReady
from kivyblocks.bgcolorbehavior import BGColorBehavior from kivyblocks.bgcolorbehavior import BGColorBehavior
from kivyblocks.utils import CSize, SUPER from kivyblocks.utils import CSize, SUPER, blockImage
from kivyblocks.baseWidget import Box, Text from kivyblocks.baseWidget import Box, Text
from kivyblocks.widget_css import WidgetCSS from kivyblocks.widget_css import WidgetCSS
class TinyText(Text): class TinyText(Text):
def __init__(self, **kw): def __init__(self, **kw):
SUPER(TinyText, self, kw) SUPER(TinyText, self, kw)
self.size_hint = (None, None)
self.on_texture_size(self, (1,1)) self.on_texture_size(self, (1,1))
def on_texture_size(self, o, ts): def on_texture_size(self, o, ts):
@ -28,6 +29,7 @@ class ClickableBox(TouchRippleButtonBehavior, Box):
border_width=1, border_width=1,
**kw): **kw):
SUPER(ClickableBox, self, kw) SUPER(ClickableBox, self, kw)
self.size_hint = [None, None]
self.border_width = border_width self.border_width = border_width
# self.bind(minimum_height=self.setter('height')) # self.bind(minimum_height=self.setter('height'))
# self.bind(minimum_width=self.setter('width')) # self.bind(minimum_width=self.setter('width'))
@ -49,7 +51,6 @@ class ClickableText(ClickableBox):
text = StringProperty(' ') text = StringProperty(' ')
fontsize = NumericProperty(1) fontsize = NumericProperty(1)
def __init__(self, **kw): def __init__(self, **kw):
print('ClickableText begin inited')
self.txt_w = None self.txt_w = None
SUPER(ClickableText, self, kw) SUPER(ClickableText, self, kw)
self.txt_w = TinyText(otext=self.text, self.txt_w = TinyText(otext=self.text,
@ -72,7 +73,6 @@ class ClickableIconText(ClickableText):
def __init__(self, **kw): def __init__(self, **kw):
self.img_w = None self.img_w = None
SUPER(ClickableIconText, self, kw) SUPER(ClickableIconText, self, kw)
print('ClickableIconText inited')
def on_source(self, o, source): def on_source(self, o, source):
if self.img_w: if self.img_w:
@ -111,7 +111,6 @@ class ToggleText(ClickableText):
def on_select_state(self, o, f): def on_select_state(self, o, f):
self.csscls = self.css_on if f else self.css_off self.csscls = self.css_on if f else self.css_off
print(f'using {self.csscls}')
class ToggleIconText(ToggleText): class ToggleIconText(ToggleText):
""" """
@ -149,8 +148,6 @@ class ClickableImage(ClickableBox):
def __init__(self, **kw): def __init__(self, **kw):
self.img_w = None self.img_w = None
SUPER(ClickableImage, self, kw) SUPER(ClickableImage, self, kw)
# self.img_w = AsyncImage(source=self.source, **self.img_kw)
# self.add_widget(self.img_w)
def on_source(self, o, source): def on_source(self, o, source):
if self.source is None: if self.source is None:
@ -200,25 +197,69 @@ class ToggleImage(ClickableImage):
else: else:
self.source = self.source_off self.source = self.source_off
class CheckBox(ToggleImage): class SingleCheckBox(ClickableBox):
otext = StringProperty(None) otext = StringProperty(None)
select_state = BooleanProperty(False)
def __init__(self, **kw): def __init__(self, **kw):
SUPER(CheckBox, self, kw) self.old_state = None
self.register_event_type('on_changed')
SUPER(SingleCheckBox, self, kw)
self.source_on = blockImage('checkbox-on.png') self.source_on = blockImage('checkbox-on.png')
self.source_off = blockImage('ceckbox-off.png') self.source_off = blockImage('checkbox-off.png')
self.select(False)
self.create_img_w()
if self.otext: if self.otext:
self.txt_w = TinyText(otext=self.otext, i18n=True) self.txt_w = TinyText(otext=self.otext, i18n=True)
self.txt_w.bind(size=self.reset_size)
self.add_widget(self.txt_w) self.add_widget(self.txt_w)
self.reset_size(self, None)
def on_changed(self, o=None):
pass
def on_press(self, o=None):
self.toggle()
def select(self, f):
self.select_state = f
def change_img_source(self):
self.img_w.source = self.source_on if self.select_state else \
self.source_off
def toggle(self):
self.select_state = False if self.select_state else True
def state(self):
return self.select_state
def on_select_state(self, o, f):
self.change_img_source()
self.dispatch('on_changed', self.select_state)
def getValue(self): def getValue(self):
return self.state() return self.state()
def setValue(self, v): def setValue(self, v):
self.select_state = False if v else True self.select(True if v else False)
def create_img_w(self):
if self.select_state:
self.img_w = AsyncImage(source=self.source_on,
size_hint=(None, None),
size=CSize(1, 1)
)
else:
self.img_w = AsyncImage(source=self.source_off,
size_hint=(None, None),
size=CSize(1, 1)
)
self.add_widget(self.img_w)
self.img_w.bind(size=self.reset_size)
r = Factory.register r = Factory.register
r('TinyText', TinyText) r('TinyText', TinyText)
r('CheckBox', CheckBox) r('SingleCheckBox', SingleCheckBox)
r('ClickableBox', ClickableBox) r('ClickableBox', ClickableBox)
r('ClickableText',ClickableText) r('ClickableText',ClickableText)
r('ClickableIconText',ClickableIconText) r('ClickableIconText',ClickableIconText)

View File

@ -1,67 +1,149 @@
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.uix.stacklayout import StackLayout
from kivy.properties import BooleanProperty, StringProperty,\ from kivy.properties import BooleanProperty, StringProperty,\
ListProperty, DictProperty ListProperty, DictProperty, OptionProperty, \
NumericProperty
from kivyblocks.baseWidget import VBox from kivyblocks.baseWidget import VBox
from kivyblocks.clickable import ToggleText, ToggleImage from kivyblocks.clickable import ToggleText, ToggleImage
from kivyblocks.typewriterbox import TypeWriterBox from kivyblocks.utils import SUPER, CSize
from kivy.factory import Factory from kivyblocks.widget_css import WidgetCSS
from kivyblocks.ready import WidgetReady
class MultiSelect(TypeWriterBox): class MultiSelect(WidgetCSS, WidgetReady, StackLayout):
"""
{
"widgettype":"MultiSelect",
"options":{
"valueField"
"textField"
"items"
"item_css"
"item_selected_css"
"all_position"
"need_others"
"default_selected"
}
}
"""
valueField = StringProperty('value')
textField = StringProperty('text')
x_spacing_c = NumericProperty(1)
y_spacing_c = NumericProperty(0.5)
items = ListProperty([]) items = ListProperty([])
item_css = DictProperty({}) item_css = StringProperty({})
item_selected_css = DictProperty({}) item_selected_css = StringProperty({})
all_button_position = StringProperty(None) all_position = OptionProperty(None, \
default_selected=StringProperty([]) options=[None, 'begin', 'end'])
need_others = BooleanProperty(False)
default_selected=ListProperty([])
result = ListProperty([])
def __init__(self, **kw): def __init__(self, **kw):
super(MultiSelect, self).__init__(**kw) SUPER(MultiSelect, self, kw)
self.spacing = CSize(self.x_spacing_c, self.y_spacing_c)
self.orientation = 'lr-tb'
self.build_all_items()
self.old_result = []
self.register_event_type('on_changed')
self.button_dic = {} self.button_dic = {}
self.value_b = {} self.value_b = {}
self.buildWidgets()
def buildItem(self, dic): def build_all_items(self):
items = [i for i in self.items ]
if self.need_others:
dic = {
self.valueField:'_other_',
self.textField:'others'
}
items.append(dic)
if self.all_position is not None:
dic = {
self.textField:'all',
self.valueField:'_all_',
}
if self.all_position == 'begin':
items.insert(0, dic)
else:
items.append(dic)
self.all_items = items
def on_changed(self, d):
pass
def build_item_widget(self, dic):
keys = dic.keys() keys = dic.keys()
ToggleText = Factory.ToggleText ToggleText = Factory.ToggleText
ToggleImage = Factory.ToggleImage ToggleImage = Factory.ToggleImage
if 'text' in keys and 'value' in keys: ToggleIconText = Factory.ToggleIconText
desc = dic.copy() if self.textField in keys and 'source_on' in keys and \
desc['off_css'] = self.item_css 'source_off' in keys:
desc['on_css'] = self.item_selected_css desc['text'] = dic[self.textField]
return ToggleText(**desc) desc['css_off'] = self.item_css
if 'source' in keys and 'on_source' in keys: desc['css_on'] = self.item_selected_css
return ToggleImage(**dic) desc["source_on"] = dic['source_on'],
desc["source_off"] = dic['source_off']
print('ToggleIconText', desc)
return ToggleIconText(**desc)
def on_items(self, o, items): if self.textField in keys:
self.clear_widgets() desc = {}
if all_button_position is not None: desc['text'] = dic[self.textField]
dic = { desc['css_off'] = self.item_css
'text':'all', desc['css_on'] = self.item_selected_css
'value':'_all_', print('ToggleText', desc)
return ToggleText(**desc)
if 'source_on' in keys and 'source_off' in keys:
desc = {
"source_on":dic['source_on'],
"source_off":dic['source_off']
} }
if all_button_position == 'begin': print('ToggleImage', desc)
items.insert(dic,0) return ToggleImage(**desc)
else:
items.append(dic) def buildWidgets(self):
for item in items: self.clear_widgets()
b = self.buildItem(item) for item in self.all_items:
b = self.build_item_widget(item)
b.bind(on_press=self.button_pressed) b.bind(on_press=self.button_pressed)
self.button_dic.update({b:dic}) self.button_dic.update({b:item})
self.value_b.update({dic['value']:b}) self.add_widget(b)
def button_pressed(self, o): def button_pressed(self, o):
o.toggle() o.toggle()
if self.button_dic[o]['value'] == '_all_' and o.state(): if self.button_dic[o][self.valueField] == '_all_' and o.state():
for b, dic in self.button_dic.copy().items(): for b, dic in self.button_dic.items():
if b == o: if b == o:
continue continue
b.select(False) b.select(False)
if self.button_dic[o][self.valueField] == '_other_' and o.state():
for b, dic in self.button_dic.items():
if b == o:
continue
b.select(False)
if self.button_dic[o][self.valueField] not in ['_all_', '_other_'] \
and o.state():
for b, dic in self.button_dic.items():
if dic[self.valueField] in ['_all_', '_other_']:
b.select(False)
Clock.schedule_once(self.set_result, 0.1)
def set_result(self, t=None):
self.result = [ d[self.valueField] for b, d in \
self.button_dic.items() if b.state() ]
if self.result != self.old_result:
self.dispatch('on_changed', self.result)
self.old_result = self.result
def getValue(self): def getValue(self):
selected_buttons = [ b for b in self.button_dic.item() \ self.set_result()
if b.state() ] return self.result
r = [ dic['value'] for b, dic in self.button_dic.items() \
if b in selected_buttons ]
return r
def setValue(self, value): def setValue(self, value):
self.result = value
self.old_result = value
for v in value: for v in value:
b = self.value_b[v] b = self.value_b[v]
b.select(True) b.select(True)

View File

@ -1,6 +1,8 @@
from traceback import print_exc from traceback import print_exc
from contextlib import contextmanager from contextlib import contextmanager
from kivy.graphics import Fbo, Color, Rectangle
from kivy.core.window import Window from kivy.core.window import Window
from kivy.clock import Clock from kivy.clock import Clock
from kivy.utils import platform from kivy.utils import platform

View File

@ -19,7 +19,7 @@ from appPublic.registerfunction import getRegisterFunctionByName
from .baseWidget import PressableLabel, Text, HBox, VBox from .baseWidget import PressableLabel, Text, HBox, VBox
from .color_definitions import getColors from .color_definitions import getColors
from .widget_css import WidgetCSS from .widget_css import WidgetCSS
from .utils import alert,absurl from .utils import alert,absurl, SUPER
from .toggleitems import PressableBox from .toggleitems import PressableBox
from .threadcall import HttpClient from .threadcall import HttpClient
@ -38,12 +38,11 @@ class EmptyBox(Label):
class NodeTrigger(ButtonBehavior, EmptyBox): class NodeTrigger(ButtonBehavior, EmptyBox):
open_status = BooleanProperty(False) open_status = BooleanProperty(False)
color = ListProperty([1,0,0,1]) color = ListProperty([1,0,0,1])
def __init__(self, color=[1,0,0,1],**kw): def __init__(self, **kw):
# super(NodeTrigger, self).__init__(**kw) self.open_points = None
EmptyBox.__init__(self, **kw) self.close_points = None
ButtonBehavior.__init__(self) SUPER(NodeTrigger, self, kw)
self.countPoints() self.countPoints()
self.color = color
self.bind(size=self.onSize,pos=self.onSize) self.bind(size=self.onSize,pos=self.onSize)
def countPoints(self): def countPoints(self):
@ -65,7 +64,6 @@ class NodeTrigger(ButtonBehavior, EmptyBox):
def on_press(self, *args): def on_press(self, *args):
self.open_status = False if self.open_status else True self.open_status = False if self.open_status else True
# self.showOpenStatus()
def on_open_status(self, *largs): def on_open_status(self, *largs):
self.showOpenStatus() self.showOpenStatus()
@ -74,6 +72,8 @@ class NodeTrigger(ButtonBehavior, EmptyBox):
self.showOpenStatus() self.showOpenStatus()
def showOpenStatus(self): def showOpenStatus(self):
if self.close_points is None:
return
points = self.close_points points = self.close_points
if self.open_status: if self.open_status:
points = self.open_points points = self.open_points

View File

@ -1,50 +0,0 @@
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.factory import Factory
from kivyblocks.widget_css import WidgetCSS
from kivyblocks.ready import WidgetReady
class TypeWriterBox(WidgetCSS, WidgetReady, Widget):
def __init__(self, **kw):
super(TypeWriterBox, self).__init__(**kw)
self.size_hint_y = None
self.sub_widgets = []
self.curbox = self.add_vertical_box()
self.bind(minimum_height=self.setter('height'))
def on_width(self, o, size):
self.relocate()
def add_widget(self, w, *args):
width = 0
for c in self.curbox.children:
width += c.width
if width + c.width > self.width:
self.curbox = self.add_vertical_box()
self.curbox.add_widget(w, *args)
self.sub_widgets.append(w)
def del_widget(self, w):
self.sub_widgets = [i for i in self.sub_widgets.copy() if i !=w ]
self.relocate()
def add_veritcal_box(self):
box = BoxLayout(orientation='vertical', size_hint_y=None)
box.bind(minimum_height = box.setter('height'))
super(TypeWriterBox, self).add_widget(box)
return box
def relocate(self):
with self.fboContext():
for b in self.children:
b.clear_widgets()
width = 0
self.clear_widgets()
self.curbox = add_vertical_box()
for w in self.sub_widgets:
if width + w.width > self.width:
self.curbox = self.add_vertical_box()
width = 0
self.curbox.add_widget(w)
Factory.register('TypeWriterBox', TypeWriterBox)

View File

@ -1,5 +1,6 @@
import os import os
from traceback import print_exc from traceback import print_exc
from traceback import print_exc
from kivy.app import App from kivy.app import App
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
from kivy.uix.popup import Popup from kivy.uix.popup import Popup
@ -42,7 +43,12 @@ def SUPER(klass, obj, kw):
dic = { k:kw.pop(k) for k in keys if hasattr(obj, k) } dic = { k:kw.pop(k) for k in keys if hasattr(obj, k) }
super(klass, obj).__init__(**kw) super(klass, obj).__init__(**kw)
for k,v in dic.items(): for k,v in dic.items():
setattr(obj, k, v) try:
setattr(obj, k, v)
except Exception as e:
print(f'obj={obj}, setattr(obj, "{k}","{v}") error')
print_exc()
raise e
def blockImage(name): def blockImage(name):
p = os.path.dirname(os.path.abspath(__file__)) p = os.path.dirname(os.path.abspath(__file__))

View File

@ -77,7 +77,6 @@ class StrInput(TextInput):
def checkChange(self,o,v=None): def checkChange(self,o,v=None):
v = self.getValue() v = self.getValue()
print('StrInput():v=', v)
if v != self.old_value: if v != self.old_value:
self.old_value = v self.old_value = v
self.dispatch('on_changed',v) self.dispatch('on_changed',v)
@ -89,6 +88,8 @@ class StrInput(TextInput):
if v is None: if v is None:
v = '' v = ''
self.text = str(v) self.text = str(v)
self.old_value = self.text
class Password(StrInput): class Password(StrInput):
def __init__(self, **kw): def __init__(self, **kw):