You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
Merge pull request #77 from pavelmachek/m_10_navstar
navstar: Simple navigation application
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "Navstar",
|
||||
"publisher": "Pavel Machek",
|
||||
"short_description": "Simple navigation app.",
|
||||
"long_description": "Simple navigation app using data from NAVSTAR GPS and other GNSS systems.",
|
||||
"icon_url": "https://apps.micropythonos.com/apps/cz.ucw.pavel.xxx/icons/cz.ucw.pavel.xxx_0.0.1_64x64.png",
|
||||
"download_url": "https://apps.micropythonos.com/apps/cz.ucw.pavel.xxx/mpks/cz.ucw.pavel.xxx_0.0.1.mpk",
|
||||
"fullname": "cz.ucw.pavel.xxx",
|
||||
"version": "0.0.1",
|
||||
"category": "utilities",
|
||||
"activities": [
|
||||
{
|
||||
"entrypoint": "assets/main.py",
|
||||
"classname": "Main",
|
||||
"intent_filters": [
|
||||
{
|
||||
"action": "main",
|
||||
"category": "launcher"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,306 @@
|
||||
import lvgl as lv
|
||||
import mpos
|
||||
from mpos import Activity, MposKeyboard
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# Canvas (LVGL)
|
||||
# -----------------------------
|
||||
|
||||
class Canvas:
|
||||
"""
|
||||
LVGL canvas + layer drawing Canvas.
|
||||
|
||||
This matches ports where:
|
||||
- lv.canvas has init_layer() / finish_layer()
|
||||
- primitives are drawn via lv.draw_* into lv.layer_t
|
||||
"""
|
||||
|
||||
def __init__(self, scr, canvas):
|
||||
self.scr = scr
|
||||
|
||||
# Screen size
|
||||
self.W = scr.get_width()
|
||||
self.H = scr.get_height()
|
||||
|
||||
# Bottom button bar
|
||||
self.margin = 2
|
||||
self.bar_h = 39
|
||||
|
||||
# Canvas drawing area (everything above button bar)
|
||||
self.draw_w = self.W
|
||||
self.draw_h = self.H - (self.bar_h + self.margin * 2)
|
||||
|
||||
self.canvas = canvas
|
||||
|
||||
# Background: white (change if you want dark theme)
|
||||
self.canvas.set_style_bg_color(lv.color_white(), lv.PART.MAIN)
|
||||
|
||||
# Buffer: your working example uses 4 bytes/pixel
|
||||
# Reality filter: this depends on LV_COLOR_DEPTH; but your example proves it works.
|
||||
self.buf = bytearray(self.draw_w * self.draw_h * 4)
|
||||
self.canvas.set_buffer(self.buf, self.draw_w, self.draw_h, lv.COLOR_FORMAT.NATIVE)
|
||||
|
||||
# Layer used for draw engine
|
||||
self.layer = lv.layer_t()
|
||||
self.canvas.init_layer(self.layer)
|
||||
|
||||
# Persistent draw descriptors (avoid allocations)
|
||||
self._line_dsc = lv.draw_line_dsc_t()
|
||||
lv.draw_line_dsc_t.init(self._line_dsc)
|
||||
self._line_dsc.width = 1
|
||||
self._line_dsc.color = lv.color_black()
|
||||
self._line_dsc.round_end = 1
|
||||
self._line_dsc.round_start = 1
|
||||
|
||||
self._label_dsc = lv.draw_label_dsc_t()
|
||||
lv.draw_label_dsc_t.init(self._label_dsc)
|
||||
self._label_dsc.color = lv.color_black()
|
||||
self._label_dsc.font = lv.font_montserrat_24
|
||||
|
||||
self._rect_dsc = lv.draw_rect_dsc_t()
|
||||
lv.draw_rect_dsc_t.init(self._rect_dsc)
|
||||
self._rect_dsc.bg_opa = lv.OPA.TRANSP
|
||||
self._rect_dsc.border_opa = lv.OPA.COVER
|
||||
self._rect_dsc.border_width = 1
|
||||
self._rect_dsc.border_color = lv.color_black()
|
||||
|
||||
self._fill_dsc = lv.draw_rect_dsc_t()
|
||||
lv.draw_rect_dsc_t.init(self._fill_dsc)
|
||||
self._fill_dsc.bg_opa = lv.OPA.COVER
|
||||
self._fill_dsc.bg_color = lv.color_black()
|
||||
self._fill_dsc.border_width = 1
|
||||
|
||||
# Clear once
|
||||
self.clear()
|
||||
|
||||
# ----------------------------
|
||||
# Layer lifecycle
|
||||
# ----------------------------
|
||||
|
||||
def _begin(self):
|
||||
# Start drawing into the layer
|
||||
self.canvas.init_layer(self.layer)
|
||||
|
||||
def _end(self):
|
||||
# Commit drawing
|
||||
self.canvas.finish_layer(self.layer)
|
||||
|
||||
# ----------------------------
|
||||
# Public API: drawing
|
||||
# ----------------------------
|
||||
|
||||
def clear(self):
|
||||
# Clear the canvas background
|
||||
self.canvas.fill_bg(lv.color_white(), lv.OPA.COVER)
|
||||
|
||||
def text(self, x, y, s, fg = lv.color_black()):
|
||||
self._begin()
|
||||
|
||||
dsc = lv.draw_label_dsc_t()
|
||||
lv.draw_label_dsc_t.init(dsc)
|
||||
dsc.text = str(s)
|
||||
dsc.font = lv.font_montserrat_24
|
||||
dsc.color = lv.color_black()
|
||||
|
||||
area = lv.area_t()
|
||||
area.x1 = x
|
||||
area.y1 = y
|
||||
area.x2 = x + self.W
|
||||
area.y2 = y + self.H
|
||||
|
||||
lv.draw_label(self.layer, dsc, area)
|
||||
|
||||
self._end()
|
||||
|
||||
def line(self, x1, y1, x2, y2, fg = lv.color_black()):
|
||||
self._begin()
|
||||
|
||||
dsc = self._line_dsc
|
||||
dsc.p1 = lv.point_precise_t()
|
||||
dsc.p2 = lv.point_precise_t()
|
||||
dsc.p1.x = int(x1)
|
||||
dsc.p1.y = int(y1)
|
||||
dsc.p2.x = int(x2)
|
||||
dsc.p2.y = int(y2)
|
||||
|
||||
lv.draw_line(self.layer, dsc)
|
||||
|
||||
self._end()
|
||||
|
||||
def circle(self, x, y, r, fg = lv.color_black()):
|
||||
# Rounded rectangle trick (works everywhere)
|
||||
self._begin()
|
||||
|
||||
a = lv.area_t()
|
||||
a.x1 = int(x - r)
|
||||
a.y1 = int(y - r)
|
||||
a.x2 = int(x + r)
|
||||
a.y2 = int(y + r)
|
||||
|
||||
dsc = self._rect_dsc
|
||||
dsc.radius = lv.RADIUS_CIRCLE
|
||||
dsc.border_color = fg
|
||||
|
||||
lv.draw_rect(self.layer, dsc, a)
|
||||
|
||||
self._end()
|
||||
|
||||
def fill_circle(self, x, y, r, fg = lv.color_black(), bg = lv.color_white()):
|
||||
self._begin()
|
||||
|
||||
a = lv.area_t()
|
||||
a.x1 = int(x - r)
|
||||
a.y1 = int(y - r)
|
||||
a.x2 = int(x + r)
|
||||
a.y2 = int(y + r)
|
||||
|
||||
dsc = self._rect_dsc
|
||||
dsc.radius = lv.RADIUS_CIRCLE
|
||||
dsc.border_color = fg
|
||||
dsc.bg_color = bg
|
||||
|
||||
lv.draw_rect(self.layer, dsc, a)
|
||||
|
||||
self._end()
|
||||
|
||||
def fill_rect(self, x, y, sx, sy, fg = lv.color_black(), bg = lv.color_white()):
|
||||
self._begin()
|
||||
|
||||
a = lv.area_t()
|
||||
a.x1 = x
|
||||
a.y1 = y
|
||||
a.x2 = x+sx
|
||||
a.y2 = y+sy
|
||||
|
||||
dsc = self._fill_dsc
|
||||
dsc.border_color = fg
|
||||
dsc.bg_color = bg
|
||||
|
||||
lv.draw_rect(self.layer, dsc, a)
|
||||
|
||||
self._end()
|
||||
|
||||
def update(self):
|
||||
# Nothing needed; drawing is committed per primitive.
|
||||
# If you want, you can change the implementation so that:
|
||||
# - draw ops happen between clear() and update()
|
||||
# But then you must ensure the app calls update() once per frame.
|
||||
pass
|
||||
|
||||
# ----------------------------
|
||||
# App logic
|
||||
# ----------------------------
|
||||
|
||||
class PagedCanvas(Activity):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.page = 0
|
||||
self.pages = 3
|
||||
|
||||
def onCreate(self):
|
||||
self.scr = lv.obj()
|
||||
scr = self.scr
|
||||
|
||||
# Screen size
|
||||
self.W = scr.get_width()
|
||||
self.H = scr.get_height()
|
||||
|
||||
# Bottom button bar
|
||||
self.margin = 2
|
||||
self.bar_h = 39
|
||||
|
||||
# Canvas drawing area (everything above button bar)
|
||||
self.draw_w = self.W
|
||||
self.draw_h = self.H - (self.bar_h + self.margin * 2)
|
||||
|
||||
# Canvas
|
||||
self.canvas = lv.canvas(self.scr)
|
||||
self.canvas.set_size(self.draw_w, self.draw_h)
|
||||
self.canvas.align(lv.ALIGN.TOP_LEFT, 0, 0)
|
||||
self.canvas.set_style_border_width(0, 0)
|
||||
|
||||
self.c = Canvas(self.scr, self.canvas)
|
||||
|
||||
# Build buttons
|
||||
self.build_buttons()
|
||||
self.setContentView(self.c.scr)
|
||||
|
||||
# ----------------------------
|
||||
# Button bar
|
||||
# ----------------------------
|
||||
|
||||
def _make_btn(self, parent, x, y, w, h, label):
|
||||
b = lv.button(parent)
|
||||
b.set_pos(x, y)
|
||||
b.set_size(w, h)
|
||||
|
||||
l = lv.label(b)
|
||||
l.set_text(label)
|
||||
l.center()
|
||||
|
||||
return b
|
||||
|
||||
def _btn_cb(self, evt, tag):
|
||||
self.page = tag
|
||||
|
||||
def template_buttons(self, names):
|
||||
margin = self.margin
|
||||
y = self.H - self.bar_h - margin
|
||||
|
||||
num = len(names)
|
||||
if num == 0:
|
||||
self.buttons = []
|
||||
return
|
||||
|
||||
w = (self.W - margin * (num + 1)) // num
|
||||
h = self.bar_h
|
||||
x0 = margin
|
||||
|
||||
self.buttons = []
|
||||
|
||||
for i, label in enumerate(names):
|
||||
x = x0 + (w + margin) * i
|
||||
btn = self._make_btn(self.scr, x, y, w, h, label)
|
||||
|
||||
# capture index correctly
|
||||
btn.add_event_cb(
|
||||
lambda evt, idx=i: self._btn_cb(evt, idx),
|
||||
lv.EVENT.CLICKED,
|
||||
None
|
||||
)
|
||||
|
||||
self.buttons.append(btn)
|
||||
|
||||
def build_buttons(self):
|
||||
self.template_buttons(["Pg0", "Pg1", "Pg2", "Pg3", "..."])
|
||||
|
||||
def onResume(self, screen):
|
||||
self.timer = lv.timer_create(self.tick, 1000, None)
|
||||
|
||||
def onPause(self, screen):
|
||||
if self.timer:
|
||||
self.timer.delete()
|
||||
self.timer = None
|
||||
|
||||
def tick(self, t):
|
||||
self.update()
|
||||
self.draw()
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def draw_page_example(self):
|
||||
ui = self.c
|
||||
ui.clear()
|
||||
|
||||
st = 28
|
||||
y = 2*st
|
||||
ui.text(0, y, "Hello world, page is %d" % self.page)
|
||||
y += st
|
||||
|
||||
def draw(self):
|
||||
self.draw_page_example()
|
||||
|
||||
def handle_buttons(self):
|
||||
ui = self.c
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
Reference in New Issue
Block a user