20 #include <QDockWidget>
21 #include <QMessageBox>
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);
37 QRect ecvLayoutManager::getScreenGeometry()
const {
38 QScreen* screen = QGuiApplication::primaryScreen();
42 return screen ? screen->geometry() : QRect(0, 0, 1920, 1080);
45 QSize ecvLayoutManager::getIconSizeForScreen(
int screenWidth)
const {
51 QScreen* screen = QGuiApplication::primaryScreen();
52 qreal dpr = screen ? screen->devicePixelRatio() : 1.0;
60 int physicalWidth =
static_cast<int>(screenWidth * dpr);
70 if (physicalWidth >= 7680) {
73 }
else if (physicalWidth >= 3840) {
77 }
else if (physicalWidth >= 2560) {
80 }
else if (physicalWidth >= 1920) {
89 if (physicalWidth >= 7680) {
92 }
else if (physicalWidth >= 3840) {
95 }
else if (physicalWidth >= 2560) {
100 baseSize =
static_cast<int>(22 * (1.0 + (dpr - 1.0) * 0.3));
101 baseSize = qBound(22, baseSize, 28);
102 }
else if (physicalWidth >= 1920) {
106 baseSize =
static_cast<int>(18 * (1.0 + (dpr - 1.0) * 0.2));
107 baseSize = qBound(18, baseSize, 22);
114 return QSize(baseSize, baseSize);
118 if (!toolbar)
return;
120 QSize iconSize = getIconSizeForScreen(screenWidth);
121 toolbar->setIconSize(iconSize);
128 (iconSize.width() <= 16 ? 2 : 4);
129 toolbar->setStyleSheet(QString(
"QToolBar#%1 QToolButton { "
131 " min-height: %2px; "
133 " max-height: %2px; "
136 "QToolBar#%1 QToolButton::menu-indicator { "
139 .arg(toolbar->objectName())
144 QList<QAction*> actions = toolbar->actions();
145 for (QAction* action : actions) {
146 if (!action->icon().isNull()) {
147 QIcon originalIcon = action->icon();
149 QPixmap pixmap = originalIcon.pixmap(iconSize);
150 if (pixmap.isNull()) {
152 QList<QSize> availableSizes = originalIcon.availableSizes();
153 if (!availableSizes.isEmpty()) {
154 pixmap = originalIcon.pixmap(availableSizes.first());
157 if (!pixmap.isNull()) {
159 if (pixmap.size() != iconSize) {
160 pixmap = pixmap.scaled(iconSize, Qt::KeepAspectRatio,
161 Qt::SmoothTransformation);
164 QIcon scaledIcon(pixmap);
165 action->setIcon(scaledIcon);
171 toolbar->adjustSize();
172 toolbar->updateGeometry();
179 QList<QToolBar*> additionalToolbars =
182 for (QToolBar* toolbar : additionalToolbars) {
190 if (toolbar->parent() == m_mainWindow) {
191 m_mainWindow->removeToolBar(toolbar);
194 toolbar->setParent(
nullptr);
195 toolbar->setVisible(
false);
203 QList<QToolBar*> allToolbars = m_mainWindow->findChildren<QToolBar*>();
204 QToolBar* unifiedPluginToolbar =
nullptr;
206 for (QToolBar* tb : allToolbars) {
207 if (tb->objectName() ==
"UnifiedPluginToolbar") {
208 unifiedPluginToolbar = tb;
213 if (!unifiedPluginToolbar) {
214 CVLog::Warning(
"[ecvLayoutManager] UnifiedPluginToolbar not found!");
218 if (unifiedPluginToolbar->actions().isEmpty()) {
220 "[ecvLayoutManager] UnifiedPluginToolbar has no actions!");
225 if (unifiedPluginToolbar->parent() != m_mainWindow) {
226 unifiedPluginToolbar->setParent(m_mainWindow);
230 Qt::ToolBarArea area = m_mainWindow->toolBarArea(unifiedPluginToolbar);
231 if (area == Qt::NoToolBarArea) {
233 m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
234 }
else if (area != Qt::TopToolBarArea) {
236 m_mainWindow->removeToolBar(unifiedPluginToolbar);
237 m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
240 unifiedPluginToolbar->setVisible(
true);
241 unifiedPluginToolbar->show();
244 void ecvLayoutManager::setupToolbarLayout(
int screenWidth) {
246 QList<QToolBar*> toolBars = m_mainWindow->findChildren<QToolBar*>();
247 QSet<QToolBar*> processedToolbars;
249 QList<QToolBar*> topToolbars;
250 QList<QToolBar*> rightToolbars;
251 QList<QToolBar*> leftToolbars;
255 QList<QToolBar*> additionalPluginToolbars =
257 QSet<QToolBar*> additionalToolbarsSet;
258 for (QToolBar* toolbar : additionalPluginToolbars) {
261 additionalToolbarsSet.insert(toolbar);
266 for (QToolBar* toolbar : toolBars) {
268 if (!toolbar->isVisible() && toolbar->parent() == m_mainWindow &&
269 toolbar->objectName() !=
"UnifiedPluginToolbar") {
274 if (additionalToolbarsSet.contains(toolbar)) {
279 if (toolbar->objectName() ==
"UnifiedPluginToolbar") {
280 if (toolbar->actions().isEmpty() ||
281 processedToolbars.contains(toolbar)) {
284 processedToolbars.insert(toolbar);
285 m_mainWindow->removeToolBar(toolbar);
286 topToolbars.append(toolbar);
291 if (m_rightSideToolBars.contains(toolbar)) {
292 m_mainWindow->removeToolBar(toolbar);
293 rightToolbars.append(toolbar);
297 m_mainWindow->removeToolBar(toolbar);
299 if (m_leftSideToolBars.contains(toolbar)) {
300 leftToolbars.append(toolbar);
302 topToolbars.append(toolbar);
307 for (QToolBar* toolbar : rightToolbars) {
308 m_mainWindow->addToolBar(Qt::RightToolBarArea, toolbar);
309 toolbar->setVisible(
true);
314 for (QToolBar* toolbar : leftToolbars) {
315 m_mainWindow->addToolBar(Qt::LeftToolBarArea, toolbar);
316 toolbar->setVisible(
true);
328 QMap<QString, QToolBar*> toolbarMap;
329 QList<QToolBar*> reconstructionToolbars;
330 QList<QToolBar*> pythonPluginToolbars;
331 QToolBar* unifiedPluginToolbar =
nullptr;
333 for (QToolBar* toolbar : topToolbars) {
334 QString toolbarName = toolbar->objectName();
336 if (toolbarName ==
"UnifiedPluginToolbar") {
337 if (!unifiedPluginToolbar && !toolbar->actions().isEmpty()) {
338 unifiedPluginToolbar = toolbar;
340 }
else if (toolbarName ==
"Reconstruction") {
341 reconstructionToolbars.append(toolbar);
344 pythonPluginToolbars.append(toolbar);
346 toolbarMap[toolbarName] = toolbar;
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);
358 toolbarMap.remove(
name);
365 m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
368 for (QToolBar* toolbar : reconstructionToolbars) {
369 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
370 toolbar->setVisible(
true);
375 if (unifiedPluginToolbar && !unifiedPluginToolbar->actions().isEmpty()) {
376 m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
377 unifiedPluginToolbar->setVisible(
true);
382 m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
385 QStringList thirdRowOrder = {
"AnnotationToolBar",
"MeasurementsToolBar",
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);
393 toolbarMap.remove(
name);
398 for (QToolBar* toolbar : toolbarMap.values()) {
399 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
400 toolbar->setVisible(
true);
405 for (QToolBar* toolbar : pythonPluginToolbars) {
406 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
407 toolbar->setVisible(
true);
413 if (unifiedPluginToolbar && !unifiedPluginToolbar->actions().isEmpty()) {
414 m_mainWindow->addToolBar(Qt::TopToolBarArea, unifiedPluginToolbar);
415 unifiedPluginToolbar->setVisible(
true);
420 m_mainWindow->addToolBarBreak(Qt::TopToolBarArea);
423 for (QToolBar* toolbar : reconstructionToolbars) {
424 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
425 toolbar->setVisible(
true);
430 QStringList secondRowOrder = {
"AnnotationToolBar",
"MeasurementsToolBar",
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);
438 toolbarMap.remove(
name);
443 for (QToolBar* toolbar : toolbarMap.values()) {
444 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
445 toolbar->setVisible(
true);
450 for (QToolBar* toolbar : pythonPluginToolbars) {
451 m_mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
452 toolbar->setVisible(
true);
460 void ecvLayoutManager::setupDockWidgetLayout(
int screenWidth,
462 Q_UNUSED(screenWidth);
463 Q_UNUSED(screenHeight);
466 QList<QDockWidget*> dockWidgets =
467 m_mainWindow->findChildren<QDockWidget*>();
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)) {
476 m_mainWindow->addDockWidget(Qt::RightDockWidgetArea, dw);
485 void ecvLayoutManager::setupMainWindowGeometry(
int screenWidth,
488 m_mainWindow->showMaximized();
491 QString(
"[ecvLayoutManager] Main window maximized (screen: %1x%2)")
498 QRect screenGeometry = getScreenGeometry();
499 int screenWidth = screenGeometry.width();
500 int screenHeight = screenGeometry.height();
507 setupToolbarLayout(screenWidth);
508 setupDockWidgetLayout(screenWidth, screenHeight);
509 setupMainWindowGeometry(screenWidth, screenHeight);
515 if (!m_autoSaveEnabled) {
530 bool ecvLayoutManager::isAutoRestoreEnabled()
const {
535 bool doNotAutoRestoreGeometry =
537 return !doNotAutoRestoreGeometry;
545 if (isAutoRestoreEnabled()) {
547 "[ecvLayoutManager] Auto-restore enabled, using default "
556 QRect screenGeometry = getScreenGeometry();
557 int screenWidth = screenGeometry.width();
559 if (!forceDefault && geometry.isValid()) {
561 m_mainWindow->restoreGeometry(geometry.toByteArray());
562 m_mainWindow->restoreState(
574 QList<QToolBar*> allToolbars = m_mainWindow->findChildren<QToolBar*>();
575 for (QToolBar* toolbar : allToolbars) {
576 if (toolbar && toolbar->parent() == m_mainWindow) {
582 "[ecvLayoutManager] GUI layout restored from settings");
592 m_rightSideToolBars.insert(toolbar);
598 m_leftSideToolBars.insert(toolbar);
604 m_bottomDockWidgets.insert(dockWidget);
610 m_rightSideDockWidgets.insert(dockWidget);
616 CVLog::Error(
"[ecvLayoutManager] Main window is null!");
629 CVLog::Error(
"[ecvLayoutManager] Main window is null!");
643 "[ecvLayoutManager] Default layout restored successfully");
648 CVLog::Error(
"[ecvLayoutManager] Main window is null!");
656 if (!geometry.isValid() || !state.isValid()) {
657 CVLog::Warning(
"[ecvLayoutManager] No saved custom layout found");
662 m_mainWindow->restoreGeometry(geometry.toByteArray());
663 m_mainWindow->restoreState(state.toByteArray());
666 "[ecvLayoutManager] Custom layout restored successfully");
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool PrintVerbose(const char *format,...)
Prints out a verbose formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
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()