@@ -63,7 +63,8 @@ def __init__(self, model: "Table | None" = None) -> None:
6363 """Initializes the TableView.
6464
6565 Args:
66- model (Table | None, optional): The data model for the table. Defaults to None.
66+ model (Table | None, optional): The data model for the table.
67+ Defaults to None.
6768 """
6869 super ().__init__ ()
6970 if model is not None :
@@ -226,7 +227,8 @@ def __init__(self, parent=None, current_value=None) -> None:
226227
227228 Args:
228229 parent (QWidget, optional): Parent widget. Defaults to None.
229- current_value (str, optional): Current value ("ON", "OFF", or "Mon-Tue..."). Defaults to None.
230+ current_value (str, optional): Current value ("ON", "OFF", or "Mon-Tue...").
231+ Defaults to None.
230232 """
231233 super ().__init__ (parent )
232234 self .setWindowTitle ("Select Days or On/Off" )
@@ -344,7 +346,8 @@ def getSelection(self) -> str | None:
344346 """Constructs the result string based on selected days.
345347
346348 Returns:
347- str: A string representing the selected days (e.g., "Mon-Wed-Fri") or "ON"/"OFF".
349+ str: A string representing the selected days
350+ (e.g., "Mon-Wed-Fri") or "ON"/"OFF".
348351 """
349352 if self .on_checkbox .isChecked ():
350353 return "ON"
@@ -413,11 +416,13 @@ def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
413416 return self .df .shape [1 ]
414417
415418 def data (self , index : QModelIndex , role : int = Qt .DisplayRole ) -> Any :
416- """Returns the data stored under the given role for the item referred to by the index.
419+ """Returns the data stored under the given role for the item
420+ referred to by the index.
417421
418422 Args:
419423 index (QModelIndex): The index of the item.
420- role (int, optional): The role for which data is requested. Defaults to Qt.DisplayRole.
424+ role (int, optional): The role for which data is requested.
425+ Defaults to Qt.DisplayRole.
421426
422427 Returns:
423428 Any: The data for the given role.
@@ -454,12 +459,15 @@ def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
454459 def headerData (
455460 self , section : int , orientation : Qt .Orientation , role : int = Qt .DisplayRole
456461 ) -> Any :
457- """Returns the data for the given role and section in the header with the specified orientation.
462+ """Returns the data for the given role and section in the header
463+ with the specified orientation.
458464
459465 Args:
460466 section (int): The section number (row or column index).
461- orientation (Qt.Orientation): The orientation of the header (Horizontal or Vertical).
462- role (int, optional): The role for which data is requested. Defaults to Qt.DisplayRole.
467+ orientation (Qt.Orientation): The orientation of the header
468+ (Horizontal or Vertical).
469+ role (int, optional): The role for which data is requested.
470+ Defaults to Qt.DisplayRole.
463471
464472 Returns:
465473 Any: The header data.
@@ -738,7 +746,8 @@ def change_to_df(self) -> None:
738746 self .central_layout .setCurrentWidget (self .page1 )
739747
740748 def update_data (self ) -> None :
741- """Updates the data displayed in the current layout based on the selected table."""
749+ """Updates the data displayed in the current layout based on
750+ the selected table."""
742751 if self .central_layout .currentIndex () == 0 :
743752 self .page1Layout .update_data ()
744753 self .page1Layout .create_table ()
@@ -1168,7 +1177,8 @@ def connect_button_to_add(self, button: QPushButton) -> None:
11681177 button .show ()
11691178
11701179 def update_buttons (self ) -> None :
1171- """Updates the state and visibility of action buttons based on selection and table type."""
1180+ """Updates the state and visibility of action buttons based on selection
1181+ and table type."""
11721182 sel_model = self .table_view .selectionModel ()
11731183 selected_indexes = sel_model .selectedRows () if sel_model else []
11741184 match manager .table :
@@ -1315,7 +1325,8 @@ def get_selected_row_series(self) -> pd.Series | None:
13151325 return self .model .df .iloc [index .row ()]
13161326
13171327 def get_seconds_from_session_row (self ) -> int :
1318- """Calculates the time elapsed in seconds from the session start for the selected row.
1328+ """Calculates the time elapsed in seconds from the session start
1329+ for the selected row.
13191330
13201331 Returns:
13211332 int: The elapsed time in seconds.
@@ -1405,7 +1416,8 @@ def get_paths_from_sessions_summary_row(self, row: pd.Series) -> list[str]:
14051416 row (pd.Series): The session summary row.
14061417
14071418 Returns:
1408- list[str]: A list containing session paths (csv, raw, json, video, video_data).
1419+ list[str]: A list containing session paths
1420+ (csv, raw, json, video, video_data).
14091421 """
14101422 date_str = row ["date" ]
14111423 task = row ["task" ]
@@ -1820,8 +1832,7 @@ def __init__(self, window: GuiWindow, rows: int, columns: int) -> None:
18201832 columns (int): Number of columns.
18211833 """
18221834 super ().__init__ (window , rows = rows , columns = columns )
1823- self .deltas : list [float ] = []
1824- self .now = time_utils .get_time_monotonic ()
1835+ self .video_path = ""
18251836 self .draw ()
18261837
18271838 def draw (self ) -> None :
@@ -1913,6 +1924,36 @@ def draw(self) -> None:
19131924 self .backward_five_minutes ,
19141925 "Skip backward 5 minutes" ,
19151926 )
1927+ self .create_and_add_button (
1928+ "Previous video" ,
1929+ 26 ,
1930+ 155 ,
1931+ 15 ,
1932+ 2 ,
1933+ self .previous_video ,
1934+ "Play the previous video" ,
1935+ )
1936+ self .create_and_add_button (
1937+ "Next video" ,
1938+ 26 ,
1939+ 170 ,
1940+ 15 ,
1941+ 2 ,
1942+ self .next_video ,
1943+ "Play the next video" ,
1944+ )
1945+
1946+ def next_video (self ) -> None :
1947+ path = time_utils .next_video_path (self .video_path )
1948+ if path is not None :
1949+ self .stop_button_clicked ()
1950+ self .start_video (path , 0 )
1951+
1952+ def previous_video (self ) -> None :
1953+ path = time_utils .previous_video_path (self .video_path )
1954+ if path is not None :
1955+ self .stop_button_clicked ()
1956+ self .start_video (path , 0 )
19161957
19171958 def start_video (self , path : str , seconds : int ) -> None :
19181959 """Starts video playback from a specific time.
@@ -1921,6 +1962,7 @@ def start_video(self, path: str, seconds: int) -> None:
19211962 path (str): The path to the video file.
19221963 seconds (int): The number of seconds to skip.
19231964 """
1965+ self .video_path = path
19241966 try :
19251967 self .cap = cv2 .VideoCapture (path )
19261968 self .fps = int (self .cap .get (cv2 .CAP_PROP_FPS ))
@@ -2059,16 +2101,9 @@ def close(self) -> None:
20592101 """Closes the video layout and saves playback data."""
20602102 self .stop_button_clicked ()
20612103 self .data_from_video_change_requested .emit ("" )
2062- with open ("deltas.txt" , "w" ) as f :
2063- for delta in self .deltas :
2064- f .write (f"{ delta } \n " )
20652104
20662105 def next_frame_slot (self ) -> None :
20672106 """Handles the next frame timer event to update the video display."""
2068- last = self .now
2069- self .now = time_utils .get_time_monotonic ()
2070- delta = int ((self .now - last ) * 1000 )
2071- self .deltas .append (delta )
20722107
20732108 ret , frame = self .cap .read ()
20742109 if ret :
0 commit comments