<html> <script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js”></script> <script src=“https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js”></script> <script src=“https://embeddedt.github.io/lv_micropython/ports/javascript/lvgl_mp.js”></script>
<link rel=“stylesheet” href=“https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/xterm.min.css” integrity=“sha512-iLYuqv+v/P4u9erpk+KM83Ioe/l7SEmr7wB6g+Kg1qmEit8EShDKnKtLHlv2QXUp7GGJhmqDI+1PhJYLTsfb8w==” crossorigin=“anonymous” /> <script src=“https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/xterm.min.js” integrity=“sha512-2PRgAav8Os8vLcOAh1gSaDoNLe1fAyq8/G3QSdyjFFD+OqNjLeHE/8q4+S4MEZgPsuo+itHopj+hJvqS8XUQ8A==” crossorigin=“anonymous”></script> <script src=“https://cdnjs.cloudflare.com/ajax/libs/xterm/3.14.5/addons/fit/fit.min.js” integrity=“sha512-+wh8VA1djpWk3Dj9/IJDu6Ufi4vVQ0zxLv9Vmfo70AbmYFJm0z3NLnV98vdRKBdPDV4Kwpi7EZdr8mDY9L8JIA==” crossorigin=“anonymous”></script>
<table> <tbody> <tr><td> <textarea name=“my-python-editor” id=“my-python-editor” data-editor=“python” data-gutter=“1” rows=“50” cols=“90”> import imp, sys sys.path.append('https://raw.githubusercontent.com/littlevgl/lv_binding_micropython/master/lib') import display_driver import lvgl as lv
# lvgl must be initialized before any lvgl function is called or object/struct is constructed!
lv.init()
############################################################################## # Styles ##############################################################################
class ColorStyle(lv.style_t):
def __init__(self, color):
super().__init__()
self.set_bg_opa(lv.STATE.DEFAULT, lv.OPA.COVER);
self.set_bg_color(lv.STATE.DEFAULT, lv.color_hex3(color))
self.set_bg_grad_color(lv.STATE.DEFAULT, lv.color_hex3(0xFFF));
self.set_bg_grad_dir(lv.STATE.DEFAULT, lv.GRAD_DIR.VER);
# self.set_bg_main_stop(lv.STATE.DEFAULT, 0);
# self.set_bg_grad_stop(lv.STATE.DEFAULT, 128);
class ChartPaddingStyle(lv.style_t):
def __init__(self):
super().__init__()
self.set_pad_left(lv.STATE.DEFAULT, 10);
self.set_pad_right(lv.STATE.DEFAULT, 10);
self.set_pad_bottom(lv.STATE.DEFAULT, 10);
self.set_pad_top(lv.STATE.DEFAULT, 10);
class ShadowStyle(lv.style_t):
def __init__(self):
super().__init__()
self.set_shadow_opa(lv.STATE.DEFAULT, lv.OPA.COVER);
self.set_shadow_width(lv.STATE.DEFAULT, 3);
self.set_shadow_color(lv.STATE.DEFAULT, lv.color_hex3(0xAAA));
self.set_shadow_ofs_x(lv.STATE.DEFAULT, 5);
self.set_shadow_ofs_y(lv.STATE.DEFAULT, 3);
self.set_shadow_spread(lv.STATE.DEFAULT, 0);
class ContainerStyle(lv.style_t):
def __init__(self):
super().__init__()
self.set_value_align(lv.STATE.DEFAULT, lv.ALIGN.OUT_TOP_LEFT)
self.set_value_ofs_y(lv.STATE.DEFAULT, -10)
self.set_margin_top(lv.STATE.DEFAULT, 30)
# lv_style_set_value_ofs_y(&style_box, LV_STATE_DEFAULT, - LV_DPX(10)); # lv_style_set_margin_top(&style_box, LV_STATE_DEFAULT, LV_DPX(30));
# A square button with a shadow when not pressed class ButtonStyle(lv.style_t):
def __init__(self):
super().__init__()
self.set_radius(lv.STATE.DEFAULT, lv.dpx(8))
self.set_shadow_opa(lv.STATE.DEFAULT, lv.OPA.COVER);
self.set_shadow_width(lv.STATE.DEFAULT, lv.dpx(10));
self.set_shadow_color(lv.STATE.DEFAULT, lv.color_hex3(0xAAA));
self.set_shadow_ofs_x(lv.STATE.DEFAULT, lv.dpx(10));
self.set_shadow_ofs_y(lv.STATE.DEFAULT, lv.dpx(10));
self.set_shadow_spread(lv.STATE.DEFAULT, 0);
self.set_shadow_ofs_x(lv.STATE.PRESSED, lv.dpx(0));
self.set_shadow_ofs_y(lv.STATE.PRESSED, lv.dpx(0));
############################################################################## # Themes ##############################################################################
class AdvancedDemoTheme(lv.theme_t):
def __init__(self):
super().__init__()
self.button_style = ButtonStyle()
# This theme is based on active theme (material)
base_theme = lv.theme_get_act()
self.copy(base_theme)
# This theme will be applied only after base theme is applied
self.set_base(base_theme)
# Set the "apply" callback of this theme to our custom callback
self.set_apply_cb(self.apply)
# Activate this theme
self.set_act()
def apply(self, theme, obj, name):
if name == lv.THEME.BTN:
obj.add_style(obj.PART.MAIN, self.button_style)
##############################################################################
def get_member_name(obj, value):
for member in dir(obj):
if getattr(obj, member) == value:
return member
class SymbolButton(lv.btn):
def __init__(self, parent, symbol, text):
super().__init__(parent)
self.symbol = lv.label(self)
self.symbol.set_text(symbol)
self.label = lv.label(self)
self.label.set_text(text)
class Page_Buttons:
def __init__(self, app, page):
self.app = app
self.page = page
self.btn1 = SymbolButton(page, lv.SYMBOL.PLAY, "Play")
self.btn1.set_size(80, 80)
self.btn1.align(page, lv.ALIGN.IN_TOP_LEFT, 30, 30)
self.btn2 = SymbolButton(page, lv.SYMBOL.PAUSE, "Pause")
self.btn2.set_size(80, 80)
self.btn2.align(page, lv.ALIGN.IN_TOP_RIGHT, -30, 30)
self.label = lv.label(page)
self.label.align(page, lv.ALIGN.IN_BOTTOM_LEFT, 30, -30)
for btn, name in [(self.btn1, 'Play'), (self.btn2, 'Pause')]:
btn.set_event_cb(lambda obj=None, event=-1, name=name: self.label.set_text('%s %s' % (name, get_member_name(lv.EVENT, event))))
class Page_Simple:
def __init__(self, app, page):
self.app = app
self.page = page
# slider
self.slider = lv.slider(page)
self.slider.set_width(160)
self.slider.align(page, lv.ALIGN.IN_TOP_LEFT, 20, 20)
self.slider_label = lv.label(page)
self.slider_label.align(self.slider, lv.ALIGN.OUT_RIGHT_MID, 15, 0)
self.slider.set_event_cb(self.on_slider_changed)
self.on_slider_changed(None)
# style selector
self.styles = [('Gray', ColorStyle(0xCCC)),
('Red', ColorStyle(0xF00)),
('Green',ColorStyle(0x0F0)),
('Blue', ColorStyle(0x00F))]
self.style_selector = lv.dropdown(page)
self.style_selector.add_style(self.style_selector.PART.MAIN, ShadowStyle())
self.style_selector.align(self.slider, lv.ALIGN.OUT_BOTTOM_LEFT, 0, 40)
self.style_selector.set_options('\n'.join(x[0] for x in self.styles))
self.style_selector.set_event_cb(self.on_style_selector_changed)
# counter button
self.counter_btn = lv.btn(page)
self.counter_btn.set_size(80,80)
self.counter_btn.align(self.page, lv.ALIGN.IN_BOTTOM_MID, 0, -20)
self.counter_label = lv.label(self.counter_btn)
self.counter_label.set_text("Count")
self.counter_btn.set_event_cb(self.on_counter_btn)
self.counter = 0
def on_slider_changed(self, obj=None, event=-1):
self.slider_label.set_text(str(self.slider.get_value()))
def on_style_selector_changed(self, obj=None, event=-1):
selected = self.style_selector.get_selected()
tabview = self.app.screen_main.tabview
if hasattr(self, 'selected_style'): tabview.remove_style(tabview.PART.BG, self.selected_style)
self.selected_style = self.styles[selected][1]
tabview.add_style(tabview.PART.BG, self.selected_style)
def on_counter_btn(self, obj, event):
if event == lv.EVENT.CLICKED:
self.counter += 1
self.counter_label.set_text(str(self.counter))
class Anim(lv.anim_t):
def __init__(self, obj, val, size, exec_cb, path_cb, time=500, playback=False, ready_cb=None):
super().__init__()
self.init()
self.set_time(time)
self.set_values(val, val + size)
if callable(exec_cb):
self.set_custom_exec_cb(exec_cb)
else:
self.set_exec_cb(obj, exec_cb)
path = lv.anim_path_t({'cb': path_cb})
self.set_path(path)
if playback:
self.set_playback(0)
if ready_cb:
self.set_ready_cb(ready_cb)
self.start()
class AnimatedChart(lv.chart):
def __init__(self, parent, val, size):
super().__init__(parent)
self.val = val
self.size = size
self.max = 2000
self.min = 500
self.factor = 100
self.anim_phase1()
def anim_phase1(self):
self.phase1 = Anim(
self,
self.val,
self.size,
lambda a, val: self.set_y_range(self.AXIS.PRIMARY_Y,0, val),
lv.anim_path_t.ease_in,
ready_cb=lambda a:self.anim_phase2(),
time=(self.max * self.factor) // 100,
)
def anim_phase2(self):
self.phase2 = Anim(
self,
self.val + self.size,
-self.size,
lambda a, val: self.set_y_range(self.AXIS.PRIMARY_Y, 0, val),
lv.anim_path_t.ease_out,
ready_cb=lambda a:self.anim_phase1(),
time=(self.min * self.factor) // 100,
)
class Page_Chart:
def __init__(self, app, page):
self.app = app
self.page = page
self.chart = AnimatedChart(page, 100, 1000)
self.chart.set_width(page.get_width() - 80)
self.series1 = self.chart.add_series(lv.color_hex(0xFF0000))
self.chart.set_type(self.chart.TYPE.LINE)
self.chart.set_style_local_line_width(self.chart.PART.SERIES, lv.STATE.DEFAULT, 3)
self.chart.add_style(self.chart.PART.SERIES, ColorStyle(0x055))
self.chart.add_style(self.chart.PART.BG, ChartPaddingStyle())
self.chart.set_y_range(self.chart.AXIS.PRIMARY_Y, 0,100)
self.chart.init_points(self.series1, 10)
self.chart.set_points(self.series1, [10, 20, 30, 20, 10, 40, 50, 90, 95, 90])
self.chart.set_x_tick_texts("a\nb\nc\nd\ne", 2, lv.chart.AXIS.DRAW_LAST_TICK)
self.chart.set_x_tick_length(10, 5)
self.chart.set_y_tick_texts("1\n2\n3\n4\n5", 2, lv.chart.AXIS.DRAW_LAST_TICK)
self.chart.set_y_tick_length(10, 5)
self.chart.set_div_line_count(3, 3)
self.chart.set_height(self.page.get_height() - 60)
self.chart.align(page, lv.ALIGN.CENTER, 0, 0)
# Create a slider that controls the chart animation speed
def on_slider_changed(obj=None, event=-1):
self.chart.factor = self.slider.get_value()
self.slider = lv.slider(page)
self.slider.align(self.chart, lv.ALIGN.OUT_RIGHT_TOP, 10, 0)
self.slider.set_width(10)
self.slider.set_height(self.chart.get_height())
self.slider.set_range(10, 200)
self.slider.set_value(self.chart.factor, 0)
self.slider.set_event_cb(on_slider_changed)
class Page_Controls:
def __init__(self, app, page):
self.app = app
self.page = page
# self.page.set_scrl_layout(lv.LAYOUT.PRETTY_TOP)
# not know how does msgbox works
# self.mbox = lv.msgbox(lv.scr_act())
# self.mbox.set_text("A message box with two buttons.")
# self.mbox.add_btns({"Cancel", "Ok"})
# self.mbox.set_width(200)
# self.mbox.align(Null, lv.ALIGN.CENTER, 0, 0)
CtrlBasicContainer = lv.cont(page)
CtrlBasicContainer.set_layout(lv.LAYOUT.PRETTY_MID)
CtrlBasicContainer.add_style(lv.cont.PART.MAIN, ContainerStyle())
CtrlBasicContainer.set_drag_parent(True)
CtrlBasicContainer.align(page, lv.ALIGN.IN_TOP_LEFT, 10, 30)
CtrlBasicContainer.set_style_local_value_str(lv.cont.PART.MAIN, lv.STATE.DEFAULT, "Basics")
CtrlBasicContainer.set_fit2(lv.FIT.NONE, lv.FIT.TIGHT)
CtrlBasicContainer.set_width(
page.get_width_grid(2, 1)
);
btn1 = lv.btn(CtrlBasicContainer)
btn1.set_fit2(lv.FIT.NONE, lv.FIT.TIGHT)
lbl1 = lv.label(btn1)
lbl1.set_text("Button1")
btn2 = lv.btn(CtrlBasicContainer)
btn2.toggle()
lbl2 = lv.label(btn2)
lbl2.set_text("Button2")
sw1 = lv.switch(CtrlBasicContainer)
CtrlTextContainer = lv.cont(page)
CtrlTextContainer.set_layout(lv.LAYOUT.PRETTY_MID)
CtrlTextContainer.add_style(lv.cont.PART.MAIN, ContainerStyle())
CtrlTextContainer.set_drag_parent(True)
CtrlTextContainer.align(page, lv.ALIGN.IN_TOP_RIGHT, -1 * CtrlTextContainer.get_width() - 60, 30)
CtrlTextContainer.set_style_local_value_str(lv.cont.PART.MAIN, lv.STATE.DEFAULT, "Text Input")
CtrlTextContainer.set_fit2(lv.FIT.NONE, lv.FIT.TIGHT)
CtrlTextContainer.set_width(
page.get_width_grid(2, 1)
);
btn1z = lv.btn(CtrlTextContainer)
btn1z.set_fit2(lv.FIT.NONE, lv.FIT.TIGHT)
lbl1z = lv.label(btn1z)
lbl1z.set_text("Button1")
btn2z = lv.btn(CtrlTextContainer)
btn2z.toggle()
lbl2z = lv.label(btn2z);
lbl2z.set_text("Button2");
class Screen_Main(lv.obj):
def color_chg_event_cb(self, obj, evt):
if evt == lv.EVENT.VALUE_CHANGED:
flag = lv.THEME_MATERIAL_FLAG.LIGHT;
if obj.get_state():
flag = lv.THEME_MATERIAL_FLAG.DARK;
# LV_THEME_DEFAULT_INIT(lv_theme_get_color_primary(), lv_theme_get_color_secondary(),
# flag,
# lv_theme_get_font_small(), lv_theme_get_font_normal(), lv_theme_get_font_subtitle(), lv_theme_get_font_title());
print("TODO: Pasikei2ia templeitas ", flag, )
def __init__(self, app, *args, **kwds):
self.app = app
super().__init__(*args, **kwds)
self.theme = AdvancedDemoTheme()
self.tabview = lv.tabview(self)
self.tabview.set_style_local_pad_left(lv.tabview.PART.TAB_BG, lv.STATE.DEFAULT, 120)
self.tabview.set_btns_pos(lv.tabview.TAB_POS.TOP)
self.sw=lv.switch(self)
self.sw.set_pos(5, 11)
self.sw.set_style_local_value_str(lv.switch.PART.BG, lv.STATE.DEFAULT, "Dark")
self.sw.set_style_local_value_align(lv.switch.PART.BG, lv.STATE.DEFAULT, lv.ALIGN.OUT_RIGHT_MID)
self.sw.set_style_local_value_ofs_x(lv.switch.PART.BG, lv.STATE.DEFAULT, 3)
self.sw.set_event_cb(self.color_chg_event_cb)
self.page_simple = Page_Simple(self.app, self.tabview.add_tab("Simple"))
self.page_controls = Page_Controls(self.app, self.tabview.add_tab("Controls"))
# self.page_buttons = Page_Buttons(self.app, self.tabview.add_tab("Buttons"))
# self.page_chart = Page_Chart(self.app, self.tabview.add_tab("Chart"))
# def bandymas(obj, evt):
# print('bandymas', obj, evt)
# self.tabview.set_event_cb(bandymas)
lv.scr_load(Screen_Main(lv))
</textarea> </td> <td>
<canvas id=“canvas” width=“480” height=“320” oncontextmenu=“event.preventDefault()” tabindex=“-1”></canvas>
</td> </tr> </tbody> </table>
<script type=“text/javascript”> Hook up ACE editor to all textareas with data-editor attribute jQuery(function() { jQuery('textarea[data-editor]').each(function() { var textarea = $(this); var mode = textarea.data('editor'); var editDiv = $('<div>', { position: 'absolute', width: textarea.width(), height: textarea.height(), 'class': textarea.attr('class') }).insertBefore(textarea); textarea.css('display', 'none'); var editor = ace.edit(editDiv[0]); editor.renderer.setShowGutter(textarea.data('gutter')); editor.getSession().setValue(textarea.val()); editor.getSession().setMode(“ace/mode/” + mode); editor.setTheme(“ace/theme/tomorrow”); copy back to textarea on form submit…
textarea.closest('form').submit(function() {
textarea.val(editor.getSession().getValue());
})
});
});
/*Write text to the terminal */
function sendText(text) {
var print = new Event('print');
print.data = text;
mp_js_stdout.dispatchEvent(print);
}
function processScriptArg(url){
// read text from URL location
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.send(null);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var type = request.getResponseHeader('Content-Type');
if (type.indexOf("text") !== 1) {
mp_js_do_str(request.responseText);
}
}
}
}
Module.canvas = (function() {
var canvas = document.getElementById('canvas');
return canvas;
})();
var lines = [
"import lvgl as lv",
"lv.init()",
"import SDL",
"SDL.init()",
/* Register SDL display driver. */
"disp_drv = lv.disp_drv_t()",
"lv.disp_drv_init(disp_drv)",
"disp_drv.disp_flush = SDL.monitor_flush",
"disp_drv.disp_fill = SDL.monitor_fill",
"disp_drv.disp_map = SDL.monitor_map",
"lv.disp_drv_register(disp_drv)",
/*Regsiter SDL mouse driver*/
"indev_drv = lv.indev_drv_t()",
"lv.indev_drv_init(indev_drv)",
"indev_drv.type = lv.INDEV_TYPE.POINTER;",
"indev_drv.read = SDL.mouse_read;",
"lv.indev_drv_register(indev_drv);",
/* Create a screen with a button and a label */
"scr = lv.obj()",
"btn = lv.btn(scr)",
"btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)",
"label = lv.label(btn)",
"label.set_text('Button')",
/* Load the screen */
"lv.scr_load(scr)"
];
/*Initialization function*/
window.onload = function() {
Terminal.applyAddon(fit);
term = new Terminal();
mp_js_stdout = document.getElementById('terminal');
mp_js_stdout.value = "";
term.open(mp_js_stdout);
term.fit();
/*Initialize MicroPython itself*/
mp_js_init(1 * 1024 * 1024);
/*Setup printing event handler*/
mp_js_stdout.addEventListener('print', function(e) {
text = e.data;
term.write(text);
}, false);
/*Setup key input handler */
term.on('data', function(key, e) {
console.log(key);
for(var i = 0; i < key.length; i++) {
mp_js_process_char(key.charCodeAt(i));
}
});
/* Run init script */
for(var i = 0;i < lines.length;i++){
mp_js_do_str(lines[i]);
}
/* Run custom script if passed */
var custom = undefined;
try {
custom = new URL(window.location.href).searchParams.get("script");
} catch (e) {
console.log(e + ": URL seems to be unsupported");
}
console.log("Custom script: " + custom);
if(custom !== undefined && custom !== null)
processScriptArg(custom);
/*Setup lv_task_handler loop*/
var the_mp_handle_pending = Module.cwrap('mp_handle_pending', null);
function handle_pending() {
the_mp_handle_pending();
setTimeout(handle_pending, 20); // should call lv_task_handler()
}
/*Initialize the REPL.*/
mp_js_init_repl();
/*Start the main loop, asynchronously.*/
handle_pending();
}
</script>
</html>