Skip to content

Commit a19fd8e

Browse files
committed
feat(scripts): add lvgl_demo
1 parent 188ce42 commit a19fd8e

File tree

1 file changed

+318
-0
lines changed

1 file changed

+318
-0
lines changed

scripts/lvgl_demo.py

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
import usys as sys
2+
sys.path.append('') # See: https://github.com/micropython/micropython/issues/6419
3+
4+
# See: https://pymotw.com/2/sys/tracing.html
5+
6+
def mp_trace(frame, event, arg):
7+
co = frame.f_code
8+
func_name = co.co_name
9+
func_line_no = frame.f_lineno
10+
func_filename = co.co_filename
11+
print('[%s] [%s] %s:%s' % (event, func_name, func_filename, func_line_no))
12+
return mp_trace
13+
14+
# sys.settrace(mp_trace)
15+
16+
import lvgl as lv
17+
18+
##############################################################################
19+
# Styles
20+
##############################################################################
21+
22+
class ColorStyle(lv.style_t):
23+
def __init__(self, color):
24+
super().__init__()
25+
self.set_bg_opa(lv.OPA.COVER)
26+
self.set_bg_color(lv.color_hex3(color))
27+
self.set_bg_grad_color(lv.color_hex3(0xFFF))
28+
self.set_bg_grad_dir(lv.GRAD_DIR.VER)
29+
self.set_bg_main_stop(0)
30+
self.set_bg_grad_stop(128)
31+
32+
class ShadowStyle(lv.style_t):
33+
def __init__(self):
34+
super().__init__()
35+
self.set_shadow_opa(lv.OPA.COVER)
36+
self.set_shadow_width(3)
37+
self.set_shadow_color(lv.color_hex3(0xAAA))
38+
self.set_shadow_offset_x(5)
39+
self.set_shadow_offset_y(3)
40+
self.set_shadow_spread(0)
41+
42+
# A square button with a shadow when not pressed
43+
class ButtonStyle(lv.style_t):
44+
def __init__(self):
45+
super().__init__()
46+
self.set_radius(lv.dpx(8))
47+
self.set_shadow_opa(lv.OPA.COVER)
48+
self.set_shadow_width(lv.dpx(10))
49+
self.set_shadow_color(lv.color_hex3(0xAAA))
50+
self.set_shadow_offset_x(lv.dpx(10))
51+
self.set_shadow_offset_y(lv.dpx(10))
52+
self.set_shadow_spread(0)
53+
54+
class ButtonPressedStyle(lv.style_t):
55+
def __init__(self):
56+
super().__init__()
57+
self.set_shadow_offset_x(lv.dpx(0))
58+
self.set_shadow_offset_y(lv.dpx(0))
59+
60+
61+
##############################################################################
62+
# Themes
63+
##############################################################################
64+
65+
class AdvancedDemoTheme(lv.theme_t):
66+
67+
def __init__(self):
68+
super().__init__()
69+
self.button_style = ButtonStyle()
70+
self.button_pressed_style = ButtonPressedStyle()
71+
72+
# This theme is based on active theme (material)
73+
base_theme = lv.theme_get_from_obj(lv.screen_active())
74+
75+
# This theme will be applied only after base theme is applied
76+
self.set_parent(base_theme)
77+
78+
# Set the "apply" callback of this theme to our custom callback
79+
self.set_apply_cb(self.apply)
80+
81+
# Activate this theme on default display
82+
lv.display_get_default().set_theme(self)
83+
84+
def apply(self, theme, obj):
85+
if obj.get_class() == lv.button_class:
86+
obj.add_style(self.button_style, lv.PART.MAIN)
87+
obj.add_style(self.button_pressed_style, lv.PART.MAIN | lv.STATE.PRESSED)
88+
89+
##############################################################################
90+
91+
member_name_cache = {}
92+
93+
def get_member_name(obj, value):
94+
try:
95+
return member_name_cache[id(obj)][id(value)]
96+
except KeyError:
97+
pass
98+
99+
for member in dir(obj):
100+
if getattr(obj, member) == value:
101+
try:
102+
member_name_cache[id(obj)][id(value)] = member
103+
except KeyError:
104+
member_name_cache[id(obj)] = {id(value): member}
105+
return member
106+
107+
108+
class SymbolButton(lv.button):
109+
def __init__(self, parent, symbol, text):
110+
super().__init__(parent)
111+
self.symbol = lv.label(self)
112+
self.symbol.set_text(symbol)
113+
self.label = lv.label(self)
114+
self.label.set_text(text)
115+
self.set_flex_flow(lv.FLEX_FLOW.COLUMN)
116+
self.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
117+
118+
119+
class Page_Buttons:
120+
def __init__(self, app, page):
121+
self.app = app
122+
self.page = page
123+
self.button_event_count = {'Play': 0, 'Pause': 0}
124+
125+
self.page.set_flex_flow(lv.FLEX_FLOW.ROW)
126+
self.page.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START)
127+
128+
self.button1 = SymbolButton(page, lv.SYMBOL.PLAY, "Play")
129+
self.button1.set_size(80, 80)
130+
131+
self.button2 = SymbolButton(page, lv.SYMBOL.PAUSE, "Pause")
132+
self.button2.set_size(80, 80)
133+
134+
self.label = lv.label(page)
135+
self.label.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
136+
self.label.align(lv.ALIGN.BOTTOM_LEFT, 0, 0)
137+
138+
def button_cb(event, name):
139+
self.button_event_count[name] += 1
140+
event_name = get_member_name(lv.EVENT, event.code)
141+
if all((not event_name.startswith(s)) for s in ['DRAW', 'GET', 'STYLE', 'REFR']):
142+
self.label.set_text('[%d] %s %s' % (self.button_event_count[name], name, event_name))
143+
144+
for button, name in [(self.button1, 'Play'), (self.button2, 'Pause')]:
145+
button.add_event_cb(lambda event, button_name=name: button_cb(event, button_name), lv.EVENT.ALL, None)
146+
147+
148+
class Page_Simple:
149+
def __init__(self, app, page):
150+
self.app = app
151+
self.page = page
152+
self.test_events = []
153+
154+
self.page.set_flex_flow(lv.FLEX_FLOW.COLUMN)
155+
self.page.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
156+
157+
# slider
158+
self.slider = lv.slider(page)
159+
self.slider.set_width(lv.pct(80))
160+
self.slider_label = lv.label(page)
161+
self.slider.add_event_cb(self.on_slider_changed, lv.EVENT.VALUE_CHANGED, None)
162+
self.on_slider_changed(None)
163+
164+
# style selector
165+
self.styles = [('Gray', ColorStyle(0xCCC)),
166+
('Red', ColorStyle(0xF00)),
167+
('Green',ColorStyle(0x0F0)),
168+
('Blue', ColorStyle(0x00F))]
169+
170+
self.style_selector = lv.dropdown(page)
171+
self.style_selector.add_style(ShadowStyle(), lv.PART.MAIN)
172+
self.style_selector.align(lv.ALIGN.OUT_BOTTOM_LEFT, 0, 40)
173+
self.style_selector.set_options('\n'.join(x[0] for x in self.styles))
174+
self.style_selector.add_event_cb(self.on_style_selector_changed, lv.EVENT.VALUE_CHANGED, None)
175+
176+
# counter button
177+
self.counter_button = lv.button(page)
178+
self.counter_button.set_size(80,80)
179+
self.counter_label = lv.label(self.counter_button)
180+
self.counter_label.set_text("Count")
181+
self.counter_label.align(lv.ALIGN.CENTER, 0, 0)
182+
self.counter_button.add_event_cb(self.on_counter_button, lv.EVENT.CLICKED, None)
183+
self.counter = 0
184+
185+
def on_slider_changed(self, event):
186+
self.slider_label.set_text(str(self.slider.get_value()))
187+
188+
def on_style_selector_changed(self, event):
189+
selected = self.style_selector.get_selected()
190+
tabview = self.app.screen_main.tabview
191+
if hasattr(self, 'selected_style'): tabview.remove_style(self.selected_style, lv.PART.MAIN)
192+
self.selected_style = self.styles[selected][1]
193+
tabview.add_style(self.selected_style, lv.PART.MAIN)
194+
195+
def on_counter_button(self, event):
196+
self.counter += 1
197+
self.counter_label.set_text(str(self.counter))
198+
199+
class Anim(lv.anim_t):
200+
def __init__(self, obj, val, size, exec_cb, path_cb, time=500, playback=False, completed_cb=None):
201+
super().__init__()
202+
self.init()
203+
self.set_time(time)
204+
self.set_values(val, val + size)
205+
if callable(exec_cb):
206+
self.set_custom_exec_cb(exec_cb)
207+
else:
208+
self.set_exec_cb(obj, exec_cb)
209+
self.set_path_cb(path_cb)
210+
if playback:
211+
self.set_playback(0)
212+
if completed_cb:
213+
self.set_completed_cb(completed_cb)
214+
self.start()
215+
216+
217+
class AnimatedChart(lv.chart):
218+
def __init__(self, parent, val, size):
219+
super().__init__(parent)
220+
self.val = val
221+
self.size = size
222+
self.max = 2000
223+
self.min = 500
224+
self.factor = 100
225+
self.anim_phase1()
226+
227+
def anim_phase1(self):
228+
self.phase1 = Anim(
229+
self,
230+
self.val,
231+
self.size,
232+
lambda a, val: self.set_range(self.AXIS.PRIMARY_Y, 0, val),
233+
lv.anim_t.path_ease_in,
234+
completed_cb=lambda a:self.anim_phase2(),
235+
time=(self.max * self.factor) // 100,
236+
)
237+
238+
def anim_phase2(self):
239+
self.phase2 = Anim(
240+
self,
241+
self.val + self.size,
242+
-self.size,
243+
lambda a, val: self.set_range(self.AXIS.PRIMARY_Y, 0, val),
244+
lv.anim_t.path_ease_out,
245+
completed_cb=lambda a:self.anim_phase1(),
246+
time=(self.min * self.factor) // 100,
247+
)
248+
class Page_Text:
249+
def __init__(self, app, page):
250+
self.app = app
251+
self.page = page
252+
self.page.set_flex_flow(lv.FLEX_FLOW.ROW)
253+
self.page.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
254+
self.ta = lv.textarea(self.page)
255+
self.ta.set_height(lv.pct(100))
256+
self.ta.set_width(lv.pct(100))
257+
258+
class Page_Chart:
259+
def __init__(self, app, page):
260+
self.app = app
261+
self.page = page
262+
self.page.set_flex_flow(lv.FLEX_FLOW.ROW)
263+
self.page.set_flex_align(lv.FLEX_ALIGN.SPACE_EVENLY, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
264+
self.page.set_style_pad_all(10, lv.PART.MAIN)
265+
self.page.set_style_pad_gap(10, lv.PART.MAIN)
266+
self.chart = AnimatedChart(page, 100, 1000)
267+
self.chart.set_flex_grow(1)
268+
self.chart.set_height(lv.pct(100))
269+
self.series1 = self.chart.add_series(lv.color_hex(0xFF0000), self.chart.AXIS.PRIMARY_Y)
270+
self.chart.set_type(self.chart.TYPE.LINE)
271+
self.chart.set_style_line_width(3, lv.PART.ITEMS)
272+
self.chart.add_style(ColorStyle(0x055), lv.PART.ITEMS)
273+
self.chart.set_range(self.chart.AXIS.PRIMARY_Y, 0, 100)
274+
self.chart.set_point_count(10)
275+
self.chart.set_ext_y_array(self.series1, [10, 20, 30, 20, 10, 40, 50, 90, 95, 90])
276+
# self.chart.set_x_tick_texts("a\nb\nc\nd\ne", 2, lv.chart.AXIS.DRAW_LAST_TICK)
277+
# self.chart.set_x_tick_length(10, 5)
278+
# self.chart.set_y_tick_texts("1\n2\n3\n4\n5", 2, lv.chart.AXIS.DRAW_LAST_TICK)
279+
# self.chart.set_y_tick_length(10, 5)
280+
self.chart.set_div_line_count(5, 5)
281+
282+
# Create a slider that controls the chart animation speed
283+
284+
def on_slider_changed(event):
285+
self.chart.factor = self.slider.get_value()
286+
287+
self.slider = lv.slider(page)
288+
self.slider.set_size(10, lv.pct(100))
289+
self.slider.set_range(10, 200)
290+
self.slider.set_value(self.chart.factor, 0)
291+
self.slider.add_event_cb(on_slider_changed, lv.EVENT.VALUE_CHANGED, None)
292+
293+
class Screen_Main(lv.obj):
294+
def __init__(self, app, *args, **kwds):
295+
self.app = app
296+
super().__init__(*args, **kwds)
297+
self.theme = AdvancedDemoTheme()
298+
self.tabview = lv.tabview(self)
299+
self.page_simple = Page_Simple(self.app, self.tabview.add_tab("Simple"))
300+
self.page_buttons = Page_Buttons(self.app, self.tabview.add_tab("Buttons"))
301+
self.page_text = Page_Text(self.app, self.tabview.add_tab("Text"))
302+
self.page_chart = Page_Chart(self.app, self.tabview.add_tab("Chart"))
303+
304+
305+
class AdvancedDemoApplication:
306+
def init_gui(self):
307+
308+
self.group = lv.group_create()
309+
self.group.set_default()
310+
311+
# Identify platform and initialize it
312+
313+
self.screen_main = Screen_Main(self)
314+
lv.screen_load(self.screen_main)
315+
316+
317+
app = AdvancedDemoApplication()
318+
app.init_gui()

0 commit comments

Comments
 (0)