import  pyray  as  rl 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  enum  import  IntEnum 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  abc  import  ABC ,  abstractmethod 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  collections . abc  import  Callable 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  dataclasses  import  dataclass 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . common . params  import  Params 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . system . hardware  import  HARDWARE 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . system . ui . lib . application  import  gui_app ,  FontWeight ,  FONT_SCALE 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . system . ui . lib . scroll_panel  import  GuiScrollPanel 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . system . ui . lib . text_measure  import  measure_text_cached 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . system . ui . lib . wrap_text  import  wrap_text 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . system . ui . widgets  import  Widget 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . system . ui . widgets . html_render  import  HtmlRenderer 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								from  openpilot . selfdrive . selfdrived . alertmanager  import  OFFROAD_ALERTS 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								NO_RELEASE_NOTES  =  " <h2>No release notes available.</h2> " 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  AlertColors : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  HIGH_SEVERITY  =  rl . Color ( 226 ,  44 ,  44 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LOW_SEVERITY  =  rl . Color ( 41 ,  41 ,  41 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  BACKGROUND  =  rl . Color ( 57 ,  57 ,  57 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  BUTTON  =  rl . WHITE 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  BUTTON_PRESSED  =  rl . Color ( 200 ,  200 ,  200 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  BUTTON_TEXT  =  rl . BLACK 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  SNOOZE_BG  =  rl . Color ( 79 ,  79 ,  79 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  SNOOZE_BG_PRESSED  =  rl . Color ( 100 ,  100 ,  100 ,  255 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  TEXT  =  rl . WHITE 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  AlertConstants : 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  MIN_BUTTON_WIDTH  =  400 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  BUTTON_HEIGHT  =  125 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  MARGIN  =  50 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  SPACING  =  30 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  FONT_SIZE  =  48 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  BORDER_RADIUS  =  30  *  2   # matches Qt's 30px 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ALERT_HEIGHT  =  120 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  ALERT_SPACING  =  10 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  ALERT_INSET  =  60 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								@dataclass 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  AlertData : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  key :  str 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  text :  str 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  severity :  int 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  visible :  bool  =  False 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								class  ButtonStyle ( IntEnum ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  LIGHT  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  DARK  =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  ActionButton ( Widget ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ,  text :  str ,  style :  ButtonStyle  =  ButtonStyle . LIGHT , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								               min_width :  int  =  AlertConstants . MIN_BUTTON_WIDTH ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    super ( ) . __init__ ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _style  =  style 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _min_width  =  min_width 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _font  =  gui_app . font ( FontWeight . MEDIUM ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . set_text ( text ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  set_text ( self ,  text :  str ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _text  =  text 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _text_size  =  measure_text_cached ( gui_app . font ( FontWeight . MEDIUM ) ,  self . _text ,  AlertConstants . FONT_SIZE ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _rect . width  =  max ( self . _text_size . x  +  60  *  2 ,  self . _min_width ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _rect . height  =  AlertConstants . BUTTON_HEIGHT 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render ( self ,  _ ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    roundness  =  AlertConstants . BORDER_RADIUS  /  self . _rect . height 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    bg_color  =  AlertColors . BUTTON  if  self . _style  ==  ButtonStyle . LIGHT  else  AlertColors . SNOOZE_BG 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  self . is_pressed : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      bg_color  =  AlertColors . BUTTON_PRESSED  if  self . _style  ==  ButtonStyle . LIGHT  else  AlertColors . SNOOZE_BG_PRESSED 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    rl . draw_rectangle_rounded ( self . _rect ,  roundness ,  10 ,  bg_color ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # center text 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    color  =  rl . WHITE  if  self . _style  ==  ButtonStyle . DARK  else  rl . BLACK 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    text_x  =  int ( self . _rect . x  +  ( self . _rect . width  -  self . _text_size . x )  / /  2 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    text_y  =  int ( self . _rect . y  +  ( self . _rect . height  -  self . _text_size . y )  / /  2 ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    rl . draw_text_ex ( self . _font ,  self . _text ,  rl . Vector2 ( text_x ,  text_y ) ,  AlertConstants . FONT_SIZE ,  0 ,  color ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								class  AbstractAlert ( Widget ,  ABC ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ,  has_reboot_btn :  bool  =  False ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    super ( ) . __init__ ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . params  =  Params ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . has_reboot_btn  =  has_reboot_btn 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . dismiss_callback :  Callable  |  None  =  None 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    def  snooze_callback ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . params . put_bool ( " SnoozeUpdate " ,  True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  self . dismiss_callback : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . dismiss_callback ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    def  excessive_actuation_callback ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . params . remove ( " Offroad_ExcessiveActuation " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  self . dismiss_callback : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . dismiss_callback ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . dismiss_btn  =  ActionButton ( " Close " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . snooze_btn  =  ActionButton ( " Snooze Update " ,  style = ButtonStyle . DARK ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . snooze_btn . set_click_callback ( snooze_callback ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . excessive_actuation_btn  =  ActionButton ( " Acknowledge Excessive Actuation " ,  style = ButtonStyle . DARK ,  min_width = 800 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . excessive_actuation_btn . set_click_callback ( excessive_actuation_callback ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . reboot_btn  =  ActionButton ( " Reboot and Update " ,  min_width = 600 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . reboot_btn . set_click_callback ( lambda :  HARDWARE . reboot ( ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    # TODO: just use a Scroller? 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . content_rect  =  rl . Rectangle ( 0 ,  0 ,  0 ,  0 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scroll_panel_rect  =  rl . Rectangle ( 0 ,  0 ,  0 ,  0 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scroll_panel  =  GuiScrollPanel ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  show_event ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scroll_panel . set_offset ( 0 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  set_dismiss_callback ( self ,  callback :  Callable ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . dismiss_callback  =  callback 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . dismiss_btn . set_click_callback ( self . dismiss_callback ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @abstractmethod 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  refresh ( self )  - >  bool : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @abstractmethod 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  get_content_height ( self )  - >  float : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  _render ( self ,  rect :  rl . Rectangle ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    rl . draw_rectangle_rounded ( rect ,  AlertConstants . BORDER_RADIUS  /  rect . height ,  10 ,  AlertColors . BACKGROUND ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    footer_height  =  AlertConstants . BUTTON_HEIGHT  +  AlertConstants . SPACING 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    content_height  =  rect . height  -  2  *  AlertConstants . MARGIN  -  footer_height 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . content_rect  =  rl . Rectangle ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      rect . x  +  AlertConstants . MARGIN , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      rect . y  +  AlertConstants . MARGIN , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      rect . width  -  2  *  AlertConstants . MARGIN , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      content_height , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scroll_panel_rect  =  rl . Rectangle ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . content_rect . x ,  self . content_rect . y ,  self . content_rect . width ,  self . content_rect . height 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _render_scrollable_content ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _render_footer ( rect ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render_scrollable_content ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    content_total_height  =  self . get_content_height ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    content_bounds  =  rl . Rectangle ( 0 ,  0 ,  self . scroll_panel_rect . width ,  content_total_height ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    scroll_offset  =  self . scroll_panel . update ( self . scroll_panel_rect ,  content_bounds ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    rl . begin_scissor_mode ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int ( self . scroll_panel_rect . x ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int ( self . scroll_panel_rect . y ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int ( self . scroll_panel_rect . width ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      int ( self . scroll_panel_rect . height ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    content_rect_with_scroll  =  rl . Rectangle ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . scroll_panel_rect . x , 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      self . scroll_panel_rect . y  +  scroll_offset , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . scroll_panel_rect . width , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      content_total_height , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _render_content ( content_rect_with_scroll ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    rl . end_scissor_mode ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @abstractmethod 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render_content ( self ,  content_rect :  rl . Rectangle ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pass 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render_footer ( self ,  rect :  rl . Rectangle ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    footer_y  =  rect . y  +  rect . height  -  AlertConstants . MARGIN  -  AlertConstants . BUTTON_HEIGHT 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    dismiss_x  =  rect . x  +  AlertConstants . MARGIN 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . dismiss_btn . set_position ( dismiss_x ,  footer_y ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . dismiss_btn . render ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  self . has_reboot_btn : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      reboot_x  =  rect . x  +  rect . width  -  AlertConstants . MARGIN  -  self . reboot_btn . rect . width 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . reboot_btn . set_position ( reboot_x ,  footer_y ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . reboot_btn . render ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    elif  self . excessive_actuation_btn . is_visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      actuation_x  =  rect . x  +  rect . width  -  AlertConstants . MARGIN  -  self . excessive_actuation_btn . rect . width 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . excessive_actuation_btn . set_position ( actuation_x ,  footer_y ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . excessive_actuation_btn . render ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    elif  self . snooze_btn . is_visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      snooze_x  =  rect . x  +  rect . width  -  AlertConstants . MARGIN  -  self . snooze_btn . rect . width 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . snooze_btn . set_position ( snooze_x ,  footer_y ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . snooze_btn . render ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  OffroadAlert ( AbstractAlert ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    super ( ) . __init__ ( has_reboot_btn = False ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . sorted_alerts :  list [ AlertData ]  =  [ ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  refresh ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  self . sorted_alerts : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _build_alerts ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    active_count  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    connectivity_needed  =  False 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    excessive_actuation  =  False 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  alert_data  in  self . sorted_alerts : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      text  =  " " 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      alert_json  =  self . params . get ( alert_data . key ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  alert_json : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        text  =  alert_json . get ( " text " ,  " " ) . replace ( " % 1 " ,  alert_json . get ( " extra " ,  " " ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      alert_data . text  =  text 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      alert_data . visible  =  bool ( text ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  alert_data . visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        active_count  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  alert_data . key  ==  " Offroad_ConnectivityNeeded "  and  alert_data . visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        connectivity_needed  =  True 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  alert_data . key  ==  " Offroad_ExcessiveActuation "  and  alert_data . visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        excessive_actuation  =  True 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . excessive_actuation_btn . set_visible ( excessive_actuation ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . snooze_btn . set_visible ( connectivity_needed  and  not  excessive_actuation ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  active_count 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  get_content_height ( self )  - >  float : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  self . sorted_alerts : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    total_height  =  20 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    font  =  gui_app . font ( FontWeight . NORMAL ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  alert_data  in  self . sorted_alerts : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  not  alert_data . visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        continue 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      text_width  =  int ( self . content_rect . width  -  ( AlertConstants . ALERT_INSET  *  2 ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      wrapped_lines  =  wrap_text ( font ,  alert_data . text ,  AlertConstants . FONT_SIZE ,  text_width ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      line_count  =  len ( wrapped_lines ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      text_height  =  line_count  *  ( AlertConstants . FONT_SIZE  *  FONT_SCALE ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      alert_item_height  =  max ( text_height  +  ( AlertConstants . ALERT_INSET  *  2 ) ,  AlertConstants . ALERT_HEIGHT ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      total_height  + =  round ( alert_item_height  +  AlertConstants . ALERT_SPACING ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  total_height  >  20 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      total_height  =  total_height  -  AlertConstants . ALERT_SPACING  +  20 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  total_height 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _build_alerts ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . sorted_alerts  =  [ ] 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  key ,  config  in  sorted ( OFFROAD_ALERTS . items ( ) ,  key = lambda  x :  x [ 1 ] . get ( " severity " ,  0 ) ,  reverse = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      severity  =  config . get ( " severity " ,  0 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      alert_data  =  AlertData ( key = key ,  text = " " ,  severity = severity ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . sorted_alerts . append ( alert_data ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render_content ( self ,  content_rect :  rl . Rectangle ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    y_offset  =  AlertConstants . ALERT_SPACING 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    font  =  gui_app . font ( FontWeight . NORMAL ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  alert_data  in  self . sorted_alerts : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  not  alert_data . visible : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        continue 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      bg_color  =  AlertColors . HIGH_SEVERITY  if  alert_data . severity  >  0  else  AlertColors . LOW_SEVERITY 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      text_width  =  int ( content_rect . width  -  ( AlertConstants . ALERT_INSET  *  2 ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      wrapped_lines  =  wrap_text ( font ,  alert_data . text ,  AlertConstants . FONT_SIZE ,  text_width ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      line_count  =  len ( wrapped_lines ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      text_height  =  line_count  *  ( AlertConstants . FONT_SIZE  *  FONT_SCALE ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      alert_item_height  =  max ( text_height  +  ( AlertConstants . ALERT_INSET  *  2 ) ,  AlertConstants . ALERT_HEIGHT ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      alert_rect  =  rl . Rectangle ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        content_rect . x  +  10 , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        content_rect . y  +  y_offset , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        content_rect . width  -  30 , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        alert_item_height , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      roundness  =  AlertConstants . BORDER_RADIUS  /  min ( alert_rect . height ,  alert_rect . width ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      rl . draw_rectangle_rounded ( alert_rect ,  roundness ,  10 ,  bg_color ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      text_x  =  alert_rect . x  +  AlertConstants . ALERT_INSET 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      text_y  =  alert_rect . y  +  AlertConstants . ALERT_INSET 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  i ,  line  in  enumerate ( wrapped_lines ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        rl . draw_text_ex ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          font , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          line , 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								          rl . Vector2 ( text_x ,  text_y  +  i  *  AlertConstants . FONT_SIZE  *  FONT_SCALE ) , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          AlertConstants . FONT_SIZE , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          0 , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          AlertColors . TEXT , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      y_offset  + =  round ( alert_item_height  +  AlertConstants . ALERT_SPACING ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  UpdateAlert ( AbstractAlert ) : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    super ( ) . __init__ ( has_reboot_btn = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . release_notes  =  " " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _wrapped_release_notes  =  " " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _cached_content_height :  float  =  0.0 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _html_renderer  =  HtmlRenderer ( text = " " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  refresh ( self )  - >  bool : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    update_available :  bool  =  self . params . get_bool ( " UpdateAvailable " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  update_available : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      self . release_notes  =  ( self . params . get ( " UpdaterNewReleaseNotes " )  or  b " " ) . decode ( " utf8 " ) . strip ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _html_renderer . parse_html_content ( self . release_notes  or  NO_RELEASE_NOTES ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _cached_content_height  =  0 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _html_renderer . parse_html_content ( NO_RELEASE_NOTES ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  update_available 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  get_content_height ( self )  - >  float : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  self . release_notes : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  100 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  self . _cached_content_height  ==  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _wrapped_release_notes  =  self . release_notes 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      size  =  measure_text_cached ( gui_app . font ( FontWeight . NORMAL ) ,  self . _wrapped_release_notes ,  AlertConstants . FONT_SIZE ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _cached_content_height  =  max ( size . y  +  60 ,  100 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  self . _cached_content_height 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _render_content ( self ,  content_rect :  rl . Rectangle ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    notes_rect  =  rl . Rectangle ( content_rect . x  +  30 ,  content_rect . y  +  30 ,  content_rect . width  -  60 ,  content_rect . height  -  60 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _html_renderer . render ( notes_rect )