Implement resource usage tracking and statistics display; enhance theme application timing and UI controls

This commit is contained in:
2025-07-31 15:07:11 +02:00
parent 2a6940ea3e
commit 6309edaeea
+158 -54
View File
@@ -1299,12 +1299,26 @@ class MainWindow(QtWidgets.QMainWindow):
self._last_warning_messages = {} # Track last warning messages to prevent duplicates self._last_warning_messages = {} # Track last warning messages to prevent duplicates
self._warning_cooldown = 30 # Seconds between duplicate warnings self._warning_cooldown = 30 # Seconds between duplicate warnings
# Resource usage tracking for max/average values
self._resource_history = {
'memory_mb': [],
'memory_percent': [],
'cpu_percent': [],
'system_memory_percent': [],
'gpu_utilization': [],
'loop_times': []
}
self._max_resource_samples = 50 # Keep last 50 samples for statistics
self.init_ui() self.init_ui()
self.load_scenarios() self.load_scenarios()
# Restore window geometry (size and position) # Restore window geometry (size and position)
self._restore_window_geometry() self._restore_window_geometry()
# Apply theme after restoration (delayed to ensure window is ready)
QtCore.QTimer.singleShot(100, self._apply_initial_theme)
# Setup cleanup on close # Setup cleanup on close
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
@@ -1318,14 +1332,10 @@ class MainWindow(QtWidgets.QMainWindow):
# Initial resource display update (delayed to prevent startup hanging) # Initial resource display update (delayed to prevent startup hanging)
QtCore.QTimer.singleShot(2000, self._enable_resource_monitoring) QtCore.QTimer.singleShot(2000, self._enable_resource_monitoring)
# Setup system theme monitoring timer (only when in system mode) # Setup system theme monitoring timer (will be started by _apply_initial_theme if needed)
self.theme_monitor_timer = QtCore.QTimer() self.theme_monitor_timer = QtCore.QTimer()
self.theme_monitor_timer.timeout.connect(self._check_system_theme_change) self.theme_monitor_timer.timeout.connect(self._check_system_theme_change)
self._last_system_theme = None self._last_system_theme = None
# Start theme monitoring if in system mode
if self.theme_mode == 'system':
self.theme_monitor_timer.start(5000) # Check every 5 seconds
def _check_system_theme_change(self): def _check_system_theme_change(self):
""" """
@@ -1352,6 +1362,63 @@ class MainWindow(QtWidgets.QMainWindow):
except Exception as e: except Exception as e:
logger.debug(f"Error checking system theme change: {e}") logger.debug(f"Error checking system theme change: {e}")
def _update_resource_history(self, memory_info):
"""
Update resource usage history for calculating max/average values.
"""
try:
# Add current values to history
if memory_info.get('has_psutil', False):
self._resource_history['memory_mb'].append(memory_info['process_memory_mb'])
self._resource_history['memory_percent'].append(memory_info['process_memory_percent'])
self._resource_history['cpu_percent'].append(memory_info['cpu_percent'])
self._resource_history['system_memory_percent'].append(memory_info['system_memory_percent'])
if memory_info.get('gpu_has_gpu', False):
self._resource_history['gpu_utilization'].append(memory_info['gpu_utilization_percent'])
# Add loop time if available
if hasattr(self, '_loop_times') and self._loop_times:
avg_loop_time = sum(self._loop_times) / len(self._loop_times)
self._resource_history['loop_times'].append(avg_loop_time * 1000) # Convert to ms
# Keep only the last N samples for each metric
for key in self._resource_history:
if len(self._resource_history[key]) > self._max_resource_samples:
self._resource_history[key] = self._resource_history[key][-self._max_resource_samples:]
except Exception as e:
logger.debug(f"Error updating resource history: {e}")
def _get_resource_stats(self, values_list):
"""
Calculate current, max, and average values from a list of values.
Returns (current, max, avg) or (0, 0, 0) if list is empty.
"""
if not values_list:
return 0, 0, 0
current = values_list[-1] if values_list else 0
max_val = max(values_list)
avg_val = sum(values_list) / len(values_list)
return current, max_val, avg_val
def _apply_initial_theme(self):
"""
Apply the initial theme and start theme monitoring after UI is ready.
"""
# Apply the theme (includes title bar theming)
self.apply_theme()
self._update_theme_combo_text()
# Start theme monitoring if in system mode
if self.theme_mode == 'system':
self._last_system_theme = self.is_system_dark_theme()
self.theme_monitor_timer.start(5000) # Check every 5 seconds
logger.debug(f"Applied initial theme: {self.theme_mode}")
def _enable_resource_monitoring(self): def _enable_resource_monitoring(self):
"""Enable resource monitoring after startup delay.""" """Enable resource monitoring after startup delay."""
if not hasattr(self, 'resource_monitoring_enabled') or not self.resource_monitoring_enabled: if not hasattr(self, 'resource_monitoring_enabled') or not self.resource_monitoring_enabled:
@@ -1443,17 +1510,23 @@ class MainWindow(QtWidgets.QMainWindow):
def _update_resource_display(self, memory_info): def _update_resource_display(self, memory_info):
""" """
Update the resource usage display in the UI with theme-aware colors. Update the resource usage display in the UI with theme-aware colors and max/average statistics.
""" """
try: try:
colors = self.get_theme_styles() colors = self.get_theme_styles()
# Memory usage # Update resource history for statistics
self._update_resource_history(memory_info)
# Memory usage with statistics
if memory_info.get('has_psutil', False): if memory_info.get('has_psutil', False):
memory_text = f"Memory: {memory_info['process_memory_mb']:.1f}MB ({memory_info['process_memory_percent']:.1f}%)" current_mb, max_mb, avg_mb = self._get_resource_stats(self._resource_history['memory_mb'])
memory_color = colors['error'] if memory_info['process_memory_percent'] > 10 else colors['success'] current_pct, max_pct, avg_pct = self._get_resource_stats(self._resource_history['memory_percent'])
memory_text = f"Memory: {current_mb:.1f}MB ({current_pct:.1f}%)\nMax: {max_mb:.1f}MB ({max_pct:.1f}%) | Avg: {avg_mb:.1f}MB ({avg_pct:.1f}%)"
memory_color = colors['error'] if current_pct > 10 else colors['success']
else: else:
memory_text = "Memory: N/A (psutil needed)" memory_text = "Memory: N/A (psutil needed)\nInstall psutil for detailed monitoring"
memory_color = colors['warning'] memory_color = colors['warning']
self.memory_label.setText(memory_text) self.memory_label.setText(memory_text)
@@ -1464,36 +1537,40 @@ class MainWindow(QtWidgets.QMainWindow):
self.memory_label.mousePressEvent = lambda event: self._show_psutil_info() self.memory_label.mousePressEvent = lambda event: self._show_psutil_info()
self.memory_label.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor)) self.memory_label.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
# CPU usage # CPU usage with statistics
if memory_info.get('has_psutil', False): if memory_info.get('has_psutil', False):
cpu_text = f"CPU: {memory_info['cpu_percent']:.1f}%" current_cpu, max_cpu, avg_cpu = self._get_resource_stats(self._resource_history['cpu_percent'])
cpu_color = colors['error'] if memory_info['cpu_percent'] > 50 else colors['success']
cpu_text = f"CPU: {current_cpu:.1f}%\nMax: {max_cpu:.1f}% | Avg: {avg_cpu:.1f}%"
cpu_color = colors['error'] if current_cpu > 50 else colors['success']
else: else:
cpu_text = "CPU: N/A" cpu_text = "CPU: N/A\nInstall psutil for monitoring"
cpu_color = colors['text_light'] cpu_color = colors['text_light']
self.cpu_label.setText(cpu_text) self.cpu_label.setText(cpu_text)
self.cpu_label.setStyleSheet(f'font-size: 9pt; color: {cpu_color};') self.cpu_label.setStyleSheet(f'font-size: 9pt; color: {cpu_color};')
# System memory # System memory with statistics
if memory_info.get('has_psutil', False): if memory_info.get('has_psutil', False):
system_text = f"System: {memory_info['system_memory_percent']:.1f}% ({memory_info['system_memory_available_gb']:.1f}GB free)" current_sys, max_sys, avg_sys = self._get_resource_stats(self._resource_history['system_memory_percent'])
system_color = colors['error'] if memory_info['system_memory_percent'] > 85 else colors['success']
system_text = f"System: {current_sys:.1f}% ({memory_info['system_memory_available_gb']:.1f}GB free)\nMax: {max_sys:.1f}% | Avg: {avg_sys:.1f}%"
system_color = colors['error'] if current_sys > 85 else colors['success']
else: else:
system_text = "System: N/A" system_text = "System: N/A\nInstall psutil for monitoring"
system_color = colors['text_light'] system_color = colors['text_light']
self.system_memory_label.setText(system_text) self.system_memory_label.setText(system_text)
self.system_memory_label.setStyleSheet(f'font-size: 9pt; color: {system_color};') self.system_memory_label.setStyleSheet(f'font-size: 9pt; color: {system_color};')
# Cache info # Cache info (enhanced display)
cache_text = f"Cache: {memory_info['template_cache_size']} templates, {memory_info['cooldown_entries']} cooldowns" cache_text = f"Cache: {memory_info['template_cache_size']} templates\n{memory_info['cooldown_entries']} cooldowns"
cache_color = colors['warning'] if memory_info['template_cache_size'] > 20 else colors['info'] cache_color = colors['warning'] if memory_info['template_cache_size'] > 20 else colors['info']
self.cache_label.setText(cache_text) self.cache_label.setText(cache_text)
self.cache_label.setStyleSheet(f'font-size: 9pt; color: {cache_color};') self.cache_label.setStyleSheet(f'font-size: 9pt; color: {cache_color};')
# GPU memory info # GPU memory info with statistics
gpu_method = memory_info.get('gpu_method', 'unknown') gpu_method = memory_info.get('gpu_method', 'unknown')
if memory_info.get('gpu_has_gpu', False): if memory_info.get('gpu_has_gpu', False):
@@ -1501,24 +1578,27 @@ class MainWindow(QtWidgets.QMainWindow):
gpu_total_mb = memory_info.get('gpu_total_mb', 0) gpu_total_mb = memory_info.get('gpu_total_mb', 0)
gpu_utilization = memory_info.get('gpu_utilization_percent', 0) gpu_utilization = memory_info.get('gpu_utilization_percent', 0)
# Get GPU statistics
current_gpu, max_gpu, avg_gpu = self._get_resource_stats(self._resource_history['gpu_utilization'])
if gpu_total_mb > 0: if gpu_total_mb > 0:
gpu_text = f"GPU: {gpu_used_mb:.0f}/{gpu_total_mb:.0f}MB ({gpu_utilization:.1f}%)" gpu_text = f"GPU: {gpu_used_mb:.0f}/{gpu_total_mb:.0f}MB ({current_gpu:.1f}%)\nMax: {max_gpu:.1f}% | Avg: {avg_gpu:.1f}%"
gpu_color = colors['error'] if gpu_utilization > 80 else colors['warning'] if gpu_utilization > 60 else colors['success'] gpu_color = colors['error'] if current_gpu > 80 else colors['warning'] if current_gpu > 60 else colors['success']
# Add GPU name as tooltip # Add GPU name as tooltip
gpu_name = memory_info.get('gpu_name', 'Unknown GPU') gpu_name = memory_info.get('gpu_name', 'Unknown GPU')
self.gpu_label.setToolTip(f"GPU: {gpu_name} (detected via {gpu_method})") self.gpu_label.setToolTip(f"GPU: {gpu_name} (detected via {gpu_method})")
else: else:
gpu_text = f"GPU: Detected ({gpu_method})" gpu_text = f"GPU: Detected ({gpu_method})\nUtilization: {current_gpu:.1f}%"
gpu_color = colors['info'] gpu_color = colors['info']
gpu_name = memory_info.get('gpu_name', 'Unknown GPU') gpu_name = memory_info.get('gpu_name', 'Unknown GPU')
self.gpu_label.setToolTip(f"GPU: {gpu_name} (limited info via {gpu_method})") self.gpu_label.setToolTip(f"GPU: {gpu_name} (limited info via {gpu_method})")
elif gpu_method == 'loading': elif gpu_method == 'loading':
gpu_text = "GPU: Loading..." gpu_text = "GPU: Loading...\nDetection in progress"
gpu_color = colors['warning'] gpu_color = colors['warning']
self.gpu_label.setToolTip("GPU detection in progress...") self.gpu_label.setToolTip("GPU detection in progress...")
else: else:
gpu_text = "GPU: Not detected" gpu_text = "GPU: Not detected\nClick for setup info"
gpu_color = colors['text_light'] gpu_color = colors['text_light']
self.gpu_label.setToolTip( self.gpu_label.setToolTip(
"No GPU detected or GPU monitoring libraries not available.\n\n" "No GPU detected or GPU monitoring libraries not available.\n\n"
@@ -1542,13 +1622,14 @@ class MainWindow(QtWidgets.QMainWindow):
self.gpu_label.mousePressEvent = None self.gpu_label.mousePressEvent = None
self.gpu_label.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor)) self.gpu_label.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.ArrowCursor))
# Performance info # Performance info with statistics
if hasattr(self, '_loop_times') and self._loop_times: if hasattr(self, '_loop_times') and self._loop_times:
avg_time = sum(self._loop_times) / len(self._loop_times) current_loop, max_loop, avg_loop = self._get_resource_stats(self._resource_history['loop_times'])
perf_text = f"Performance: {avg_time*1000:.0f}ms avg loop time"
perf_color = colors['error'] if avg_time > 0.5 else colors['success'] perf_text = f"Performance: {current_loop:.0f}ms loop time\nMax: {max_loop:.0f}ms | Avg: {avg_loop:.0f}ms"
perf_color = colors['error'] if current_loop > 500 else colors['success']
else: else:
perf_text = "Performance: Not running" perf_text = "Performance: Not running\nStart automation to see metrics"
perf_color = colors['text_light'] perf_color = colors['text_light']
self.performance_label.setText(perf_text) self.performance_label.setText(perf_text)
@@ -1556,7 +1637,7 @@ class MainWindow(QtWidgets.QMainWindow):
# Show error if any # Show error if any
if 'error' in memory_info: if 'error' in memory_info:
self.performance_label.setText(f"Error: {memory_info['error'][:50]}...") self.performance_label.setText(f"Error: {memory_info['error'][:30]}...\nCheck logs for details")
self.performance_label.setStyleSheet(f'font-size: 9pt; color: {colors["error"]};') self.performance_label.setStyleSheet(f'font-size: 9pt; color: {colors["error"]};')
except Exception as e: except Exception as e:
@@ -1564,17 +1645,17 @@ class MainWindow(QtWidgets.QMainWindow):
colors = self.get_theme_styles() colors = self.get_theme_styles()
# Show basic fallback info with theme-aware colors # Show basic fallback info with theme-aware colors
error_color = colors['error'] error_color = colors['error']
self.memory_label.setText("Memory: Error") self.memory_label.setText("Memory: Error\nCheck logs for details")
self.memory_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.memory_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
self.cpu_label.setText("CPU: Error") self.cpu_label.setText("CPU: Error\nCheck logs for details")
self.cpu_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.cpu_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
self.system_memory_label.setText("System: Error") self.system_memory_label.setText("System: Error\nCheck logs for details")
self.system_memory_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.system_memory_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
self.cache_label.setText("Cache: Error") self.cache_label.setText("Cache: Error\nCheck logs for details")
self.cache_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.cache_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
self.gpu_label.setText("GPU: Error") self.gpu_label.setText("GPU: Error\nCheck logs for details")
self.gpu_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.gpu_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
self.performance_label.setText(f"Display Error: {str(e)[:30]}...") self.performance_label.setText(f"Display Error: {str(e)[:20]}...\nResource monitoring failed")
self.performance_label.setStyleSheet(f'font-size: 9pt; color: {error_color};') self.performance_label.setStyleSheet(f'font-size: 9pt; color: {error_color};')
def stop_monitoring(self): def stop_monitoring(self):
@@ -1594,7 +1675,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.cache_label.hide() self.cache_label.hide()
self.gpu_label.hide() self.gpu_label.hide()
self.performance_label.hide() self.performance_label.hide()
self.interval_label.hide()
self.update_interval_combo.hide() self.update_interval_combo.hide()
self.toggle_resources_btn.setText('Show Resources') self.toggle_resources_btn.setText('Show Resources')
self.resource_widgets_visible = False self.resource_widgets_visible = False
@@ -1606,7 +1686,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.cache_label.show() self.cache_label.show()
self.gpu_label.show() self.gpu_label.show()
self.performance_label.show() self.performance_label.show()
self.interval_label.show()
self.update_interval_combo.show() self.update_interval_combo.show()
self.toggle_resources_btn.setText('Hide Resources') self.toggle_resources_btn.setText('Hide Resources')
self.resource_widgets_visible = True self.resource_widgets_visible = True
@@ -1698,6 +1777,7 @@ class MainWindow(QtWidgets.QMainWindow):
# Update with window geometry and settings # Update with window geometry and settings
existing_config['main_window'] = geometry_data existing_config['main_window'] = geometry_data
existing_config['update_interval'] = self.update_interval_combo.currentData() existing_config['update_interval'] = self.update_interval_combo.currentData()
existing_config['theme_mode'] = self.theme_mode
with open(config_path, 'w') as f: with open(config_path, 'w') as f:
json.dump(existing_config, f, indent=2) json.dump(existing_config, f, indent=2)
@@ -1758,6 +1838,16 @@ class MainWindow(QtWidgets.QMainWindow):
break break
logger.debug(f"Restored update interval: {saved_interval}ms") logger.debug(f"Restored update interval: {saved_interval}ms")
# Restore theme mode if saved
saved_theme = config.get('theme_mode')
if saved_theme and saved_theme in ['system', 'light', 'dark']:
self.theme_mode = saved_theme
# Update the combo box to match the restored theme
theme_display_map = {'system': 'System', 'light': 'Light', 'dark': 'Dark'}
theme_display = theme_display_map.get(saved_theme, 'System')
self.theme_combo.setCurrentText(theme_display)
logger.debug(f"Restored theme mode: {saved_theme}")
logger.debug(f"Restored window geometry: x={x}, y={y}, w={width}, h={height}") logger.debug(f"Restored window geometry: x={x}, y={y}, w={width}, h={height}")
except (json.JSONDecodeError, IOError, KeyError) as e: except (json.JSONDecodeError, IOError, KeyError) as e:
@@ -1831,6 +1921,9 @@ class MainWindow(QtWidgets.QMainWindow):
self._loop_times.clear() self._loop_times.clear()
if hasattr(self, '_step_cooldown'): if hasattr(self, '_step_cooldown'):
self._step_cooldown.clear() self._step_cooldown.clear()
if hasattr(self, '_resource_history'):
for key in self._resource_history:
self._resource_history[key].clear()
# Force garbage collection # Force garbage collection
gc.collect() gc.collect()
@@ -2093,8 +2186,8 @@ class MainWindow(QtWidgets.QMainWindow):
colors = self.get_theme_styles() colors = self.get_theme_styles()
is_dark = self.get_effective_dark_mode() is_dark = self.get_effective_dark_mode()
# Apply dark title bar if in dark mode # Apply dark title bar if in dark mode (with small delay to ensure window is ready)
self.apply_dark_title_bar(is_dark) QtCore.QTimer.singleShot(10, lambda: self.apply_dark_title_bar(is_dark))
# Main window style # Main window style
main_style = f""" main_style = f"""
@@ -2193,7 +2286,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.cache_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};') self.cache_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};')
self.gpu_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};') self.gpu_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};')
self.performance_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};') self.performance_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};')
self.interval_label.setStyleSheet(f'font-size: 9pt; color: {colors["text_light"]};')
def on_theme_changed(self, theme_text): def on_theme_changed(self, theme_text):
""" """
@@ -2223,6 +2315,9 @@ class MainWindow(QtWidgets.QMainWindow):
self.apply_theme() self.apply_theme()
self._update_theme_combo_text() self._update_theme_combo_text()
# Save the theme preference immediately
self._save_window_geometry()
logger.info(f'Theme changed to: {self.theme_mode} mode') logger.info(f'Theme changed to: {self.theme_mode} mode')
def _update_theme_combo_text(self): def _update_theme_combo_text(self):
@@ -2389,15 +2484,13 @@ class MainWindow(QtWidgets.QMainWindow):
self.performance_label = QtWidgets.QLabel('Performance: --') self.performance_label = QtWidgets.QLabel('Performance: --')
resource_layout.addWidget(self.performance_label, 2, 0, 1, 3) resource_layout.addWidget(self.performance_label, 2, 0, 1, 3)
# Controls row (toggle button, update interval, and theme selector) # Controls row - Update interval group
self.toggle_resources_btn = QtWidgets.QPushButton('Hide Resources') interval_group = QtWidgets.QGroupBox('Update Interval')
self.toggle_resources_btn.setMaximumWidth(100) interval_group.setSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed)
self.toggle_resources_btn.setToolTip('Toggle resource usage display. Install psutil for detailed system metrics.') interval_layout = QtWidgets.QHBoxLayout()
self.toggle_resources_btn.clicked.connect(self._toggle_resource_display) interval_layout.setContentsMargins(4, 4, 4, 4)
resource_layout.addWidget(self.toggle_resources_btn, 3, 0) interval_layout.setSpacing(4)
# Update interval controls
self.interval_label = QtWidgets.QLabel('Update:')
self.update_interval_combo = QtWidgets.QComboBox() self.update_interval_combo = QtWidgets.QComboBox()
self.update_interval_combo.setMaximumWidth(80) self.update_interval_combo.setMaximumWidth(80)
self.update_interval_combo.setToolTip('Set resource monitoring update interval') self.update_interval_combo.setToolTip('Set resource monitoring update interval')
@@ -2419,8 +2512,19 @@ class MainWindow(QtWidgets.QMainWindow):
self.update_interval_combo.setCurrentIndex(2) self.update_interval_combo.setCurrentIndex(2)
self.update_interval_combo.currentIndexChanged.connect(self._on_update_interval_changed) self.update_interval_combo.currentIndexChanged.connect(self._on_update_interval_changed)
resource_layout.addWidget(self.interval_label, 3, 1) interval_layout.addWidget(self.update_interval_combo)
resource_layout.addWidget(self.update_interval_combo, 3, 2) interval_layout.addStretch(1)
interval_group.setLayout(interval_layout)
# Toggle button
self.toggle_resources_btn = QtWidgets.QPushButton('Hide Resources')
self.toggle_resources_btn.setMaximumWidth(100)
self.toggle_resources_btn.setToolTip('Toggle resource usage display. Install psutil for detailed system metrics.')
self.toggle_resources_btn.clicked.connect(self._toggle_resource_display)
# Add controls to layout
resource_layout.addWidget(interval_group, 3, 0)
resource_layout.addWidget(self.toggle_resources_btn, 3, 1)
self.resource_group.setLayout(resource_layout) self.resource_group.setLayout(resource_layout)
self.resource_widgets_visible = True self.resource_widgets_visible = True