diff --git a/kivyblocks/baseWidget.py b/kivyblocks/baseWidget.py index 9d28876..155ce21 100755 --- a/kivyblocks/baseWidget.py +++ b/kivyblocks/baseWidget.py @@ -165,6 +165,12 @@ class Text(Label): if self.bgcolor: self.color = self.bgcolor + def get_wraped_size(self): + if self.text: + self._label.refresh() + return self._label.size + return (None,None) + def on_size(self,o,size): # super().on_size(o,size) if self.wrap: @@ -345,7 +351,7 @@ class HTTPDataHandler(EventDispatcher): def getDataHandler(url,**kwargs): if url.startswith('file://'): return FILEDataHandler(url,**kwargs) - return HTTPDataHandler(url, **kwaegs) + return HTTPDataHandler(url, **kwargs) def device_type(): if platform != "android" and platform != "ios": diff --git a/kivyblocks/markdown.py b/kivyblocks/markdown.py new file mode 100644 index 0000000..b86d619 --- /dev/null +++ b/kivyblocks/markdown.py @@ -0,0 +1,157 @@ +from kivy.properties import StringProperty +from kivy.factory import Factory +from kivy.clock import Clock + +from .baseWidget import ScrollWidget, getDataHandler +from .utils import CSize +import re + +class Markdown(ScrollWidget): + """ +# Markdown +MArkdown widget using to render a markdown file and show it +description file format +{ + "widgettype":"Markdown", + "options":{ + "source": the markdown file + other options + } +} + """ + source = StringProperty(None) + def __init__(self, **kw): + ScrollWidget.__init__(self, **kw) + self.bind(source=self.load_text) + if self.source: + Clock.schedule_once(self.load_text, 0.3) + + def load_text(self, *args): + print('source fired, hahaha', *args) + self.clear_widgets() + h = getDataHandler(self.source) + h.bind(on_success=self.update) + h.bind(on_error=self.show_error) + h.handle() + + def show_error(self, o, e): + print('load_text(), error=',e) + + def update(self, o, text): + print('text=',text, type(text)) + if not text: + return + for l in text.split('\n'): + l = ''.join([i for i in l if i != '\r']) + self.parse_line(l) + + def parse_title(self,txt, level): + w = Factory.Blocks().widgetBuild({ + "widgettype":f"Title{level}", + "options":{ + "text":txt, + "size_hint_x":None, + "width":self.width, + "size_hint_y":None, + "markup":True, + "wrap":True, + "halign":"left", + "valign":"middle" + } + }) + _,h = w.get_wraped_size() + clen = CSize(1) + if h is None or h < clen: + h = clen + w.height = h + print(w,h,w.height) + w.bind(on_ref_press=self.open_new_md) + self.add_widget(w) + + def parse_line(self, l): + if l.startswith('###### '): + t = self.mktext_bbtext(l[7:]) + return self.parse_title(t,6) + if l.startswith('##### '): + t = self.mktext2bbtext(l[6:]) + return self.parse_title(t,5) + if l.startswith('#### '): + t = self.mktext2bbtext(l[5:]) + return self.parse_title(t,4) + if l.startswith('### '): + t = self.mktext2bbtext(l[4:]) + return self.parse_title(t,3) + if l.startswith('## '): + t = self.mktext2bbtext(l[3:]) + return self.parse_title(t,2) + if l.startswith('# '): + t = self.mktext2bbtext(l[2:]) + return self.parse_title(t,1) + t = self.mktext2bbtext(l) + w = Factory.Blocks().widgetBuild({ + "widgettype":"Text", + "options":{ + "text":t, + "wrap":True, + "size_hint_x":None, + "width":self.width, + "markup":True, + "valign":"middle", + "halign":"left" + } + }) + _,h = w.get_wraped_size() + clen = CSize(1) + if h is None or h < clen: + h = clen + w.height = h + w.bind(on_ref_press=self.open_new_md) + self.add_widget(w) + + def open_new_md(self, o, value): + print(value,'is it a link') + self.source = value + + def mktext2bbtext(self,mdtext): + """ + convert markdown text to bbtag text kivy Label Widget recognized + + markdown syntax + *XXX* Italic + **XXX** Bold + ***XXX*** Bold + Italic + > XXXX reference + >> XXXX reference inside reference + [-*] XXX list + [0-9]*[.] XXX list + *** split line + --- split line + ___ split line + [.*](url) link + ![.*](url) image + [![.*](url)](url) image link + !v[.*](url) video* plan to extend + !a[.*](url) audio* plan to extend + + bb tag syntax + [b]XXX[/b] Bold + [i]XXX[/i] Italic + [sub]XXX[/sub] + """ + mdtext = re.sub('\*\*\*(.*)\*\*\*', \ + lambda x: '[b][i]'+x.group(1)+'[/i][/b]', \ + mdtext) + + mdtext = re.sub('\*\*(.*)\*\*', \ + lambda x: '[b]'+x.group(1)+'[/b]', \ + mdtext) + + mdtext = re.sub('\*(.*)\*', \ + lambda x: '[i]'+x.group(1)+'[/i]', \ + mdtext) + + mdtext = re.sub('([^!]?)\[(.*)\]\((.*)\)', \ + lambda x:x.group(1) + '[ref='+x.group(3)+'][color=00ff00]'+ x.group(2)+'[/color][/ref]', \ + mdtext) + + return mdtext diff --git a/kivyblocks/pagepanel.py b/kivyblocks/pagepanel.py index d866df7..296d2bb 100644 --- a/kivyblocks/pagepanel.py +++ b/kivyblocks/pagepanel.py @@ -232,7 +232,7 @@ sub-widget's description file format return True def pop(self, o, *args): - if len(self.sub_widgets) < 1: + if len(self.sub_widgets) < 2: return self.clear_widgets() diss_w = self.sub_widgets[-1] diff --git a/kivyblocks/register.py b/kivyblocks/register.py index f0fe8ac..15d4175 100644 --- a/kivyblocks/register.py +++ b/kivyblocks/register.py @@ -23,8 +23,10 @@ from .mapview import MapView from .chart2d import Chart2d from .message import Conform from .pagepanel import PagePanel +from .markdown import Markdown r = Factory.register +r('Markdown', Markdown) r('PagePanel', PagePanel) r('Conform', Conform) r('Chart2d', Chart2d) diff --git a/kivyblocks/widgetExt/scrollwidget.py b/kivyblocks/widgetExt/scrollwidget.py index a070917..a5207c3 100755 --- a/kivyblocks/widgetExt/scrollwidget.py +++ b/kivyblocks/widgetExt/scrollwidget.py @@ -5,9 +5,9 @@ from kivy.graphics import Color, Ellipse,Rectangle class ScrollWidget(ScrollView): def __init__(self,**kw): - self._inner = BoxLayout(orientation='vertical',padding=2, - spacing=2,size_hint=(None,None)) super(ScrollWidget,self).__init__(**kw) + self._inner = BoxLayout(orientation='vertical',padding=5, + spacing=8,size_hint=(None,None)) self._inner.bind( minimum_height=self._inner.setter('height')) self._inner.bind(