kivyblocks/kivyblocks/toolbar.py
2022-01-29 16:32:51 +08:00

318 lines
8.2 KiB
Python

from kivy.logger import Logger
from kivy.graphics import Color, Rectangle
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import AsyncImage
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.properties import StringProperty, DictProperty, \
OptionProperty, ListProperty, NumericProperty, \
BooleanProperty
from appPublic.dictObject import DictObject
from appPublic.registerfunction import RegisterFunction
from .widgetExt.scrollwidget import ScrollWidget
from .utils import *
from .ready import WidgetReady
from .color_definitions import getColors
from .baseWidget import Text, Box
from .scrollpanel import ScrollPanel
from .command_action import cmd_action
class Toolbar(ScrollPanel):
"""
tool has the follow attributes
{
"name",
"source_on,
"source_off,
# source_on, source_off, or "img_src",
"label",
"deletable"
"url",
"rfname",
}
toolbar has follow attributes
{
"img_size_c":image height in charecter size
"text_size_c":
"toolbar_orient":"H" or "V"
"tool_orient":"horizontal" or "vertical"
"css_on",
"css_off",
"tools":
}
"""
css_on = StringProperty('default')
css_off = StringProperty('default')
tools = ListProperty([])
tool_orient = OptionProperty('horizontal', \
options=['horizontal', 'vertical'])
toolbar_orient = OptionProperty('H', options=['H', 'V'])
img_size_c = NumericProperty(2)
text_size_c = NumericProperty(1)
target = StringProperty(None)
executable = BooleanProperty(False)
def __init__(self, **kw):
self.w_dic = {}
SUPER(Toolbar, self, kw)
self.buffer = {}
self.register_event_type('on_press')
self.register_event_type('on_delete_tool')
if self.toolbar_orient == 'H':
self._inner.orientation = 'horizontal'
else:
self._inner.orientation = 'vertical'
self.clear_widgets()
for t in self.tools:
self.add_tool(t)
self.bar_width = 0
if self.toolbar_orient == 'H':
self.do_scroll_y = False
else:
self.do_scroll_x = False
def on_children_size(self, o, size):
self.on_size(None, None)
def on_size(self, o, size):
if self.toolbar_orient == 'H':
self.size_hint_x = 1
self.size_hint_y = None
if len(self.w_dic.keys()) > 0:
self.height = max([w.height for w in self.w_dic.keys()])
else:
self.size_hint_x = None
self.size_hint_y = 1
if len(self.w_dic.keys()) > 0:
self.width = max([w.width for w in self.w_dic.keys() ])
def add_tool(self, t):
label = t.get('label', t.get('name', None))
source_on = t.get('source_on', t.get('img_src',None))
source_off = t.get('source_off', t.get('img_src', None))
ToggleIconText = Factory.ToggleIconText
ToggleText = Factory.ToggleText
ToggleImage = Factory.ToggleImage
ClickableImage = Factory.ClickableImage
if label and source_on:
w = ToggleIconText(css_on=self.css_on,
css_off=self.css_off,
text=label,
size_hint = (None, None),
fontsize=self.text_size_c,
source_on=source_on,
source_off=source_off,
orientation=self.tool_orient,
img_kw={
"size_hint":(None, None),
"height":CSize(self.img_size_c),
"width":CSize(self.img_size_c)
}
)
elif label:
w = ToggleText(css_on=self.css_on,
css_off=self.css_off,
size_hint = (None, None),
orientation=self.tool_orient,
fontsize=CSize(self.text_size_c),
text=label)
elif source_on:
w = ToggleImage( source_on=source_on,
source_off=source_off,
size_hint = (None, None),
orientation=self.tool_orient,
img_kw={
"size_hint":(None, None),
"height":CSize(self.img_size_c),
"width":CSize(self.img_size_c)
}
)
w.widget_id = t['name']
if t.get('deletable', False):
x = ClickableImage(source=blockImage('delete.png'),
size_hint=(None,None),
size=CSize(1,1)
)
x.data = (w, t)
x.bind(on_press=self.delete_tool)
w.add_widget(x)
if w:
self.add_widget(w)
self.w_dic[w] = t.copy()
self.w_dic[w]['widget'] = w
w.select(False)
w.bind(size=self.on_children_size)
w.bind(on_press=self.tool_press)
w.bind(minimum_width=w.setter('width'))
w.bind(minimum_height=w.setter('height'))
def delete_tool(self, o):
w, t = o.data
self.del_tool(w)
self.dispatch('on_delete_tool', o.data)
def on_delete_tool(self, o, d=None):
pass
def del_tool(self, w):
self.remove_widget(w)
self.w_dic = {k:v for k,v in self.w_dic.copy().items() \
if k != w }
def on_press(self, o):
pass
def select(self,name):
for w, v in self.w_dic.items():
if v['name'] == name:
w.select(True)
self.tool_press(w)
break
def tool_press(self, o):
for w,v in self.w_dic.items():
if w == o:
ret_v = v
w.select(True)
else:
w.select(False)
if not self.executable:
self.dispatch('on_press', ret_v)
return
desc = self.w_dic[o].copy()
if not desc.get('target'):
desc['target'] = self.target
cmd_action(desc, self)
class ToolPage(Box):
"""
ToolPage:
{
toolbar_size:
tool_at
toolbar
}
"""
toolbar_size = NumericProperty(2)
tool_at = OptionProperty('top', \
options=['top', 'bottom', 'left', 'right'])
toolbar = DictProperty({})
def __init__(self, **kw):
SUPER(ToolPage, self, kw)
if self.tool_at in [ 'top','bottom']:
self.orientation = 'vertical'
else:
self.orientation = 'horizontal'
if not self.toolbar_size:
self.toolbar_size = self.img_size + self.text_size + 0.3
self.content_widgets = {}
self.content_w = None
self.toolbar_w = None
self.init()
self.toolbar_w.bind(on_delete_tool=self.delete_content_widget)
name = self.toolbar['tools'][0]['name']
self.toolbar_w.select(name)
def get_subwidgets(self):
children = [ i for i in self.children]
x = [ i for i in self.content_widgets.values() ]
return children + x
def delete_content_widget(self, o, d):
w, dic = d
self.del_tool(dic['name'])
def add_tool(self, tool):
self.toolbar_w.add_tool(tool)
def del_tool(self, name):
g = self.content_widgets.copy()
self.content_widgets = {k:v for k,v in g.items() if k!=name}
def on_size(self,obj,size):
if self.content_w is None:
return
if self.tool_at in ['top','bottom']:
self.toolbar_w.size_hint_y = None
self.content_w.height = self.height - self.toolbar_w.height
else:
self.toolbar_w.size_hint_x = None
self.content_w.width = self.width - self.toolbar_w.width
def init(self):
self.content_w = BoxLayout()
self.content_w.widget_id = 'content'
self.toolbar_w = Toolbar(**self.toolbar)
if self.tool_at in ['top','left']:
self.add_widget(self.toolbar_w)
self.add_widget(self.content_w)
else:
self.add_widget(self.content_w)
self.add_widget(self.toolbar_w)
self.toolbar_w.bind(on_press=self.on_press_handle)
def build_widget(self, url):
desc = {
"widgettype":"urlwidget",
"options":{
"url":url
}
}
b = Factory.Blocks()
return b.widgetBuild(desc)
def print_all(self):
self.print_info(self)
self.print_info(self.toolbar_w)
for w in self.toolbar_w.w_dic.keys():
self.print_info(w)
for c in w.children:
self.print_info(c)
self.print_info(self.content_w)
for c in self.content_w.children:
self.print_info(c)
def print_info(self, o):
print('self.size_hint=', o.__class__, o.size_hint,
'self.x,y=', o.width, o.height)
def on_press_handle(self, o, v):
name = v.get('name')
refresh = v.get('refresh', False)
# self.print_all()
w = self.content_widgets.get(name)
self.content_w.clear_widgets()
if w and not refresh:
self.content_w.add_widget(w)
return
url = v.get('url')
if url:
w = self.build_widget(url)
if w:
self.content_widgets[name] = w
self.content_w.add_widget(w)
return
rfname = v.get('rfname')
if rfname:
rf = RegisterFunction()
f = rf.get(rfname)
if f:
r = f()
if isinstance(r,Widget):
self.content_w.add_widget(r)