ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ecvLayoutManager.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ecvLayoutManager.h"
9 
10 // Local
11 #include "MainWindow.h"
12 #include "ecvPersistentSettings.h"
13 #include "ecvSettingManager.h"
15 
16 // CV_CORE_LIB
17 #include <CVLog.h>
18 
19 // Qt
20 #include <QDockWidget>
21 #include <QMessageBox>
22 #include <QSettings>
23 #include <QToolBar>
24 
25 ecvLayoutManager::ecvLayoutManager(QMainWindow* mainWindow,
26  ccPluginUIManager* pluginManager)
27  : QObject(mainWindow),
28  m_mainWindow(mainWindow),
29  m_pluginManager(pluginManager),
30  m_autoSaveEnabled(true) {
31  Q_ASSERT(m_mainWindow);
32  Q_ASSERT(m_pluginManager);
33 }
34 
36 
37 QRect ecvLayoutManager::getScreenGeometry() const {
38  QScreen* screen = QGuiApplication::primaryScreen();
39  // Use geometry() instead of availableGeometry() to match
40  // MainWindow::updateAllToolbarIconSizes() This ensures consistent screen
41  // width calculation
42  return screen ? screen->geometry() : QRect(0, 0, 1920, 1080);
43 }
44 
45 QSize ecvLayoutManager::getIconSizeForScreen(int screenWidth) const {
46  // Icon size scaling based on physical screen resolution
47  // Consider devicePixelRatio for High DPI displays (especially macOS Retina)
48  // This ensures proper icon sizing across Windows, Linux, and macOS
49  // platforms
50 
51  QScreen* screen = QGuiApplication::primaryScreen();
52  qreal dpr = screen ? screen->devicePixelRatio() : 1.0;
53 
54  // Calculate physical resolution (logical resolution × devicePixelRatio)
55  // This gives us the actual pixel density of the display
56  // Examples:
57  // - macOS Retina: logical 1920 × dpr 2.0 = physical 3840 (4K)
58  // - Standard 2K: logical 2560 × dpr 1.0 = physical 2560 (2K)
59  // - 8K display: logical 7680 × dpr 1.0 = physical 7680 (8K)
60  int physicalWidth = static_cast<int>(screenWidth * dpr);
61 
62  // Icon size calculation based on physical resolution
63  // Supports: 8K, 4K, 2K, 1080p, HD+, HD, and lower resolutions
64  int baseSize;
65 
66 #ifdef Q_OS_MAC
67  // macOS: Use moderate icon sizes for better visibility while fitting in 3
68  // rows macOS Retina displays have high DPR, use 3-row layout for better
69  // organization
70  if (physicalWidth >= 7680) {
71  // 8K physical resolution (7680x4320)
72  baseSize = 28;
73  } else if (physicalWidth >= 3840) {
74  // 4K physical resolution (3840x2160) - macOS Retina displays
75  // Balanced size for good visibility and 3-row layout
76  baseSize = 24;
77  } else if (physicalWidth >= 2560) {
78  // 2K physical resolution (2560x1440)
79  baseSize = 22;
80  } else if (physicalWidth >= 1920) {
81  // Full HD physical resolution (1920x1080)
82  baseSize = 20;
83  } else {
84  // HD+ (1600x900), HD (1280x720), and lower resolutions
85  baseSize = 18;
86  }
87 #else
88  // Windows and Linux: Use standard icon sizes
89  if (physicalWidth >= 7680) {
90  // 8K physical resolution (7680x4320)
91  baseSize = 40;
92  } else if (physicalWidth >= 3840) {
93  // 4K physical resolution (3840x2160)
94  baseSize = 32;
95  } else if (physicalWidth >= 2560) {
96  // 2K physical resolution (2560x1440)
97  // Scale icon size based on DPR for better visual consistency
98  // For standard 2K (dpr=1.0): 22px
99  // For scaled displays (dpr>1.0): scale up proportionally
100  baseSize = static_cast<int>(22 * (1.0 + (dpr - 1.0) * 0.3));
101  baseSize = qBound(22, baseSize, 28); // Clamp between 22 and 28
102  } else if (physicalWidth >= 1920) {
103  // Full HD physical resolution (1920x1080)
104  // For standard 1080p (dpr=1.0): 18px
105  // For slightly scaled displays (1.0 < dpr < 2.0): scale up slightly
106  baseSize = static_cast<int>(18 * (1.0 + (dpr - 1.0) * 0.2));
107  baseSize = qBound(18, baseSize, 22); // Clamp between 18 and 22
108  } else {
109  // HD+ (1600x900), HD (1280x720), and lower resolutions - minimum size
110  baseSize = 16;
111  }
112 #endif
113 
114  return QSize(baseSize, baseSize);
115 }
116 
117 void ecvLayoutManager::setToolbarIconSize(QToolBar* toolbar, int screenWidth) {
118  if (!toolbar) return;
119 
120  QSize iconSize = getIconSizeForScreen(screenWidth);
121  toolbar->setIconSize(iconSize);
122 
123  // Set stylesheet to ensure buttons have proper size and icons fill the
124  // button Use consistent padding across all toolbars
125  // Reduce padding for smaller icons to make buttons more compact
126  int buttonSize =
127  iconSize.width() +
128  (iconSize.width() <= 16 ? 2 : 4); // Less padding for small icons
129  toolbar->setStyleSheet(QString("QToolBar#%1 QToolButton { "
130  " min-width: %2px; "
131  " min-height: %2px; "
132  " max-width: %2px; "
133  " max-height: %2px; "
134  " padding: 1px; "
135  "} "
136  "QToolBar#%1 QToolButton::menu-indicator { "
137  " image: none; "
138  "}")
139  .arg(toolbar->objectName())
140  .arg(buttonSize));
141 
142  // Scale icons to match the toolbar icon size and ensure they fill the
143  // button
144  QList<QAction*> actions = toolbar->actions();
145  for (QAction* action : actions) {
146  if (!action->icon().isNull()) {
147  QIcon originalIcon = action->icon();
148  // Get the pixmap at the desired size
149  QPixmap pixmap = originalIcon.pixmap(iconSize);
150  if (pixmap.isNull()) {
151  // If pixmap is null, try to get any available size
152  QList<QSize> availableSizes = originalIcon.availableSizes();
153  if (!availableSizes.isEmpty()) {
154  pixmap = originalIcon.pixmap(availableSizes.first());
155  }
156  }
157  if (!pixmap.isNull()) {
158  // Scale to exact size while keeping aspect ratio
159  if (pixmap.size() != iconSize) {
160  pixmap = pixmap.scaled(iconSize, Qt::KeepAspectRatio,
161  Qt::SmoothTransformation);
162  }
163  // Create new icon with properly sized pixmap
164  QIcon scaledIcon(pixmap);
165  action->setIcon(scaledIcon);
166  }
167  }
168  }
169 
170  // Force toolbar to update
171  toolbar->adjustSize();
172  toolbar->updateGeometry();
173  toolbar->update();
174 }
175 
177  // Hide all additional plugin toolbars that were unified
178  // But exclude Python plugins - they should remain visible
179  QList<QToolBar*> additionalToolbars =
180  m_pluginManager->additionalPluginToolbars();
181 
182  for (QToolBar* toolbar : additionalToolbars) {
183  if (toolbar) {
184  // Skip Python plugin toolbars - they are handled separately
186  continue;
187  }
188 
189  // Remove from main window if attached
190  if (toolbar->parent() == m_mainWindow) {
191  m_mainWindow->removeToolBar(toolbar);
192  }
193  // Set parent to nullptr to prevent restoreState from re-adding it
194  toolbar->setParent(nullptr);
195  toolbar->setVisible(false);
196  toolbar->hide();
197  }
198  }
199 }
200 
202  // Find UnifiedPluginToolbar - search all children
203  QList<QToolBar*> allToolbars = m_mainWindow->findChildren<QToolBar*>();
204  QToolBar* unifiedPluginToolbar = nullptr;
205 
206  for (QToolBar* tb : allToolbars) {
207  if (tb->objectName() == "UnifiedPluginToolbar") {
208  unifiedPluginToolbar = tb;
209  break;
210  }
211  }
212 
213  if (!unifiedPluginToolbar) {
214  CVLog::Warning("[ecvLayoutManager] UnifiedPluginToolbar not found!");
215  return;
216  }
217 
218  if (unifiedPluginToolbar->actions().isEmpty()) {
220  "[ecvLayoutManager] UnifiedPluginToolbar has no actions!");
221  return;
222  }
223 
224  // Ensure it's attached to main window
225  if (unifiedPluginToolbar->parent() != m_mainWindow) {
226  unifiedPluginToolbar->setParent(m_mainWindow);
227  }
228 
229  // Simply ensure it's visible and in the top area
230  Qt::ToolBarArea area = m_mainWindow->toolBarArea(unifiedPluginToolbar);
231  if (area == Qt::NoToolBarArea) {
232  // Not added yet, add it to top
233  m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
234  } else if (area != Qt::TopToolBarArea) {
235  // In wrong area, move it to top
236  m_mainWindow->removeToolBar(unifiedPluginToolbar);
237  m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
238  }
239 
240  unifiedPluginToolbar->setVisible(true);
241  unifiedPluginToolbar->show();
242 }
243 
244 void ecvLayoutManager::setupToolbarLayout(int screenWidth) {
245  // Get all toolbars and categorize them
246  QList<QToolBar*> toolBars = m_mainWindow->findChildren<QToolBar*>();
247  QSet<QToolBar*> processedToolbars;
248 
249  QList<QToolBar*> topToolbars;
250  QList<QToolBar*> rightToolbars;
251  QList<QToolBar*> leftToolbars;
252 
253  // Get list of additional plugin toolbars that were unified (to skip them)
254  // But exclude Python plugins - they should be handled normally
255  QList<QToolBar*> additionalPluginToolbars =
256  m_pluginManager->additionalPluginToolbars();
257  QSet<QToolBar*> additionalToolbarsSet;
258  for (QToolBar* toolbar : additionalPluginToolbars) {
259  // Don't skip Python plugin toolbars - they are handled separately
261  additionalToolbarsSet.insert(toolbar);
262  }
263  }
264 
265  // Categorize toolbars by area
266  for (QToolBar* toolbar : toolBars) {
267  // Skip hidden toolbars
268  if (!toolbar->isVisible() && toolbar->parent() == m_mainWindow &&
269  toolbar->objectName() != "UnifiedPluginToolbar") {
270  continue;
271  }
272 
273  // Skip unified additional plugin toolbars (but not Python plugins)
274  if (additionalToolbarsSet.contains(toolbar)) {
275  continue;
276  }
277 
278  // Handle UnifiedPluginToolbar
279  if (toolbar->objectName() == "UnifiedPluginToolbar") {
280  if (toolbar->actions().isEmpty() ||
281  processedToolbars.contains(toolbar)) {
282  continue;
283  }
284  processedToolbars.insert(toolbar);
285  m_mainWindow->removeToolBar(toolbar);
286  topToolbars.append(toolbar);
287  continue;
288  }
289 
290  // Categorize by side
291  if (m_rightSideToolBars.contains(toolbar)) {
292  m_mainWindow->removeToolBar(toolbar);
293  rightToolbars.append(toolbar);
294  continue;
295  }
296 
297  m_mainWindow->removeToolBar(toolbar);
298 
299  if (m_leftSideToolBars.contains(toolbar)) {
300  leftToolbars.append(toolbar);
301  } else {
302  topToolbars.append(toolbar);
303  }
304  }
305 
306  // Add right-side toolbars
307  for (QToolBar* toolbar : rightToolbars) {
308  m_mainWindow->addToolBar(Qt::RightToolBarArea, toolbar);
309  toolbar->setVisible(true);
310  setToolbarIconSize(toolbar, screenWidth);
311  }
312 
313  // Add left-side toolbars
314  for (QToolBar* toolbar : leftToolbars) {
315  m_mainWindow->addToolBar(Qt::LeftToolBarArea, toolbar);
316  toolbar->setVisible(true);
317  setToolbarIconSize(toolbar, screenWidth);
318  }
319 
320  // Setup top toolbars configuration
321  // macOS: 3-row layout for better organization
322  // Windows/Linux: 2-row layout
323  // First row: mainToolBar, SFToolBar, FilterToolBar
324  // Second row (macOS only): UnifiedPluginToolbar, [Reconstruction]
325  // Last row: AnnotationToolBar, MeasurementsToolBar, SelectionToolBar,
326  // [Others]
327 
328  QMap<QString, QToolBar*> toolbarMap;
329  QList<QToolBar*> reconstructionToolbars;
330  QList<QToolBar*> pythonPluginToolbars;
331  QToolBar* unifiedPluginToolbar = nullptr;
332 
333  for (QToolBar* toolbar : topToolbars) {
334  QString toolbarName = toolbar->objectName();
335 
336  if (toolbarName == "UnifiedPluginToolbar") {
337  if (!unifiedPluginToolbar && !toolbar->actions().isEmpty()) {
338  unifiedPluginToolbar = toolbar;
339  }
340  } else if (toolbarName == "Reconstruction") {
341  reconstructionToolbars.append(toolbar);
342  } else if (ccPluginUIManager::isPythonPluginToolbar(toolbar)) {
343  // Collect Python plugin toolbars separately
344  pythonPluginToolbars.append(toolbar);
345  } else {
346  toolbarMap[toolbarName] = toolbar;
347  }
348  }
349 
350  // Add first row toolbars
351  QStringList firstRowOrder = {"mainToolBar", "SFToolBar", "FilterToolBar"};
352  for (const QString& name : firstRowOrder) {
353  if (toolbarMap.contains(name)) {
354  QToolBar* toolbar = toolbarMap[name];
355  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
356  toolbar->setVisible(true);
357  setToolbarIconSize(toolbar, screenWidth);
358  toolbarMap.remove(name);
359  }
360  }
361 
362 #ifdef Q_OS_MAC
363  // macOS: 3-row layout
364  // Add toolbar break for second row
365  m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
366 
367  // Add reconstruction toolbars in second row
368  for (QToolBar* toolbar : reconstructionToolbars) {
369  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
370  toolbar->setVisible(true);
371  setToolbarIconSize(toolbar, screenWidth);
372  }
373 
374  // Add UnifiedPluginToolbar at beginning of second row
375  if (unifiedPluginToolbar && !unifiedPluginToolbar->actions().isEmpty()) {
376  m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
377  unifiedPluginToolbar->setVisible(true);
378  setToolbarIconSize(unifiedPluginToolbar, screenWidth);
379  }
380 
381  // Add toolbar break for third row
382  m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
383 
384  // Add third row toolbars
385  QStringList thirdRowOrder = {"AnnotationToolBar", "MeasurementsToolBar",
386  "SelectionToolBar"};
387  for (const QString& name : thirdRowOrder) {
388  if (toolbarMap.contains(name)) {
389  QToolBar* toolbar = toolbarMap[name];
390  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
391  toolbar->setVisible(true);
392  setToolbarIconSize(toolbar, screenWidth);
393  toolbarMap.remove(name);
394  }
395  }
396 
397  // Add remaining toolbars to third row
398  for (QToolBar* toolbar : toolbarMap.values()) {
399  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
400  toolbar->setVisible(true);
401  setToolbarIconSize(toolbar, screenWidth);
402  }
403 
404  // Add Python plugin toolbars at the end of third row
405  for (QToolBar* toolbar : pythonPluginToolbars) {
406  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
407  toolbar->setVisible(true);
408  setToolbarIconSize(toolbar, screenWidth);
409  }
410 #else
411  // Windows/Linux: 2-row layout
412  // Add UnifiedPluginToolbar at end of first row
413  if (unifiedPluginToolbar && !unifiedPluginToolbar->actions().isEmpty()) {
414  m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
415  unifiedPluginToolbar->setVisible(true);
416  setToolbarIconSize(unifiedPluginToolbar, screenWidth);
417  }
418 
419  // Add toolbar break for second row
420  m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
421 
422  // Add reconstruction toolbars at beginning of second row
423  for (QToolBar* toolbar : reconstructionToolbars) {
424  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
425  toolbar->setVisible(true);
426  setToolbarIconSize(toolbar, screenWidth);
427  }
428 
429  // Add second row toolbars
430  QStringList secondRowOrder = {"AnnotationToolBar", "MeasurementsToolBar",
431  "SelectionToolBar"};
432  for (const QString& name : secondRowOrder) {
433  if (toolbarMap.contains(name)) {
434  QToolBar* toolbar = toolbarMap[name];
435  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
436  toolbar->setVisible(true);
437  setToolbarIconSize(toolbar, screenWidth);
438  toolbarMap.remove(name);
439  }
440  }
441 
442  // Add remaining toolbars
443  for (QToolBar* toolbar : toolbarMap.values()) {
444  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
445  toolbar->setVisible(true);
446  setToolbarIconSize(toolbar, screenWidth);
447  }
448 
449  // Add Python plugin toolbars at the end of second row
450  for (QToolBar* toolbar : pythonPluginToolbars) {
451  m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
452  toolbar->setVisible(true);
453  setToolbarIconSize(toolbar, screenWidth);
454  }
455 #endif
456 
457  CVLog::PrintVerbose("[ecvLayoutManager] Toolbar layout configured");
458 }
459 
460 void ecvLayoutManager::setupDockWidgetLayout(int screenWidth,
461  int screenHeight) {
462  Q_UNUSED(screenWidth);
463  Q_UNUSED(screenHeight);
464 
465  // Get all dock widgets
466  QList<QDockWidget*> dockWidgets =
467  m_mainWindow->findChildren<QDockWidget*>();
468 
469  // Setup dock widgets based on their registered positions
470  for (QDockWidget* dw : dockWidgets) {
471  if (m_bottomDockWidgets.contains(dw)) {
472  m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dw);
473  } else if (m_rightSideDockWidgets.contains(dw)) {
474  // Right side dock widgets should be hidden by default in default
475  // layout
476  m_mainWindow->addDockWidget(Qt::RightDockWidgetArea, dw);
477  dw->hide(); // Hide by default for cleaner initial layout
478  }
479  // Other dock widgets are handled by MainWindow
480  }
481 
482  CVLog::PrintVerbose("[ecvLayoutManager] Dock widget layout configured");
483 }
484 
485 void ecvLayoutManager::setupMainWindowGeometry(int screenWidth,
486  int screenHeight) {
487  // Always maximize the main window on startup
488  m_mainWindow->showMaximized();
489 
491  QString("[ecvLayoutManager] Main window maximized (screen: %1x%2)")
492  .arg(screenWidth)
493  .arg(screenHeight));
494 }
495 
497  // Get screen resolution
498  QRect screenGeometry = getScreenGeometry();
499  int screenWidth = screenGeometry.width();
500  int screenHeight = screenGeometry.height();
501 
502  CVLog::PrintDebug(QString("[ecvLayoutManager] Screen resolution: %1x%2")
503  .arg(screenWidth)
504  .arg(screenHeight));
505 
506  // Setup components
507  setupToolbarLayout(screenWidth);
508  setupDockWidgetLayout(screenWidth, screenHeight);
509  setupMainWindowGeometry(screenWidth, screenHeight);
510 
511  CVLog::PrintVerbose("[ecvLayoutManager] GUI Default layout setup complete");
512 }
513 
515  if (!m_autoSaveEnabled) {
516  return;
517  }
518 
519  // Ensure additional plugin toolbars remain hidden before saving
521 
522  // Save the state as settings
523  QSettings settings;
524  settings.setValue(ecvPS::MainWinGeom(), m_mainWindow->saveGeometry());
525  settings.setValue(ecvPS::MainWinState(), m_mainWindow->saveState());
526 
527  CVLog::PrintVerbose("[ecvLayoutManager] GUI layout saved");
528 }
529 
530 bool ecvLayoutManager::isAutoRestoreEnabled() const {
531  QSettings settings;
532  // Default value is true (restore enabled), which matches the UI action's
533  // default checked state (true = restore enabled)
534  // We check DoNotRestoreWindowGeometry and invert it
535  bool doNotAutoRestoreGeometry =
536  settings.value(ecvPS::DoNotRestoreWindowGeometry(), false).toBool();
537  return !doNotAutoRestoreGeometry;
538 }
539 
540 void ecvLayoutManager::restoreGUILayout(bool forceDefault) {
541  QSettings settings;
542 
543  // Check if auto-restore is enabled (do this check first, matching
544  // CloudCompare)
545  if (isAutoRestoreEnabled()) {
547  "[ecvLayoutManager] Auto-restore enabled, using default "
548  "layout");
550  return;
551  }
552 
553  QVariant geometry = settings.value(ecvPS::MainWinGeom());
554 
555  // Get screen resolution for icon size calculation
556  QRect screenGeometry = getScreenGeometry();
557  int screenWidth = screenGeometry.width();
558 
559  if (!forceDefault && geometry.isValid()) {
560  // Restore saved layout
561  m_mainWindow->restoreGeometry(geometry.toByteArray());
562  m_mainWindow->restoreState(
563  settings.value(ecvPS::MainWinState()).toByteArray());
564 
565  // After restoring, hide additional plugin toolbars
567 
568  // Ensure UnifiedPluginToolbar is visible
570 
571  // Update icon sizes for all toolbars after restoring layout
572  // This ensures icons are properly sized even when restoring from saved
573  // state
574  QList<QToolBar*> allToolbars = m_mainWindow->findChildren<QToolBar*>();
575  for (QToolBar* toolbar : allToolbars) {
576  if (toolbar && toolbar->parent() == m_mainWindow) {
577  setToolbarIconSize(toolbar, screenWidth);
578  }
579  }
580 
582  "[ecvLayoutManager] GUI layout restored from settings");
583  } else {
584  // Use default layout
586  CVLog::PrintVerbose("[ecvLayoutManager] GUI Using default layout");
587  }
588 }
589 
591  if (toolbar) {
592  m_rightSideToolBars.insert(toolbar);
593  }
594 }
595 
597  if (toolbar) {
598  m_leftSideToolBars.insert(toolbar);
599  }
600 }
601 
602 void ecvLayoutManager::registerBottomDockWidget(QDockWidget* dockWidget) {
603  if (dockWidget) {
604  m_bottomDockWidgets.insert(dockWidget);
605  }
606 }
607 
608 void ecvLayoutManager::registerRightSideDockWidget(QDockWidget* dockWidget) {
609  if (dockWidget) {
610  m_rightSideDockWidgets.insert(dockWidget);
611  }
612 }
613 
615  if (!m_mainWindow) {
616  CVLog::Error("[ecvLayoutManager] Main window is null!");
617  return;
618  }
619 
620  QSettings settings;
621  settings.setValue(ecvPS::CustomLayoutGeom(), m_mainWindow->saveGeometry());
622  settings.setValue(ecvPS::CustomLayoutState(), m_mainWindow->saveState());
623 
624  CVLog::PrintVerbose("[ecvLayoutManager] Custom layout saved successfully");
625 }
626 
628  if (!m_mainWindow) {
629  CVLog::Error("[ecvLayoutManager] Main window is null!");
630  return;
631  }
632 
633  // Clear main window state to restore default layout
634  QSettings settings;
635  settings.remove(ecvPS::MainWinGeom());
636  settings.remove(ecvPS::MainWinState());
637 
638  // Setup default layout
640  saveGUILayout();
641 
643  "[ecvLayoutManager] Default layout restored successfully");
644 }
645 
647  if (!m_mainWindow) {
648  CVLog::Error("[ecvLayoutManager] Main window is null!");
649  return false;
650  }
651 
652  QSettings settings;
653  QVariant geometry = settings.value(ecvPS::CustomLayoutGeom());
654  QVariant state = settings.value(ecvPS::CustomLayoutState());
655 
656  if (!geometry.isValid() || !state.isValid()) {
657  CVLog::Warning("[ecvLayoutManager] No saved custom layout found");
658  return false;
659  }
660 
661  // Restore custom layout
662  m_mainWindow->restoreGeometry(geometry.toByteArray());
663  m_mainWindow->restoreState(state.toByteArray());
664 
666  "[ecvLayoutManager] Custom layout restored successfully");
667  return true;
668 }
std::string name
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
Definition: CVLog.cpp:153
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool PrintVerbose(const char *format,...)
Prints out a verbose formatted message in console.
Definition: CVLog.cpp:103
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Plugin UI manager.
QList< QToolBar * > & additionalPluginToolbars()
static bool isPythonPluginToolbar(QToolBar *toolbar)
void registerBottomDockWidget(QDockWidget *dockWidget)
Register a dock widget to be placed at the bottom.
void registerLeftSideToolBar(QToolBar *toolbar)
Register a toolbar to be placed on the left side.
void restoreGUILayout(bool forceDefault=false)
Restore GUI layout from settings.
void repositionUnifiedPluginToolbar()
Reposition the unified plugin toolbar to the end of the first row.
void setToolbarIconSize(QToolBar *toolbar, int screenWidth)
ecvLayoutManager(QMainWindow *mainWindow, ccPluginUIManager *pluginManager)
Constructor.
bool restoreCustomLayout()
Restore previously saved custom layout.
void registerRightSideToolBar(QToolBar *toolbar)
Register a toolbar to be placed on the right side.
void saveGUILayout()
Save current GUI layout to settings.
void registerRightSideDockWidget(QDockWidget *dockWidget)
Register a dock widget to be placed on the right side.
void hideAdditionalPluginToolbars()
void restoreDefaultLayout()
Restore the default layout.
void setupDefaultLayout()
Setup default layout for the main window.
virtual ~ecvLayoutManager()
Destructor.
void saveCustomLayout()
Save current layout as custom layout.
static const QString CustomLayoutGeom()
static const QString CustomLayoutState()
static const QString MainWinState()
static const QString MainWinGeom()
static const QString DoNotRestoreWindowGeometry()