From 64c8a11b16ac9ae05c983b2638f517a4ef2954e4 Mon Sep 17 00:00:00 2001 From: wuminggao Date: Fri, 15 Apr 2022 03:30:25 +0000 Subject: [PATCH 1/3] add README.md. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..f04748d --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# project-2 + +#### 介绍 +期中作业 +完成内容:- +使用方法:- + +参考资料:- + -- Gitee From f8281b0e164b973596d6b567556a08cc4f8ad262 Mon Sep 17 00:00:00 2001 From: mooganic <41576653+mooganic@users.noreply.github.com> Date: Mon, 18 Apr 2022 16:23:46 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0checkbox?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/modules.xml | 8 + .idea/project-2.iml | 14 + .idea/vcs.xml | 6 + serv/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 134 bytes serv/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 142 bytes serv/__pycache__/__main__.cpython-36.pyc | Bin 0 -> 1711 bytes serv/__pycache__/__main__.cpython-38.pyc | Bin 0 -> 1733 bytes serv/lib/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 138 bytes serv/lib/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 146 bytes serv/lib/__pycache__/http_.cpython-36.pyc | Bin 0 -> 15753 bytes serv/lib/__pycache__/http_.cpython-38.pyc | Bin 0 -> 15809 bytes serv/lib/__pycache__/path_.cpython-36.pyc | Bin 0 -> 1831 bytes serv/lib/__pycache__/path_.cpython-38.pyc | Bin 0 -> 1838 bytes web/main.py | 8 +- web/py_lib/flutter.py | 996 +++++++++++-------- web/py_lib/flutter_test_3.py | 84 ++ 17 files changed, 680 insertions(+), 444 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/project-2.iml create mode 100644 .idea/vcs.xml create mode 100644 serv/__pycache__/__init__.cpython-36.pyc create mode 100644 serv/__pycache__/__init__.cpython-38.pyc create mode 100644 serv/__pycache__/__main__.cpython-36.pyc create mode 100644 serv/__pycache__/__main__.cpython-38.pyc create mode 100644 serv/lib/__pycache__/__init__.cpython-36.pyc create mode 100644 serv/lib/__pycache__/__init__.cpython-38.pyc create mode 100644 serv/lib/__pycache__/http_.cpython-36.pyc create mode 100644 serv/lib/__pycache__/http_.cpython-38.pyc create mode 100644 serv/lib/__pycache__/path_.cpython-36.pyc create mode 100644 serv/lib/__pycache__/path_.cpython-38.pyc create mode 100644 web/py_lib/flutter_test_3.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..21fb283 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project-2.iml b/.idea/project-2.iml new file mode 100644 index 0000000..d92223b --- /dev/null +++ b/.idea/project-2.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/serv/__pycache__/__init__.cpython-36.pyc b/serv/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ef279cb08bc35ba0c6ac717886391d5e7609712 GIT binary patch literal 134 zcmXr!<>fklGa`ur2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU&i{O#i>Qb`nie8 z`p!O?`FR0F`B|ySCB^y$5QeUiK2SlKetdjpUS>&ryk0@&Ee@O9{FKt1R6CGi#X!se E00l=M+5i9m literal 0 HcmV?d00001 diff --git a/serv/__pycache__/__init__.cpython-38.pyc b/serv/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d30c5646ab5d5fa304c50176187829acaaf9960 GIT binary patch literal 142 zcmWIL<>g`kg5x(Ml0fuh5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HqerR!OQL%n* zVzR!oPiB5zKv8~HYH~@jegTA`YorfUP^KRrpP83g5+AQuPm%*h-t?(ih_2kN-4&lR#9S;)mGC-+tM$E;3a9A{+COP=42|1ZfrT z`bt#Dslx02Dih3#OLe`**(l&_7{eZn*(!E93O)+fS?;YvNA76F`KqIb;!1X*<#>Hq zx7n6$mA$l+4}AU%Mk=rb{(r%ZTbn&Ahw9QnT%*tlyyu!Gs*D)6Hoah#v z+#R^0J2sO#Gi8yROrCvDy4snoc2?R>ktc`tnDfHQjbe~13K#3_gF$92R?ODBeYzMR zV5%<~nS>ifPi5Lg54YpIZ0kFwpTvzlIMF(9GHqJ@wB0)WK9Zf&MK^0((<-ORu~%Af zxZIMmkE2StRBpRSO6*-qK^MOO!FbF)zQF5zKbn3DGc%OP3Cx(H^fVO3M?UVE5k3lN z5Dv{?Wq5qqv~{PnCwoOZrE@QB>TKin!*t`FaY?cDydK~Ao=G0598Py3k@;L7E}^Rrd(-2M61?#*j= zzxn;%54U$dy@TbA0oB{l#_qL`VVTao));z68_k-F%2cO)Bi+Iq29zNL&uCo`$4!yD zpjV{IxH(<6LG+8@zuwk#rA}PRwv7wapkJC~aSzwuT|K)(_0X*Ch45Ld)z6SPNMeyf z`6z)TpnP&KxNc3!05~2zdUW=!+~>&JX4ojmd1KC_mHb7xoA zh6||XNddP$L^pcCTg@n`^*R?&U`V46BWY4km6FqEWO6H$s-6@?5*nK#C93L0c)7j^ib+Yu@LAv!$zMQ4W z+_LR;56-t9#0_c{4m7AKi>5S9u4^QOo}i&g>ZYipy;kQQcaOm=#d6k5$ZKdm+CyGtt|>~mKFXNY#1O4#{CBNw{>HE^YhW&pKfpcd}Z^?D_h^(`uEo#?)>rF=B=+96jauh`e|FHaW5$a zSaPZV^v*0qZv8Uax^eB!x4+;0@z&;Ne`0#0Pjord*t+%!Jmaxf8w2N1qggA1Jl1i~ z$a4C11F{fqC$!Fp-6l&*ubainl#@DdgW?y!e7&aWI!kdeSu>@l`n}vl2llZ1oyC(2 zR0+-6UKkHxt|l7kC#l_6$A@^J@a(t+1FQgTU4YDZZj^6b6^vYXx2X;jA|H?d2E+uIoZQ$ zE$RlBE(czVP9M2%oj4tdQzsWs52jJeRr$6)f*9WCt!5C_x}EbVEu_&6B#r8^QgZx= zR5w%AbX6FUZ)}W|sIKP_sSi?D&GE+bi7313Yib-$k4T~=1saNAxOGBdyXogK);abp zWA_xaW}s&wGy(81w|s{I)!tc61Ga5}924-K8T A*Z=?k literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/__init__.cpython-36.pyc b/serv/lib/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21fe8d4f62cf6c294fe0fb96c1e5a9b8d147a428 GIT binary patch literal 138 zcmXr!<>fklGa`ur2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU*`Iu#i>Qb`nie8 z`p!O?`FR0F`B|ySCB^y$5QeUiK2SlKeokhRetdjpUS>&ryk0@&Ee@O9{FKt1R6CG? I#X!se0FgN%L;wH) literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/__init__.cpython-38.pyc b/serv/lib/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b39d1bc54d0298fcadaa6ece73bcbfe7e2756ae GIT binary patch literal 146 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 D`vsZB literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/path_.cpython-36.pyc b/serv/lib/__pycache__/path_.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3136d675a0b590156ceb3dc3b137836e3bc3b5cc GIT binary patch literal 1831 zcmcIkOK&4Z5bo}Icx)$5Hk)PT@LI%$kswCwYPm$KMJpB#D}!W^B40+fYn-$_iLLG? zTCW@l$@^#amvG_-Fjr2wA#vLiU$q^R1P<5)+PbLoVWbLrG5n2Uv6sD(UN zb49W#Aj78E71%dvccZ@5ukvm@G)vttCWEnsduVdF`@OTCF3M=AiyYn|d(*HCNe^5Z zywcNBO>9}QuIJ8%HVv>*(X+={cWdR!hB`0EX5C1i4ky_gVL0)(k6J(4+}PGhZ_s-7 zLQhV=H6SGHZq?nkFpkQq=C1Km};y+om-pW=Ql%bnV^D^qsTyD#7 zG|{K2EW@5TvL4G)B$!`DJeY04TxGT`Yszfn|61udGhe!IVQ^k!Wi}}4z#jSLStt|` z9yT-~^ z%{RvLG%yi%D?>ggW#zlh*TziDD)BNpnNa@Ef@n+HWGU8J?tdYbY@i$sY2L@*|C;m9 zf9GuW5X`&_amn+0?6|>mMO(f#vd=MgGusc~TW8Dd%BR;e%psQT9S yy<(VX&x6m;@WO6r^Xb*5^NjkNEjd6#{#4{o7?b5AmLy4(#7RA=CKdk%N$?kZB|%gG literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/path_.cpython-38.pyc b/serv/lib/__pycache__/path_.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb8fed75ea5858b6fc7475cf38200216155f12f9 GIT binary patch literal 1838 zcmcIk&u<$=6rP#=;kBI~ZknnX3TjI$SP8nQLX<;P6;%`tl|gc=hP|w8zjd|u3@Ze%o7(BseHX%rm%tb6nk@Jg)CAs85EApuZ?NC5x4F3sK0aEYz_x z6({mY9mzvARV3R2(rt@%fxUxH?Db7{kjDN{SGu2%2O|UbP^WPBdwabsFTG)wr|=Hh z8@i=S*`O$$gKSc&u_Gzb3f%jl&^ zwTX6mgXrn=Y`puU9=}cpg^4DW@%h6D3-+Qs>qnDbv7J1a?3c}IbB;7&Zj28hqd>n;>R54dx`Lc@i__wEH2?e;i|Cz+eqmp zQeD``h>6@21tLM?5y}a3pOKu3A=6Ek*te|l;rF@{TLtAuu9agCHO?JG;g3Ij!J#~vEeN!a2 zF=199F2ZR^{Q*2zpfI)ewtWrb;8r1yLB)yWaykS-q@Ez?k$Q#laYdm<4gF9G?mr1~ zyJ8dX1E}$;!a5ay3X$>K@oeU34?C7FUzf7>L-$*)#~So8fY{p^Q+kz-%uuG25G#y* zp`?;4w(C3a{lBs6TR0*UZxOrx5T?G(Vj;=3%Y2xJRk055U;(RfZ^i5_8lRUzb^GF)fN7wh^yAlb% z7&a2FjI%hHX3(cPr(6g6V-_6gBJTQDTI>|rPMSQ%tl>K#r2Yi*zn;Sh`R8*2oMRus zZ?Np_7_JA+cRg%YY2g>qK0Nkz+Pby{qL~7V-iD_6$JjOL*gzHjoTrZ& Vj^X=1 - self.text = text - self.color = color - self.textAlign = textAlign - self.style = style - self.overflow = overflow - self.maxLines = maxLines - def render(self): - style = {} - if self.style is not None: - style['font'] = str(self.style) - if self.style.letterSpacing is not None: - letterSpacing = self.style.letterSpacing - if isinstance(letterSpacing, int): - letterSpacing = f'{letterSpacing}px' - style['letter-spacing'] = letterSpacing - if self.style.fontStyle is not None: - style['font-style'] = self.style.fontStyle - if self.color is not None: - style['color'] = self.color - if self.maxLines is not None: - style['overflow'] = 'hidden' - style['text-overflow'] = self.overflow - style['display'] = '-webkit-box' - style['-webkit-line-clamp'] = self.maxLines - style['-webkit-box-orient'] = 'vertical' - e = maketag('div', style=style) - p = javascript.document.createTextNode(self.text) - e.appendChild(p) - return e + def __init__(self, text, color=None, textAlign=None, style=None, + overflow=TextOverflow.clip, maxLines=None): + assert (textAlign is None) or (isinstance(textAlign, str)) + assert (style is None) or (isinstance(style, TextStyle)) + assert (color is None) or (isinstance(color, str)) + assert isinstance(overflow, str) + if maxLines is not None: + assert isinstance(maxLines, int) + assert maxLines >= 1 + self.text = text + self.color = color + self.textAlign = textAlign + self.style = style + self.overflow = overflow + self.maxLines = maxLines + + def render(self): + style = {} + if self.style is not None: + style['font'] = str(self.style) + if self.style.letterSpacing is not None: + letterSpacing = self.style.letterSpacing + if isinstance(letterSpacing, int): + letterSpacing = f'{letterSpacing}px' + style['letter-spacing'] = letterSpacing + if self.style.fontStyle is not None: + style['font-style'] = self.style.fontStyle + if self.color is not None: + style['color'] = self.color + if self.maxLines is not None: + style['overflow'] = 'hidden' + style['text-overflow'] = self.overflow + style['display'] = '-webkit-box' + style['-webkit-line-clamp'] = self.maxLines + style['-webkit-box-orient'] = 'vertical' + e = maketag('div', style=style) + p = javascript.document.createTextNode(self.text) + e.appendChild(p) + return e + class RichText: - def __init__(self, text): - assert isinstance(text, TextSpan) - self.text = text - def render(self): - return self.text.render() + def __init__(self, text): + assert isinstance(text, TextSpan) + self.text = text + + def render(self): + return self.text.render() + class TextSpan: - def __init__(self, text=None, color=None, style=None, children=None): - assert (text is not None) or (children is not None) - assert (color is None) or (isinstance(color, str)) - assert (style is None) or isinstance(style, TextStyle) - if text is not None: - assert isinstance(text, str) - if children is not None: - assert isinstance(children, (tuple,list)) - for c in children: - assert isinstance(c, TextSpan) - self.text = text - self.color = color - self.style = style - self.children = children - def render(self): - style = {} - if self.style is not None: - style['font'] = str(self.style) - if self.style.letterSpacing is not None: - letterSpacing = self.style.letterSpacing - if isinstance(letterSpacing, int): - letterSpacing = f'{letterSpacing}px' - style['letter-spacing'] = letterSpacing - if self.style.fontStyle is not None: - style['font-style'] = self.style.fontStyle - if self.color is not None: - style['color'] = self.color - e = maketag('span', style=style) - if self.text is not None: - p = javascript.document.createTextNode(self.text) - e.appendChild(p) - elif self.children is not None: - for c in self.children: - e.appendChild(c.render()) - return e + def __init__(self, text=None, color=None, style=None, children=None): + assert (text is not None) or (children is not None) + assert (color is None) or (isinstance(color, str)) + assert (style is None) or isinstance(style, TextStyle) + if text is not None: + assert isinstance(text, str) + if children is not None: + assert isinstance(children, (tuple, list)) + for c in children: + assert isinstance(c, TextSpan) + self.text = text + self.color = color + self.style = style + self.children = children + + def render(self): + style = {} + if self.style is not None: + style['font'] = str(self.style) + if self.style.letterSpacing is not None: + letterSpacing = self.style.letterSpacing + if isinstance(letterSpacing, int): + letterSpacing = f'{letterSpacing}px' + style['letter-spacing'] = letterSpacing + if self.style.fontStyle is not None: + style['font-style'] = self.style.fontStyle + if self.color is not None: + style['color'] = self.color + e = maketag('span', style=style) + if self.text is not None: + p = javascript.document.createTextNode(self.text) + e.appendChild(p) + elif self.children is not None: + for c in self.children: + e.appendChild(c.render()) + return e + class Center: - def __init__(self, child): - assert hasattr(child, 'render') and callable(child.render) - self.child = child - def render(self): - e = maketag('div', style={'display': 'flex', 'align-items': 'center', - 'justify-content': 'center', 'width': '100%', 'height': '100%'}) - e.appendChild(self.child.render()) - return e + def __init__(self, child): + assert hasattr(child, 'render') and callable(child.render) + self.child = child + + def render(self): + e = maketag('div', style={'display': 'flex', 'align-items': 'center', + 'justify-content': 'center', 'width': '100%', 'height': '100%'}) + e.appendChild(self.child.render()) + return e + class Stack: - def __init__(self, children): - assert isinstance(children, (tuple,list)) - for c in children: - assert isinstance(c, Positioned) - self.children = children - def render(self): - e = maketag('div',style={'position':'relative'}) - for c in self.children: - e.appendChild(c.render()) - return e + def __init__(self, children): + assert isinstance(children, (tuple, list)) + for c in children: + assert isinstance(c, Positioned) + self.children = children + + def render(self): + e = maketag('div', style={'position': 'relative'}) + for c in self.children: + e.appendChild(c.render()) + return e + class Positioned: - def __init__(self, child, left, top): - assert hasattr(child, 'render') and callable(child.render) - assert isinstance(left, (int, str)) - assert isinstance(top, (int, str)) - self.child = child - self.left = left - self.top = top - def render(self): - top = f'{self.top}px' if isinstance(self.top, int) else self.top - left = f'{self.left}px' if isinstance(self.left, int) else self.left - e = maketag('div', style={'position':'absolute','top':top,'left':left}) - e.appendChild(self.child.render()) - return e + def __init__(self, child, left, top): + assert hasattr(child, 'render') and callable(child.render) + assert isinstance(left, (int, str)) + assert isinstance(top, (int, str)) + self.child = child + self.left = left + self.top = top + + def render(self): + top = f'{self.top}px' if isinstance(self.top, int) else self.top + left = f'{self.left}px' if isinstance(self.left, int) else self.left + e = maketag('div', style={'position': 'absolute', 'top': top, 'left': left}) + e.appendChild(self.child.render()) + return e + class Transform: - def __init__(self, child, rotate=None, scale=None): - assert hasattr(child, 'render') and callable(child.render) - assert (rotate is None) or isinstance(rotate, (int, str)) - assert (scale is None) or isinstance(scale, float) - self.child = child - self.rotate = rotate - self.scale = scale - def render(self): - transform = [] - if self.rotate is not None: - rotate = f'{self.rotate}deg' if isinstance(self.rotate, int) else self.rotate - transform.append(f'rotate({rotate})') - if self.scale is not None: - transform.append(f'scale({self.scale})') - e = maketag('div') - if len(transform)>0: - e.style.transform = ' '.join(transform) - e.appendChild(self.child.render()) - return e - - -#https://www.cnblogs.com/hellocd/p/10443237.html - -class Axis: # flex-direction - horizontal = 'row' - vertical = 'column' - -class MainAxisAlignment: # justify-content - center = 'center' - end = 'flex-end' - spaceAround = 'space-around' - spaceBetween = 'space-between' - spaceEvenly = 'space-evenly' - start = 'flex-start' - -class CrossAxisAlignment: # align-items - baseline = 'baseline' - center = 'center' - end = 'end' - start = 'start' - stretch = 'stretch' + def __init__(self, child, rotate=None, scale=None): + assert hasattr(child, 'render') and callable(child.render) + assert (rotate is None) or isinstance(rotate, (int, str)) + assert (scale is None) or isinstance(scale, float) + self.child = child + self.rotate = rotate + self.scale = scale + + def render(self): + transform = [] + if self.rotate is not None: + rotate = f'{self.rotate}deg' if isinstance(self.rotate, int) else self.rotate + transform.append(f'rotate({rotate})') + if self.scale is not None: + transform.append(f'scale({self.scale})') + e = maketag('div') + if len(transform) > 0: + e.style.transform = ' '.join(transform) + e.appendChild(self.child.render()) + return e + + +# https://www.cnblogs.com/hellocd/p/10443237.html + +class Axis: # flex-direction + horizontal = 'row' + vertical = 'column' + + +class MainAxisAlignment: # justify-content + center = 'center' + end = 'flex-end' + spaceAround = 'space-around' + spaceBetween = 'space-between' + spaceEvenly = 'space-evenly' + start = 'flex-start' + + +class CrossAxisAlignment: # align-items + baseline = 'baseline' + center = 'center' + end = 'end' + start = 'start' + stretch = 'stretch' + class MainAxisSize: - max = 'max' - min = 'min' + max = 'max' + min = 'min' + class Flex: - def __init__(self, children, direction, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - assert isinstance(children, (tuple,list)) - for child in children: - assert hasattr(child, 'render') and callable(child.render), type(child).__name__ - self.children = children - assert direction in (Axis.horizontal, Axis.vertical) - assert mainAxisAlignment in (MainAxisAlignment.center, - MainAxisAlignment.end, - MainAxisAlignment.spaceAround, - MainAxisAlignment.spaceBetween, - MainAxisAlignment.spaceEvenly, - MainAxisAlignment.start) - assert crossAxisAlignment in (CrossAxisAlignment.baseline, - CrossAxisAlignment.center, - CrossAxisAlignment.end, - CrossAxisAlignment.start, - CrossAxisAlignment.stretch) - assert mainAxisSize in (MainAxisSize.max, - MainAxisSize.min) - self.direction = direction - self.mainAxisAlignment = mainAxisAlignment - self.crossAxisAlignment = crossAxisAlignment - self.mainAxisSize = mainAxisSize - def render(self): - style = {'display': 'flex', - 'flex-direction': self.direction, - 'flex-wrap': 'nowrap', - 'justify-content':self.mainAxisAlignment, - 'align-items':self.crossAxisAlignment} - if self.mainAxisSize==MainAxisSize.max: - if self.direction=='row': - style['width'] = '100%' - else: - style['height'] = '100%' - e = maketag('div', style=style) - for child in self.children: - e.appendChild(child.render()) - return e + def __init__(self, children, direction, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + assert isinstance(children, (tuple, list)) + for child in children: + assert hasattr(child, 'render') and callable(child.render), type(child).__name__ + self.children = children + assert direction in (Axis.horizontal, Axis.vertical) + assert mainAxisAlignment in (MainAxisAlignment.center, + MainAxisAlignment.end, + MainAxisAlignment.spaceAround, + MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceEvenly, + MainAxisAlignment.start) + assert crossAxisAlignment in (CrossAxisAlignment.baseline, + CrossAxisAlignment.center, + CrossAxisAlignment.end, + CrossAxisAlignment.start, + CrossAxisAlignment.stretch) + assert mainAxisSize in (MainAxisSize.max, + MainAxisSize.min) + self.direction = direction + self.mainAxisAlignment = mainAxisAlignment + self.crossAxisAlignment = crossAxisAlignment + self.mainAxisSize = mainAxisSize + + def render(self): + style = {'display': 'flex', + 'flex-direction': self.direction, + 'flex-wrap': 'nowrap', + 'justify-content': self.mainAxisAlignment, + 'align-items': self.crossAxisAlignment} + if self.mainAxisSize == MainAxisSize.max: + if self.direction == 'row': + style['width'] = '100%' + else: + style['height'] = '100%' + e = maketag('div', style=style) + for child in self.children: + e.appendChild(child.render()) + return e + class Row(Flex): - def __init__(self, children, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - super(Row, self).__init__(children, - direction=Axis.horizontal, - mainAxisAlignment=mainAxisAlignment, - crossAxisAlignment=crossAxisAlignment, - mainAxisSize=mainAxisSize) + def __init__(self, children, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + super(Row, self).__init__(children, + direction=Axis.horizontal, + mainAxisAlignment=mainAxisAlignment, + crossAxisAlignment=crossAxisAlignment, + mainAxisSize=mainAxisSize) + class Column(Flex): - def __init__(self, children, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - super(Column, self).__init__(children, - direction=Axis.vertical, - mainAxisAlignment=mainAxisAlignment, - crossAxisAlignment=crossAxisAlignment, - mainAxisSize=mainAxisSize) + def __init__(self, children, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + super(Column, self).__init__(children, + direction=Axis.vertical, + mainAxisAlignment=mainAxisAlignment, + crossAxisAlignment=crossAxisAlignment, + mainAxisSize=mainAxisSize) # 如何开发 MaterialDesignWidgets (用AppBar作为例子): @@ -480,81 +527,91 @@ class Column(Flex): # 3. 设计和实现各个需要的 Python 类: Scaffold, AppBar, IconButton, Icon, Icons class Scaffold: - def __init__(self, appBar, body): - if appBar is not None: - assert hasattr(appBar, 'render') and callable(appBar.render) - if body is not None: - assert hasattr(body, 'render') and callable(body.render) - self.appBar = appBar - self.body = body - def render(self): - e = maketag('div') - header = maketag('header', {'class':'mdc-top-app-bar'}) - e.appendChild(header) - main = maketag('header', {'class':'mdc-top-app-bar--fixed-adjust'}) - e.appendChild(main) - header.appendChild(self.appBar.render()) - main.appendChild(self.body.render()) - return e + def __init__(self, appBar, body): + if appBar is not None: + assert hasattr(appBar, 'render') and callable(appBar.render) + if body is not None: + assert hasattr(body, 'render') and callable(body.render) + self.appBar = appBar + self.body = body + + def render(self): + e = maketag('div') + header = maketag('header', {'class': 'mdc-top-app-bar'}) + e.appendChild(header) + main = maketag('header', {'class': 'mdc-top-app-bar--fixed-adjust'}) + e.appendChild(main) + header.appendChild(self.appBar.render()) + main.appendChild(self.body.render()) + return e + class AppBar: - def __init__(self, leading=None, title=None, actions=None): - if leading is not None: - assert hasattr(leading, 'render') and callable(leading.render) - if title is not None: - assert hasattr(title, 'render') and callable(title.render) - if actions is not None: - assert isinstance(actions, (tuple,list)) - for action in actions: - assert hasattr(action, 'render') and callable(action.render) - self.leading = leading - self.title = title - self.actions = actions - def render(self): - e = maketag('div', {'class':'mdc-top-app-bar__row'}) - start = maketag('header', {'class':'mdc-top-app-bar__section mdc-top-app-bar__section--align-start'}) - e.appendChild(start) - end = maketag('header', {'class':'mdc-top-app-bar__section mdc-top-app-bar__section--align-end', 'rule':'toolbar'}) - e.appendChild(end) - if self.leading is not None: - leading = self.leading.render() - add_class(leading, 'mdc-top-app-bar__navigation-icon') - start.appendChild(leading) - if self.title is not None: - title = self.title.render() - add_class(title, 'mdc-top-app-bar__title') - start.appendChild(title) - if self.actions is not None: - for action in self.actions: - action = action.render() - add_class(action, 'mdc-top-app-bar__action-item') - end.appendChild(action) - return e + def __init__(self, leading=None, title=None, actions=None): + if leading is not None: + assert hasattr(leading, 'render') and callable(leading.render) + if title is not None: + assert hasattr(title, 'render') and callable(title.render) + if actions is not None: + assert isinstance(actions, (tuple, list)) + for action in actions: + assert hasattr(action, 'render') and callable(action.render) + self.leading = leading + self.title = title + self.actions = actions + + def render(self): + e = maketag('div', {'class': 'mdc-top-app-bar__row'}) + start = maketag('header', {'class': 'mdc-top-app-bar__section mdc-top-app-bar__section--align-start'}) + e.appendChild(start) + end = maketag('header', + {'class': 'mdc-top-app-bar__section mdc-top-app-bar__section--align-end', 'rule': 'toolbar'}) + e.appendChild(end) + if self.leading is not None: + leading = self.leading.render() + add_class(leading, 'mdc-top-app-bar__navigation-icon') + start.appendChild(leading) + if self.title is not None: + title = self.title.render() + add_class(title, 'mdc-top-app-bar__title') + start.appendChild(title) + if self.actions is not None: + for action in self.actions: + action = action.render() + add_class(action, 'mdc-top-app-bar__action-item') + end.appendChild(action) + return e + class IconButton: - def __init__(self, icon, onPressed=None): - assert isinstance(icon, Icon) - if onPressed is not None: - assert callable(onPressed) - self.icon = icon - self.onPressed = onPressed - def render(self): - e = maketag('button', {'class':'material-icons mdc-top-app-bar__action-item mdc-icon-button'}) - e.appendChild(javascript.document.createTextNode(self.icon.icon)) - if self.onPressed is not None: - e.bind('click', self.onPressed) - return e + def __init__(self, icon, onPressed=None): + assert isinstance(icon, Icon) + if onPressed is not None: + assert callable(onPressed) + self.icon = icon + self.onPressed = onPressed + + def render(self): + e = maketag('button', {'class': 'material-icons mdc-top-app-bar__action-item mdc-icon-button'}) + e.appendChild(javascript.document.createTextNode(self.icon.icon)) + if self.onPressed is not None: + e.bind('click', self.onPressed) + return e + class Icon: - def __init__(self, icon): - assert isinstance(icon, str) - self.icon = icon - def render(self): - e = maketag('span', {'class':'material-icons'}) - e.appendChild(javascript.document.createTextNode(self.icon)) - return e + def __init__(self, icon): + assert isinstance(icon, str) + self.icon = icon + + def render(self): + e = maketag('span', {'class': 'material-icons'}) + e.appendChild(javascript.document.createTextNode(self.icon)) + return e + from . import flutter_icons + Icons = flutter_icons.Icons @@ -576,3 +633,58 @@ Icons = flutter_icons.Icons # https://material.io/components/tabs # https://material.io/components/text-fields # https://material.io/components/tooltips + +import time +# checkbox控件实现 +# class CheckboxFold: +# def __init__(self, column): +# if column is not None: +# assert hasattr(column, 'render') and callable(column.render) +# self.column = column +# +# def render(self): +# e = maketag('div', style={'background': 'orange'}) +# e.appendChild(self.column.render()) +# return e + + +class Checkbox: + def __init__(self, onChanged, tristate, value=False, activeColor=Colors.black): + assert isinstance(onChanged, (None, bool)) + if tristate is not None: + assert isinstance(tristate, bool) + if value is not None: + assert isinstance(value, bool) + if activeColor is not None: + assert isinstance(activeColor, str) + self.onChanged = onChanged + self.tristate = tristate + self.value = value + self.activeColor = activeColor + + def render(self): + e = maketag('div', {'class': 'mdc-form-field'}) + mdcCheckbox = maketag('div', {'class': 'mdc-checkbox'}) + e.appendChild(mdcCheckbox) + checkBoxId = 'checkbox-'+str(time.time()) + checkbox = maketag('input', {'class': 'mdc-checkbox__native-control', + 'type': 'checkbox', + 'id': checkBoxId}) + # if (self.onChanged == None): + # checkbox + mdcCheckbox.appendChild(checkbox) + mdcCheckboxBackground = maketag('div', {'class': 'mdc-checkbox__background'}) + mdcCheckbox.appendChild(mdcCheckboxBackground) + svg = maketag('svg', {'class': 'mdc-checkbox__checkmark', 'viewBox': '0 0 24 24'}) + mdcCheckboxBackground.appendChild(svg) + path = maketag('path', {'class': 'mdc-checkbox__checkmark-path', + 'fill': "none", 'd': 'M1.73,12.91 8.1,19.28 22.79,4.59'}) + svg.appendChild(path) + mdcCheckboxMixedmark = maketag('div', {'class': 'mdc-checkbox__mixedmark'}) + mdcCheckboxBackground.appendChild(mdcCheckboxMixedmark) + mdcCheckboxRipple = maketag('div', {'class': 'mdc-checkbox__ripple"'}) + mdcCheckbox.appendChild(mdcCheckboxRipple) + # label = maketag('label', {'for': checkBoxId}) + # label.appendChild(javascript.document.createTextNode(checkBoxId)) + # e.appendChild(label) + return e diff --git a/web/py_lib/flutter_test_3.py b/web/py_lib/flutter_test_3.py new file mode 100644 index 0000000..874709e --- /dev/null +++ b/web/py_lib/flutter_test_3.py @@ -0,0 +1,84 @@ +## 实现控件checkbox +from . import flutter + +TextStyle = flutter.TextStyle +Container = flutter.Container +Center = flutter.Center +Text = flutter.Text +Stack = flutter.Stack +Positioned = flutter.Positioned +Transform = flutter.Transform +LinearGradient = flutter.LinearGradient +Colors = flutter.Colors +TextAlign = flutter.TextAlign +EdgeInsets = flutter.EdgeInsets +FontWeight = flutter.FontWeight +FontStyle = flutter.FontStyle +BoxShadow = flutter.BoxShadow +BoxShape = flutter.BoxShape +RichText = flutter.RichText +TextSpan = flutter.TextSpan +TextOverflow = flutter.TextOverflow +BorderRadius = flutter.BorderRadius +Offset = flutter.Offset +Scaffold = flutter.Scaffold +AppBar = flutter.AppBar +IconButton = flutter.IconButton +Icon = flutter.Icon +Icons = flutter.Icons +Checkbox = flutter.Checkbox +CheckboxFold = flutter.CheckboxFold +Column = flutter.Column +Row = flutter.Row +MainAxisAlignment = flutter.MainAxisAlignment + + +# https://flutter.cn/docs/development/ui/widgets-intro +def 使用Material组件(): + return Scaffold( + appBar=AppBar( + leading=IconButton( + icon=Icon(Icons.menu), + onPressed=None, + ), + title=Text('Checkboxes demo'), + actions=[ + IconButton( + icon=Icon(Icons.search), + onPressed=None, + ), + ], + ), + # body is the majority of the screen. + body=Container( + width=312, + height=480-72, + color=Colors.white, + margin=EdgeInsets.symmetric(vertical=48), + child=Column(children=[ + Row( + children=[ + Checkbox( + # todo: else setState() + onChanged=None if i == 4 else False, + tristate=(i == 1), + value=False, + activeColor=Colors.argb('FF6200EE') + ), + Text( + f'Checkbox {i + 1}', + color=(Colors.black38 if i == 4 else Colors.black) + ) + ], + mainAxisAlignment=MainAxisAlignment.center + ) for i in range(5) + ] + ) + + ), + ) + + +def run_app(): + widget = 使用Material组件() + javascript.document.body.appendChild(widget.render()) -- Gitee From f2fefe5237146f7aa3d6a39221fda9c25d501138 Mon Sep 17 00:00:00 2001 From: mooganic <41576653+mooganic@users.noreply.github.com> Date: Tue, 19 Apr 2022 16:34:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0checkbox=E5=92=8Cswitch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/modules.xml | 8 + .idea/project-2.iml | 14 + .idea/vcs.xml | 6 + serv/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 134 bytes serv/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 142 bytes serv/__pycache__/__main__.cpython-36.pyc | Bin 0 -> 1711 bytes serv/__pycache__/__main__.cpython-38.pyc | Bin 0 -> 1733 bytes serv/lib/__pycache__/__init__.cpython-36.pyc | Bin 0 -> 138 bytes serv/lib/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 146 bytes serv/lib/__pycache__/http_.cpython-36.pyc | Bin 0 -> 15753 bytes serv/lib/__pycache__/http_.cpython-38.pyc | Bin 0 -> 15809 bytes serv/lib/__pycache__/path_.cpython-36.pyc | Bin 0 -> 1831 bytes serv/lib/__pycache__/path_.cpython-38.pyc | Bin 0 -> 1838 bytes web/main.py | 14 +- web/py_lib/flutter.py | 1061 ++++++++++-------- web/py_lib/flutter_test_3.py | 82 ++ web/py_lib/flutter_test_4.py | 76 ++ 18 files changed, 824 insertions(+), 445 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/project-2.iml create mode 100644 .idea/vcs.xml create mode 100644 serv/__pycache__/__init__.cpython-36.pyc create mode 100644 serv/__pycache__/__init__.cpython-38.pyc create mode 100644 serv/__pycache__/__main__.cpython-36.pyc create mode 100644 serv/__pycache__/__main__.cpython-38.pyc create mode 100644 serv/lib/__pycache__/__init__.cpython-36.pyc create mode 100644 serv/lib/__pycache__/__init__.cpython-38.pyc create mode 100644 serv/lib/__pycache__/http_.cpython-36.pyc create mode 100644 serv/lib/__pycache__/http_.cpython-38.pyc create mode 100644 serv/lib/__pycache__/path_.cpython-36.pyc create mode 100644 serv/lib/__pycache__/path_.cpython-38.pyc create mode 100644 web/py_lib/flutter_test_3.py create mode 100644 web/py_lib/flutter_test_4.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..21fb283 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project-2.iml b/.idea/project-2.iml new file mode 100644 index 0000000..d92223b --- /dev/null +++ b/.idea/project-2.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/serv/__pycache__/__init__.cpython-36.pyc b/serv/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ef279cb08bc35ba0c6ac717886391d5e7609712 GIT binary patch literal 134 zcmXr!<>fklGa`ur2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU&i{O#i>Qb`nie8 z`p!O?`FR0F`B|ySCB^y$5QeUiK2SlKetdjpUS>&ryk0@&Ee@O9{FKt1R6CGi#X!se E00l=M+5i9m literal 0 HcmV?d00001 diff --git a/serv/__pycache__/__init__.cpython-38.pyc b/serv/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d30c5646ab5d5fa304c50176187829acaaf9960 GIT binary patch literal 142 zcmWIL<>g`kg5x(Ml0fuh5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HqerR!OQL%n* zVzR!oPiB5zKv8~HYH~@jegTA`YorfUP^KRrpP83g5+AQuPm%*h-t?(ih_2kN-4&lR#9S;)mGC-+tM$E;3a9A{+COP=42|1ZfrT z`bt#Dslx02Dih3#OLe`**(l&_7{eZn*(!E93O)+fS?;YvNA76F`KqIb;!1X*<#>Hq zx7n6$mA$l+4}AU%Mk=rb{(r%ZTbn&Ahw9QnT%*tlyyu!Gs*D)6Hoah#v z+#R^0J2sO#Gi8yROrCvDy4snoc2?R>ktc`tnDfHQjbe~13K#3_gF$92R?ODBeYzMR zV5%<~nS>ifPi5Lg54YpIZ0kFwpTvzlIMF(9GHqJ@wB0)WK9Zf&MK^0((<-ORu~%Af zxZIMmkE2StRBpRSO6*-qK^MOO!FbF)zQF5zKbn3DGc%OP3Cx(H^fVO3M?UVE5k3lN z5Dv{?Wq5qqv~{PnCwoOZrE@QB>TKin!*t`FaY?cDydK~Ao=G0598Py3k@;L7E}^Rrd(-2M61?#*j= zzxn;%54U$dy@TbA0oB{l#_qL`VVTao));z68_k-F%2cO)Bi+Iq29zNL&uCo`$4!yD zpjV{IxH(<6LG+8@zuwk#rA}PRwv7wapkJC~aSzwuT|K)(_0X*Ch45Ld)z6SPNMeyf z`6z)TpnP&KxNc3!05~2zdUW=!+~>&JX4ojmd1KC_mHb7xoA zh6||XNddP$L^pcCTg@n`^*R?&U`V46BWY4km6FqEWO6H$s-6@?5*nK#C93L0c)7j^ib+Yu@LAv!$zMQ4W z+_LR;56-t9#0_c{4m7AKi>5S9u4^QOo}i&g>ZYipy;kQQcaOm=#d6k5$ZKdm+CyGtt|>~mKFXNY#1O4#{CBNw{>HE^YhW&pKfpcd}Z^?D_h^(`uEo#?)>rF=B=+96jauh`e|FHaW5$a zSaPZV^v*0qZv8Uax^eB!x4+;0@z&;Ne`0#0Pjord*t+%!Jmaxf8w2N1qggA1Jl1i~ z$a4C11F{fqC$!Fp-6l&*ubainl#@DdgW?y!e7&aWI!kdeSu>@l`n}vl2llZ1oyC(2 zR0+-6UKkHxt|l7kC#l_6$A@^J@a(t+1FQgTU4YDZZj^6b6^vYXx2X;jA|H?d2E+uIoZQ$ zE$RlBE(czVP9M2%oj4tdQzsWs52jJeRr$6)f*9WCt!5C_x}EbVEu_&6B#r8^QgZx= zR5w%AbX6FUZ)}W|sIKP_sSi?D&GE+bi7313Yib-$k4T~=1saNAxOGBdyXogK);abp zWA_xaW}s&wGy(81w|s{I)!tc61Ga5}924-K8T A*Z=?k literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/__init__.cpython-36.pyc b/serv/lib/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21fe8d4f62cf6c294fe0fb96c1e5a9b8d147a428 GIT binary patch literal 138 zcmXr!<>fklGa`ur2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CU*`Iu#i>Qb`nie8 z`p!O?`FR0F`B|ySCB^y$5QeUiK2SlKeokhRetdjpUS>&ryk0@&Ee@O9{FKt1R6CG? I#X!se0FgN%L;wH) literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/__init__.cpython-38.pyc b/serv/lib/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b39d1bc54d0298fcadaa6ece73bcbfe7e2756ae GIT binary patch literal 146 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 D`vsZB literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/path_.cpython-36.pyc b/serv/lib/__pycache__/path_.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3136d675a0b590156ceb3dc3b137836e3bc3b5cc GIT binary patch literal 1831 zcmcIkOK&4Z5bo}Icx)$5Hk)PT@LI%$kswCwYPm$KMJpB#D}!W^B40+fYn-$_iLLG? zTCW@l$@^#amvG_-Fjr2wA#vLiU$q^R1P<5)+PbLoVWbLrG5n2Uv6sD(UN zb49W#Aj78E71%dvccZ@5ukvm@G)vttCWEnsduVdF`@OTCF3M=AiyYn|d(*HCNe^5Z zywcNBO>9}QuIJ8%HVv>*(X+={cWdR!hB`0EX5C1i4ky_gVL0)(k6J(4+}PGhZ_s-7 zLQhV=H6SGHZq?nkFpkQq=C1Km};y+om-pW=Ql%bnV^D^qsTyD#7 zG|{K2EW@5TvL4G)B$!`DJeY04TxGT`Yszfn|61udGhe!IVQ^k!Wi}}4z#jSLStt|` z9yT-~^ z%{RvLG%yi%D?>ggW#zlh*TziDD)BNpnNa@Ef@n+HWGU8J?tdYbY@i$sY2L@*|C;m9 zf9GuW5X`&_amn+0?6|>mMO(f#vd=MgGusc~TW8Dd%BR;e%psQT9S yy<(VX&x6m;@WO6r^Xb*5^NjkNEjd6#{#4{o7?b5AmLy4(#7RA=CKdk%N$?kZB|%gG literal 0 HcmV?d00001 diff --git a/serv/lib/__pycache__/path_.cpython-38.pyc b/serv/lib/__pycache__/path_.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb8fed75ea5858b6fc7475cf38200216155f12f9 GIT binary patch literal 1838 zcmcIk&u<$=6rP#=;kBI~ZknnX3TjI$SP8nQLX<;P6;%`tl|gc=hP|w8zjd|u3@Ze%o7(BseHX%rm%tb6nk@Jg)CAs85EApuZ?NC5x4F3sK0aEYz_x z6({mY9mzvARV3R2(rt@%fxUxH?Db7{kjDN{SGu2%2O|UbP^WPBdwabsFTG)wr|=Hh z8@i=S*`O$$gKSc&u_Gzb3f%jl&^ zwTX6mgXrn=Y`puU9=}cpg^4DW@%h6D3-+Qs>qnDbv7J1a?3c}IbB;7&Zj28hqd>n;>R54dx`Lc@i__wEH2?e;i|Cz+eqmp zQeD``h>6@21tLM?5y}a3pOKu3A=6Ek*te|l;rF@{TLtAuu9agCHO?JG;g3Ij!J#~vEeN!a2 zF=199F2ZR^{Q*2zpfI)ewtWrb;8r1yLB)yWaykS-q@Ez?k$Q#laYdm<4gF9G?mr1~ zyJ8dX1E}$;!a5ay3X$>K@oeU34?C7FUzf7>L-$*)#~So8fY{p^Q+kz-%uuG25G#y* zp`?;4w(C3a{lBs6TR0*UZxOrx5T?G(Vj;=3%Y2xJRk055U;(RfZ^i5_8lRUzb^GF)fN7wh^yAlb% z7&a2FjI%hHX3(cPr(6g6V-_6gBJTQDTI>|rPMSQ%tl>K#r2Yi*zn;Sh`R8*2oMRus zZ?Np_7_JA+cRg%YY2g>qK0Nkz+Pby{qL~7V-iD_6$JjOL*gzHjoTrZ& Vj^X=1 - self.text = text - self.color = color - self.textAlign = textAlign - self.style = style - self.overflow = overflow - self.maxLines = maxLines - def render(self): - style = {} - if self.style is not None: - style['font'] = str(self.style) - if self.style.letterSpacing is not None: - letterSpacing = self.style.letterSpacing - if isinstance(letterSpacing, int): - letterSpacing = f'{letterSpacing}px' - style['letter-spacing'] = letterSpacing - if self.style.fontStyle is not None: - style['font-style'] = self.style.fontStyle - if self.color is not None: - style['color'] = self.color - if self.maxLines is not None: - style['overflow'] = 'hidden' - style['text-overflow'] = self.overflow - style['display'] = '-webkit-box' - style['-webkit-line-clamp'] = self.maxLines - style['-webkit-box-orient'] = 'vertical' - e = maketag('div', style=style) - p = javascript.document.createTextNode(self.text) - e.appendChild(p) - return e + def __init__(self, text, color=None, textAlign=None, style=None, + overflow=TextOverflow.clip, maxLines=None): + assert (textAlign is None) or (isinstance(textAlign, str)) + assert (style is None) or (isinstance(style, TextStyle)) + assert (color is None) or (isinstance(color, str)) + assert isinstance(overflow, str) + if maxLines is not None: + assert isinstance(maxLines, int) + assert maxLines >= 1 + self.text = text + self.color = color + self.textAlign = textAlign + self.style = style + self.overflow = overflow + self.maxLines = maxLines + + def render(self): + style = {} + if self.style is not None: + style['font'] = str(self.style) + if self.style.letterSpacing is not None: + letterSpacing = self.style.letterSpacing + if isinstance(letterSpacing, int): + letterSpacing = f'{letterSpacing}px' + style['letter-spacing'] = letterSpacing + if self.style.fontStyle is not None: + style['font-style'] = self.style.fontStyle + if self.color is not None: + style['color'] = self.color + if self.maxLines is not None: + style['overflow'] = 'hidden' + style['text-overflow'] = self.overflow + style['display'] = '-webkit-box' + style['-webkit-line-clamp'] = self.maxLines + style['-webkit-box-orient'] = 'vertical' + e = maketag('div', style=style) + p = javascript.document.createTextNode(self.text) + e.appendChild(p) + return e + class RichText: - def __init__(self, text): - assert isinstance(text, TextSpan) - self.text = text - def render(self): - return self.text.render() + def __init__(self, text): + assert isinstance(text, TextSpan) + self.text = text + + def render(self): + return self.text.render() + class TextSpan: - def __init__(self, text=None, color=None, style=None, children=None): - assert (text is not None) or (children is not None) - assert (color is None) or (isinstance(color, str)) - assert (style is None) or isinstance(style, TextStyle) - if text is not None: - assert isinstance(text, str) - if children is not None: - assert isinstance(children, (tuple,list)) - for c in children: - assert isinstance(c, TextSpan) - self.text = text - self.color = color - self.style = style - self.children = children - def render(self): - style = {} - if self.style is not None: - style['font'] = str(self.style) - if self.style.letterSpacing is not None: - letterSpacing = self.style.letterSpacing - if isinstance(letterSpacing, int): - letterSpacing = f'{letterSpacing}px' - style['letter-spacing'] = letterSpacing - if self.style.fontStyle is not None: - style['font-style'] = self.style.fontStyle - if self.color is not None: - style['color'] = self.color - e = maketag('span', style=style) - if self.text is not None: - p = javascript.document.createTextNode(self.text) - e.appendChild(p) - elif self.children is not None: - for c in self.children: - e.appendChild(c.render()) - return e + def __init__(self, text=None, color=None, style=None, children=None): + assert (text is not None) or (children is not None) + assert (color is None) or (isinstance(color, str)) + assert (style is None) or isinstance(style, TextStyle) + if text is not None: + assert isinstance(text, str) + if children is not None: + assert isinstance(children, (tuple, list)) + for c in children: + assert isinstance(c, TextSpan) + self.text = text + self.color = color + self.style = style + self.children = children + + def render(self): + style = {} + if self.style is not None: + style['font'] = str(self.style) + if self.style.letterSpacing is not None: + letterSpacing = self.style.letterSpacing + if isinstance(letterSpacing, int): + letterSpacing = f'{letterSpacing}px' + style['letter-spacing'] = letterSpacing + if self.style.fontStyle is not None: + style['font-style'] = self.style.fontStyle + if self.color is not None: + style['color'] = self.color + e = maketag('span', style=style) + if self.text is not None: + p = javascript.document.createTextNode(self.text) + e.appendChild(p) + elif self.children is not None: + for c in self.children: + e.appendChild(c.render()) + return e + class Center: - def __init__(self, child): - assert hasattr(child, 'render') and callable(child.render) - self.child = child - def render(self): - e = maketag('div', style={'display': 'flex', 'align-items': 'center', - 'justify-content': 'center', 'width': '100%', 'height': '100%'}) - e.appendChild(self.child.render()) - return e + def __init__(self, child): + assert hasattr(child, 'render') and callable(child.render) + self.child = child + + def render(self): + e = maketag('div', style={'display': 'flex', 'align-items': 'center', + 'justify-content': 'center', 'width': '100%', 'height': '100%'}) + e.appendChild(self.child.render()) + return e + class Stack: - def __init__(self, children): - assert isinstance(children, (tuple,list)) - for c in children: - assert isinstance(c, Positioned) - self.children = children - def render(self): - e = maketag('div',style={'position':'relative'}) - for c in self.children: - e.appendChild(c.render()) - return e + def __init__(self, children): + assert isinstance(children, (tuple, list)) + for c in children: + assert isinstance(c, Positioned) + self.children = children + + def render(self): + e = maketag('div', style={'position': 'relative'}) + for c in self.children: + e.appendChild(c.render()) + return e + class Positioned: - def __init__(self, child, left, top): - assert hasattr(child, 'render') and callable(child.render) - assert isinstance(left, (int, str)) - assert isinstance(top, (int, str)) - self.child = child - self.left = left - self.top = top - def render(self): - top = f'{self.top}px' if isinstance(self.top, int) else self.top - left = f'{self.left}px' if isinstance(self.left, int) else self.left - e = maketag('div', style={'position':'absolute','top':top,'left':left}) - e.appendChild(self.child.render()) - return e + def __init__(self, child, left, top): + assert hasattr(child, 'render') and callable(child.render) + assert isinstance(left, (int, str)) + assert isinstance(top, (int, str)) + self.child = child + self.left = left + self.top = top + + def render(self): + top = f'{self.top}px' if isinstance(self.top, int) else self.top + left = f'{self.left}px' if isinstance(self.left, int) else self.left + e = maketag('div', style={'position': 'absolute', 'top': top, 'left': left}) + e.appendChild(self.child.render()) + return e + class Transform: - def __init__(self, child, rotate=None, scale=None): - assert hasattr(child, 'render') and callable(child.render) - assert (rotate is None) or isinstance(rotate, (int, str)) - assert (scale is None) or isinstance(scale, float) - self.child = child - self.rotate = rotate - self.scale = scale - def render(self): - transform = [] - if self.rotate is not None: - rotate = f'{self.rotate}deg' if isinstance(self.rotate, int) else self.rotate - transform.append(f'rotate({rotate})') - if self.scale is not None: - transform.append(f'scale({self.scale})') - e = maketag('div') - if len(transform)>0: - e.style.transform = ' '.join(transform) - e.appendChild(self.child.render()) - return e - - -#https://www.cnblogs.com/hellocd/p/10443237.html - -class Axis: # flex-direction - horizontal = 'row' - vertical = 'column' - -class MainAxisAlignment: # justify-content - center = 'center' - end = 'flex-end' - spaceAround = 'space-around' - spaceBetween = 'space-between' - spaceEvenly = 'space-evenly' - start = 'flex-start' - -class CrossAxisAlignment: # align-items - baseline = 'baseline' - center = 'center' - end = 'end' - start = 'start' - stretch = 'stretch' + def __init__(self, child, rotate=None, scale=None): + assert hasattr(child, 'render') and callable(child.render) + assert (rotate is None) or isinstance(rotate, (int, str)) + assert (scale is None) or isinstance(scale, float) + self.child = child + self.rotate = rotate + self.scale = scale + + def render(self): + transform = [] + if self.rotate is not None: + rotate = f'{self.rotate}deg' if isinstance(self.rotate, int) else self.rotate + transform.append(f'rotate({rotate})') + if self.scale is not None: + transform.append(f'scale({self.scale})') + e = maketag('div') + if len(transform) > 0: + e.style.transform = ' '.join(transform) + e.appendChild(self.child.render()) + return e + + +# https://www.cnblogs.com/hellocd/p/10443237.html + +class Axis: # flex-direction + horizontal = 'row' + vertical = 'column' + + +class MainAxisAlignment: # justify-content + center = 'center' + end = 'flex-end' + spaceAround = 'space-around' + spaceBetween = 'space-between' + spaceEvenly = 'space-evenly' + start = 'flex-start' + + +class CrossAxisAlignment: # align-items + baseline = 'baseline' + center = 'center' + end = 'end' + start = 'start' + stretch = 'stretch' + class MainAxisSize: - max = 'max' - min = 'min' + max = 'max' + min = 'min' + class Flex: - def __init__(self, children, direction, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - assert isinstance(children, (tuple,list)) - for child in children: - assert hasattr(child, 'render') and callable(child.render), type(child).__name__ - self.children = children - assert direction in (Axis.horizontal, Axis.vertical) - assert mainAxisAlignment in (MainAxisAlignment.center, - MainAxisAlignment.end, - MainAxisAlignment.spaceAround, - MainAxisAlignment.spaceBetween, - MainAxisAlignment.spaceEvenly, - MainAxisAlignment.start) - assert crossAxisAlignment in (CrossAxisAlignment.baseline, - CrossAxisAlignment.center, - CrossAxisAlignment.end, - CrossAxisAlignment.start, - CrossAxisAlignment.stretch) - assert mainAxisSize in (MainAxisSize.max, - MainAxisSize.min) - self.direction = direction - self.mainAxisAlignment = mainAxisAlignment - self.crossAxisAlignment = crossAxisAlignment - self.mainAxisSize = mainAxisSize - def render(self): - style = {'display': 'flex', - 'flex-direction': self.direction, - 'flex-wrap': 'nowrap', - 'justify-content':self.mainAxisAlignment, - 'align-items':self.crossAxisAlignment} - if self.mainAxisSize==MainAxisSize.max: - if self.direction=='row': - style['width'] = '100%' - else: - style['height'] = '100%' - e = maketag('div', style=style) - for child in self.children: - e.appendChild(child.render()) - return e + def __init__(self, children, direction, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + assert isinstance(children, (tuple, list)) + for child in children: + assert hasattr(child, 'render') and callable(child.render), type(child).__name__ + self.children = children + assert direction in (Axis.horizontal, Axis.vertical) + assert mainAxisAlignment in (MainAxisAlignment.center, + MainAxisAlignment.end, + MainAxisAlignment.spaceAround, + MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceEvenly, + MainAxisAlignment.start) + assert crossAxisAlignment in (CrossAxisAlignment.baseline, + CrossAxisAlignment.center, + CrossAxisAlignment.end, + CrossAxisAlignment.start, + CrossAxisAlignment.stretch) + assert mainAxisSize in (MainAxisSize.max, + MainAxisSize.min) + self.direction = direction + self.mainAxisAlignment = mainAxisAlignment + self.crossAxisAlignment = crossAxisAlignment + self.mainAxisSize = mainAxisSize + + def render(self): + style = {'display': 'flex', + 'flex-direction': self.direction, + 'flex-wrap': 'nowrap', + 'justify-content': self.mainAxisAlignment, + 'align-items': self.crossAxisAlignment} + if self.mainAxisSize == MainAxisSize.max: + if self.direction == 'row': + style['width'] = '100%' + else: + style['height'] = '100%' + e = maketag('div', style=style) + for child in self.children: + e.appendChild(child.render()) + return e + class Row(Flex): - def __init__(self, children, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - super(Row, self).__init__(children, - direction=Axis.horizontal, - mainAxisAlignment=mainAxisAlignment, - crossAxisAlignment=crossAxisAlignment, - mainAxisSize=mainAxisSize) + def __init__(self, children, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + super(Row, self).__init__(children, + direction=Axis.horizontal, + mainAxisAlignment=mainAxisAlignment, + crossAxisAlignment=crossAxisAlignment, + mainAxisSize=mainAxisSize) + class Column(Flex): - def __init__(self, children, - mainAxisAlignment=MainAxisAlignment.start, - crossAxisAlignment=CrossAxisAlignment.center, - mainAxisSize=MainAxisSize.min): - super(Column, self).__init__(children, - direction=Axis.vertical, - mainAxisAlignment=mainAxisAlignment, - crossAxisAlignment=crossAxisAlignment, - mainAxisSize=mainAxisSize) + def __init__(self, children, + mainAxisAlignment=MainAxisAlignment.start, + crossAxisAlignment=CrossAxisAlignment.center, + mainAxisSize=MainAxisSize.min): + super(Column, self).__init__(children, + direction=Axis.vertical, + mainAxisAlignment=mainAxisAlignment, + crossAxisAlignment=crossAxisAlignment, + mainAxisSize=mainAxisSize) # 如何开发 MaterialDesignWidgets (用AppBar作为例子): @@ -480,83 +527,92 @@ class Column(Flex): # 3. 设计和实现各个需要的 Python 类: Scaffold, AppBar, IconButton, Icon, Icons class Scaffold: - def __init__(self, appBar, body): - if appBar is not None: - assert hasattr(appBar, 'render') and callable(appBar.render) - if body is not None: - assert hasattr(body, 'render') and callable(body.render) - self.appBar = appBar - self.body = body - def render(self): - e = maketag('div') - header = maketag('header', {'class':'mdc-top-app-bar'}) - e.appendChild(header) - main = maketag('header', {'class':'mdc-top-app-bar--fixed-adjust'}) - e.appendChild(main) - header.appendChild(self.appBar.render()) - main.appendChild(self.body.render()) - return e + def __init__(self, appBar, body): + if appBar is not None: + assert hasattr(appBar, 'render') and callable(appBar.render) + if body is not None: + assert hasattr(body, 'render') and callable(body.render) + self.appBar = appBar + self.body = body + + def render(self): + e = maketag('div') + header = maketag('header', {'class': 'mdc-top-app-bar'}) + e.appendChild(header) + main = maketag('header', {'class': 'mdc-top-app-bar--fixed-adjust'}) + e.appendChild(main) + header.appendChild(self.appBar.render()) + main.appendChild(self.body.render()) + return e + class AppBar: - def __init__(self, leading=None, title=None, actions=None): - if leading is not None: - assert hasattr(leading, 'render') and callable(leading.render) - if title is not None: - assert hasattr(title, 'render') and callable(title.render) - if actions is not None: - assert isinstance(actions, (tuple,list)) - for action in actions: - assert hasattr(action, 'render') and callable(action.render) - self.leading = leading - self.title = title - self.actions = actions - def render(self): - e = maketag('div', {'class':'mdc-top-app-bar__row'}) - start = maketag('header', {'class':'mdc-top-app-bar__section mdc-top-app-bar__section--align-start'}) - e.appendChild(start) - end = maketag('header', {'class':'mdc-top-app-bar__section mdc-top-app-bar__section--align-end', 'rule':'toolbar'}) - e.appendChild(end) - if self.leading is not None: - leading = self.leading.render() - add_class(leading, 'mdc-top-app-bar__navigation-icon') - start.appendChild(leading) - if self.title is not None: - title = self.title.render() - add_class(title, 'mdc-top-app-bar__title') - start.appendChild(title) - if self.actions is not None: - for action in self.actions: - action = action.render() - add_class(action, 'mdc-top-app-bar__action-item') - end.appendChild(action) - return e + def __init__(self, leading=None, title=None, actions=None): + if leading is not None: + assert hasattr(leading, 'render') and callable(leading.render) + if title is not None: + assert hasattr(title, 'render') and callable(title.render) + if actions is not None: + assert isinstance(actions, (tuple, list)) + for action in actions: + assert hasattr(action, 'render') and callable(action.render) + self.leading = leading + self.title = title + self.actions = actions + + def render(self): + e = maketag('div', {'class': 'mdc-top-app-bar__row'}) + start = maketag('header', {'class': 'mdc-top-app-bar__section mdc-top-app-bar__section--align-start'}) + e.appendChild(start) + end = maketag('header', + {'class': 'mdc-top-app-bar__section mdc-top-app-bar__section--align-end', 'rule': 'toolbar'}) + e.appendChild(end) + if self.leading is not None: + leading = self.leading.render() + add_class(leading, 'mdc-top-app-bar__navigation-icon') + start.appendChild(leading) + if self.title is not None: + title = self.title.render() + add_class(title, 'mdc-top-app-bar__title') + start.appendChild(title) + if self.actions is not None: + for action in self.actions: + action = action.render() + add_class(action, 'mdc-top-app-bar__action-item') + end.appendChild(action) + return e + class IconButton: - def __init__(self, icon, onPressed=None): - assert isinstance(icon, Icon) - if onPressed is not None: - assert callable(onPressed) - self.icon = icon - self.onPressed = onPressed - def render(self): - e = maketag('button', {'class':'material-icons mdc-top-app-bar__action-item mdc-icon-button'}) - e.appendChild(javascript.document.createTextNode(self.icon.icon)) - if self.onPressed is not None: - e.bind('click', self.onPressed) - return e + def __init__(self, icon, onPressed=None): + assert isinstance(icon, Icon) + if onPressed is not None: + assert callable(onPressed) + self.icon = icon + self.onPressed = onPressed + + def render(self): + e = maketag('button', {'class': 'material-icons mdc-top-app-bar__action-item mdc-icon-button'}) + e.appendChild(javascript.document.createTextNode(self.icon.icon)) + if self.onPressed is not None: + e.bind('click', self.onPressed) + return e + class Icon: - def __init__(self, icon): - assert isinstance(icon, str) - self.icon = icon - def render(self): - e = maketag('span', {'class':'material-icons'}) - e.appendChild(javascript.document.createTextNode(self.icon)) - return e + def __init__(self, icon): + assert isinstance(icon, str) + self.icon = icon + + def render(self): + e = maketag('span', {'class': 'material-icons'}) + e.appendChild(javascript.document.createTextNode(self.icon)) + return e + from . import flutter_icons -Icons = flutter_icons.Icons +Icons = flutter_icons.Icons # TODO # https://material.io/components/banners @@ -576,3 +632,122 @@ Icons = flutter_icons.Icons # https://material.io/components/tabs # https://material.io/components/text-fields # https://material.io/components/tooltips + +# checkbox控件 +import time + + +class Checkbox: + def __init__(self, onChanged, tristate, value=False, activeColor=Colors.black, id='checkbox'): + assert isinstance(onChanged, bool) + if tristate is not None: + assert isinstance(tristate, bool) + if value is not None: + assert isinstance(value, bool) + if activeColor is not None: + assert isinstance(activeColor, str) + assert isinstance(id, str) + self.onChanged = onChanged + self.tristate = tristate + self.value = value + self.activeColor = activeColor + if id == 'checkbox': + self.checkBoxId = 'checkbox-' + str(time.time()) + else: + self.checkBoxId = id + + def render(self): + e = maketag('div', {'class': 'mdc-form-field'}) + mdcCheckbox = maketag('div', {'class': 'mdc-checkbox mdc-checkbox--touch'}) + e.appendChild(mdcCheckbox) + checkbox = maketag('input', {'class': 'mdc-checkbox__native-control', + 'type': 'checkbox', + 'id': self.checkBoxId}, + {'color': self.activeColor}) + if not self.onChanged: + checkbox.setAttribute('disabled', 'true') + if self.value: + checkbox.setAttribute('checked', "true") + checkbox.setAttribute('data-indeterminate', "true" if self.tristate else "false") + mdcCheckbox.appendChild(checkbox) + mdcCheckboxBackground = maketag('div', {'class': 'mdc-checkbox__background'}) + mdcCheckbox.appendChild(mdcCheckboxBackground) + # todo: svg未正确作用 + svg = maketag('svg', {'class': 'mdc-checkbox__checkmark', 'viewBox': '0 0 24 24', + 'xmlns': 'http://www.w3.org/2000/svg', 'version': '1.1'}) + mdcCheckboxBackground.appendChild(svg) + path = maketag('path', {'class': 'mdc-checkbox__checkmark-path', + 'fill': "none", 'd': 'M1.73,12.91 8.1,19.28 22.79,4.59'}) + svg.appendChild(path) + mdcCheckboxMixedmark = maketag('div', {'class': 'mdc-checkbox__mixedmark'}) + mdcCheckboxBackground.appendChild(mdcCheckboxMixedmark) + mdcCheckboxRipple = maketag('div', {'class': 'mdc-checkbox__ripple"'}) + mdcCheckbox.appendChild(mdcCheckboxRipple) + return e + + +class Switch: + def __init__(self, onChanged, value=False, activeColor=Colors.black, id='switch'): + assert isinstance(onChanged, bool) + assert isinstance(value, bool) + assert isinstance(activeColor, str) + self.onChanged = onChanged + self.value = value + self.activeColor = activeColor + assert isinstance(id, str) + if id == 'switch': + self.switchId = 'switch-' + str(time.time()) + else: + self.switchId = id + + def render(self): + e = maketag('div', {'class': 'mdc-touch-target-wrapper'}, {'margin-top': '10px'}) + button = maketag('button', {'id': self.switchId, + 'class': 'mdc-switch mdc-switch--selected' if self.value + else 'mdc-switch mdc-switch--unselected', + 'type': 'button', + 'role': 'switch', 'aria-checked': 'true' if self.value else 'false'}, + {'color': self.activeColor}) + button.bind('mouseup', self.onClick) + if not self.onChanged: + button.setAttribute('disabled', 'true') + e.appendChild(button) + mdcSwitchTrack = maketag('div', {'class': 'mdc-switch__track'}) + button.appendChild(mdcSwitchTrack) + mdcSwitchHandleTrack = maketag('div', {'class': 'mdc-switch__handle-track'}) + button.appendChild(mdcSwitchHandleTrack) + mdcSwitchHandle = maketag('div', {'class': 'mdc-switch__handle'}) + mdcSwitchHandleTrack.appendChild(mdcSwitchHandle) + mdcSwitchShadow = maketag('div', {'class': 'mdc-switch__shadow'}) + mdcSwitchHandle.appendChild(mdcSwitchShadow) + mdcElevationOverlay = maketag('div', {'class': 'mdc-elevation-overlay'}) + mdcSwitchShadow.appendChild(mdcElevationOverlay) + mdcSwitchRipple = maketag('div', {'class': 'mdc-switch__ripple'}) + mdcSwitchHandle.appendChild(mdcSwitchRipple) + mdcSwitchIcons = maketag('div', {'class': 'mdc-switch__icons'}) + mdcSwitchHandle.appendChild(mdcSwitchIcons) + # todo: svg未正确作用 + svg1 = maketag('svg', {'class': 'mdc-switch__icon mdc-switch__icon--on', 'viewBox': '0 0 24 24', + 'xmlns': 'http://www.w3.org/2000/svg', 'version': '1.1'}) + path1 = maketag('path', {'d': 'M19.69,5.23L8.96,15.96l-4.23-4.23L2.96,13.5l6,6L21.46,7L19.69,5.23z'}) + svg2 = maketag('svg', {'class': 'mdc-switch__icon mdc-switch__icon--off', 'viewBox': '0 0 24 24', + 'xmlns': 'http://www.w3.org/2000/svg', 'version': '1.1'}) + path2 = maketag('path', {'d': 'M20 13H4v-2h16v2z'}) + mdcSwitchIcons.appendChild(svg1) + mdcSwitchIcons.appendChild(svg2) + svg1.appendChild(path1) + svg2.appendChild(path2) + # label = maketag('label', {'for': self.switchId}) + # labelText = javascript.document.createTextNode('off/on') + # e.appendChild(label) + # label.appendChild(labelText) + return e + + def onClick(self, event): + elt = javascript.document.getElementById(self.switchId) + elt.setAttribute('aria-checked', 'false' if elt.getAttribute('aria-checked').data() == 'true' else 'true') + elt.classList.toggle('mdc-switch--selected') + elt.classList.toggle('mdc-switch--unselected') + + + diff --git a/web/py_lib/flutter_test_3.py b/web/py_lib/flutter_test_3.py new file mode 100644 index 0000000..9f683f3 --- /dev/null +++ b/web/py_lib/flutter_test_3.py @@ -0,0 +1,82 @@ +## 实现控件checkbox +from . import flutter + +TextStyle = flutter.TextStyle +Container = flutter.Container +Center = flutter.Center +Text = flutter.Text +Stack = flutter.Stack +Positioned = flutter.Positioned +Transform = flutter.Transform +LinearGradient = flutter.LinearGradient +Colors = flutter.Colors +TextAlign = flutter.TextAlign +EdgeInsets = flutter.EdgeInsets +FontWeight = flutter.FontWeight +FontStyle = flutter.FontStyle +BoxShadow = flutter.BoxShadow +BoxShape = flutter.BoxShape +RichText = flutter.RichText +TextSpan = flutter.TextSpan +TextOverflow = flutter.TextOverflow +BorderRadius = flutter.BorderRadius +Offset = flutter.Offset +Scaffold = flutter.Scaffold +AppBar = flutter.AppBar +IconButton = flutter.IconButton +Icon = flutter.Icon +Icons = flutter.Icons +Checkbox = flutter.Checkbox +Column = flutter.Column +Row = flutter.Row +MainAxisAlignment = flutter.MainAxisAlignment +Switch = flutter.Switch + + +# https://flutter.cn/docs/development/ui/widgets-intro +def 使用Material组件(): + children_list = [ + Row(children=[ + Checkbox( + onChanged=False if i == 4 else True, + tristate=(i == 1), + value=True if i in (0, 1, 4) else False, + # todo: activeColor未正确作用 + activeColor=Colors.argb("FF6200EE"), + id=f'checkbox-{i}' + ), + Text( + f'Checkbox {i + 1}', + color=(Colors.black38 if i == 4 else Colors.black)) + ], + mainAxisAlignment=MainAxisAlignment.center + ) for i in range(5) + ] + return Scaffold( + appBar=AppBar( + leading=IconButton( + icon=Icon(Icons.menu), + onPressed=None, + ), + title=Text('Checkboxes demo'), + actions=[ + IconButton( + icon=Icon(Icons.search), + onPressed=None, + ), + ], + ), + # body is the majority of the screen. + body=Container( + width=312, + height=480 - 72, + color=Colors.white, + # margin=EdgeInsets.symmetric(vertical=48), + child=Column(children=children_list) + ), + ) + + +def run_app(): + widget = 使用Material组件() + javascript.document.body.appendChild(widget.render()) diff --git a/web/py_lib/flutter_test_4.py b/web/py_lib/flutter_test_4.py new file mode 100644 index 0000000..e2dc86f --- /dev/null +++ b/web/py_lib/flutter_test_4.py @@ -0,0 +1,76 @@ +## 实现控件switch +from . import flutter + +TextStyle = flutter.TextStyle +Container = flutter.Container +Center = flutter.Center +Text = flutter.Text +Stack = flutter.Stack +Positioned = flutter.Positioned +Transform = flutter.Transform +LinearGradient = flutter.LinearGradient +Colors = flutter.Colors +TextAlign = flutter.TextAlign +EdgeInsets = flutter.EdgeInsets +FontWeight = flutter.FontWeight +FontStyle = flutter.FontStyle +BoxShadow = flutter.BoxShadow +BoxShape = flutter.BoxShape +RichText = flutter.RichText +TextSpan = flutter.TextSpan +TextOverflow = flutter.TextOverflow +BorderRadius = flutter.BorderRadius +Offset = flutter.Offset +Scaffold = flutter.Scaffold +AppBar = flutter.AppBar +IconButton = flutter.IconButton +Icon = flutter.Icon +Icons = flutter.Icons +Checkbox = flutter.Checkbox +Column = flutter.Column +Row = flutter.Row +MainAxisAlignment = flutter.MainAxisAlignment +Switch = flutter.Switch + + +# https://flutter.cn/docs/development/ui/widgets-intro +def 使用Material组件(): + children_list = [ + Row(children=[ + Switch( + value=True if (i in (0, 2)) else False, + activeColor=Colors.argb('FF6200EE'), + onChanged=False if i == 4 else True, + id=f'switch-{i}', + ), + Text(text=f'Switch{i + 1}') + ]) for i in range(5) + ] + return Scaffold( + appBar=AppBar( + leading=IconButton( + icon=Icon(Icons.menu), + onPressed=None, + ), + title=Text('Switches demo'), + actions=[ + IconButton( + icon=Icon(Icons.search), + onPressed=None, + ), + ], + ), + # body is the majority of the screen. + body=Container( + width=312, + height=480 - 72, + color=Colors.white, + # margin=EdgeInsets.symmetric(vertical=48), + child=Column(children=children_list) + ), + ) + + +def run_app(): + widget = 使用Material组件() + javascript.document.body.appendChild(widget.render()) -- Gitee