You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
Introduce DisplayMetrics framework
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import gc
|
||||
import os
|
||||
|
||||
from mpos import Activity, smooth_show, smooth_hide, pct_of_display_width, pct_of_display_height
|
||||
from mpos import Activity, smooth_show, smooth_hide, DisplayMetrics
|
||||
|
||||
class ImageView(Activity):
|
||||
|
||||
@@ -271,8 +271,8 @@ class ImageView(Activity):
|
||||
pct = 100
|
||||
else:
|
||||
pct = 70
|
||||
lvgl_w = pct_of_display_width(pct)
|
||||
lvgl_h = pct_of_display_height(pct)
|
||||
lvgl_w = DisplayMetrics.pct_of_width(pct)
|
||||
lvgl_h = DisplayMetrics.pct_of_height(pct)
|
||||
print(f"scaling to size: {lvgl_w}x{lvgl_h}")
|
||||
header = lv.image_header_t()
|
||||
self.image.decoder_get_info(self.image.get_src(), header)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import lvgl as lv
|
||||
|
||||
from mpos import Activity, min_resolution
|
||||
from mpos import Activity, DisplayMetrics
|
||||
|
||||
class FullscreenQR(Activity):
|
||||
# No __init__() so super.__init__() will be called automatically
|
||||
@@ -28,7 +28,7 @@ class FullscreenQR(Activity):
|
||||
qr_screen.set_scroll_dir(lv.DIR.NONE)
|
||||
qr_screen.add_event_cb(lambda e: self.finish(),lv.EVENT.CLICKED,None)
|
||||
big_receive_qr = lv.qrcode(qr_screen)
|
||||
big_receive_qr.set_size(min_resolution())
|
||||
big_receive_qr.set_size(DisplayMetrics.min_dimension())
|
||||
big_receive_qr.set_dark_color(lv.color_black())
|
||||
big_receive_qr.set_light_color(lv.color_white())
|
||||
big_receive_qr.center()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import lvgl as lv
|
||||
|
||||
from mpos import Activity, Intent, ConnectivityManager, pct_of_display_width, pct_of_display_height, SharedPreferences, SettingsActivity
|
||||
from mpos import Activity, Intent, ConnectivityManager, DisplayMetrics, SharedPreferences, SettingsActivity
|
||||
from fullscreen_qr import FullscreenQR
|
||||
|
||||
class ShowNpubQRActivity(Activity):
|
||||
@@ -82,13 +82,13 @@ class NostrApp(Activity):
|
||||
self.balance_label.align(lv.ALIGN.TOP_LEFT, 0, 0)
|
||||
self.balance_label.set_style_text_font(lv.font_montserrat_24, 0)
|
||||
self.balance_label.add_flag(lv.obj.FLAG.CLICKABLE)
|
||||
self.balance_label.set_width(pct_of_display_width(100))
|
||||
self.balance_label.set_width(DisplayMetrics.pct_of_width(100))
|
||||
# Events label
|
||||
self.events_label = lv.label(self.main_screen)
|
||||
self.events_label.set_text("")
|
||||
self.events_label.align_to(header_line,lv.ALIGN.OUT_BOTTOM_LEFT,0,10)
|
||||
self.update_events_label_font()
|
||||
self.events_label.set_width(pct_of_display_width(100))
|
||||
self.events_label.set_width(DisplayMetrics.pct_of_width(100))
|
||||
self.events_label.add_flag(lv.obj.FLAG.CLICKABLE)
|
||||
self.events_label.add_event_cb(self.events_label_clicked,lv.EVENT.CLICKED,None)
|
||||
settings_button = lv.button(self.main_screen)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from mpos import Activity, pct_of_display_width, get_display_width, get_display_height, get_dpi
|
||||
from mpos import Activity, DisplayMetrics
|
||||
|
||||
import mpos.info
|
||||
import sys
|
||||
@@ -38,7 +38,7 @@ class About(Activity):
|
||||
screen = lv.obj()
|
||||
screen.set_style_border_width(0, 0)
|
||||
screen.set_flex_flow(lv.FLEX_FLOW.COLUMN)
|
||||
screen.set_style_pad_all(pct_of_display_width(2), 0)
|
||||
screen.set_style_pad_all(DisplayMetrics.pct_of_width(2), 0)
|
||||
# Make the screen focusable so it can be scrolled with the arrow keys
|
||||
focusgroup = lv.group_get_default()
|
||||
if focusgroup:
|
||||
@@ -147,10 +147,10 @@ class About(Activity):
|
||||
# Display info
|
||||
try:
|
||||
self._add_label(screen, f"{lv.SYMBOL.IMAGE} Display", is_header=True)
|
||||
hor_res = get_display_width()
|
||||
ver_res = get_display_height()
|
||||
hor_res = DisplayMetrics.width()
|
||||
ver_res = DisplayMetrics.height()
|
||||
self._add_label(screen, f"Resolution: {hor_res}x{ver_res}")
|
||||
dpi = get_dpi()
|
||||
dpi = DisplayMetrics.dpi()
|
||||
self._add_label(screen, f"Dots Per Inch (dpi): {dpi}")
|
||||
except Exception as e:
|
||||
print(f"Could not get display info: {e}")
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# Most of this time is actually spent reading and parsing manifests.
|
||||
import lvgl as lv
|
||||
import mpos.apps
|
||||
from mpos import NOTIFICATION_BAR_HEIGHT, PackageManager, Activity, pct_of_display_width
|
||||
from mpos import NOTIFICATION_BAR_HEIGHT, PackageManager, Activity, DisplayMetrics
|
||||
import time
|
||||
import uhashlib
|
||||
import ubinascii
|
||||
@@ -29,7 +29,7 @@ class Launcher(Activity):
|
||||
main_screen.set_style_border_width(0, lv.PART.MAIN)
|
||||
main_screen.set_style_radius(0, 0)
|
||||
main_screen.set_pos(0, NOTIFICATION_BAR_HEIGHT)
|
||||
main_screen.set_style_pad_hor(pct_of_display_width(2), 0)
|
||||
main_screen.set_style_pad_hor(DisplayMetrics.pct_of_width(2), 0)
|
||||
main_screen.set_style_pad_ver(NOTIFICATION_BAR_HEIGHT, 0)
|
||||
main_screen.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
|
||||
self.setContentView(main_screen)
|
||||
|
||||
@@ -2,7 +2,7 @@ import lvgl as lv
|
||||
import ujson
|
||||
import time
|
||||
|
||||
from mpos import Activity, PackageManager, ConnectivityManager, TaskManager, DownloadManager, pct_of_display_width, pct_of_display_height
|
||||
from mpos import Activity, PackageManager, ConnectivityManager, TaskManager, DownloadManager, DisplayMetrics
|
||||
import mpos.info
|
||||
|
||||
class OSUpdate(Activity):
|
||||
@@ -39,7 +39,7 @@ class OSUpdate(Activity):
|
||||
|
||||
def onCreate(self):
|
||||
self.main_screen = lv.obj()
|
||||
self.main_screen.set_style_pad_all(pct_of_display_width(2), 0)
|
||||
self.main_screen.set_style_pad_all(DisplayMetrics.pct_of_width(2), 0)
|
||||
|
||||
# Make the screen focusable so it can be scrolled with the arrow keys
|
||||
if focusgroup := lv.group_get_default():
|
||||
@@ -51,7 +51,7 @@ class OSUpdate(Activity):
|
||||
self.force_update = lv.checkbox(self.main_screen)
|
||||
self.force_update.set_text("Force Update")
|
||||
self.force_update.add_event_cb(lambda *args: self.force_update_clicked(), lv.EVENT.VALUE_CHANGED, None)
|
||||
self.force_update.align_to(self.current_version_label, lv.ALIGN.OUT_BOTTOM_LEFT, 0, pct_of_display_height(5))
|
||||
self.force_update.align_to(self.current_version_label, lv.ALIGN.OUT_BOTTOM_LEFT, 0, DisplayMetrics.pct_of_height(5))
|
||||
self.install_button = lv.button(self.main_screen)
|
||||
self.install_button.align(lv.ALIGN.TOP_RIGHT, 0, 0)
|
||||
self.install_button.add_state(lv.STATE.DISABLED) # button will be enabled if there is an update available
|
||||
@@ -72,7 +72,7 @@ class OSUpdate(Activity):
|
||||
check_again_label.center()
|
||||
|
||||
self.status_label = lv.label(self.main_screen)
|
||||
self.status_label.align_to(self.force_update, lv.ALIGN.OUT_BOTTOM_LEFT, 0, pct_of_display_height(5))
|
||||
self.status_label.align_to(self.force_update, lv.ALIGN.OUT_BOTTOM_LEFT, 0, DisplayMetrics.pct_of_height(5))
|
||||
self.setContentView(self.main_screen)
|
||||
|
||||
def _update_ui_for_state(self):
|
||||
|
||||
@@ -10,7 +10,7 @@ Guides user through IMU calibration process:
|
||||
import lvgl as lv
|
||||
import time
|
||||
import sys
|
||||
from mpos import Activity, SensorManager, wait_for_render, pct_of_display_width
|
||||
from mpos import Activity, SensorManager, wait_for_render, DisplayMetrics
|
||||
|
||||
|
||||
class CalibrationState:
|
||||
@@ -40,7 +40,7 @@ class CalibrateIMUActivity(Activity):
|
||||
|
||||
def onCreate(self):
|
||||
screen = lv.obj()
|
||||
screen.set_style_pad_all(pct_of_display_width(3), 0)
|
||||
screen.set_style_pad_all(DisplayMetrics.pct_of_width(3), 0)
|
||||
screen.set_flex_flow(lv.FLEX_FLOW.COLUMN)
|
||||
screen.set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.CENTER)
|
||||
focusgroup = lv.group_get_default()
|
||||
|
||||
+3
-3
@@ -7,7 +7,7 @@ variance, expected value comparison, and overall quality score.
|
||||
import lvgl as lv
|
||||
import time
|
||||
import sys
|
||||
from mpos import Activity, SensorManager, pct_of_display_width
|
||||
from mpos import Activity, SensorManager, DisplayMetrics
|
||||
|
||||
|
||||
class CheckIMUCalibrationActivity(Activity):
|
||||
@@ -34,7 +34,7 @@ class CheckIMUCalibrationActivity(Activity):
|
||||
|
||||
def onCreate(self):
|
||||
screen = lv.obj()
|
||||
screen.set_style_pad_all(pct_of_display_width(1), 0)
|
||||
screen.set_style_pad_all(DisplayMetrics.pct_of_width(1), 0)
|
||||
#screen.set_style_pad_all(0, 0)
|
||||
screen.set_flex_flow(lv.FLEX_FLOW.COLUMN)
|
||||
focusgroup = lv.group_get_default()
|
||||
@@ -96,7 +96,7 @@ class CheckIMUCalibrationActivity(Activity):
|
||||
|
||||
# Gyroscope section
|
||||
gyro_cont = lv.obj(data_cont)
|
||||
gyro_cont.set_width(pct_of_display_width(45))
|
||||
gyro_cont.set_width(DisplayMetrics.pct_of_width(45))
|
||||
gyro_cont.set_height(lv.SIZE_CONTENT)
|
||||
gyro_cont.set_style_border_width(0, 0)
|
||||
gyro_cont.set_style_pad_all(0, 0)
|
||||
|
||||
@@ -2,7 +2,7 @@ import time
|
||||
import lvgl as lv
|
||||
import _thread
|
||||
|
||||
from mpos import Activity, Intent, MposKeyboard, WifiService, CameraActivity, pct_of_display_width, CameraManager
|
||||
from mpos import Activity, Intent, MposKeyboard, WifiService, CameraActivity, DisplayMetrics, CameraManager
|
||||
import mpos.apps
|
||||
|
||||
class WiFi(Activity):
|
||||
@@ -238,8 +238,8 @@ class EditNetwork(Activity):
|
||||
label.set_text(f"Network name:")
|
||||
self.ssid_ta = lv.textarea(password_page)
|
||||
self.ssid_ta.set_width(lv.pct(100))
|
||||
self.ssid_ta.set_style_margin_left(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.ssid_ta.set_style_margin_right(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.ssid_ta.set_style_margin_left(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.ssid_ta.set_style_margin_right(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.ssid_ta.set_one_line(True)
|
||||
self.ssid_ta.set_placeholder_text("Enter the SSID")
|
||||
self.keyboard = MposKeyboard(password_page)
|
||||
@@ -254,8 +254,8 @@ class EditNetwork(Activity):
|
||||
label.set_text(f"Password for '{self.selected_ssid}':")
|
||||
self.password_ta = lv.textarea(password_page)
|
||||
self.password_ta.set_width(lv.pct(100))
|
||||
self.password_ta.set_style_margin_left(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.password_ta.set_style_margin_right(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.password_ta.set_style_margin_left(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.password_ta.set_style_margin_right(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.password_ta.set_one_line(True)
|
||||
if known_password:
|
||||
self.password_ta.set_text(known_password)
|
||||
@@ -267,7 +267,7 @@ class EditNetwork(Activity):
|
||||
# Hidden network:
|
||||
self.hidden_cb = lv.checkbox(password_page)
|
||||
self.hidden_cb.set_text("Hidden network (always try connecting)")
|
||||
self.hidden_cb.set_style_margin_left(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.hidden_cb.set_style_margin_left(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
if known_hidden:
|
||||
self.hidden_cb.set_state(lv.STATE.CHECKED, True)
|
||||
|
||||
|
||||
@@ -31,11 +31,7 @@ from .ui.testing import (
|
||||
)
|
||||
|
||||
# UI utility functions
|
||||
from .ui.display import (
|
||||
pct_of_display_width, pct_of_display_height,
|
||||
get_display_width, get_display_height, get_dpi,
|
||||
min_resolution, max_resolution, get_pointer_xy
|
||||
)
|
||||
from .ui.display_metrics import DisplayMetrics
|
||||
from .ui.event import get_event_name, print_event
|
||||
from .ui.view import setContentView, back_screen
|
||||
from .ui.theme import set_theme
|
||||
@@ -73,10 +69,8 @@ __all__ = [
|
||||
"SettingActivity", "SettingsActivity", "CameraActivity",
|
||||
# UI components
|
||||
"MposKeyboard",
|
||||
# UI utility functions
|
||||
"pct_of_display_width", "pct_of_display_height",
|
||||
"get_display_width", "get_display_height", "get_dpi",
|
||||
"min_resolution", "max_resolution", "get_pointer_xy",
|
||||
# UI utility - DisplayMetrics
|
||||
"DisplayMetrics",
|
||||
"get_event_name", "print_event",
|
||||
"setContentView", "back_screen",
|
||||
"set_theme",
|
||||
|
||||
@@ -6,12 +6,7 @@ from .gesture_navigation import handle_back_swipe, handle_top_swipe
|
||||
from .theme import set_theme
|
||||
from .topmenu import open_bar, close_bar, open_drawer, drawer_open, NOTIFICATION_BAR_HEIGHT
|
||||
from .focus import save_and_clear_current_focusgroup
|
||||
from .display import (
|
||||
get_display_width, get_display_height, get_dpi,
|
||||
pct_of_display_width, pct_of_display_height,
|
||||
min_resolution, max_resolution,
|
||||
get_pointer_xy # ← now correct
|
||||
)
|
||||
from .display_metrics import DisplayMetrics
|
||||
from .event import get_event_name, print_event
|
||||
from .util import shutdown, set_foreground_app, get_foreground_app
|
||||
from .setting_activity import SettingActivity
|
||||
@@ -28,10 +23,7 @@ __all__ = [
|
||||
"set_theme",
|
||||
"open_bar", "close_bar", "open_drawer", "drawer_open", "NOTIFICATION_BAR_HEIGHT",
|
||||
"save_and_clear_current_focusgroup",
|
||||
"get_display_width", "get_display_height", "get_dpi",
|
||||
"pct_of_display_width", "pct_of_display_height",
|
||||
"min_resolution", "max_resolution",
|
||||
"get_pointer_xy",
|
||||
"DisplayMetrics",
|
||||
"get_event_name", "print_event",
|
||||
"shutdown", "set_foreground_app", "get_foreground_app",
|
||||
"SettingActivity",
|
||||
|
||||
@@ -99,11 +99,11 @@ class CameraActivity(Activity):
|
||||
|
||||
|
||||
self.status_label_cont = lv.obj(self.main_screen)
|
||||
width = mpos_ui.pct_of_display_width(70)
|
||||
height = mpos_ui.pct_of_display_width(60)
|
||||
width = mpos_ui.DisplayMetrics.pct_of_width(70)
|
||||
height = mpos_ui.DisplayMetrics.pct_of_width(60)
|
||||
self.status_label_cont.set_size(width,height)
|
||||
center_w = round((mpos_ui.pct_of_display_width(100) - self.button_width - 5 - width)/2)
|
||||
center_h = round((mpos_ui.pct_of_display_height(100) - height)/2)
|
||||
center_w = round((mpos_ui.DisplayMetrics.pct_of_width(100) - self.button_width - 5 - width)/2)
|
||||
center_h = round((mpos_ui.DisplayMetrics.pct_of_height(100) - height)/2)
|
||||
self.status_label_cont.set_pos(center_w,center_h)
|
||||
self.status_label_cont.set_style_bg_color(lv.color_white(), 0)
|
||||
self.status_label_cont.set_style_bg_opa(66, 0)
|
||||
|
||||
@@ -2,7 +2,7 @@ import lvgl as lv
|
||||
|
||||
from ..config import SharedPreferences
|
||||
from ..app.activity import Activity
|
||||
from .display import pct_of_display_width, pct_of_display_height
|
||||
from .display import DisplayMetrics
|
||||
from . import anim
|
||||
|
||||
class CameraSettingsActivity(Activity):
|
||||
@@ -125,7 +125,7 @@ class CameraSettingsActivity(Activity):
|
||||
|
||||
# Create tabview
|
||||
tabview = lv.tabview(screen)
|
||||
tabview.set_tab_bar_size(pct_of_display_height(15))
|
||||
tabview.set_tab_bar_size(DisplayMetrics.pct_of_height(15))
|
||||
#tabview.set_size(lv.pct(100), pct_of_display_height(80))
|
||||
|
||||
# Create Basic tab (always)
|
||||
@@ -239,7 +239,7 @@ class CameraSettingsActivity(Activity):
|
||||
def add_buttons(self, parent):
|
||||
# Save/Cancel buttons at bottom
|
||||
button_cont = lv.obj(parent)
|
||||
button_cont.set_size(lv.pct(100), pct_of_display_height(20))
|
||||
button_cont.set_size(lv.pct(100), DisplayMetrics.pct_of_height(20))
|
||||
button_cont.remove_flag(lv.obj.FLAG.SCROLLABLE)
|
||||
button_cont.align(lv.ALIGN.BOTTOM_MID, 0, 0)
|
||||
button_cont.set_style_border_width(0, 0)
|
||||
@@ -256,9 +256,9 @@ class CameraSettingsActivity(Activity):
|
||||
save_label.center()
|
||||
|
||||
cancel_button = lv.button(button_cont)
|
||||
cancel_button.set_size(pct_of_display_width(25), lv.SIZE_CONTENT)
|
||||
cancel_button.set_size(DisplayMetrics.pct_of_width(25), lv.SIZE_CONTENT)
|
||||
if self.scanqr_mode:
|
||||
cancel_button.align(lv.ALIGN.BOTTOM_MID, pct_of_display_width(10), 0)
|
||||
cancel_button.align(lv.ALIGN.BOTTOM_MID, DisplayMetrics.pct_of_width(10), 0)
|
||||
else:
|
||||
cancel_button.align(lv.ALIGN.BOTTOM_MID, 0, 0)
|
||||
cancel_button.add_event_cb(lambda e: self.finish(), lv.EVENT.CLICKED, None)
|
||||
@@ -267,7 +267,7 @@ class CameraSettingsActivity(Activity):
|
||||
cancel_label.center()
|
||||
|
||||
erase_button = lv.button(button_cont)
|
||||
erase_button.set_size(pct_of_display_width(20), lv.SIZE_CONTENT)
|
||||
erase_button.set_size(DisplayMetrics.pct_of_width(20), lv.SIZE_CONTENT)
|
||||
erase_button.align(lv.ALIGN.BOTTOM_RIGHT, 0, 0)
|
||||
erase_button.add_event_cb(lambda e: self.erase_and_close(), lv.EVENT.CLICKED, None)
|
||||
erase_label = lv.label(erase_button)
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# lib/mpos/ui/display.py
|
||||
import lvgl as lv
|
||||
"""
|
||||
Display initialization module.
|
||||
|
||||
_horizontal_resolution = None
|
||||
_vertical_resolution = None
|
||||
_dpi = None
|
||||
Handles LVGL display initialization and sets up DisplayMetrics.
|
||||
"""
|
||||
|
||||
import lvgl as lv
|
||||
from .display_metrics import DisplayMetrics
|
||||
|
||||
# White text on black logo works (for dark mode) and can be inverted (for light mode)
|
||||
logo_white = "M:builtin/res/mipmap-mdpi/MicroPythonOS-logo-white-long-w296_without_border_266x39.png"
|
||||
@@ -13,20 +16,27 @@ logo_white = "M:builtin/res/mipmap-mdpi/MicroPythonOS-logo-white-long-w296_witho
|
||||
# Even when it's on a white (instead of transparent) background
|
||||
#logo_black = "M:builtin/res/mipmap-mdpi/MicroPythonOS-logo-black-long-w240.png"
|
||||
|
||||
|
||||
def init_rootscreen():
|
||||
global _horizontal_resolution, _vertical_resolution, _dpi
|
||||
"""Initialize the root screen and set display metrics."""
|
||||
screen = lv.screen_active()
|
||||
disp = screen.get_display()
|
||||
_horizontal_resolution = disp.get_horizontal_resolution()
|
||||
_vertical_resolution = disp.get_vertical_resolution()
|
||||
_dpi = disp.get_dpi()
|
||||
print(f"init_rootscreen set resolution to {_horizontal_resolution}x{_vertical_resolution} at {_dpi} DPI")
|
||||
width = disp.get_horizontal_resolution()
|
||||
height = disp.get_vertical_resolution()
|
||||
dpi = disp.get_dpi()
|
||||
|
||||
# Initialize DisplayMetrics with actual display values
|
||||
DisplayMetrics.set_resolution(width, height)
|
||||
DisplayMetrics.set_dpi(dpi)
|
||||
|
||||
print(f"init_rootscreen set resolution to {width}x{height} at {dpi} DPI")
|
||||
|
||||
try:
|
||||
img = lv.image(screen)
|
||||
img.set_src(logo_white)
|
||||
img.set_blend_mode(lv.BLEND_MODE.DIFFERENCE)
|
||||
img.center()
|
||||
except Exception as e: # if image loading fails
|
||||
except Exception as e: # if image loading fails
|
||||
print(f"ERROR: logo image failed, LVGL will be in a bad state and the UI will hang: {e}")
|
||||
import sys
|
||||
sys.print_exception(e)
|
||||
@@ -35,38 +45,3 @@ def init_rootscreen():
|
||||
label.set_text("MicroPythonOS")
|
||||
label.set_style_text_font(lv.font_montserrat_20, lv.PART.MAIN)
|
||||
label.center()
|
||||
|
||||
def get_pointer_xy():
|
||||
indev = lv.indev_active()
|
||||
if indev:
|
||||
p = lv.point_t()
|
||||
indev.get_point(p)
|
||||
return p.x, p.y
|
||||
return -1, -1
|
||||
|
||||
def pct_of_display_width(pct):
|
||||
if pct == 100:
|
||||
return _horizontal_resolution
|
||||
return round(_horizontal_resolution * pct / 100)
|
||||
|
||||
def pct_of_display_height(pct):
|
||||
if pct == 100:
|
||||
return _vertical_resolution
|
||||
return round(_vertical_resolution * pct / 100)
|
||||
|
||||
def min_resolution():
|
||||
return min(_horizontal_resolution, _vertical_resolution)
|
||||
|
||||
def max_resolution():
|
||||
return max(_horizontal_resolution, _vertical_resolution)
|
||||
|
||||
def get_display_width():
|
||||
return _horizontal_resolution
|
||||
|
||||
def get_display_height():
|
||||
return _vertical_resolution
|
||||
|
||||
def get_dpi():
|
||||
print(f"get_dpi_called {_dpi}")
|
||||
return _dpi
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# lib/mpos/ui/display_metrics.py
|
||||
"""
|
||||
DisplayMetrics - Android-inspired display metrics singleton.
|
||||
|
||||
Provides a clean, unified API for accessing display properties like width, height, and DPI.
|
||||
All methods are class methods, so no instance creation is needed.
|
||||
"""
|
||||
|
||||
|
||||
class DisplayMetrics:
|
||||
"""
|
||||
Display metrics singleton (Android-inspired).
|
||||
|
||||
Provides static/class methods for accessing display properties.
|
||||
Initialized by display.init_rootscreen() which calls set_resolution() and set_dpi().
|
||||
"""
|
||||
|
||||
_width = None
|
||||
_height = None
|
||||
_dpi = None
|
||||
|
||||
@classmethod
|
||||
def set_resolution(cls, width, height):
|
||||
"""Set the display resolution (called by init_rootscreen)."""
|
||||
cls._width = width
|
||||
cls._height = height
|
||||
|
||||
@classmethod
|
||||
def set_dpi(cls, dpi):
|
||||
"""Set the display DPI (called by init_rootscreen)."""
|
||||
cls._dpi = dpi
|
||||
|
||||
@classmethod
|
||||
def width(cls):
|
||||
"""Get display width in pixels."""
|
||||
return cls._width
|
||||
|
||||
@classmethod
|
||||
def height(cls):
|
||||
"""Get display height in pixels."""
|
||||
return cls._height
|
||||
|
||||
@classmethod
|
||||
def dpi(cls):
|
||||
"""Get display DPI (dots per inch)."""
|
||||
return cls._dpi
|
||||
|
||||
@classmethod
|
||||
def pct_of_width(cls, pct):
|
||||
"""Get percentage of display width."""
|
||||
if pct == 100:
|
||||
return cls._width
|
||||
return round(cls._width * pct / 100)
|
||||
|
||||
@classmethod
|
||||
def pct_of_height(cls, pct):
|
||||
"""Get percentage of display height."""
|
||||
if pct == 100:
|
||||
return cls._height
|
||||
return round(cls._height * pct / 100)
|
||||
|
||||
@classmethod
|
||||
def min_dimension(cls):
|
||||
"""Get minimum dimension (width or height)."""
|
||||
return min(cls._width, cls._height)
|
||||
|
||||
@classmethod
|
||||
def max_dimension(cls):
|
||||
"""Get maximum dimension (width or height)."""
|
||||
return max(cls._width, cls._height)
|
||||
|
||||
@classmethod
|
||||
def pointer_xy(cls):
|
||||
"""Get current pointer/touch coordinates."""
|
||||
import lvgl as lv
|
||||
indev = lv.indev_active()
|
||||
if indev:
|
||||
p = lv.point_t()
|
||||
indev.get_point(p)
|
||||
return p.x, p.y
|
||||
return -1, -1
|
||||
@@ -3,7 +3,7 @@ from lvgl import LvReferenceError
|
||||
from .anim import smooth_show, smooth_hide
|
||||
from .view import back_screen
|
||||
from mpos.ui import topmenu as topmenu
|
||||
from .display import get_display_width, get_display_height
|
||||
from .display import DisplayMetrics
|
||||
|
||||
downbutton = None
|
||||
backbutton = None
|
||||
@@ -56,7 +56,7 @@ def _back_swipe_cb(event):
|
||||
if backbutton_visible:
|
||||
backbutton_visible = False
|
||||
smooth_hide(backbutton)
|
||||
if x > get_display_width() / 5:
|
||||
if x > DisplayMetrics.width() / 5:
|
||||
if topmenu.drawer_open :
|
||||
topmenu.close_drawer()
|
||||
else :
|
||||
@@ -97,7 +97,7 @@ def _top_swipe_cb(event):
|
||||
smooth_hide(downbutton)
|
||||
dx = abs(x - down_start_x)
|
||||
dy = abs(y - down_start_y)
|
||||
if y > get_display_height() / 5:
|
||||
if y > DisplayMetrics.height() / 5:
|
||||
topmenu.open_drawer()
|
||||
elif is_short_movement(dx, dy):
|
||||
# print("Short movement - treating as tap")
|
||||
|
||||
@@ -2,7 +2,7 @@ import lvgl as lv
|
||||
|
||||
from ..app.activity import Activity
|
||||
from .camera_activity import CameraActivity
|
||||
from .display import pct_of_display_width
|
||||
from .display import DisplayMetrics
|
||||
from . import anim
|
||||
from ..camera_manager import CameraManager
|
||||
|
||||
@@ -80,9 +80,9 @@ class SettingActivity(Activity):
|
||||
ui = "textarea"
|
||||
self.textarea = lv.textarea(settings_screen_detail)
|
||||
self.textarea.set_width(lv.pct(100))
|
||||
self.textarea.set_style_pad_all(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_style_margin_left(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_style_margin_right(pct_of_display_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_style_pad_all(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_style_margin_left(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_style_margin_right(DisplayMetrics.pct_of_width(2), lv.PART.MAIN)
|
||||
self.textarea.set_one_line(True)
|
||||
if current_setting:
|
||||
self.textarea.set_text(current_setting)
|
||||
|
||||
@@ -17,7 +17,7 @@ class SettingsActivity(Activity):
|
||||
|
||||
print("creating SettingsActivity ui...")
|
||||
screen = lv.obj()
|
||||
screen.set_style_pad_all(mpos.ui.pct_of_display_width(2), 0)
|
||||
screen.set_style_pad_all(mpos.ui.DisplayMetrics.pct_of_width(2), 0)
|
||||
screen.set_flex_flow(lv.FLEX_FLOW.COLUMN)
|
||||
screen.set_style_border_width(0, 0)
|
||||
self.setContentView(screen)
|
||||
@@ -43,7 +43,7 @@ class SettingsActivity(Activity):
|
||||
setting_cont.set_height(lv.SIZE_CONTENT)
|
||||
setting_cont.set_style_border_width(1, 0)
|
||||
#setting_cont.set_style_border_side(lv.BORDER_SIDE.BOTTOM, 0)
|
||||
setting_cont.set_style_pad_all(mpos.ui.pct_of_display_width(2), 0)
|
||||
setting_cont.set_style_pad_all(mpos.ui.DisplayMetrics.pct_of_width(2), 0)
|
||||
setting_cont.add_flag(lv.obj.FLAG.CLICKABLE)
|
||||
setting["cont"] = setting_cont # Store container reference for visibility control
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import lvgl as lv
|
||||
|
||||
import mpos.time
|
||||
import mpos.battery_voltage
|
||||
from .display import (get_display_width, get_display_height, pct_of_display_width, pct_of_display_height, get_pointer_xy)
|
||||
from .display_metrics import DisplayMetrics
|
||||
from .util import (get_foreground_app)
|
||||
from . import focus_direction
|
||||
from .anim import WidgetAnimator
|
||||
@@ -89,14 +89,14 @@ def create_notification_bar():
|
||||
# Time label
|
||||
time_label = lv.label(notification_bar)
|
||||
time_label.set_text("00:00:00")
|
||||
time_label.align(lv.ALIGN.LEFT_MID, pct_of_display_width(10), 0)
|
||||
time_label.align(lv.ALIGN.LEFT_MID, DisplayMetrics.pct_of_width(10), 0)
|
||||
temp_label = lv.label(notification_bar)
|
||||
temp_label.set_text("00°C")
|
||||
temp_label.align_to(time_label, lv.ALIGN.OUT_RIGHT_MID, pct_of_display_width(7) , 0)
|
||||
temp_label.align_to(time_label, lv.ALIGN.OUT_RIGHT_MID, DisplayMetrics.pct_of_width(7) , 0)
|
||||
if False:
|
||||
memfree_label = lv.label(notification_bar)
|
||||
memfree_label.set_text("")
|
||||
memfree_label.align_to(temp_label, lv.ALIGN.OUT_RIGHT_MID, pct_of_display_width(7), 0)
|
||||
memfree_label.align_to(temp_label, lv.ALIGN.OUT_RIGHT_MID, DisplayMetrics.pct_of_width(7), 0)
|
||||
#style = lv.style_t()
|
||||
#style.init()
|
||||
#style.set_text_font(lv.font_montserrat_8) # tiny font
|
||||
@@ -114,12 +114,12 @@ def create_notification_bar():
|
||||
battery_icon = lv.label(notification_bar)
|
||||
battery_icon.set_text(lv.SYMBOL.BATTERY_FULL)
|
||||
#battery_icon.align_to(battery_label, lv.ALIGN.OUT_LEFT_MID, 0, 0)
|
||||
battery_icon.align(lv.ALIGN.RIGHT_MID, -pct_of_display_width(10), 0)
|
||||
battery_icon.align(lv.ALIGN.RIGHT_MID, -DisplayMetrics.pct_of_width(10), 0)
|
||||
battery_icon.add_flag(lv.obj.FLAG.HIDDEN) # keep it hidden until it has a correct value
|
||||
# WiFi icon
|
||||
wifi_icon = lv.label(notification_bar)
|
||||
wifi_icon.set_text(lv.SYMBOL.WIFI)
|
||||
wifi_icon.align_to(battery_icon, lv.ALIGN.OUT_LEFT_MID, -pct_of_display_width(1), 0)
|
||||
wifi_icon.align_to(battery_icon, lv.ALIGN.OUT_LEFT_MID, -DisplayMetrics.pct_of_width(1), 0)
|
||||
wifi_icon.add_flag(lv.obj.FLAG.HIDDEN)
|
||||
# Update time
|
||||
def update_time(timer):
|
||||
@@ -366,13 +366,13 @@ def create_drawer(display=None):
|
||||
# Add invisible padding at the bottom to make the drawer scrollable
|
||||
l2 = lv.label(drawer)
|
||||
l2.set_text("\n")
|
||||
l2.set_pos(0,get_display_height())
|
||||
l2.set_pos(0, DisplayMetrics.height())
|
||||
|
||||
|
||||
def drawer_scroll_callback(event):
|
||||
global scroll_start_y
|
||||
event_code=event.get_code()
|
||||
x, y = get_pointer_xy()
|
||||
x, y = DisplayMetrics.pointer_xy()
|
||||
#name = mpos.ui.get_event_name(event_code)
|
||||
#print(f"drawer_scroll: code={event_code}, name={name}, ({x},{y})")
|
||||
if event_code == lv.EVENT.SCROLL_BEGIN and scroll_start_y == None:
|
||||
|
||||
Reference in New Issue
Block a user