2025-10-30 20:31:02 +01:00
import lvgl as lv
2025-11-23 09:00:38 +01:00
from lvgl import LvReferenceError
2026-01-23 21:37:53 +01:00
from . widget_animator import WidgetAnimator
2025-10-30 20:31:02 +01:00
from . view import back_screen
2025-12-05 13:37:11 +01:00
from mpos . ui import topmenu as topmenu
2026-01-23 23:25:22 +01:00
from . display_metrics import DisplayMetrics
2026-01-23 22:26:01 +01:00
from . appearance_manager import AppearanceManager
2025-10-30 20:31:02 +01:00
downbutton = None
backbutton = None
down_start_x = 0
2025-11-19 12:34:16 +01:00
down_start_y = 0
2025-10-30 20:31:02 +01:00
back_start_y = 0
2025-11-19 12:34:16 +01:00
back_start_x = 0
short_movement_threshold = 10
2025-11-20 16:36:14 +01:00
backbutton_visible = False
downbutton_visible = False
def is_short_movement ( dx , dy ) :
return dx < short_movement_threshold and dy < short_movement_threshold
2025-10-30 20:31:02 +01:00
2025-11-23 09:00:38 +01:00
def _passthrough_click ( x , y , indev ) :
obj = lv . indev_search_obj ( lv . screen_active ( ) , lv . point_t ( { ' x ' : x , ' y ' : y } ) )
# print(f"Found object: {obj}")
if obj :
try :
# print(f"Simulating press/click/release on {obj}")
obj . send_event ( lv . EVENT . PRESSED , indev )
obj . send_event ( lv . EVENT . CLICKED , indev )
obj . send_event ( lv . EVENT . RELEASED , indev ) # gets lost
except LvReferenceError as e :
print ( f " Object to click is gone: { e } " )
2025-10-30 20:31:02 +01:00
def _back_swipe_cb ( event ) :
2025-11-20 16:36:14 +01:00
global backbutton , back_start_y , back_start_x , backbutton_visible
2025-10-30 20:52:26 +01:00
event_code = event . get_code ( )
2025-10-30 20:31:02 +01:00
indev = lv . indev_active ( )
if not indev :
return
point = lv . point_t ( )
indev . get_point ( point )
2025-10-30 20:52:26 +01:00
x = point . x
y = point . y
2025-11-20 16:36:14 +01:00
dx = abs ( x - back_start_x )
dy = abs ( y - back_start_y )
2025-10-30 20:52:26 +01:00
#print(f"visual_back_swipe_cb event_code={event_code} and event_name={name} and pos: {x}, {y}")
if event_code == lv . EVENT . PRESSED :
2025-10-30 20:31:02 +01:00
back_start_y = y
2025-11-19 12:34:16 +01:00
back_start_x = x
2025-10-30 20:52:26 +01:00
elif event_code == lv . EVENT . PRESSING :
2025-11-20 16:36:14 +01:00
should_show = not is_short_movement ( dx , dy )
if should_show != backbutton_visible :
backbutton_visible = should_show
2026-01-23 21:37:53 +01:00
WidgetAnimator . smooth_show ( backbutton ) if should_show else WidgetAnimator . smooth_hide ( backbutton )
2025-11-20 16:36:14 +01:00
backbutton . set_pos ( round ( x / 10 ) , back_start_y )
2025-10-30 20:52:26 +01:00
elif event_code == lv . EVENT . RELEASED :
2025-11-20 16:36:14 +01:00
if backbutton_visible :
backbutton_visible = False
2026-01-23 21:37:53 +01:00
WidgetAnimator . smooth_hide ( backbutton )
2026-01-23 20:46:36 +01:00
if x > DisplayMetrics . width ( ) / 5 :
2025-12-05 13:37:11 +01:00
if topmenu . drawer_open :
topmenu . close_drawer ( )
else :
back_screen ( )
2025-11-20 16:36:14 +01:00
elif is_short_movement ( dx , dy ) :
2025-11-19 12:34:16 +01:00
# print("Short movement - treating as tap")
2025-11-23 09:00:38 +01:00
_passthrough_click ( x , y , indev )
2025-10-30 20:52:26 +01:00
2025-10-30 20:31:02 +01:00
def _top_swipe_cb ( event ) :
2025-12-05 13:37:11 +01:00
if topmenu . drawer_open :
2025-10-30 20:52:26 +01:00
print ( " ignoring top swipe gesture because drawer is open " )
2025-10-30 20:31:02 +01:00
return
2025-10-30 20:52:26 +01:00
2025-11-20 16:36:14 +01:00
global downbutton , down_start_x , down_start_y , downbutton_visible
2025-10-30 20:52:26 +01:00
event_code = event . get_code ( )
2025-10-30 20:31:02 +01:00
indev = lv . indev_active ( )
if not indev :
return
point = lv . point_t ( )
indev . get_point ( point )
2025-10-30 20:52:26 +01:00
x = point . x
y = point . y
2025-11-20 16:36:14 +01:00
dx = abs ( x - down_start_x )
dy = abs ( y - down_start_y )
2025-11-19 12:34:16 +01:00
# print(f"visual_back_swipe_cb event_code={event_code} and event_name={name} and pos: {x}, {y}")
2025-10-30 20:52:26 +01:00
if event_code == lv . EVENT . PRESSED :
2025-10-30 20:31:02 +01:00
down_start_x = x
2025-11-19 12:34:16 +01:00
down_start_y = y
2025-10-30 20:52:26 +01:00
elif event_code == lv . EVENT . PRESSING :
2025-11-20 16:36:14 +01:00
should_show = not is_short_movement ( dx , dy )
if should_show != downbutton_visible :
downbutton_visible = should_show
2026-01-23 21:37:53 +01:00
WidgetAnimator . smooth_show ( downbutton ) if should_show else WidgetAnimator . smooth_hide ( downbutton )
2025-11-20 16:36:14 +01:00
downbutton . set_pos ( down_start_x , round ( y / 10 ) )
2025-10-30 20:52:26 +01:00
elif event_code == lv . EVENT . RELEASED :
2025-11-20 16:36:14 +01:00
if downbutton_visible :
downbutton_visible = False
2026-01-23 21:37:53 +01:00
WidgetAnimator . smooth_hide ( downbutton )
2025-11-19 12:34:16 +01:00
dx = abs ( x - down_start_x )
dy = abs ( y - down_start_y )
2026-01-23 20:46:36 +01:00
if y > DisplayMetrics . height ( ) / 5 :
2025-12-05 13:37:11 +01:00
topmenu . open_drawer ( )
2025-11-20 16:36:14 +01:00
elif is_short_movement ( dx , dy ) :
2025-11-19 12:34:16 +01:00
# print("Short movement - treating as tap")
2025-11-23 09:00:38 +01:00
_passthrough_click ( x , y , indev )
2025-10-30 20:52:26 +01:00
2025-10-30 20:31:02 +01:00
def handle_back_swipe ( ) :
global backbutton
rect = lv . obj ( lv . layer_top ( ) )
2026-01-23 22:26:01 +01:00
rect . set_size ( AppearanceManager . NOTIFICATION_BAR_HEIGHT , lv . layer_top ( ) . get_height ( ) - AppearanceManager . NOTIFICATION_BAR_HEIGHT ) # narrow because it overlaps buttons
2025-10-30 20:31:02 +01:00
rect . set_scrollbar_mode ( lv . SCROLLBAR_MODE . OFF )
2025-10-30 20:52:26 +01:00
rect . set_scroll_dir ( lv . DIR . NONE )
2026-01-23 22:26:01 +01:00
rect . set_pos ( 0 , AppearanceManager . NOTIFICATION_BAR_HEIGHT )
2025-10-30 20:31:02 +01:00
style = lv . style_t ( )
style . init ( )
style . set_bg_opa ( lv . OPA . TRANSP )
style . set_border_width ( 0 )
2025-10-30 20:52:26 +01:00
style . set_radius ( 0 )
2025-11-21 09:12:45 +01:00
if False : # debug the swipe zone with a red border
2025-10-30 20:52:26 +01:00
style . set_bg_opa ( 15 )
style . set_border_width ( 4 )
style . set_border_color ( lv . color_hex ( 0xFF0000 ) ) # Red border for visibility
style . set_border_opa ( lv . OPA . _50 ) # 50% opacity for the border
2025-10-30 20:31:02 +01:00
rect . add_style ( style , 0 )
rect . add_event_cb ( _back_swipe_cb , lv . EVENT . PRESSED , None )
rect . add_event_cb ( _back_swipe_cb , lv . EVENT . PRESSING , None )
rect . add_event_cb ( _back_swipe_cb , lv . EVENT . RELEASED , None )
2025-10-30 20:52:26 +01:00
# button with label that shows up during the dragging:
2025-10-30 20:31:02 +01:00
backbutton = lv . button ( lv . layer_top ( ) )
2025-10-30 20:52:26 +01:00
backbutton . set_pos ( 0 , round ( lv . layer_top ( ) . get_height ( ) / 2 ) )
2025-10-30 20:31:02 +01:00
backbutton . add_flag ( lv . obj . FLAG . HIDDEN )
backbutton . add_state ( lv . STATE . DISABLED )
2025-10-30 20:52:26 +01:00
backlabel = lv . label ( backbutton )
backlabel . set_text ( lv . SYMBOL . LEFT )
2026-01-26 12:30:50 +01:00
backlabel . set_style_text_font ( lv . font_montserrat_18 , lv . PART . MAIN )
2025-10-30 20:52:26 +01:00
backlabel . center ( )
2025-10-30 20:31:02 +01:00
def handle_top_swipe ( ) :
global downbutton
rect = lv . obj ( lv . layer_top ( ) )
2026-01-23 22:26:01 +01:00
rect . set_size ( lv . pct ( 100 ) , AppearanceManager . NOTIFICATION_BAR_HEIGHT )
2025-10-30 20:31:02 +01:00
rect . set_pos ( 0 , 0 )
rect . set_scrollbar_mode ( lv . SCROLLBAR_MODE . OFF )
style = lv . style_t ( )
style . init ( )
style . set_bg_opa ( lv . OPA . TRANSP )
2025-10-30 20:52:26 +01:00
style . set_border_width ( 0 )
style . set_radius ( 0 )
2025-11-21 09:12:45 +01:00
if False : # debug the swipe zone with a red border
style . set_bg_opa ( 15 )
style . set_border_width ( 4 )
style . set_border_color ( lv . color_hex ( 0xFF0000 ) ) # Red border for visibility
style . set_border_opa ( lv . OPA . _50 ) # 50% opacity for the border
2025-10-30 20:31:02 +01:00
rect . add_style ( style , 0 )
rect . add_event_cb ( _top_swipe_cb , lv . EVENT . PRESSED , None )
rect . add_event_cb ( _top_swipe_cb , lv . EVENT . PRESSING , None )
rect . add_event_cb ( _top_swipe_cb , lv . EVENT . RELEASED , None )
2025-10-30 20:52:26 +01:00
# button with label that shows up during the dragging:
2025-10-30 20:31:02 +01:00
downbutton = lv . button ( lv . layer_top ( ) )
2025-10-30 20:52:26 +01:00
downbutton . set_pos ( 0 , round ( lv . layer_top ( ) . get_height ( ) / 2 ) )
2025-10-30 20:31:02 +01:00
downbutton . add_flag ( lv . obj . FLAG . HIDDEN )
downbutton . add_state ( lv . STATE . DISABLED )
2025-10-30 20:52:26 +01:00
downlabel = lv . label ( downbutton )
downlabel . set_text ( lv . SYMBOL . DOWN )
2026-01-26 12:30:50 +01:00
downlabel . set_style_text_font ( lv . font_montserrat_18 , lv . PART . MAIN )
2025-10-30 20:52:26 +01:00
downlabel . center ( )