@@ -113,13 +113,11 @@ def update_visible_topics(self):
113113
114114 self .visible_topics .sort ()
115115
116- def toggle_topic_monitoring (self , topic_name : str ):
116+ def toggle_topic_monitoring (self , topic_name : str ) -> tuple [ bool , str ] :
117117 """Toggle monitoring for a topic."""
118118 if self .ui_adaptor :
119- self .ui_adaptor .toggle_topic_monitoring (topic_name )
120- self .show_status (f'Toggling monitoring for { topic_name } ' )
121- else :
122- self .show_status ('UI adaptor not available' )
119+ return self .ui_adaptor .toggle_topic_monitoring (topic_name )
120+ return False , 'UI adaptor not available'
123121
124122 def show_status (self , message : str ):
125123 """Show a status message for 3 seconds."""
@@ -141,6 +139,7 @@ def curses_main(stdscr, node):
141139 last_redraw = 0
142140 status_message = ''
143141 status_timeout = 0
142+ status_is_error = False
144143 input_mode = None
145144 input_buffer = ''
146145
@@ -231,12 +230,15 @@ def curses_main(stdscr, node):
231230 success , msg = node .ui_adaptor .set_expected_frequency (
232231 topic_name , hz , tolerance )
233232 status_message = f'Set frequency for { topic_name } : { hz } Hz'
233+ status_is_error = not success
234234 if not success :
235235 status_message = f'Error: { msg } '
236236 else :
237237 status_message = 'Invalid input format'
238+ status_is_error = True
238239 except ValueError :
239240 status_message = 'Invalid frequency values'
241+ status_is_error = True
240242 status_timeout = current_time + 3.0
241243 input_mode = None
242244 input_buffer = ''
@@ -273,19 +275,23 @@ def curses_main(stdscr, node):
273275 elif key == ord ('\n ' ) or key == ord (' ' ):
274276 if 0 <= selected_row < len (node .visible_topics ):
275277 topic_name = node .visible_topics [selected_row ]
276- node .toggle_topic_monitoring (topic_name )
277- status_message = f'Toggled monitoring for { topic_name } '
278+ success , msg = node .toggle_topic_monitoring (topic_name )
279+ status_message = msg if not success else f'Toggled monitoring for { topic_name } '
280+ status_is_error = not success
278281 status_timeout = current_time + 3.0
279282 elif key == ord ('f' ) or key == ord ('F' ):
280283 if 0 <= selected_row < len (node .visible_topics ):
281284 input_mode = 'frequency'
282285 input_buffer = ''
286+ status_timeout = 0
287+ status_is_error = False
283288 elif key == ord ('c' ) or key == ord ('C' ):
284289 if 0 <= selected_row < len (node .visible_topics ):
285290 topic_name = node .visible_topics [selected_row ]
286291 success , msg = node .ui_adaptor .set_expected_frequency (
287292 topic_name , clear = True )
288293 status_message = f'Cleared frequency for { topic_name } '
294+ status_is_error = not success
289295 if not success :
290296 status_message = f'Error: { msg } '
291297 status_timeout = current_time + 3.0
@@ -295,6 +301,7 @@ def curses_main(stdscr, node):
295301 node .update_visible_topics ()
296302 mode_text = 'monitored only' if node .hide_unmonitored else 'all topics'
297303 status_message = f'Showing { mode_text } '
304+ status_is_error = False
298305 status_timeout = current_time + 3.0
299306
300307 # Get data safely
@@ -400,8 +407,9 @@ def curses_main(stdscr, node):
400407 # Status message
401408 if current_time < status_timeout :
402409 try :
403- stdscr .addstr (height - 3 , 0 , status_message [:width - 1 ],
404- curses .color_pair (COLOR_STATUS_MSG ))
410+ color = curses .color_pair (COLOR_ERROR ) if status_is_error \
411+ else curses .color_pair (COLOR_STATUS_MSG )
412+ stdscr .addstr (height - 3 , 0 , status_message [:width - 1 ], color )
405413 except curses .error :
406414 pass
407415
@@ -470,6 +478,7 @@ def parse_args(args=None):
470478def main (args = None ):
471479 """Entry point for the ncurses frontend application."""
472480 parsed_args , ros_args = parse_args (args )
481+ ros_args .extend (['--ros-args' , '--disable-stdout-logs' ])
473482 rclpy .init (args = ros_args )
474483 node = GreenwaveNcursesFrontend (hide_unmonitored = parsed_args .hide_unmonitored )
475484 thread = None
0 commit comments