import  dearpygui . dearpygui  as  dpg 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . tools . jotpluggler . data  import  DataManager 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								from  openpilot . tools . jotpluggler . views  import  TimeSeriesPanel 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								GRIP_SIZE  =  4 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								MIN_PANE_SIZE  =  60 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								class  LayoutManager : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ,  data_manager ,  playback_manager ,  worker_manager ,  scale :  float  =  1.0 ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . data_manager  =  data_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . playback_manager  =  playback_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . worker_manager  =  worker_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scale  =  scale 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . container_tag  =  " plot_layout_container " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . tab_bar_tag  =  " tab_bar_container " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . tab_content_tag  =  " tab_content_area " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_tab  =  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    initial_panel_layout  =  PanelLayoutManager ( data_manager ,  playback_manager ,  worker_manager ,  scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . tabs :  dict  =  { 0 :  { " name " :  " Tab 1 " ,  " panel_layout " :  initial_panel_layout } } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _next_tab_id  =  self . active_tab  +  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  to_dict ( self )  - >  dict : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      " tabs " :  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        str ( tab_id ) :  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          " name " :  tab_data [ " name " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          " panel_layout " :  tab_data [ " panel_layout " ] . to_dict ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  tab_id ,  tab_data  in  self . tabs . items ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  clear_and_load_from_dict ( self ,  data :  dict ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    tab_ids_to_close  =  list ( self . tabs . keys ( ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  tab_id  in  tab_ids_to_close : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . close_tab ( tab_id ,  force = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  tab_id_str ,  tab_data  in  data [ " tabs " ] . items ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      tab_id  =  int ( tab_id_str ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      panel_layout  =  PanelLayoutManager . load_from_dict ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        tab_data [ " panel_layout " ] ,  self . data_manager ,  self . playback_manager , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . worker_manager ,  self . scale 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . tabs [ tab_id ]  =  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " name " :  tab_data [ " name " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " panel_layout " :  panel_layout 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_tab  =  min ( self . tabs . keys ( ) )  if  self . tabs  else  0 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _next_tab_id  =  max ( self . tabs . keys ( ) )  +  1  if  self . tabs  else  1 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  create_ui ( self ,  parent_tag :  str ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  dpg . does_item_exist ( self . container_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . delete_item ( self . container_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  dpg . child_window ( tag = self . container_tag ,  parent = parent_tag ,  border = False ,  width = - 1 ,  height = - 1 ,  no_scrollbar = True ,  no_scroll_with_mouse = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _create_tab_bar ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _create_tab_content ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . bind_item_theme ( self . tab_bar_tag ,  " tab_bar_theme " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_tab_bar ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    text_size  =  int ( 13  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  dpg . child_window ( tag = self . tab_bar_tag ,  parent = self . container_tag ,  height = ( text_size  +  8 ) ,  border = False ,  horizontal_scrollbar = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  dpg . group ( horizontal = True ,  tag = " tab_bar_group " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  tab_id ,  tab_data  in  self . tabs . items ( ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          self . _create_tab_ui ( tab_id ,  tab_data [ " name " ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . add_image_button ( texture_tag = " plus_texture " ,  callback = self . add_tab ,  width = text_size ,  height = text_size ,  tag = " add_tab_button " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . bind_item_theme ( " add_tab_button " ,  " inactive_tab_theme " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_tab_ui ( self ,  tab_id :  int ,  tab_name :  str ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    text_size  =  int ( 13  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    tab_width  =  int ( 140  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    with  dpg . child_window ( width = tab_width ,  height = - 1 ,  border = False ,  no_scrollbar = True ,  tag = f " tab_window_ { tab_id } " ,  parent = " tab_bar_group " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  dpg . group ( horizontal = True ,  tag = f " tab_group_ { tab_id } " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . add_input_text ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          default_value = tab_name ,  width = tab_width  -  text_size  -  16 ,  callback = lambda  s ,  v ,  u :  self . rename_tab ( u ,  v ) ,  user_data = tab_id ,  tag = f " tab_input_ { tab_id } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . add_image_button ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          texture_tag = " x_texture " ,  callback = lambda  s ,  a ,  u :  self . close_tab ( u ) ,  user_data = tab_id ,  width = text_size ,  height = text_size ,  tag = f " tab_close_ { tab_id } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  dpg . item_handler_registry ( tag = f " tab_handler_ { tab_id } " ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . add_item_clicked_handler ( callback = lambda  s ,  a ,  u :  self . switch_tab ( u ) ,  user_data = tab_id ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . bind_item_handler_registry ( f " tab_group_ { tab_id } " ,  f " tab_handler_ { tab_id } " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    theme_tag  =  " active_tab_theme "  if  tab_id  ==  self . active_tab  else  " inactive_tab_theme " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . bind_item_theme ( f " tab_window_ { tab_id } " ,  theme_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_tab_content ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  dpg . child_window ( tag = self . tab_content_tag ,  parent = self . container_tag ,  border = False ,  width = - 1 ,  height = - 1 ,  no_scrollbar = True ,  no_scroll_with_mouse = True ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  self . active_tab  in  self . tabs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        active_panel_layout  =  self . tabs [ self . active_tab ] [ " panel_layout " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        active_panel_layout . create_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  add_tab ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    new_panel_layout  =  PanelLayoutManager ( self . data_manager ,  self . playback_manager ,  self . worker_manager ,  self . scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    new_tab  =  { " name " :  f " Tab  { self . _next_tab_id  +  1 } " ,  " panel_layout " :  new_panel_layout } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . tabs [ self . _next_tab_id ]  =  new_tab 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _create_tab_ui ( self . _next_tab_id ,  new_tab [ " name " ] ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    dpg . move_item ( " add_tab_button " ,  parent = " tab_bar_group " )   # move plus button to end 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . switch_tab ( self . _next_tab_id ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _next_tab_id  + =  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  close_tab ( self ,  tab_id :  int ,  force  =  False ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  len ( self . tabs )  < =  1  and  not  force : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      return   # don't allow closing the last tab 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    tab_to_close  =  self . tabs [ tab_id ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    tab_to_close [ " panel_layout " ] . destroy_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  suffix  in  [ " window " ,  " group " ,  " input " ,  " close " ,  " handler " ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      tag  =  f " tab_ { suffix } _ { tab_id } " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  dpg . does_item_exist ( tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . delete_item ( tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    del  self . tabs [ tab_id ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  self . active_tab  ==  tab_id  and  self . tabs :  # switch to another tab if we closed the active one 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      self . active_tab  =  next ( iter ( self . tabs . keys ( ) ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _switch_tab_content ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . bind_item_theme ( f " tab_window_ { self . active_tab } " ,  " active_tab_theme " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  switch_tab ( self ,  tab_id :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  tab_id  ==  self . active_tab  or  tab_id  not  in  self . tabs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    current_panel_layout  =  self . tabs [ self . active_tab ] [ " panel_layout " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    current_panel_layout . destroy_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . bind_item_theme ( f " tab_window_ { self . active_tab } " ,  " inactive_tab_theme " )   # deactivate old tab 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_tab  =  tab_id 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . bind_item_theme ( f " tab_window_ { tab_id } " ,  " active_tab_theme " )   # activate new tab 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _switch_tab_content ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _switch_tab_content ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . delete_item ( self . tab_content_tag ,  children_only = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    active_panel_layout  =  self . tabs [ self . active_tab ] [ " panel_layout " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    active_panel_layout . create_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    active_panel_layout . update_all_panels ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  rename_tab ( self ,  tab_id :  int ,  new_name :  str ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  tab_id  in  self . tabs : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . tabs [ tab_id ] [ " name " ]  =  new_name 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  update_all_panels ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . tabs [ self . active_tab ] [ " panel_layout " ] . update_all_panels ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  on_viewport_resize ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . tabs [ self . active_tab ] [ " panel_layout " ] . on_viewport_resize ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								class  PanelLayoutManager : 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  __init__ ( self ,  data_manager :  DataManager ,  playback_manager ,  worker_manager ,  scale :  float  =  1.0 ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . data_manager  =  data_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . playback_manager  =  playback_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . worker_manager  =  worker_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . scale  =  scale 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_panels :  list  =  [ ] 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . parent_tag  =  " tab_content_area " 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _queue_resize  =  False 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _created_handler_tags :  set [ str ]  =  set ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . grip_size  =  int ( GRIP_SIZE  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . min_pane_size  =  int ( MIN_PANE_SIZE  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    initial_panel  =  TimeSeriesPanel ( data_manager ,  playback_manager ,  worker_manager ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . layout :  dict  =  { " type " :  " panel " ,  " panel " :  initial_panel } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  to_dict ( self )  - >  dict : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  self . _layout_to_dict ( self . layout ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _layout_to_dict ( self ,  layout :  dict )  - >  dict : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  layout [ " type " ]  ==  " panel " : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " type " :  " panel " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " panel " :  layout [ " panel " ] . to_dict ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else :   # split 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " type " :  " split " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " orientation " :  layout [ " orientation " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " proportions " :  layout [ " proportions " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " children " :  [ self . _layout_to_dict ( child )  for  child  in  layout [ " children " ] ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  @classmethod 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  load_from_dict ( cls ,  data :  dict ,  data_manager ,  playback_manager ,  worker_manager ,  scale :  float  =  1.0 ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    manager  =  cls ( data_manager ,  playback_manager ,  worker_manager ,  scale ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    manager . layout  =  manager . _dict_to_layout ( data ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _dict_to_layout ( self ,  data :  dict )  - >  dict : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  data [ " type " ]  ==  " panel " : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      panel_data  =  data [ " panel " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  panel_data [ " type " ]  ==  " timeseries " : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        panel  =  TimeSeriesPanel . load_from_dict ( 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          panel_data ,  self . data_manager ,  self . playback_manager ,  self . worker_manager 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { " type " :  " panel " ,  " panel " :  panel } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        # Handle future panel types here or make a general mapping 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        raise  ValueError ( f " Unknown panel type:  { panel_data [ ' type ' ] } " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else :   # split 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " type " :  " split " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " orientation " :  data [ " orientation " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " proportions " :  data [ " proportions " ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " children " :  [ self . _dict_to_layout ( child )  for  child  in  data [ " children " ] ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  create_ui ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_panels . clear ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  dpg . does_item_exist ( self . parent_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . delete_item ( self . parent_tag ,  children_only = True ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _cleanup_all_handlers ( ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    container_width ,  container_height  =  dpg . get_item_rect_size ( self . parent_tag ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  container_width  ==  0  and  container_height  ==  0 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _queue_resize  =  True 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _create_ui_recursive ( self . layout ,  self . parent_tag ,  [ ] ,  container_width ,  container_height ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  destroy_ui ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _cleanup_ui_recursive ( self . layout ,  [ ] ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . _cleanup_all_handlers ( ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    self . active_panels . clear ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  _cleanup_all_handlers ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  handler_tag  in  list ( self . _created_handler_tags ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  dpg . does_item_exist ( handler_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . delete_item ( handler_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _created_handler_tags . clear ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_ui_recursive ( self ,  layout :  dict ,  parent_tag :  str ,  path :  list [ int ] ,  width :  int ,  height :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  layout [ " type " ]  ==  " panel " : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      self . _create_panel_ui ( layout ,  parent_tag ,  path ,  width ,  height ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _create_split_ui ( layout ,  parent_tag ,  path ,  width ,  height ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  def  _create_panel_ui ( self ,  layout :  dict ,  parent_tag :  str ,  path :  list [ int ] ,  width :  int ,  height :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    panel_tag  =  self . _path_to_tag ( path ,  " panel " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    panel  =  layout [ " panel " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . active_panels . append ( panel ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    text_size  =  int ( 13  *  self . scale ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    bar_height  =  ( text_size  +  24 )  if  width  <  int ( 329  *  self . scale  +  64 )  else  ( text_size  +  8 )   # adjust height to allow for scrollbar 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    with  dpg . child_window ( parent = parent_tag ,  border = False ,  width = - 1 ,  height = - 1 ,  no_scrollbar = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  dpg . group ( horizontal = True ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        with  dpg . child_window ( tag = panel_tag ,  width = - ( text_size  +  16 ) ,  height = bar_height ,  horizontal_scrollbar = True ,  no_scroll_with_mouse = True ,  border = False ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          with  dpg . group ( horizontal = True ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								            # if you change the widths make sure to change the sum of widths (currently 329 * scale) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dpg . add_input_text ( default_value = panel . title ,  width = int ( 150  *  self . scale ) ,  callback = lambda  s ,  v :  setattr ( panel ,  " title " ,  v ) ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								            dpg . add_combo ( items = [ " Time Series " ] ,  default_value = " Time Series " ,  width = int ( 100  *  self . scale ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dpg . add_button ( label = " Clear " ,  callback = lambda :  self . clear_panel ( panel ) ,  width = int ( 40  *  self . scale ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dpg . add_image_button ( texture_tag = " split_h_texture " ,  callback = lambda :  self . split_panel ( path ,  0 ) ,  width = text_size ,  height = text_size ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dpg . add_image_button ( texture_tag = " split_v_texture " ,  callback = lambda :  self . split_panel ( path ,  1 ) ,  width = text_size ,  height = text_size ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dpg . add_image_button ( texture_tag = " x_texture " ,  callback = lambda :  self . delete_panel ( path ) ,  width = text_size ,  height = text_size ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . add_separator ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      content_tag  =  self . _path_to_tag ( path ,  " content " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      with  dpg . child_window ( tag = content_tag ,  border = False ,  height = - 1 ,  width = - 1 ,  no_scrollbar = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        panel . create_ui ( content_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_split_ui ( self ,  layout :  dict ,  parent_tag :  str ,  path :  list [ int ] ,  width :  int ,  height :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    split_tag  =  self . _path_to_tag ( path ,  " split " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    orientation ,  _ ,  pane_sizes  =  self . _get_split_geometry ( layout ,  ( width ,  height ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  dpg . group ( tag = split_tag ,  parent = parent_tag ,  horizontal = orientation  ==  0 ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  i ,  child_layout  in  enumerate ( layout [ " children " ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        child_path  =  path  +  [ i ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        container_tag  =  self . _path_to_tag ( child_path ,  " container " ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        pane_width ,  pane_height  =  [ ( pane_sizes [ i ] ,  - 1 ) ,  ( - 1 ,  pane_sizes [ i ] ) ] [ orientation ]   # fill 2nd dim up to the border 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        with  dpg . child_window ( tag = container_tag ,  width = pane_width ,  height = pane_height ,  border = False ,  no_scrollbar = True ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          child_width ,  child_height  =  [ ( pane_sizes [ i ] ,  height ) ,  ( width ,  pane_sizes [ i ] ) ] [ orientation ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          self . _create_ui_recursive ( child_layout ,  container_tag ,  child_path ,  child_width ,  child_height ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  i  <  len ( layout [ " children " ] )  -  1 : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          self . _create_grip ( split_tag ,  path ,  i ,  orientation ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  clear_panel ( self ,  panel ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    panel . clear ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  delete_panel ( self ,  panel_path :  list [ int ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  panel_path :   # Root deletion 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      old_panel  =  self . layout [ " panel " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      old_panel . destroy_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . active_panels . remove ( old_panel ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      new_panel  =  TimeSeriesPanel ( self . data_manager ,  self . playback_manager ,  self . worker_manager ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . layout  =  { " type " :  " panel " ,  " panel " :  new_panel } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _rebuild_ui_at_path ( [ ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parent ,  child_index  =  self . _get_parent_and_index ( panel_path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout_to_delete  =  parent [ " children " ] [ child_index ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _cleanup_ui_recursive ( layout_to_delete ,  panel_path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parent [ " children " ] . pop ( child_index ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parent [ " proportions " ] . pop ( child_index ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  len ( parent [ " children " ] )  ==  1 :   # remove parent and collapse 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      remaining_child  =  parent [ " children " ] [ 0 ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  len ( panel_path )  ==  1 :   # parent is at root level - promote remaining child to root 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . layout  =  remaining_child 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _rebuild_ui_at_path ( [ ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else :   # replace parent with remaining child in grandparent 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        grandparent_path  =  panel_path [ : - 2 ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        parent_index  =  panel_path [ - 2 ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _replace_layout_at_path ( grandparent_path  +  [ parent_index ] ,  remaining_child ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _rebuild_ui_at_path ( grandparent_path  +  [ parent_index ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else :   # redistribute proportions 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      equal_prop  =  1.0  /  len ( parent [ " children " ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      parent [ " proportions " ]  =  [ equal_prop ]  *  len ( parent [ " children " ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _rebuild_ui_at_path ( panel_path [ : - 1 ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  split_panel ( self ,  panel_path :  list [ int ] ,  orientation :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    current_layout  =  self . _get_layout_at_path ( panel_path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    existing_panel  =  current_layout [ " panel " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    new_panel  =  TimeSeriesPanel ( self . data_manager ,  self . playback_manager ,  self . worker_manager ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parent ,  child_index  =  self . _get_parent_and_index ( panel_path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  parent  is  None :   # Root split 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . layout  =  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " type " :  " split " , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " orientation " :  orientation , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " children " :  [ { " type " :  " panel " ,  " panel " :  existing_panel } ,  { " type " :  " panel " ,  " panel " :  new_panel } ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        " proportions " :  [ 0.5 ,  0.5 ] , 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _rebuild_ui_at_path ( [ ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    elif  parent [ " type " ]  ==  " split "  and  parent [ " orientation " ]  ==  orientation :   # Same orientation - insert into existing split 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      parent [ " children " ] . insert ( child_index  +  1 ,  { " type " :  " panel " ,  " panel " :  new_panel } ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      parent [ " proportions " ]  =  [ 1.0  /  len ( parent [ " children " ] ) ]  *  len ( parent [ " children " ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _rebuild_ui_at_path ( panel_path [ : - 1 ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else :   # Different orientation - create new split level 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      new_split  =  { " type " :  " split " ,  " orientation " :  orientation ,  " children " :  [ current_layout ,  { " type " :  " panel " ,  " panel " :  new_panel } ] ,  " proportions " :  [ 0.5 ,  0.5 ] } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _replace_layout_at_path ( panel_path ,  new_split ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . _rebuild_ui_at_path ( panel_path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _rebuild_ui_at_path ( self ,  path :  list [ int ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout  =  self . _get_layout_at_path ( path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  path : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      container_tag  =  self . _path_to_tag ( path ,  " container " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else :   # Root update 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      container_tag  =  self . parent_tag 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _cleanup_ui_recursive ( layout ,  path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    dpg . delete_item ( container_tag ,  children_only = True ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    width ,  height  =  dpg . get_item_rect_size ( container_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _create_ui_recursive ( layout ,  container_tag ,  path ,  width ,  height ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _cleanup_ui_recursive ( self ,  layout :  dict ,  path :  list [ int ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  layout [ " type " ]  ==  " panel " : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      panel  =  layout [ " panel " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      panel . destroy_ui ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  panel  in  self . active_panels : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . active_panels . remove ( panel ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  i  in  range ( len ( layout [ " children " ] )  -  1 ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        handler_tag  =  f " { self . _path_to_tag ( path ,  f ' grip_ { i } ' ) } _handler " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  dpg . does_item_exist ( handler_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          dpg . delete_item ( handler_tag ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        self . _created_handler_tags . discard ( handler_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      for  i ,  child  in  enumerate ( layout [ " children " ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _cleanup_ui_recursive ( child ,  path  +  [ i ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  update_all_panels ( self ) : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  self . _queue_resize : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( size  :=  dpg . get_item_rect_size ( self . parent_tag ) )  !=  [ 0 ,  0 ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _queue_resize  =  False 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        self . _resize_splits_recursive ( self . layout ,  [ ] ,  * size ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  panel  in  self . active_panels : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      panel . update ( ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  on_viewport_resize ( self ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _resize_splits_recursive ( self . layout ,  [ ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _resize_splits_recursive ( self ,  layout :  dict ,  path :  list [ int ] ,  width :  int  |  None  =  None ,  height :  int  |  None  =  None ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  layout [ " type " ]  ==  " split " : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      split_tag  =  self . _path_to_tag ( path ,  " split " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  dpg . does_item_exist ( split_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        available_sizes  =  ( width ,  height )  if  width  and  height  else  dpg . get_item_rect_size ( dpg . get_item_parent ( split_tag ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        orientation ,  _ ,  pane_sizes  =  self . _get_split_geometry ( layout ,  available_sizes ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        size_properties  =  ( " width " ,  " height " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  i ,  child_layout  in  enumerate ( layout [ " children " ] ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          child_path  =  path  +  [ i ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          container_tag  =  self . _path_to_tag ( child_path ,  " container " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  dpg . does_item_exist ( container_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dpg . configure_item ( container_tag ,  * * { size_properties [ orientation ] :  pane_sizes [ i ] } ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            child_width ,  child_height  =  [ ( pane_sizes [ i ] ,  available_sizes [ 1 ] ) ,  ( available_sizes [ 0 ] ,  pane_sizes [ i ] ) ] [ orientation ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            self . _resize_splits_recursive ( child_layout ,  child_path ,  child_width ,  child_height ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    else :   # leaf node/panel - adjust bar height to allow for scrollbar 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      panel_tag  =  self . _path_to_tag ( path ,  " panel " ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  width  is  not  None  and  width  <  int ( 329  *  self . scale  +  64 ) :   # scaled widths of the elements in top bar + fixed 8 padding on left and right of each item 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        dpg . configure_item ( panel_tag ,  height = ( int ( 13  *  self . scale )  +  24 ) ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      else : 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								        dpg . configure_item ( panel_tag ,  height = ( int ( 13  *  self . scale )  +  8 ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _get_split_geometry ( self ,  layout :  dict ,  available_size :  tuple [ int ,  int ] )  - >  tuple [ int ,  int ,  list [ int ] ] : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    orientation  =  layout [ " orientation " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    num_grips  =  len ( layout [ " children " ] )  -  1 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    usable_size  =  max ( self . min_pane_size ,  available_size [ orientation ]  -  ( num_grips  *  ( self . grip_size  +  8  *  ( 2  -  orientation ) ) ) )   # approximate, scaling is weird 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pane_sizes  =  [ max ( self . min_pane_size ,  int ( usable_size  *  prop ) )  for  prop  in  layout [ " proportions " ] ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  orientation ,  usable_size ,  pane_sizes 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _get_layout_at_path ( self ,  path :  list [ int ] )  - >  dict : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    current  =  self . layout 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  index  in  path : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      current  =  current [ " children " ] [ index ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  current 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _get_parent_and_index ( self ,  path :  list [ int ] )  - >  tuple : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  ( None ,  - 1 )  if  not  path  else  ( self . _get_layout_at_path ( path [ : - 1 ] ) ,  path [ - 1 ] ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _replace_layout_at_path ( self ,  path :  list [ int ] ,  new_layout :  dict ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  path : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      self . layout  =  new_layout 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      parent ,  index  =  self . _get_parent_and_index ( path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      parent [ " children " ] [ index ]  =  new_layout 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _path_to_tag ( self ,  path :  list [ int ] ,  prefix :  str  =  " " )  - >  str : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    path_str  =  " _ " . join ( map ( str ,  path ) )  if  path  else  " root " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  f " { prefix } _ { path_str } "  if  prefix  else  path_str 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _create_grip ( self ,  parent_tag :  str ,  path :  list [ int ] ,  grip_index :  int ,  orientation :  int ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    grip_tag  =  self . _path_to_tag ( path ,  f " grip_ { grip_index } " ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    handler_tag  =  f " { grip_tag } _handler " 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    width ,  height  =  [ ( self . grip_size ,  - 1 ) ,  ( - 1 ,  self . grip_size ) ] [ orientation ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    with  dpg . child_window ( tag = grip_tag ,  parent = parent_tag ,  width = width ,  height = height ,  no_scrollbar = True ,  border = False ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      button_tag  =  dpg . add_button ( label = " " ,  width = - 1 ,  height = - 1 ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    with  dpg . item_handler_registry ( tag = handler_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      user_data  =  ( path ,  grip_index ,  orientation ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . add_item_active_handler ( callback = self . _on_grip_drag ,  user_data = user_data ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dpg . add_item_deactivated_handler ( callback = self . _on_grip_end ,  user_data = user_data ) 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    dpg . bind_item_handler_registry ( button_tag ,  handler_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _created_handler_tags . add ( handler_tag ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _on_grip_drag ( self ,  sender ,  app_data ,  user_data ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    path ,  grip_index ,  orientation  =  user_data 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout  =  self . _get_layout_at_path ( path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  " _drag_data "  not  in  layout : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      layout [ " _drag_data " ]  =  { " initial_proportions " :  layout [ " proportions " ] [ : ] ,  " start_mouse " :  dpg . get_mouse_pos ( local = False ) [ orientation ] } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    drag_data  =  layout [ " _drag_data " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    split_tag  =  self . _path_to_tag ( path ,  " split " ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  not  dpg . does_item_exist ( split_tag ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _ ,  usable_size ,  _  =  self . _get_split_geometry ( layout ,  dpg . get_item_rect_size ( split_tag ) ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    current_coord  =  dpg . get_mouse_pos ( local = False ) [ orientation ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    delta  =  current_coord  -  drag_data [ " start_mouse " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    delta_prop  =  delta  /  usable_size 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    left_idx  =  grip_index 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    right_idx  =  left_idx  +  1 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    initial  =  drag_data [ " initial_proportions " ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    min_prop  =  self . min_pane_size  /  usable_size 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    new_left  =  max ( min_prop ,  initial [ left_idx ]  +  delta_prop ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    new_right  =  max ( min_prop ,  initial [ right_idx ]  -  delta_prop ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    total_available  =  initial [ left_idx ]  +  initial [ right_idx ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  new_left  +  new_right  >  total_available : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  new_left  >  new_right : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        new_left  =  total_available  -  new_right 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        new_right  =  total_available  -  new_left 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout [ " proportions " ]  =  initial [ : ] 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout [ " proportions " ] [ left_idx ]  =  new_left 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout [ " proportions " ] [ right_idx ]  =  new_right 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _resize_splits_recursive ( layout ,  path ) 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  def  _on_grip_end ( self ,  sender ,  app_data ,  user_data ) : 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    path ,  _ ,  _  =  user_data 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    self . _get_layout_at_path ( path ) . pop ( " _drag_data " ,  None )