diff --git a/kivyblocks/__init__.py b/kivyblocks/__init__.py index 56bebc6..e4e1cff 100644 --- a/kivyblocks/__init__.py +++ b/kivyblocks/__init__.py @@ -1,9 +1,9 @@ import os -from kivy import logger -__version_info__ = (0.5.0) +from kivy.logger import logging +__version_info__ = "0.5.0" __version__ = '0.5.0' path = os.path.dirname(__file__) fonts_path = os.path.join(path,"ttf/") images_path = os.path.join(path,'imgs/') -logger.info("kivyblocks:kivblocks version:{}".format(__version__) +logging.info("kivyblocks:kivblocks version:{}".format(__version__)) diff --git a/kivyblocks/baseWidget.py b/kivyblocks/baseWidget.py index ab44238..b4b395d 100755 --- a/kivyblocks/baseWidget.py +++ b/kivyblocks/baseWidget.py @@ -55,7 +55,6 @@ from .widgetExt.inputext import FloatInput,IntegerInput, \ StrInput,SelectInput, BoolInput, AmountInput from .widgetExt.messager import Messager from .charts.bar import Bar -from .tree import Tree, TextTree if platform == 'android': from .widgetExt.phonebutton import PhoneButton diff --git a/kivyblocks/blocks.py b/kivyblocks/blocks.py index ae084c9..8a31435 100755 --- a/kivyblocks/blocks.py +++ b/kivyblocks/blocks.py @@ -30,6 +30,7 @@ from .serverImageViewer import ServerImageViewer from .vplayer import VPlayer from .form import InputBox, Form, StrSearchForm from .boxViewer import BoxViewer +from .tree import Tree, TextTree def showError(e): print('error',e) diff --git a/kivyblocks/color_definitions.py b/kivyblocks/color_definitions.py index 24cb622..058b49c 100644 --- a/kivyblocks/color_definitions.py +++ b/kivyblocks/color_definitions.py @@ -1,3 +1,5 @@ +from kivy.logger import logging + colors = { 'Red': { '200': 'ef9a9a', @@ -341,45 +343,6 @@ light_colors = { 'Light': ['White', 'MainBackground', 'DialogBackground'] } -level_bg_colors = [ - '50', - '100', - '200', - '300', -] - -level_selected_bg_colors = [ - '400', - '500', - '600', - '700' -] - -def getColors(style,level): - i = level % len(level_bg_colors) - text_color = text_colors[style][ level_bg_colors[i]] - bg_color = colors[style][ level_bg_colors[i]] - return color - -def getSelectedColors(style,level): - i = level % len(level_selected_bg_colors) - text_color = text_colors[style][ level_bg_colors[i]] - bg_color = colors[style][ level_bg_colors[i]] - return text_color, bg_color - -error_color_id = '900', -info_color_id = '800' -def getErrorColor(style): - text_color = text_colors[style][ error_color_id ] - bg_color = colors[style][ error_color_id ] - return text_color, bg_color - -def getInfoColor(style): - text_color = text_colors[style][ info_color_id ] - bg_color = colors[style][ info_color_id ] - return text_color, bg_color - - text_colors = { 'Red': { '50': '000000', @@ -674,3 +637,43 @@ text_colors = { '900': 'ffffff', }, } + +level_bg_colors = [ + '900', + '800', + '700', + '600', +] + +level_selected_bg_colors = [ + '500', + '400', + '300', + '200' +] + +def getColors(style,level=0): + i = level % len(level_bg_colors) + logging.info('TEST : style=%s,level=%d', style, level) + text_color = text_colors[style][ level_bg_colors[i]] + bg_color = colors[style][ level_bg_colors[i]] + return text_color,bg_color + +def getSelectedColors(style,level=0): + i = level % len(level_selected_bg_colors) + text_color = text_colors[style][ level_selected_bg_colors[i]] + bg_color = colors[style][ level_selected_bg_colors[i]] + return text_color, bg_color + +error_color_id = '100', +info_color_id = '50' +def getErrorColors(style): + text_color = text_colors[style][ error_color_id ] + bg_color = colors[style][ error_color_id ] + return text_color, bg_color + +def getInfoColors(style): + text_color = text_colors[style][ info_color_id ] + bg_color = colors[style][ info_color_id ] + return text_color, bg_color + diff --git a/kivyblocks/gps.py b/kivyblocks/gps.py index d953740..7408ef1 100644 --- a/kivyblocks/gps.py +++ b/kivyblocks/gps.py @@ -9,7 +9,7 @@ class GPS: pass def on_status(self,**kw): - + pass def __del__(self): gps.stop() diff --git a/kivyblocks/stylebehavior.py b/kivyblocks/stylebehavior.py new file mode 100644 index 0000000..b8c3798 --- /dev/null +++ b/kivyblocks/stylebehavior.py @@ -0,0 +1,39 @@ +from kivy.graphics import Color, Rectangle +from kivy.logger import logging + +from kivyblocks.colorcalc import toArrayColor + +from appPublic.jsonConfig import getConfig + +from .color_definitions import getColors, getSelectedColors +from .color_definitions import getInfoColors, getErrorColors + +class StyleBehavior(object): + def __init__(self,level=0): + config = getConfig() + style = config.style + self.style_level = level + self.selected_flag = False + logging.info('Tree : style=%s,level=%d',style, level) + c1, c2 = getColors(style,level) + self.text_color, self.bg_color = toArrayColor(c1),toArrayColor(c2) + c1, c2 = getSelectedColors(style,level) + self.s_text_color,self.s_bg_color = toArrayColor(c1), toArrayColor(c2) + self.bind(size=self.setBGColor,pos=self.setBGColor) + + def setBGColor(self,o=None,v=None): + c = self.bg_color + if self.selected_flag: + c = self.s_bg_color + logging.info('selected=%s,color=%s',str(self.selected_flag),str(c)) + with self.canvas.before: + Color(*c) + Rectangle(pos=self.pos,size=self.size) + + def selected(self): + self.selected_flag = True + self.setBGColor() + + def unselected(self): + self.selected_flag = False + self.setBGColor() diff --git a/kivyblocks/tree.py b/kivyblocks/tree.py index dfc3ef9..9b8fc54 100644 --- a/kivyblocks/tree.py +++ b/kivyblocks/tree.py @@ -1,60 +1,72 @@ from kivy.app import App -from kivy.graphics import Color, Triangle +from kivy.logger import logging +from kivy.graphics import Color, Rectangle, Triangle from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label from kivy.uix.widget import Widget from kivy.uix.button import ButtonBehavior - from kivyblocks.widgetExt import ScrollWidget -from kivyblocks.blocksapp import BlocksApp from kivyblocks.utils import CSize -from baseWidget import PressableLabel - from appPublic.dictObject import DictObject +from .baseWidget import PressableLabel +from .stylebehavior import StyleBehavior -class NodeTrigger(ButtonBehavior, Widget): - def __init__(self, open_status=False,color=[1,0,0,1]): - siz = CSize(1) - super().__init__(size_hint=(None,None),size=[siz,siz]) #CSize(1)) +class EmptyBox(Label): + def __init__(self,size_cnt=1): + self.size_cnt = size_cnt + siz=CSize(self.size_cnt) + super().__init__(text=' ',font_size=siz, + text_size=(siz,siz), + halign='center', + size_hint=[None,None],size=[siz,siz]) + + def onSize(self,o=None,v=None): + return + +class NodeTrigger(ButtonBehavior, EmptyBox): + def __init__(self, size_cnt=1,open_status=False,color=[1,0,0,1]): + super().__init__(size_cnt=size_cnt) self.open_status = open_status self.line_color = color - self.register_event_type('on_change') - self.open_points = [0,self.height, self.width,self.height,self.width/2,0] - self.close_points = [0,self.height, 0,0, self.width,self.height/2] + self.countPoints() self.showOpenStatus() - self.bind(size=self.on_size) + self.bind(size=self.onSize,pos=self.onSize) - def on_change(self,status): - print('new_status=',status) + def countPoints(self): + self.open_points = [0,self.height, + self.width,self.height, + self.width/2,0] + self.close_points = [0,self.height, + 0,0, self.width, + self.height/2] + def pointsShift(self,points): + x = [ p + self.pos[0] if i % 2 == 0 else p + self.pos[1] \ + for i,p in enumerate(points) ] + return x - def on_size(self,o,v): - self.open_points = [0,self.height, self.width,self.height,self.width/2,0] - self.close_points = [0,self.height, 0,0, self.width,self.height/2] + def onSize(self,o=None,v=None): + self.countPoints() + self.showOpenStatus() def on_press(self): self.open_status = False if self.open_status else True self.showOpenStatus() - self.dispatch('on_change',self.open_status) def showOpenStatus(self): points = self.close_points if self.open_status: points = self.open_points self.canvas.clear() + points = self.pointsShift(points) with self.canvas: Color(*self.line_color) Triangle(points=points) - -class EmptyBox(Widget): - def __init__(self): - siz=CSize(1) - super().__init__(size_hint=[None,None],size=[siz,siz]) - + # print('pos=',self.pos,'size=',self.size) class TreeNode(BoxLayout): - def __init__(self,tree:Tree=None, - parentNode:TreeNode=None, - data:dict): + def __init__(self,data,tree=None, + parentNode=None, + ): """ base TreeNode data:{ @@ -74,17 +86,26 @@ class TreeNode(BoxLayout): self.hasChildren_nodes = True if not n is None else False self.children_nodes = n self.children_loaded = False - self.hasChildren = data.get('hasChildren') - if hasChildren_nodes: + self.hasChildren_nodes = data.get('children') + if self.hasChildren_nodes: self.trigger = NodeTrigger() - self.trigger.bind(on_change=self.toggleChildren) + self.trigger.bind(on_press=self.toggleChildren) self.buildChildrenContainer() else: self.trigger = EmptyBox() - self.add_widget(self.node_box) self.node_box.add_widget(self.trigger) - self.buildContent() + self.add_widget(self.node_box) + self.addContent() + self.setSize() + def setSize(self): + if self.children_open: + self.height = self.node_box.height + self.node_box1.height + else: + self.height = self.node_box.height + self.width = self.trigger.width + \ + max(self.node_box.width,self.node_box1.width) + def buildChildrenContainer(self): self.node_box1.add_widget(EmptyBox()) self.children_box = BoxLayout(orientation='vertical') @@ -105,43 +126,67 @@ class TreeNode(BoxLayout): self.buildContent() self.node_box.add_widget(self.content) self.node_box.height = self.content.height + CSize(1) - self.node_box.width = self.trigger.width + self.content.width + self.node_box.width = self.trigger.width + \ + self.content.width + CSize(1) + logging.info('Tree : content=(%d,%d),box=(%d,%d)', \ + self.content.width,self.content.height, + self.node_box.width,self.node_box.height) def buildChildren(self): if self.data.children is None: + logging.info('Tree : is a leaf node') return if self.data.children == []: self.treeObj.getUrlData(self.addChildren,self.data) return if len(self.subNodes) == 0: + logging.info('Tree : add subnodes') self.addChildren(self.data.children) + else: + logging.info('Tree : not need add subnodes') + + def childrenSizeChange(self,tn,v): + h = 0 + w = 0 + for n in self.subNodes: + h += n.height + w = max(w,n.width) + + self.children_box.height = h + self.children_box.width = w + self.node_box1.height = self.children_box.height + self.node_box1.width = self.trigger.width + self.children_box.width + self.setSize() def addChildren(self,children): self.data.children = children + self.children_box.height = 0 + self.children_box.width = 0 for c in children: + options = {} options['tree'] = self.treeObj options['parentNode'] = self options['data'] = c - tn = self.teeeObj.NodeKlass(**options) + tn = self.treeObj.NodeKlass(**options) + tn.bind(size=self.childrenSizeChange) self.subNodes.append(tn) self.children_box.add_widget(tn) + self.children_box.height += tn.height + self.children_box.width = max(self.children_box.width,tn.width) + self.node_box1.height = self.children_box.height + self.node_box1.width = self.trigger.width + self.children_box.width - def toggleChildren(self,o,v): - if v: + def toggleChildren(self,o): + self.treeObj.unselected() + self.children_open = True if not self.children_open else False + if self.children_open: self.buildChildren() self.add_widget(self.node_box1) - self.children_open = True - self.height = self.node_box.height + self.node_box1.height else: self.remove_widget(self.node_box1) - self.height = self.node_box.height - self.children_open = False + self.setSize() - def on_size(self,o,v): - print('************treenode on_size', o, v) - self.node_box1.height = self.children_box.height - """ tree options { @@ -156,16 +201,31 @@ tree options "data" # array of {children:{},...} } """ -class Tree(ScrollWidget): +class Tree(StyleBehavior,ScrollWidget): def __init__(self,**options): - super().__init__() #orientation="vertical") + ScrollWidget.__init__(self) + level = options.get('level',0) + StyleBehavior.__init__(self,level=level) self.options = DictObject(**options) self.nodes = [] self.initflag = False + self.selected_node = None self.bind(size=self.onSize,pos=self.onSize) + def select_row(self, node): + self.unselect_row() + self.selected_node = node + node.selected() + + def unselect_row(self): + if self.selected_node: + logging.info('selected node unselected') + self.selected_node.unselected() + self.selected_node = None + def onSize(self,o,v=None): if not self.initflag: + self.initflag = True self.buildTree(self) for n in self.nodes: n.setMinWidth(self.width) @@ -190,8 +250,10 @@ class Tree(ScrollWidget): if self.options.url: return self.getUrlData(self.dataLoaded,kv) data = self.options.data + logging.info("Tree : buildTree,data=%s",data) self.dataLoaded(data) + def dataLoaded(self,d): self.data = d self.addNodes() @@ -201,39 +263,57 @@ class Tree(ScrollWidget): options = {} options['tree'] = self options['parentNode'] = None - options['data'] = DictObject(c) - self.nodes.append(self.NodeKlass(**options)) - for w in self.nodes: + options['data'] = DictObject(**c) + w = self.NodeKlass(**options) + self.nodes.append(w) self.add_widget(w) + logging.info('Tree : node=%s',type(w)) +class TextContent(StyleBehavior, PressableLabel): + def __init__(self,level=0,**options): + PressableLabel.__init__(self,**options) + StyleBehavior.__init__(self,level=level) + class TextTreeNode(TreeNode): def buildContent(self): txt = self.data.get(self.treeObj.options.textField, self.data.get(self.treeObj.options.idField,'defaulttext')) - self.content = PressableLabel(text=txt, + self.content = TextContent(level=self.treeObj.style_level, + text=txt, size_hint=(None,None), font_size=CSize(1), - text_size=CSize(len(txt),1), + text_size=CSize(len(txt)-1,1), halign='left', - height=CSize(2),width=CSize(len(txt))) + height=CSize(2), + width=CSize(len(txt))) + self.content.text_color = [0,0,0,1] #self.treeObj.text_color self.content.bind(on_press=self.onPress) return def onPress(self,o,v=None): + if self.hasChildren_nodes: + v = True if not self.children_open else False + self.toggleChildren(self) + self.trigger.on_press() + return + logging.info('select the leaf node') self.treeObj.select_row(self) def selected(self): - pass + logging.info('content selected ........') + self.content.selected() def unselected(self): - pass + logging.info('content unselected ........') + self.content.unselected() class TextTree(Tree): def __init__(self,**options): - self.NodeKlass = TextTReeNode + self.NodeKlass = TextTreeNode super().__init__(**options) self.register_event_type('on_press') + def onPress(self,o,v=None): if self.selectNode: self.selectNode.unselected() diff --git a/setup.py b/setup.py index ff2ba46..e90f876 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,14 @@ email = "yumoqing@icloud.com" packages=find_packages() package_data = { -"kivyblocks":['imgs/*.png', 'imgs/*.gif','imgs/*.jpg','ttf/*.ttf', 'ui/*.uidesc' ], + "kivyblocks":[ + 'imgs/*.png', + 'imgs/*.atlas', + 'imgs/*.gif', + 'imgs/*.jpg', + 'ttf/*.ttf', + 'ui/*.uidesc' + ], } setup(