├── .gitignore
├── LICENSE
├── README.md
├── index.grid.html
├── index.html
├── index.raw.html
└── src
├── apis.js
├── compiler.js
├── data.js
├── gen_apis_js.py
├── lvgl_mp.js
├── main.js
├── template.js
├── utils.js
└── wrapper.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # walv
2 | An Online, WYSIWYG GUI designer for LittlevGL. Cross-platform supported(Even Android and IOS).
3 | ## [Try it online!](https://kaiakz.github.io/walv/index.html)
4 | Make sure your browser is the latest version(Chrome, Firefox and Safari).
5 |
6 | 
7 | 
8 |
9 | ## Usage
10 | You need a browser firstly(Recommends PC with 1920x1080), and then visit [the github page](https://kaiakz.github.io/walv/index.html) or just run an HTTP server(`python -m http.server`) that serves files from this directory.
11 | ### Create
12 | 1. Click a node of the treeview in the left(as the parent), for example, `screen`.
13 | 2. Choose which widget you want, and then click the `+`.
14 | ### Generat && Export the final code
15 | 1. Click the `Generate` button to generate the source code, you can preview and edit the code in Code Editor. (You need to re-generate after modifying the widget)
16 | 2. Click the `Export` button, you can download the code in Code Editor.
17 |
18 | ## Feature
19 | * WYSIWYG, MVVM(attribute).
20 | * Just a **static** web app, you need to use it with **the latest browser**(FireFox, Chrome...even IOS Safari).
21 | * Drag and drop to control the postion of the widget.
22 | * Choose an object as the parent, and then create children on it.
23 | * Set attribute(postion, size, click, etc).
24 | * Style Editor(initial, now for text only).
25 | * Screenshot.
26 | * Code Preview.
27 | * Highlight(initial).
28 | * TFT_simulator can be customized(size), supports mutiple windows.(To do)
29 | * Animation Editor(planning).
30 | * Save and load project. The tool will save your project automatically, and could restore your work from the last closed window.
31 | * Generate C and MicroPython code: includes GUI and Callback.
32 |
33 | ## Architecture
34 | * A static webpage built with [lv_micropython](https://github.com/littlevgl/lv_micropython)(WASM) and front-end component library, so walv won't send your data to the server.
35 | * WASM part provides a Simulator.
36 | * The front-end component library provides a way to control Simulator: create,delete or modify a widget. Include attribute editor, style editor and animation editor.
37 | * Generate final code by javascript, Use `Blob` to save file.
38 | * Continue your work in last closed window: By `IndexedDB`.
39 |
40 | ## How does it work?
41 | * `lv_micropython` has some JavaScript API: `mp_js_do_str()`(`lv_micropython` will excute the parameter, just like eval() in Python or JavaScript)
42 | * walv wraps some commonly used functions(see Getter & Setter), called `template`.
43 | * walv provides a layer over the `lv_micropython`, it can generate some real functions by `template`, and then send those functions to `lv_micropython` by `mp_js_do_str`. For example, if the user want to change the X of the btn0 to 88 , walv will use the `template` (id.set_x(integer)) to generate the `btn0.set_x(88)`, and then send it to lv_micropython by `mp_js_do_str("btn0.set_x(88)")`.
44 |
45 | ## Alibaba Summer of Code 2019 : [AliOS-Things](https://github.com/alibaba/AliOS-Things/)
46 | ### Old : [lv_gui_designer](https://github.com/kaiakz/lv_gui_designer)
47 |
--------------------------------------------------------------------------------
/index.grid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | {{ checkedNode.id }}
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | REPL Terminal
121 |
122 |
123 | X: {{cursorX}}, Y: {{cursorY}} Size: 480x320
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 | Style
136 | Animation
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | {{ currentWidget.id }}
147 |
148 |
149 |
150 | CB
151 |
152 |
153 |
154 |
155 |
156 |
157 | X
158 |
159 |
160 | .
161 |
162 |
163 | Y
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | W
177 |
178 |
179 | -
180 |
181 |
182 | H
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | DRAG
192 |
193 |
194 | CLICK
195 |
196 |
197 | HIDDEN
198 |
199 |
200 | TOP
201 |
202 |
203 |
204 |
205 |
208 |
209 |
210 |
211 |
217 |
218 | Body
219 |
220 |
221 |
222 | Text
223 |
224 |
225 |
226 |
227 | font_roboto_16
228 | font_roboto_28
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {{ checkedNode.id }}
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | REPL Terminal
118 |
119 |
120 | X: {{cursorX}}, Y: {{cursorY}} Size: 480x320
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | Style
133 | Animation
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | {{ currentWidget.id }}
144 |
145 |
146 |
147 | CB
148 |
149 |
150 |
151 |
152 | X:
153 |
154 |
155 |
156 | Y:
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 | W:
166 |
167 |
168 |
169 | H:
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 | DRAG
180 |
181 |
182 | CLICK
183 |
184 |
185 |
186 |
187 | HIDDEN
188 |
189 |
190 | TOP
191 |
192 |
193 |
194 |
195 |
198 |
199 |
200 |
201 |
207 |
208 | Body
209 |
210 |
211 |
212 | Text
213 |
214 |
215 |
216 |
217 | font_roboto_16
218 | font_roboto_28
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
--------------------------------------------------------------------------------
/index.raw.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {{ checkedNode.id }}
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | REPL Terminal
118 |
119 |
120 | X: {{cursorX}}, Y: {{cursorY}}
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | Style
133 | Animation
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | {{ currentWidget.id }}
143 |
144 |
145 |
146 | CB
147 |
148 |
149 |
150 |
151 | X
152 |
153 |
154 | .
155 |
156 |
157 | Y
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 | W
166 |
167 |
168 | -
169 |
170 |
171 | H
172 |
173 |
174 |
175 |
176 |
177 |
178 | DRAG
179 |
180 |
181 | CLICK
182 |
183 |
184 | HIDDEN
185 |
186 |
187 | TOP
188 |
189 |
190 |
191 |
192 |
{{ name }}({{ setArgs(body.args) }})
193 |
194 |
195 |
196 |
197 |
203 |
204 | Body
205 |
206 |
207 |
208 | Text
209 |
210 |
211 |
212 |
213 | font_roboto_16
214 | font_roboto_28
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
--------------------------------------------------------------------------------
/src/apis.js:
--------------------------------------------------------------------------------
1 | const setter = {null:{}, "cont": {"fit": {"return_type": "NoneType", "args": [{"type": "int", "name": "fit"}], "type": "function", "api": "set_fit"}, "fit4": {"return_type": "NoneType", "args": [{"type": "int", "name": "left"}, {"type": "int", "name": "right"}, {"type": "int", "name": "top"}, {"type": "int", "name": "bottom"}], "type": "function", "api": "set_fit4"}, "fit2": {"return_type": "NoneType", "args": [{"type": "int", "name": "hor"}, {"type": "int", "name": "ver"}], "type": "function", "api": "set_fit2"}, "layout": {"return_type": "NoneType", "args": [{"type": "int", "name": "layout"}], "type": "function", "api": "set_layout"}}, "tileview": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "tile_act": {"return_type": "NoneType", "args": [{"type": "int", "name": "x"}, {"type": "int", "name": "y"}, {"type": "int", "name": "anim"}], "type": "function", "api": "set_tile_act"}, "edge_flash": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_edge_flash"}, "valid_positions": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_lv_point_t_____", "name": "valid_pos"}, {"type": "int", "name": "valid_pos_cnt"}], "type": "function", "api": "set_valid_positions"}}, "cb": {"checked": {"return_type": "NoneType", "args": [{"type": "bool", "name": "checked"}], "type": "function", "api": "set_checked"}, "text": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_text"}, "inactive": {"return_type": "NoneType", "args": [], "type": "function", "api": "set_inactive"}, "static_text": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_static_text"}}, "arc": {"angles": {"return_type": "NoneType", "args": [{"type": "int", "name": "start"}, {"type": "int", "name": "end"}], "type": "function", "api": "set_angles"}}, "gauge": {"scale": {"return_type": "NoneType", "args": [{"type": "int", "name": "angle"}, {"type": "int", "name": "line_cnt"}, {"type": "int", "name": "label_cnt"}], "type": "function", "api": "set_scale"}, "range": {"return_type": "NoneType", "args": [{"type": "int", "name": "min"}, {"type": "int", "name": "max"}], "type": "function", "api": "set_range"}, "needle_count": {"return_type": "NoneType", "args": [{"type": "int", "name": "needle_cnt"}, {"type": "mp_arr_to_lv_color_t_____", "name": "colors"}], "type": "function", "api": "set_needle_count"}, "value": {"return_type": "NoneType", "args": [{"type": "int", "name": "needle_id"}, {"type": "int", "name": "value"}], "type": "function", "api": "set_value"}, "critical_value": {"return_type": "NoneType", "args": [{"type": "int", "name": "value"}], "type": "function", "api": "set_critical_value"}}, "table": {"cell_align": {"return_type": "NoneType", "args": [{"type": "int", "name": "row"}, {"type": "int", "name": "col"}, {"type": "int", "name": "align"}], "type": "function", "api": "set_cell_align"}, "cell_value": {"return_type": "NoneType", "args": [{"type": "int", "name": "row"}, {"type": "int", "name": "col"}, {"type": "str", "name": "txt"}], "type": "function", "api": "set_cell_value"}, "col_cnt": {"return_type": "NoneType", "args": [{"type": "int", "name": "col_cnt"}], "type": "function", "api": "set_col_cnt"}, "cell_crop": {"return_type": "NoneType", "args": [{"type": "int", "name": "row"}, {"type": "int", "name": "col"}, {"type": "bool", "name": "crop"}], "type": "function", "api": "set_cell_crop"}, "cell_merge_right": {"return_type": "NoneType", "args": [{"type": "int", "name": "row"}, {"type": "int", "name": "col"}, {"type": "bool", "name": "en"}], "type": "function", "api": "set_cell_merge_right"}, "col_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "col_id"}, {"type": "int", "name": "w"}], "type": "function", "api": "set_col_width"}, "cell_type": {"return_type": "NoneType", "args": [{"type": "int", "name": "row"}, {"type": "int", "name": "col"}, {"type": "int", "name": "type"}], "type": "function", "api": "set_cell_type"}, "row_cnt": {"return_type": "NoneType", "args": [{"type": "int", "name": "row_cnt"}], "type": "function", "api": "set_row_cnt"}}, "calendar": {"highlighted_dates": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_lv_calendar_date_t_____", "name": "highlighted"}, {"type": "int", "name": "date_num"}], "type": "function", "api": "set_highlighted_dates"}, "showed_date": {"return_type": "NoneType", "args": [{"type": "calendar_date_t", "name": "showed"}], "type": "function", "api": "set_showed_date"}, "day_names": {"return_type": "NoneType", "args": [{"type": "pointer", "name": "day_names"}], "type": "function", "api": "set_day_names"}, "month_names": {"return_type": "NoneType", "args": [{"type": "pointer", "name": "month_names"}], "type": "function", "api": "set_month_names"}, "today_date": {"return_type": "NoneType", "args": [{"type": "calendar_date_t", "name": "today"}], "type": "function", "api": "set_today_date"}}, "btn": {"ink_wait_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_ink_wait_time"}, "fit": {"return_type": "NoneType", "args": [{"type": "int", "name": "fit"}], "type": "function", "api": "set_fit"}, "toggle": {"return_type": "NoneType", "args": [{"type": "bool", "name": "tgl"}], "type": "function", "api": "set_toggle"}, "ink_in_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_ink_in_time"}, "ink_out_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_ink_out_time"}, "state": {"return_type": "NoneType", "args": [{"type": "int", "name": "state"}], "type": "function", "api": "set_state"}, "fit4": {"return_type": "NoneType", "args": [{"type": "int", "name": "left"}, {"type": "int", "name": "right"}, {"type": "int", "name": "top"}, {"type": "int", "name": "bottom"}], "type": "function", "api": "set_fit4"}, "fit2": {"return_type": "NoneType", "args": [{"type": "int", "name": "hor"}, {"type": "int", "name": "ver"}], "type": "function", "api": "set_fit2"}, "layout": {"return_type": "NoneType", "args": [{"type": "int", "name": "layout"}], "type": "function", "api": "set_layout"}}, "btnm": {"pressed": {"return_type": "NoneType", "args": [{"type": "int", "name": "id"}], "type": "function", "api": "set_pressed"}, "btn_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "btn_id"}, {"type": "int", "name": "width"}], "type": "function", "api": "set_btn_width"}, "ctrl_map": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_lv_btnm_ctrl_t_____", "name": "ctrl_map"}], "type": "function", "api": "set_ctrl_map"}, "map": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_char_ptr____", "name": "map"}], "type": "function", "api": "set_map"}, "btn_ctrl": {"return_type": "NoneType", "args": [{"type": "int", "name": "btn_id"}, {"type": "int", "name": "ctrl"}], "type": "function", "api": "set_btn_ctrl"}, "one_toggle": {"return_type": "NoneType", "args": [{"type": "bool", "name": "one_toggle"}], "type": "function", "api": "set_one_toggle"}, "recolor": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_recolor"}, "btn_ctrl_all": {"return_type": "NoneType", "args": [{"type": "int", "name": "ctrl"}], "type": "function", "api": "set_btn_ctrl_all"}}, "canvas": {"buffer": {"return_type": "NoneType", "args": [{"type": "pointer", "name": "buf"}, {"type": "int", "name": "w"}, {"type": "int", "name": "h"}, {"type": "int", "name": "cf"}], "type": "function", "api": "set_buffer"}, "palette": {"return_type": "NoneType", "args": [{"type": "int", "name": "id"}, {"type": "color32_t", "name": "c"}], "type": "function", "api": "set_palette"}, "px": {"return_type": "NoneType", "args": [{"type": "int", "name": "x"}, {"type": "int", "name": "y"}, {"type": "color32_t", "name": "c"}], "type": "function", "api": "set_px"}}, "img": {"src": {"return_type": "NoneType", "args": [{"type": "pointer", "name": "src_img"}], "type": "function", "api": "set_src"}, "offx": {"return_type": "NoneType", "args": [{"type": "int", "name": "x"}], "type": "function", "api": "set_offset_x"}, "offy": {"return_type": "NoneType", "args": [{"type": "int", "name": "y"}], "type": "function", "api": "set_offset_y"}, "auto_size": {"return_type": "NoneType", "args": [{"type": "bool", "name": "autosize_en"}], "type": "function", "api": "set_auto_size"}}, "label": {"array_text": {"return_type": "NoneType", "args": [{"type": "str", "name": "array"}, {"type": "int", "name": "size"}], "type": "function", "api": "set_array_text"}, "text_sel_end": {"return_type": "NoneType", "args": [{"type": "int", "name": "index"}], "type": "function", "api": "set_text_sel_end"}, "long_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "long_mode"}], "type": "function", "api": "set_long_mode"}, "text_sel_start": {"return_type": "NoneType", "args": [{"type": "int", "name": "index"}], "type": "function", "api": "set_text_sel_start"}, "text_fmt": {"return_type": "NoneType", "args": [{"type": "str", "name": "fmt"}], "type": "function", "api": "set_text_fmt"}, "anim_speed": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_speed"}], "type": "function", "api": "set_anim_speed"}, "body_draw": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_body_draw"}, "recolor": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_recolor"}, "text": {"return_type": "NoneType", "args": [{"type": "str", "name": "text"}], "type": "function", "api": "set_text"}, "align": {"return_type": "NoneType", "args": [{"type": "int", "name": "align"}], "type": "function", "api": "set_align"}, "static_text": {"return_type": "NoneType", "args": [{"type": "str", "name": "text"}], "type": "function", "api": "set_static_text"}}, "sw": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}}, "ddlist": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "stay_open": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_stay_open"}, "fix_height": {"return_type": "NoneType", "args": [{"type": "int", "name": "h"}], "type": "function", "api": "set_fix_height"}, "draw_arrow": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_draw_arrow"}, "fix_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "w"}], "type": "function", "api": "set_fix_width"}, "selected": {"return_type": "NoneType", "args": [{"type": "int", "name": "sel_opt"}], "type": "function", "api": "set_selected"}, "sb_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "mode"}], "type": "function", "api": "set_sb_mode"}, "options": {"return_type": "NoneType", "args": [{"type": "str", "name": "options"}], "type": "function", "api": "set_options"}, "align": {"return_type": "NoneType", "args": [{"type": "int", "name": "align"}], "type": "function", "api": "set_align"}}, "win": {"btn_size": {"return_type": "NoneType", "args": [{"type": "int", "name": "size"}], "type": "function", "api": "set_btn_size"}, "anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "content_size": {"return_type": "NoneType", "args": [{"type": "int", "name": "w"}, {"type": "int", "name": "h"}], "type": "function", "api": "set_content_size"}, "layout": {"return_type": "NoneType", "args": [{"type": "int", "name": "layout"}], "type": "function", "api": "set_layout"}, "title": {"return_type": "NoneType", "args": [{"type": "str", "name": "title"}], "type": "function", "api": "set_title"}, "sb_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "sb_mode"}], "type": "function", "api": "set_sb_mode"}}, "lmeter": {"scale": {"return_type": "NoneType", "args": [{"type": "int", "name": "angle"}, {"type": "int", "name": "line_cnt"}], "type": "function", "api": "set_scale"}, "range": {"return_type": "NoneType", "args": [{"type": "int", "name": "min"}, {"type": "int", "name": "max"}], "type": "function", "api": "set_range"}, "value": {"return_type": "NoneType", "args": [{"type": "int", "name": "value"}], "type": "function", "api": "set_value"}, "angle_offset": {"return_type": "NoneType", "args": [{"type": "int", "name": "angle"}], "type": "function", "api": "set_angle_offset"}}, "ta": {"max_length": {"return_type": "NoneType", "args": [{"type": "int", "name": "num"}], "type": "function", "api": "set_max_length"}, "pwd_show_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_pwd_show_time"}, "placeholder_text": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_placeholder_text"}, "text_align": {"return_type": "NoneType", "args": [{"type": "int", "name": "align"}], "type": "function", "api": "set_text_align"}, "cursor_pos": {"return_type": "NoneType", "args": [{"type": "int", "name": "pos"}], "type": "function", "api": "set_cursor_pos"}, "text": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_text"}, "sb_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "mode"}], "type": "function", "api": "set_sb_mode"}, "one_line": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_one_line"}, "cursor_blink_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_cursor_blink_time"}, "text_sel": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_text_sel"}, "cursor_click_pos": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_cursor_click_pos"}, "scroll_propagation": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_scroll_propagation"}, "accepted_chars": {"return_type": "NoneType", "args": [{"type": "str", "name": "list"}], "type": "function", "api": "set_accepted_chars"}, "pwd_mode": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_pwd_mode"}, "edge_flash": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_edge_flash"}, "insert_replace": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_insert_replace"}, "cursor_type": {"return_type": "NoneType", "args": [{"type": "int", "name": "cur_type"}], "type": "function", "api": "set_cursor_type"}}, "preload": {"spin_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "time"}], "type": "function", "api": "set_spin_time"}, "dir": {"return_type": "NoneType", "args": [{"type": "int", "name": "dir"}], "type": "function", "api": "set_dir"}, "arc_length": {"return_type": "NoneType", "args": [{"type": "int", "name": "deg"}], "type": "function", "api": "set_arc_length"}, "type": {"return_type": "NoneType", "args": [{"type": "int", "name": "type"}], "type": "function", "api": "set_type"}}, "led": {"bright": {"return_type": "NoneType", "args": [{"type": "int", "name": "bright"}], "type": "function", "api": "set_bright"}}, "spinbox": {"range": {"return_type": "NoneType", "args": [{"type": "int", "name": "range_min"}, {"type": "int", "name": "range_max"}], "type": "function", "api": "set_range"}, "value": {"return_type": "NoneType", "args": [{"type": "int", "name": "i"}], "type": "function", "api": "set_value"}, "padding_left": {"return_type": "NoneType", "args": [{"type": "int", "name": "padding"}], "type": "function", "api": "set_padding_left"}, "step": {"return_type": "NoneType", "args": [{"type": "int", "name": "step"}], "type": "function", "api": "set_step"}, "digit_format": {"return_type": "NoneType", "args": [{"type": "int", "name": "digit_count"}, {"type": "int", "name": "separator_position"}], "type": "function", "api": "set_digit_format"}}, "chart": {"margin": {"return_type": "NoneType", "args": [{"type": "int", "name": "margin"}], "type": "function", "api": "set_margin"}, "secondary_y_tick_length": {"return_type": "NoneType", "args": [{"type": "int", "name": "major_tick_len"}, {"type": "int", "name": "minor_tick_len"}], "type": "function", "api": "set_secondary_y_tick_length"}, "next": {"return_type": "NoneType", "args": [{"type": "chart_series_t", "name": "ser"}, {"type": "int", "name": "y"}], "type": "function", "api": "set_next"}, "series_opa": {"return_type": "NoneType", "args": [{"type": "int", "name": "opa"}], "type": "function", "api": "set_series_opa"}, "range": {"return_type": "NoneType", "args": [{"type": "int", "name": "ymin"}, {"type": "int", "name": "ymax"}], "type": "function", "api": "set_range"}, "series_darking": {"return_type": "NoneType", "args": [{"type": "int", "name": "dark_eff"}], "type": "function", "api": "set_series_darking"}, "point_count": {"return_type": "NoneType", "args": [{"type": "int", "name": "point_cnt"}], "type": "function", "api": "set_point_count"}, "points": {"return_type": "NoneType", "args": [{"type": "chart_series_t", "name": "ser"}, {"type": "mp_arr_to_lv_coord_t_____", "name": "y_array"}], "type": "function", "api": "set_points"}, "y_tick_length": {"return_type": "NoneType", "args": [{"type": "int", "name": "major_tick_len"}, {"type": "int", "name": "minor_tick_len"}], "type": "function", "api": "set_y_tick_length"}, "y_tick_texts": {"return_type": "NoneType", "args": [{"type": "str", "name": "list_of_values"}, {"type": "int", "name": "num_tick_marks"}, {"type": "int", "name": "options"}], "type": "function", "api": "set_y_tick_texts"}, "secondary_y_tick_texts": {"return_type": "NoneType", "args": [{"type": "str", "name": "list_of_values"}, {"type": "int", "name": "num_tick_marks"}, {"type": "int", "name": "options"}], "type": "function", "api": "set_secondary_y_tick_texts"}, "x_tick_texts": {"return_type": "NoneType", "args": [{"type": "str", "name": "list_of_values"}, {"type": "int", "name": "num_tick_marks"}, {"type": "int", "name": "options"}], "type": "function", "api": "set_x_tick_texts"}, "type": {"return_type": "NoneType", "args": [{"type": "int", "name": "type"}], "type": "function", "api": "set_type"}, "div_line_count": {"return_type": "NoneType", "args": [{"type": "int", "name": "hdiv"}, {"type": "int", "name": "vdiv"}], "type": "function", "api": "set_div_line_count"}, "series_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "width"}], "type": "function", "api": "set_series_width"}, "x_tick_length": {"return_type": "NoneType", "args": [{"type": "int", "name": "major_tick_len"}, {"type": "int", "name": "minor_tick_len"}], "type": "function", "api": "set_x_tick_length"}, "update_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "update_mode"}], "type": "function", "api": "set_update_mode"}}, "slider": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "knob_in": {"return_type": "NoneType", "args": [{"type": "bool", "name": "in"}], "type": "function", "api": "set_knob_in"}, "range": {"return_type": "NoneType", "args": [{"type": "int", "name": "min"}, {"type": "int", "name": "max"}], "type": "function", "api": "set_range"}, "value": {"return_type": "NoneType", "args": [{"type": "int", "name": "value"}, {"type": "int", "name": "anim"}], "type": "function", "api": "set_value"}, "sym": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_sym"}}, "obj": {}, "line": {"points": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_lv_point_t_____", "name": "point_a"}, {"type": "int", "name": "point_num"}], "type": "function", "api": "set_points"}, "auto_size": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_auto_size"}, "y_invert": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_y_invert"}}, "roller": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "fix_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "w"}], "type": "function", "api": "set_fix_width"}, "selected": {"return_type": "NoneType", "args": [{"type": "int", "name": "sel_opt"}, {"type": "int", "name": "anim"}], "type": "function", "api": "set_selected"}, "options": {"return_type": "NoneType", "args": [{"type": "str", "name": "options"}, {"type": "int", "name": "mode"}], "type": "function", "api": "set_options"}, "align": {"return_type": "NoneType", "args": [{"type": "int", "name": "align"}], "type": "function", "api": "set_align"}, "visible_row_count": {"return_type": "NoneType", "args": [{"type": "int", "name": "row_cnt"}], "type": "function", "api": "set_visible_row_count"}}, "kb": {"ctrl_map": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_lv_btnm_ctrl_t_____", "name": "ctrl_map"}], "type": "function", "api": "set_ctrl_map"}, "map": {"return_type": "NoneType", "args": [{"type": "mp_arr_to_char_ptr____", "name": "map"}], "type": "function", "api": "set_map"}, "cursor_manage": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_cursor_manage"}, "mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "mode"}], "type": "function", "api": "set_mode"}, "ta": {"return_type": "NoneType", "args": [{"type": "object", "name": "ta"}], "type": "function", "api": "set_ta"}}, "bar": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "range": {"return_type": "NoneType", "args": [{"type": "int", "name": "min"}, {"type": "int", "name": "max"}], "type": "function", "api": "set_range"}, "value": {"return_type": "NoneType", "args": [{"type": "int", "name": "value"}, {"type": "int", "name": "anim"}], "type": "function", "api": "set_value"}, "sym": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_sym"}}, "imgbtn": {"src": {"return_type": "NoneType", "args": [{"type": "int", "name": "state"}, {"type": "pointer", "name": "src"}], "type": "function", "api": "set_src"}, "toggle": {"return_type": "NoneType", "args": [{"type": "bool", "name": "tgl"}], "type": "function", "api": "set_toggle"}, "state": {"return_type": "NoneType", "args": [{"type": "int", "name": "state"}], "type": "function", "api": "set_state"}}, "tabview": {"sliding": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_sliding"}, "anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "tab_act": {"return_type": "NoneType", "args": [{"type": "int", "name": "id"}, {"type": "int", "name": "anim"}], "type": "function", "api": "set_tab_act"}, "btns_hidden": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_btns_hidden"}, "btns_pos": {"return_type": "NoneType", "args": [{"type": "int", "name": "btns_pos"}], "type": "function", "api": "set_btns_pos"}}, "list": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "scroll_propagation": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_scroll_propagation"}, "single_mode": {"return_type": "NoneType", "args": [{"type": "bool", "name": "mode"}], "type": "function", "api": "set_single_mode"}, "edge_flash": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_edge_flash"}, "btn_selected": {"return_type": "NoneType", "args": [{"type": "object", "name": "btn"}], "type": "function", "api": "set_btn_selected"}, "layout": {"return_type": "NoneType", "args": [{"type": "int", "name": "layout"}], "type": "function", "api": "set_layout"}, "sb_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "mode"}], "type": "function", "api": "set_sb_mode"}}, "cpicker": {"hue": {"return_value": "bool", "args": [{"type": "int", "name": "hue"}], "type": "function", "api": "set_hue"}, "value": {"return_value": "bool", "args": [{"type": "int", "name": "val"}], "type": "function", "api": "set_value"}, "hsv": {"return_value": "bool", "args": [{"type": "color_hsv_t", "name": "hsv"}], "type": "function", "api": "set_hsv"}, "color": {"return_value": "bool", "args": [{"type": "color32_t", "name": "color"}], "type": "function", "api": "set_color"}, "color_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "mode"}], "type": "function", "api": "set_color_mode"}, "indic_colored": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_indic_colored"}, "type": {"return_type": "NoneType", "args": [{"type": "int", "name": "type"}], "type": "function", "api": "set_type"}, "saturation": {"return_value": "bool", "args": [{"type": "int", "name": "saturation"}], "type": "function", "api": "set_saturation"}, "color_mode_fixed": {"return_type": "NoneType", "args": [{"type": "bool", "name": "fixed"}], "type": "function", "api": "set_color_mode_fixed"}, "preview": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_preview"}}, "mbox": {"anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "recolor": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_recolor"}, "text": {"return_type": "NoneType", "args": [{"type": "str", "name": "txt"}], "type": "function", "api": "set_text"}}, "page": {"scrl_fit2": {"return_type": "NoneType", "args": [{"type": "int", "name": "hor"}, {"type": "int", "name": "ver"}], "type": "function", "api": "set_scrl_fit2"}, "scrl_fit4": {"return_type": "NoneType", "args": [{"type": "int", "name": "left"}, {"type": "int", "name": "right"}, {"type": "int", "name": "top"}, {"type": "int", "name": "bottom"}], "type": "function", "api": "set_scrl_fit4"}, "anim_time": {"return_type": "NoneType", "args": [{"type": "int", "name": "anim_time"}], "type": "function", "api": "set_anim_time"}, "scrl_fit": {"return_type": "NoneType", "args": [{"type": "int", "name": "fit"}], "type": "function", "api": "set_scrl_fit"}, "scrl_layout": {"return_type": "NoneType", "args": [{"type": "int", "name": "layout"}], "type": "function", "api": "set_scrl_layout"}, "scroll_propagation": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_scroll_propagation"}, "scrl_height": {"return_type": "NoneType", "args": [{"type": "int", "name": "h"}], "type": "function", "api": "set_scrl_height"}, "scrl_width": {"return_type": "NoneType", "args": [{"type": "int", "name": "w"}], "type": "function", "api": "set_scrl_width"}, "edge_flash": {"return_type": "NoneType", "args": [{"type": "bool", "name": "en"}], "type": "function", "api": "set_edge_flash"}, "sb_mode": {"return_type": "NoneType", "args": [{"type": "int", "name": "sb_mode"}], "type": "function", "api": "set_sb_mode"}}}
--------------------------------------------------------------------------------
/src/compiler.js:
--------------------------------------------------------------------------------
1 | /* generate the C or Python code to a file */
2 |
3 | function python_generator(info, widget) {
4 | let code = [];
5 |
6 | for (const key in info) {
7 | let id = key;
8 |
9 | let par_id = info[key].parent;
10 |
11 | let type = info[key].type;
12 |
13 | code.push(template_py_create(id, par_id, type)); //code: create, EX: btn0 = lv.btn(scr)
14 |
15 | if (info[id].cb) {
16 | code.push(template_py_cb(id));
17 | }
18 |
19 | const attributes = info[key].attributes;
20 | for (const attr of attributes) {
21 | let value = widget[id][attr];
22 | if (value == true) {
23 | value = "True";
24 | } else if (value == false) {
25 | value = "False";
26 | }
27 | code.push(template_py_setter_simple(id, attr, value));
28 | }
29 | }
30 | return code.join("\n");
31 | }
32 |
33 |
34 | function c_generator(info, widget) {
35 | let body = [], cb = [];
36 |
37 | for (const key in info) {
38 | let id = key;
39 |
40 | let par_id = info[key].parent;
41 |
42 | let type = info[key].type;
43 |
44 | if(info[key].cb) {
45 | cb.push(id);
46 | }
47 |
48 | body.push(template_c_create(id, par_id, type)); //code: create, EX: btn0 = lv.btn(scr)
49 |
50 | const attributes = info[key].attributes;
51 | for (const attr of attributes) {
52 | let value = widget[id][attr];
53 |
54 | body.push(template_c_setter_simple(id, "obj", attr, value));
55 | }
56 | }
57 | let cb_s = [];
58 | for (const id of cb) {
59 | cb_s.push(template_c_cb(id));
60 | }
61 |
62 | return template_c_all(body.join("\n"), cb_s.join("\n"));
63 | }
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | ELEMENT.locale(ELEMENT.lang.en) //i18n
2 |
3 | const WidgetsOption = [
4 | {
5 | value: 'obj',
6 | label: "Object"
7 | },
8 | {
9 | value: 'form',
10 | label: 'Form',
11 | children: [
12 | {
13 | value: 'btn',
14 | label: "Button"
15 | },
16 | {
17 | value: 'label',
18 | label: "Label",
19 | },
20 | {
21 | value: 'sw',
22 | label: "Switch"
23 | },
24 | {
25 | value: 'cb',
26 | label: "Checkbox"
27 | },
28 | {
29 | value: 'ddlist',
30 | label: "Drop-Down List"
31 | },
32 | {
33 | value: 'roller',
34 | label: "Roller"
35 | },
36 | {
37 | value: 'slider',
38 | label: "Slider"
39 | },
40 | ],
41 | },
42 | {
43 | value: 'data',
44 | label: 'Data',
45 | children: [
46 | {
47 | value: 'bar',
48 | label: "Bar"
49 | },
50 | {
51 | value: 'gauge',
52 | label: "Gauge"
53 | },
54 | {
55 | value: 'led',
56 | label: "LED"
57 | },
58 | {
59 | value: 'chart',
60 | label: "Chart"
61 | },
62 | {
63 | value: 'arc',
64 | label: "Arc"
65 | },
66 | {
67 | value: 'calendar',
68 | label: "Calendar"
69 | },
70 | {
71 | value: 'lmeter',
72 | label: "Line meter"
73 | },
74 | {
75 | value: 'preload',
76 | label: "Preloader"
77 | }
78 | ]
79 | },
80 | {
81 | value: 'layer',
82 | label: 'Layer',
83 | children: [
84 | {
85 | value: 'page',
86 | label: "Page"
87 | },
88 | {
89 | value: 'cont',
90 | label: "Container"
91 | },
92 | {
93 | value: 'win',
94 | label: "Window"
95 | },
96 | {
97 | value: 'mbox',
98 | label: "Message box"
99 | }
100 | ]
101 | }
102 |
103 | ]
104 |
105 |
106 | //The Python code to Initialize the environment
107 | const EnvInitCode = [
108 | "import ujson",
109 | "import lvgl as lv",
110 | "lv.init()",
111 | "import SDL",
112 | "SDL.init()",
113 | /* Register SDL display driver. */
114 | "disp_buf1 = lv.disp_buf_t()",
115 | "buf1_1 = bytes(960*10)",
116 | "lv.disp_buf_init(disp_buf1,buf1_1, None, len(buf1_1)//4)",
117 | "disp_drv = lv.disp_drv_t()",
118 | "lv.disp_drv_init(disp_drv)",
119 | "disp_drv.buffer = disp_buf1",
120 | "disp_drv.flush_cb = SDL.monitor_flush",
121 | "disp_drv.hor_res = 480",
122 | "disp_drv.ver_res = 320",
123 | "lv.disp_drv_register(disp_drv)",
124 | /*Regsiter SDL mouse driver*/
125 | "indev_drv = lv.indev_drv_t()",
126 | "lv.indev_drv_init(indev_drv)",
127 | "indev_drv.type = lv.INDEV_TYPE.POINTER;",
128 | "indev_drv.read_cb = SDL.mouse_read;",
129 | "lv.indev_drv_register(indev_drv);",
130 | /* Create a screen with a button and a label */
131 | "screen = lv.obj()",
132 | /* Load the screen */
133 | "lv.scr_load(screen)",
134 | "baseAttr = dir(lv.obj)"
135 | ];
136 |
137 |
138 | /* Define special function for python*/
139 |
140 | // old getobjattr() function:
141 | // "def getobjattr(obj,id,type_s):",
142 | // " d={}",
143 | // " d['id']=id",
144 | // " for i in dir(obj):",
145 | // " if 'get_' in i:",
146 | // " try:",
147 | // " ret = eval(id + '.' + i + '()')",
148 | // " if isinstance(ret, (int,float,str,bool)):",
149 | // " d[i] = ret",
150 | // " except:",
151 | // " pass",
152 | // " for i in ATTR:",
153 | // " d[i]=eval(id+'.'+ATTR[i]+'()')",
154 | // " print('\x06'+ujson.dumps(d)+'\x15')",
155 |
156 | const QueryCode = [
157 | //Get and send JSON format text
158 | "def query_attr(obj,id,type_s):",
159 | " d={}",
160 | " d['id']=id",
161 | " for i in ATTR['obj']:",
162 | " d[i]=eval(id+'.'+ATTR['obj'][i]+'()')",
163 | " print('\x06'+ujson.dumps(d)+'\x15')",
164 | "def query_xy(obj,id):",
165 | " d={'id':id,'x':obj.get_x(),'y':obj.get_y()}",
166 | " print('\x06'+ujson.dumps(d)+'\x15')",
167 | //Callback: only for the lv.EVENT.DRAG_END
168 | "def walv_callback(obj,id,event):",
169 | " if event == lv.EVENT.DRAG_END:",
170 | " query_xy(obj, id)"
171 | ];
172 |
173 |
174 | const Getter = {
175 | "obj": {
176 | "x": "get_x",
177 | "y": "get_y",
178 | "width": "get_width",
179 | "height": "get_height",
180 | "drag": "get_drag",
181 | "click": "get_click",
182 | "hidden": "get_hidden",
183 | "top": "get_top",
184 | },
185 |
186 | "label": {
187 | "label": "get_text",
188 | }
189 |
190 | }
191 |
192 | const Setter = {
193 | "obj": {
194 | "x": "set_x",
195 | "y": "set_y",
196 | "width": "set_width",
197 | "height": "set_height",
198 | "drag": "set_drag",
199 | "click": "set_click",
200 | "hidden": "set_hidden",
201 | "top": "set_top",
202 | },
203 | "btn": {
204 | "state": "set_state",
205 | "toggle": "set_toggle",
206 | "ink_wait_time": "set_ink_wait_time",
207 | "ink_in_time": "set_ink_in_time",
208 | },
209 | "label": {
210 | "text": "set_text",
211 | },
212 | "led": {
213 |
214 | }
215 | }
216 |
217 |
--------------------------------------------------------------------------------
/src/gen_apis_js.py:
--------------------------------------------------------------------------------
1 | # Generate the setter table for objects
2 | # https://github.com/littlevgl/lv_gui_builder/issues/1#issuecomment-528845543
3 | # Parse the lv_mpy.json(example: https://raw.githubusercontent.com/littlevgl/lv_binding_micropython/master/gen/lv_mpy_example.json)
4 |
5 | import json
6 |
7 | Setter = {}
8 | path = '../../lv_mpy_example.json' # Path to lv_mpy_example.json
9 |
10 | with open(path) as f:
11 | data = json.load(f)
12 | objs = data['objects']
13 | for o in objs:
14 | # print(o)
15 | tmp = {}
16 | for fn in objs[o]['members'].keys():
17 | if fn.startswith('set_') and fn not in objs['obj']['members'].keys():
18 | name = fn.replace('set_', '')
19 | tmp[name] = objs[o]['members'][fn]
20 | tmp[name]['api'] = fn
21 | del tmp[name]['args'][0] # The first argument is about type
22 | Setter[o] = tmp
23 | # del Setter['obj']
24 |
25 | # We also need to add 'null:{}' in apis.js
26 | f = open('apis.js', 'w')
27 | f.write("const setter = ");
28 | json.dump(Setter, f)
29 | f.close()
30 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 |
2 | var vm = null;
3 |
4 |
5 | window.onload = function() {
6 | vm = new Vue(WALV_MAIN);
7 |
8 | /* Initialize the wasm mpy */
9 | mpylvInit(vm);
10 |
11 | /* Initialize the ace editor */
12 | editorInit(vm);
13 |
14 | document.title = "WALV: The Online Designer For LittlevGL";
15 |
16 |
17 | }
18 |
19 |
20 |
21 | const mpylvInit = (vm) => {
22 |
23 | Module.canvas = document.getElementById("canvas");
24 |
25 | /* Bind mp_js_stdout */
26 | mp_js_stdout = document.getElementById('mp_js_stdout');
27 | mp_js_stdout.value = "";
28 |
29 | /* Initialize the xtermjs */
30 | Terminal.applyAddon(fit);
31 | var term = new Terminal({
32 | cursorBlink: true,
33 | // theme: {
34 | // background: '#fdf6e3'
35 | // }
36 | });
37 | term.open(document.getElementById("mpy_repl"), true);
38 | term.fit();
39 | term.write('Welcome To \x1B[1;3;31mWALV\x1B[0m');
40 |
41 | /*Initialize MicroPython itself*/
42 | mp_js_init(8 * 1024 * 1024);
43 |
44 | /*Setup printing event handler*/
45 | mp_js_stdout.addEventListener('print', function(e) {
46 | // console.log(e.data);
47 | term.write(vm.handleOutput(e.data));
48 | }, false);
49 |
50 | /*Setup key input handler */
51 | term.on('data', function(key, e) {
52 | for(var i = 0; i < key.length; i++) {
53 | mp_js_process_char(key.charCodeAt(i));
54 | }
55 | });
56 |
57 | vm.Term = term;
58 |
59 | /* Run init script */
60 | mp_js_do_str(EnvInitCode.join('\n'));
61 |
62 | /* Add function querry_attr() & walv_callback() */
63 | mp_js_do_str(QueryCode.join('\n'));
64 | wrap_equal("ATTR", JSON.stringify(Getter)); //Add ATTR to mpy, ATTR is common getter
65 |
66 | /*Setup lv_task_handler loop*/
67 | var the_mp_handle_pending = Module.cwrap('mp_handle_pending', null);
68 | function handle_pending() {
69 | the_mp_handle_pending();
70 | setTimeout(handle_pending, 10); // should call lv_task_handler()
71 | }
72 |
73 | /*Initialize the REPL.*/
74 | mp_js_init_repl();
75 |
76 | /*Start the main loop, asynchronously.*/
77 | handle_pending();
78 | }
79 |
80 | // Init the ace editor
81 | const editorInit = (vm) => {
82 | let editor = ace.edit("code-editor");
83 | editor.getSession().setUseWrapMode(true);
84 | editor.setAutoScrollEditorIntoView(true);
85 | editor.setFontSize(15);
86 | editor.resize();
87 | let c_edit_mode = ace.require("ace/mode/c_cpp").Mode;
88 | let py_edit_mode = ace.require("ace/mode/python").Mode;
89 | editor.session.setMode(new py_edit_mode());
90 | editor.setOptions({maxLines: "200px" });
91 | vm.editor = editor;
92 | vm.py_edit_mode = py_edit_mode;
93 | vm.c_edit_mode = c_edit_mode;
94 | }
95 |
96 |
97 | const WALV_MAIN = {
98 | el: "#walv",
99 |
100 | data: {
101 | editor: null,
102 | c_edit_mode: null,
103 | py_edit_mode: null,
104 | is_c_mode: false, //true: c, false: python
105 | Term: null,
106 |
107 | buffer: [],
108 | str_json: "",
109 | mask: false,
110 | currentWidget: {}, // The Attributes
111 | posJSON: {},
112 | WidgetPool: {},
113 | InfoPool: {},
114 |
115 | setter: setter,
116 | currentType: null,
117 |
118 | //Simulator
119 | cursorX: 0,
120 | cursorY: 0,
121 |
122 | //Creator
123 | creator_options: WidgetsOption,
124 | props: {emitPath: false, expandTrigger: 'hover'},
125 | selectedType: "",
126 | widgetNum: 0,
127 | Count: 0,
128 |
129 | //TreeView
130 | widget_tree: [
131 | {
132 | label: "screen",
133 | children: []
134 | },
135 | // For invisible
136 | {
137 | label: "",
138 | children: []
139 | }
140 | ],
141 | // Which node in TreeView was checked
142 | checkedNode: {
143 | id: null,
144 | obj: null,
145 | // type: null, // DEPRECATED
146 | },
147 |
148 | //Terminal
149 | term_visible: true,
150 |
151 | // Style Editor
152 | style_visible: false,
153 | style: {
154 | body: {
155 | main_color: null,
156 | grad_color: null,
157 | },
158 | text: {
159 | color: "#409EFF",
160 | font: "font_roboto_16",
161 | },
162 | image: {
163 |
164 | },
165 | line: {
166 |
167 | },
168 | }
169 | },
170 |
171 |
172 | watch: {
173 | //Parse string to JSON
174 | str_json: function() {
175 | try {
176 |
177 | let tmp = JSON.parse(this.str_json);
178 | if(Object.keys(tmp).length == 3) {
179 | this.posJSON = tmp;
180 |
181 | //Update Postion
182 | this.WidgetPool[tmp['id']]['x'] = this.posJSON['x'];
183 | this.WidgetPool[tmp['id']]['y'] = this.posJSON['y'];
184 |
185 | this.changeInfo(tmp['id'], 'x');
186 | this.changeInfo(tmp['id'], 'y');
187 |
188 | // Change the Setting to show the widget that was just moved.
189 | this.currentWidget = this.WidgetPool[tmp['id']];
190 | this.currentType = this.InfoPool[tmp['id']]['type'];
191 |
192 | this.drawRect(this.currentWidget.x, this.currentWidget.y, this.currentWidget.width, this.currentWidget.height);
193 | } else {
194 | this.WidgetPool[tmp['id']] = tmp;
195 | this.currentWidget = this.WidgetPool[tmp['id']];
196 | }
197 | } catch (error) {
198 | alert(error);
199 | }
200 | },
201 |
202 | },
203 |
204 | methods: {
205 | // Handle the information(strats with \x06, end with \x15)
206 | handleOutput: function(text) {
207 | if(text == '\x15') //End: '\x15'
208 | {
209 | this.mask = false;
210 | this.str_json = this.buffer.join('');
211 | }
212 | if(this.mask)
213 | {
214 | this.buffer.push(text);
215 | text = "";
216 | }
217 | if(text == '\x06') //Begin: '\x06'
218 | {
219 | this.mask = true;
220 | }
221 |
222 | if(text == '\n')
223 | {
224 | this.buffer.splice(0, this.buffer.length);
225 | }
226 | return text;
227 | },
228 |
229 | Creator: function() {
230 | if (this.selectedType == "") {
231 | this.$message({
232 | message: 'Please select a type',
233 | type: 'error'
234 | });
235 | return;
236 | } else {
237 | let parent_id = this.getCurrentID();
238 | if (parent_id === null) {
239 | this.$message({
240 | message: 'You must choose a widget!',
241 | type: 'error'
242 | });
243 | return;
244 | }
245 | if (parent_id == "") {
246 | this.$message({
247 | message: 'You created a widget invisible',
248 | type: 'warning'
249 | });
250 |
251 | }
252 | this.createWidget(this.selectedType, parent_id);
253 | }
254 | },
255 |
256 | //Parametres are the String type
257 | createWidget: function(type, strPar) {
258 | var id = this.makeID(type);
259 | var par = strPar;
260 |
261 | wrap_create(id, par, type);
262 |
263 | //TODO: BUG
264 | this.appendNode(id);
265 |
266 | //** walv saves the inital info to WidgetPool && InfoPool
267 |
268 | //Store Info that a widget was created from.
269 | this.addInfo(id, par, type);
270 |
271 | // Change currentType, walv will render new input for setters
272 | this.currentType = type;
273 | },
274 |
275 | // Increase by 1
276 | makeID: function(type) {
277 | let id = type + (this.Count++).toString(16);
278 | this.widgetNum += 1;
279 | return id;
280 | },
281 |
282 | // Append new node to TreeView
283 | appendNode(widget_name) {
284 | let new_child = {
285 | label: widget_name,
286 | children: [] };
287 | let node = this.$refs.TreeView.getCurrentNode();
288 | if (node != null) {
289 | node.children.push(new_child);
290 | }
291 | },
292 |
293 | // Delete node and its childs(reverse)
294 | deleteNode: function() {
295 | const node = this.checkedNode.obj;
296 | const id = this.checkedNode.id;
297 |
298 | if (id == "screen" || id == "") {
299 | this.$message({
300 | message: "You can't delete the screen or nothing!",
301 | type: 'error'
302 | });
303 | return; // Not support delete screen now
304 | }
305 | // delete child
306 | let record = [id]; // Which child was deleted
307 | reverse_del_node(node.data, record);
308 |
309 | // delete itself
310 | const children = node.parent.data.children;
311 | const index = children.findIndex(d => d.label === id);
312 | wrap_delete(id);
313 | children.splice(index, 1);
314 | this.widgetNum -= record.length;
315 |
316 | // Clear this.checkedNode
317 | this.checkedNode.obj = null;
318 | this.checkedNode.id = null;
319 |
320 | // Remove the related info
321 | pool_delete(this.WidgetPool, record);
322 | pool_delete(this.InfoPool, record);
323 | this.currentWidget = this.WidgetPool['screen'];
324 |
325 | this.$message({
326 | message: 'Delete sucessfully',
327 | type: 'success'
328 | });
329 | },
330 |
331 | // When the node is clicked, walv will: change the checkedNode, set new id for label, update the Setting
332 | // https://element.eleme.cn/#/en-US/component/tree
333 | clickNode: function(data, obj, tree_obj) {
334 | this.checkedNode.id = data.label;
335 | this.checkedNode.obj = obj;
336 |
337 | let id = data.label;
338 | if (id == "") {// NOTICE
339 | return;
340 | }
341 | // If WidgetPool doesn't has infomation of the widget
342 | if (this.WidgetPool[id] == undefined) {
343 | let type = "\'obj\'";
344 | if (id != "screen") {
345 | type = this.InfoPool[id]['type'];
346 | }
347 | wrap_query_attr(id, type);
348 | }
349 | // if (id != 'screen') {
350 | // this.checkedNode.type = this.InfoPool[id]['type']; // TODO
351 | // } DEPRECATED
352 | this.currentWidget = this.WidgetPool[id];
353 | },
354 |
355 | // Update the X & Y below the Simulator
356 | cursorXY : function(event) {
357 | this.cursorX = 0 | (event.offsetX / 1.25);
358 | this.cursorY = 0 | (event.offsetY / 1.25);
359 | },
360 |
361 | // Get the id of recently checked node
362 | getCurrentID: function() {
363 | return this.checkedNode.id;
364 | // node = this.$refs.TreeView.getCurrentNode()
365 | // if (node != null) {
366 | // return node.label;
367 | // }
368 | // return null;
369 | },
370 |
371 | // Lock the widget, so it can't move anymore
372 | // lock_widget: function() {
373 | // let drag_state = this.currentWidget["get_drag"];
374 | // if(drag_state == true) {
375 | // drag_state = "True";
376 | // } else {
377 | // drag_state = "False";
378 | // }
379 |
380 | // mp_js_do_str(this.currentWidget["id"] + ".set_drag(" + drag_state + ')');
381 | // },
382 |
383 |
384 | // Apply change to the widget: number
385 | bindWidgetNumerical: function(attribute) {
386 |
387 | let value = this.currentWidget[attribute];
388 |
389 | if(value == null) {
390 | value = 0;
391 | }
392 |
393 | let id = this.currentWidget["id"];
394 |
395 | wrap_simple_setter(id, attribute, value);
396 |
397 | this.changeInfo(id, attribute);
398 | },
399 |
400 | // Apply change to the widget: boolean
401 | bindWidgetBool: function(attribute) {
402 |
403 | let value = this.currentWidget[attribute];
404 |
405 | if(value == true) {
406 | value = "True"
407 | } else {
408 | value = "False"
409 | }
410 |
411 | let id = this.currentWidget["id"];
412 |
413 | wrap_simple_setter(id, attribute, value);
414 |
415 | this.reverseInfo(id, attribute);
416 | },
417 |
418 | bindWidgetSpecial: function(e, f) {
419 | let id = this.currentWidget["id"];
420 | let api = f['api'];
421 | let params = e.target.value;
422 | if(params == "") { // If input nothing
423 | return;
424 | }
425 | wrap_setter_str(id, api, params);
426 | },
427 |
428 | // Add some information for the new widget to InfoPool
429 | addInfo: function(id, par_name, type) {
430 | let info = {
431 | type: type,
432 | parent: par_name,
433 | cb: false,
434 | attributes: [],
435 | };
436 | this.InfoPool[id] = info;
437 | },
438 |
439 | // For text or number, save something in InfoPool
440 | changeInfo: function(id, attribute_name) {
441 | let index = this.InfoPool[id].attributes.indexOf(attribute_name);
442 | if (index == -1) {
443 | this.InfoPool[id].attributes.push(attribute_name);
444 | }
445 | },
446 |
447 | // For boolean only, save something in InfoPool
448 | reverseInfo: function(id, attribute_name) {
449 | let index = this.InfoPool[id].attributes.indexOf(attribute_name);
450 | if (index != -1) {
451 | this.InfoPool[id].attributes.splice(index, 1);
452 | } else {
453 | this.InfoPool[id].attributes.push(attribute_name);
454 | }
455 | },
456 |
457 | // User enable CallBack template
458 | enableCBInfo: function(id) {
459 | this.InfoPool[id].cb = true;
460 | },
461 |
462 | refreshTerm: function() {
463 | this.Term.clear();
464 | this.Term.write("\r\x1b[K>>> ");
465 | },
466 |
467 | // Take a screenshot for the Simulator
468 | screenshot: function() {
469 | document.getElementById("canvas").toBlob((blob) => {
470 | saveAs(blob, "screenshot.png");
471 | });
472 | },
473 |
474 | // Generate the code and print them to the editor.
475 | generateCode: function() {
476 | let preview_code = "";
477 | if (this.is_c_mode) {
478 | preview_code = c_generator(this.InfoPool, this.WidgetPool);
479 | } else {
480 | preview_code = python_generator(this.InfoPool, this.WidgetPool);
481 | }
482 | this.editor.setValue(preview_code);
483 | this.$message({
484 | message: 'Generate code sucessfully',
485 | type: 'success'
486 | });
487 | },
488 |
489 | // Export the code in editor as a file.
490 | exportCodeAsFile: function() {
491 | let code = this.editor.getValue();
492 | this.$message({
493 | message: 'Export file sucessfully',
494 | type: 'success'
495 | });
496 | let blob = new Blob([code], {type: "text/plain;charset=utf-8"});
497 | if (this.is_c_mode) {
498 | saveAs(blob, "lv_gui.h");
499 | } else {
500 | saveAs(blob, "lv_gui.py");
501 | }
502 | },
503 |
504 | // Set the style
505 | makeStyle: function() {
506 | wrap_simple_style(this.currentWidget["id"], this.style);
507 | },
508 |
509 | //Highlight object
510 | drawRect: (x, y, w, h) => {
511 | let ctx = document.getElementById("canvas").getContext("2d");
512 | ctx.strokeStyle="red";
513 | ctx.lineWidth = 2;
514 | ctx.setLineDash([5,5]);
515 | ctx.strokeRect(x, y, w, h);
516 | },
517 |
518 | setArgs: (args) => {
519 | return setArgvs(args);
520 | }
521 | },
522 | }
523 |
524 | window.addEventListener('beforeunload', (event) => {
525 | event.preventDefault();
526 | event.returnValue = '';
527 | });
--------------------------------------------------------------------------------
/src/template.js:
--------------------------------------------------------------------------------
1 | /* template: generate the related code and return as string */
2 |
3 | const template_py_create = (id, parent_id, type) => {
4 | return `${id} = lv.${type}(${parent_id})`;
5 | }
6 |
7 | const template_py_setter_number = (id, attr, param) => {
8 | return `${id}.set_${attr}(${param})`;
9 | }
10 |
11 | const template_py_setter_boolean = (id, attr, param) => {
12 | let value = "True";
13 | if (param == false) {
14 | value = "False";
15 | }
16 | return `${id}.set_${attr}(${value})`;
17 | }
18 |
19 | const template_py_setter_text = (id, attr, param) => {
20 | return `${id}.set_${attr}("${param}")`;
21 | }
22 |
23 | const template_py_setter_simple = (id, attr, param) => {
24 | return `${id}.set_${attr}(${param})`;
25 | }
26 |
27 | const template_c_create = (id, parent_id, type) => {
28 | return `lv_obj_t * ${id} = lv_${type}_create(${parent_id}, NULL);`;
29 | }
30 |
31 | const template_c_setter_simple = (id, type, attr, param) => {
32 | return `lv_${type}_set_${attr}(${id}, ${param});`;
33 | }
34 |
35 | const template_py_cb = (id) => {
36 | return `${id}.set_event_cb(lambda : ) #Put your code here`
37 | }
38 |
39 | const template_c_cb = (id) => {
40 | return `static void ${id}_event_cb(lv_obj_t * ${id}, lv_event_t event)
41 | {
42 | // Write the event handler here
43 | // if(event == LV_EVENT_) { }
44 | }`;
45 | }
46 |
47 |
48 | const template_c_all = (body, cb) => {
49 | return `
50 | /**
51 | * @file lv_gui.h
52 | * Generated By WALV
53 | */
54 |
55 | #ifndef LV_GUI_H
56 | #define LV_GUI_H
57 |
58 | #ifdef __cplusplus
59 | extern "C" {
60 | #endif
61 |
62 | #include "/*Put the path to lvgl.h here*/"
63 |
64 | /**********************
65 | * CALLBACK
66 | **********************/
67 | ${cb}
68 | /**********************
69 | * GLOBAL FUNCTIONS
70 | **********************/
71 | ${body}
72 |
73 | #ifdef __cplusplus
74 | } /* extern "C" */
75 | #endif
76 |
77 | #endif /*LV_GUI_H*/
78 | `
79 | }
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | const reverse_del_node = (node, record) => {
2 | let childs = node.children;
3 | for (const iter of childs) {
4 | reverse_del_node(iter, record);
5 | wrap_delete(iter.label);
6 | record.push(iter.label);
7 | }
8 | childs.splice(0, childs.length);
9 | }
10 |
11 | const pool_delete = (pool, list) => {
12 | for (const i of list) {
13 | delete pool[i];
14 | }
15 | }
16 |
17 | // arguments
18 | const setArgvs = (args) => {
19 | let args_list = [];
20 | for (const i of args) {
21 | args_list.push(i["name"])
22 | }
23 | return args_list.toString();
24 | }
25 |
26 | Vue.component('lvgl-setter', {
27 | props: ['id', 'name', 'body'],
28 | data: function() {
29 | return {
30 | args: [],
31 | }
32 | },
33 | methods: {
34 | checkArgs: function() {
35 | let args_list = [];
36 | for (const arg of this.args) {
37 | if (arg['value'] === "") {
38 | return
39 | }
40 | if (arg['type'] === "str") {
41 | args_list.push(`"${arg['value']}"`);
42 | } else if (arg['type'] === "bool") {
43 | if (arg['value'] === true) {
44 | args_list.push("True");
45 | } else {
46 | args_list.push("False");
47 | }
48 | } else {
49 | args_list.push(arg.value);
50 | }
51 | // TODO: We can check each value's type here
52 | }
53 | wrap_setter_str(this.id, this.body.api, args_list.toString());
54 | },
55 | },
56 | // TODO: Rewrite created && beforeUpdate
57 | created() {
58 | for (const arg of this.body.args) {
59 | arg['value'] = ""; // args: [{"name": '', "type": '', "value": ''}]
60 | this.args.push(arg);
61 | }
62 | },
63 | // Why we need beforeUpdate: https://vuejs.org/v2/guide/list.html#Maintaining-State. If template was rendered by other, Vue won't excute created but beforeUpdate
64 | beforeUpdate() {
65 | this.args.splice(0, this.args.length);
66 | for (const arg of this.body.args) {
67 | arg['value'] = "";
68 | this.args.push(arg);
69 | }
70 | },
71 | template: ' {{ name }} ({{arg.name}}: , ) '
72 | });
73 |
74 | // https://docs.littlevgl.com/en/html/object-types/obj.html
75 | // Vue.component('lvgl-layout', {
76 | // props: ['id', 'x', 'y', 'align', 'obj_ref', 'x_shift', 'y_shift'], // lv_obj_set_x, lv_obj_set_y, lv_obj_align(obj, obj_ref, LV_ALIGN_..., x_shift, y_shift)
77 | // data: function() {
78 | // return {
79 | // x: 0,
80 | // y: 0,
81 | // align: "",
82 | // }
83 | // },
84 | // template: ''
85 | // });
86 |
87 | // TODO: Only support align to its parent now
88 | Vue.component('lvgl-align', {
89 | props: ['id', 'ref_id'],
90 | data: function() {
91 | return {
92 | align: '',
93 | ref_obj: '',
94 | x_shift: 0,
95 | y_shift: 0,
96 | options: [
97 | '', 'OUT_TOP_LEFT', 'OUT_TOP_MID', 'OUT_TOP_RIGHT', '', 0,
98 | 'OUT_LEFT_TOP', 'IN_TOP_LEFT', 'IN_TOP_MID', 'IN_TOP_RIGHT', 'OUT_RIGHT_TOP', 0,
99 | 'OUT_LEFT_MID', 'IN_LEFT_MID', 'CENTER', 'IN_RIGHT_MID', 'OUT_RIGHT_MID', 0,
100 | 'OUT_LEFT_BOTTOM', 'IN_BOTTOM_LEFT', 'IN_BOTTOM_MID', 'IN_BOTTOM_RIGHT', 'OUT_RIGHT_BOTTOM', 0,
101 | '', 'OUT_BOTTOM_LEFT', 'OUT_BOTTOM_MID', 'OUT_BOTTOM_RIGHT', '', 0,
102 | ]
103 | }
104 | },
105 | watch: {
106 | align: (type) => {
107 | wrap_align(this.id, 'None', type, 0, 0);
108 | }
109 | },
110 | template: ''
111 | });
--------------------------------------------------------------------------------
/src/wrapper.js:
--------------------------------------------------------------------------------
1 | /* wrapper: generate the related code, then use `mp_js_do_str` to excute them. */
2 |
3 | // id = expr
4 | const wrap_equal = (id, expr) => {
5 | mp_js_do_str(`${id}=${expr}`);
6 | }
7 |
8 | const wrap_create = (id, parent_id, type_s) => {
9 |
10 | // id + "=lv." + type_s + "(" + parent_id + ")",
11 | // id + ".set_drag(1)",
12 | // id + ".set_protect(lv.PROTECT.PRESS_LOST)",
13 | // "query_attr(" + id + ",\'" + id + "\',\'" + type_s + "\')",
14 | // id + ".set_event_cb(lambda obj=" + id + ",event=-1,name=\'" + id + "\':walv_callback(obj,name,event))",
15 |
16 | let code = [
17 | `${id}=lv.${type_s}(${parent_id})`,
18 | `${id}.set_drag(True)`,
19 | `${id}.set_protect(lv.PROTECT.PRESS_LOST)`,
20 | `query_attr(${id},"${id}","${type_s}")`,
21 | `${id}.set_event_cb(lambda obj=${id},event=-1,name="${id}":walv_callback(obj,name,event))`,
22 | ];
23 |
24 |
25 | const ComplexWidgets = ['ddlist', 'page', 'roller'];
26 | if (ComplexWidgets.indexOf(type_s) != -1) {
27 | code.push(`${id}.get_child(None).set_drag_parent(True)`);
28 | }
29 | mp_js_do_str(code.join('\n'));
30 | }
31 |
32 | const wrap_delete = (id) => {
33 | mp_js_do_str(`${id}.delete()`);
34 | }
35 |
36 |
37 | const wrap_query_attr = (id, type_s) => {
38 | mp_js_do_str(`query_attr(${id},"${id}","${type_s}")`);
39 | }
40 |
41 | const wrap_simple_setter = (id, attr, param) => {
42 | mp_js_do_str(`${id}.set_${attr}(${param})`);
43 | }
44 |
45 | // Convert '#ffffff' to '0xffffff'
46 | const color_convert = (color) => {
47 | return color.replace("#", "0x")
48 | }
49 |
50 | const wrap_setter = (id, type, name, params, database) => {
51 | // params is a list
52 | let api = database[type][name]['api']; // "fit": {"return_type": "NoneType", "args": [{"type": "object", "name": "cont"}, {"type": "int", "name": "fit"}], "type": "function", "api": "set_fit"}
53 | let args = database[type][name]['args'];
54 | let code = `${id}.${api}(${params.toString()})`;
55 | mp_js_do_str(code);
56 | }
57 |
58 | const wrap_align = (id, ref_id, offset_x, offset_y) => {
59 | mp_js_do_str(`${id}.align(${ref_id}, ${offset_x}, ${offset_y})`);
60 | }
61 |
62 | const wrap_setter_str = (id, api, params) => {
63 | // params is a string
64 | let code = `${id}.${api}(${params})`;
65 | mp_js_do_str(code);
66 | }
67 |
68 | const wrap_simple_style = (id, style) => {
69 | let s = style.text;
70 | let code = [
71 | "s=lv.style_t(lv.style_plain)"
72 | ];
73 | let c = color_convert(s.color);
74 | code.push(`s.text.font=lv.${s.font}`);
75 | code.push(`s.text.color=lv.color_hex(${c})`);
76 | code.push(`${id}.set_style(lv.label.STYLE.MAIN,s)`);
77 | mp_js_do_str(code.join('\n'));
78 | }
--------------------------------------------------------------------------------