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.bgcolorbehavior import BGColorBehavior
from kivyblocks.utils import CSize, SUPER
from kivyblocks.utils import CSize, SUPER, blockImage
from kivyblocks.baseWidget import Box, Text
from kivyblocks.widget_css import WidgetCSS
class TinyText(Text):
def __init__(self, **kw):
SUPER(TinyText, self, kw)
self.size_hint = (None, None)
self.on_texture_size(self, (1,1))
def on_texture_size(self, o, ts):
@ -28,6 +29,7 @@ class ClickableBox(TouchRippleButtonBehavior, Box):
border_width=1,
**kw):
SUPER(ClickableBox, self, kw)
self.size_hint = [None, None]
self.border_width = border_width
# self.bind(minimum_height=self.setter('height'))
# self.bind(minimum_width=self.setter('width'))
@ -49,7 +51,6 @@ class ClickableText(ClickableBox):
text = StringProperty(' ')
fontsize = NumericProperty(1)
def __init__(self, **kw):
print('ClickableText begin inited')
self.txt_w = None
SUPER(ClickableText, self, kw)
self.txt_w = TinyText(otext=self.text,
@ -72,7 +73,6 @@ class ClickableIconText(ClickableText):
def __init__(self, **kw):
self.img_w = None
SUPER(ClickableIconText, self, kw)
print('ClickableIconText inited')
def on_source(self, o, source):
if self.img_w:
@ -111,7 +111,6 @@ class ToggleText(ClickableText):
def on_select_state(self, o, f):
self.csscls = self.css_on if f else self.css_off
print(f'using {self.csscls}')
class ToggleIconText(ToggleText):
"""
@ -149,8 +148,6 @@ class ClickableImage(ClickableBox):
def __init__(self, **kw):
self.img_w = None
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):
if self.source is None:
@ -200,25 +197,69 @@ class ToggleImage(ClickableImage):
else:
self.source = self.source_off
class CheckBox(ToggleImage):
class SingleCheckBox(ClickableBox):
otext = StringProperty(None)
select_state = BooleanProperty(False)
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_off = blockImage('ceckbox-off.png')
self.source_off = blockImage('checkbox-off.png')
self.select(False)
self.create_img_w()
if self.otext:
self.txt_w = TinyText(otext=self.otext, i18n=True)
self.txt_w.bind(size=self.reset_size)
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):
return self.state()
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('TinyText', TinyText)
r('CheckBox', CheckBox)
r('SingleCheckBox', SingleCheckBox)
r('ClickableBox', ClickableBox)
r('ClickableText',ClickableText)
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,\
ListProperty, DictProperty
ListProperty, DictProperty, OptionProperty, \
NumericProperty
from kivyblocks.baseWidget import VBox
from kivyblocks.clickable import ToggleText, ToggleImage
from kivyblocks.typewriterbox import TypeWriterBox
from kivy.factory import Factory
from kivyblocks.utils import SUPER, CSize
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([])
item_css = DictProperty({})
item_selected_css = DictProperty({})
all_button_position = StringProperty(None)
default_selected=StringProperty([])
item_css = StringProperty({})
item_selected_css = StringProperty({})
all_position = OptionProperty(None, \
options=[None, 'begin', 'end'])
need_others = BooleanProperty(False)
default_selected=ListProperty([])
result = ListProperty([])
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.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()
ToggleText = Factory.ToggleText
ToggleImage = Factory.ToggleImage
if 'text' in keys and 'value' in keys:
desc = dic.copy()
desc['off_css'] = self.item_css
desc['on_css'] = self.item_selected_css
return ToggleText(**desc)
if 'source' in keys and 'on_source' in keys:
return ToggleImage(**dic)
ToggleIconText = Factory.ToggleIconText
if self.textField in keys and 'source_on' in keys and \
'source_off' in keys:
desc['text'] = dic[self.textField]
desc['css_off'] = self.item_css
desc['css_on'] = self.item_selected_css
desc["source_on"] = dic['source_on'],
desc["source_off"] = dic['source_off']
print('ToggleIconText', desc)
return ToggleIconText(**desc)
def on_items(self, o, items):
self.clear_widgets()
if all_button_position is not None:
dic = {
'text':'all',
'value':'_all_',
if self.textField in keys:
desc = {}
desc['text'] = dic[self.textField]
desc['css_off'] = self.item_css
desc['css_on'] = self.item_selected_css
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':
items.insert(dic,0)
else:
items.append(dic)
for item in items:
b = self.buildItem(item)
print('ToggleImage', desc)
return ToggleImage(**desc)
def buildWidgets(self):
self.clear_widgets()
for item in self.all_items:
b = self.build_item_widget(item)
b.bind(on_press=self.button_pressed)
self.button_dic.update({b:dic})
self.value_b.update({dic['value']:b})
self.button_dic.update({b:item})
self.add_widget(b)
def button_pressed(self, o):
o.toggle()
if self.button_dic[o]['value'] == '_all_' and o.state():
for b, dic in self.button_dic.copy().items():
if self.button_dic[o][self.valueField] == '_all_' 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] == '_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):
selected_buttons = [ b for b in self.button_dic.item() \
if b.state() ]
r = [ dic['value'] for b, dic in self.button_dic.items() \
if b in selected_buttons ]
return r
self.set_result()
return self.result
def setValue(self, value):
self.result = value
self.old_result = value
for v in value:
b = self.value_b[v]
b.select(True)

View File

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

View File

@ -19,7 +19,7 @@ from appPublic.registerfunction import getRegisterFunctionByName
from .baseWidget import PressableLabel, Text, HBox, VBox
from .color_definitions import getColors
from .widget_css import WidgetCSS
from .utils import alert,absurl
from .utils import alert,absurl, SUPER
from .toggleitems import PressableBox
from .threadcall import HttpClient
@ -38,12 +38,11 @@ class EmptyBox(Label):
class NodeTrigger(ButtonBehavior, EmptyBox):
open_status = BooleanProperty(False)
color = ListProperty([1,0,0,1])
def __init__(self, color=[1,0,0,1],**kw):
# super(NodeTrigger, self).__init__(**kw)
EmptyBox.__init__(self, **kw)
ButtonBehavior.__init__(self)
def __init__(self, **kw):
self.open_points = None
self.close_points = None
SUPER(NodeTrigger, self, kw)
self.countPoints()
self.color = color
self.bind(size=self.onSize,pos=self.onSize)
def countPoints(self):
@ -65,7 +64,6 @@ class NodeTrigger(ButtonBehavior, EmptyBox):
def on_press(self, *args):
self.open_status = False if self.open_status else True
# self.showOpenStatus()
def on_open_status(self, *largs):
self.showOpenStatus()
@ -74,6 +72,8 @@ class NodeTrigger(ButtonBehavior, EmptyBox):
self.showOpenStatus()
def showOpenStatus(self):
if self.close_points is None:
return
points = self.close_points
if self.open_status:
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
from traceback import print_exc
from traceback import print_exc
from kivy.app import App
from appPublic.jsonConfig import getConfig
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) }
super(klass, obj).__init__(**kw)
for k,v in dic.items():
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):
p = os.path.dirname(os.path.abspath(__file__))

View File

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