1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "DockableContainer.h"
5 #include "QTrackingTooltip.h"
6 #include "Menu/AbstractMenu.h"
8 QToolWindowManagerClassFactory
* CDockableContainer::s_dockingFactory
= nullptr;
10 CDockableContainer::CDockableContainer(QWidget
* parent
, QVariantMap startingLayout
/*= QVariantMap()*/)
11 : QWidget(parent
), m_startingLayout(startingLayout
), m_toolManager(nullptr), m_defaultLayoutCallback(nullptr), m_pMenu(nullptr)
15 CDockableContainer::~CDockableContainer()
19 disconnect(m_layoutChangedConnection
);
22 for (auto& pair
: m_spawned
)
24 disconnect(pair
.second
.m_widget
, 0, this, 0);
29 void CDockableContainer::Register(QString name
, std::function
<QWidget
*()> factory
, bool isUnique
, bool isInternal
)
31 m_registry
[name
] = FactoryInfo(factory
, isUnique
, isInternal
);
34 QWidget
* CDockableContainer::Spawn(QString name
, QString forceObjectName
)
36 auto it
= m_registry
.find(name
);
37 if (it
!= m_registry
.end())
39 if (it
->second
.m_isUnique
)
41 for (auto wi
: m_spawned
)
43 if (wi
.second
.m_spawnName
== name
)
45 // Already created, return existing instance
46 return wi
.second
.m_widget
;
50 QWidget
* w
= it
->second
.m_factory();
51 if (forceObjectName
.isEmpty())
53 w
->setObjectName(CreateObjectName(name
));
57 w
->setObjectName(forceObjectName
);
59 m_spawned
[w
->objectName()] = WidgetInstance(w
, name
);
60 connect(w
, &QObject::destroyed
, this, &CDockableContainer::OnWidgetDestroyed
);
67 QWidget
* CDockableContainer::SpawnWidget(QString name
, const QToolWindowAreaTarget
& target
)
69 return SpawnWidget(name
, "", target
);
72 QWidget
* CDockableContainer::SpawnWidget(QString name
, QWidget
* pTargetWidget
, const QToolWindowAreaTarget
& target
)
74 IToolWindowArea
* pToolArea
= m_toolManager
->areaOf(pTargetWidget
);
77 return SpawnWidget(name
, "", pToolArea
, target
.reference
, target
.index
, target
.geometry
);
82 QWidget
* CDockableContainer::SpawnWidget(QString name
, QString objectName
, const QToolWindowAreaTarget
& target
)
84 return SpawnWidget(name
, objectName
, target
.area
, target
.reference
, target
.index
, target
.geometry
);
87 QWidget
* CDockableContainer::SpawnWidget(QString name
, IToolWindowArea
* area
/*= nullptr*/, QToolWindowAreaReference reference
/*= QToolWindowAreaTarget::Combine*/, int index
/*= -1*/, QRect geometry
/*= QRect()*/)
89 return SpawnWidget(name
, "", area
, reference
, index
, geometry
);
92 QWidget
* CDockableContainer::SpawnWidget(QString name
, QString objectName
, IToolWindowArea
* area
/*= nullptr*/, QToolWindowAreaReference reference
/*= QToolWindowManager::AreaReference::Combine*/, int index
/*= -1*/, QRect geometry
/*= QRect()*/)
94 QWidget
* w
= Spawn(name
, objectName
);
97 if (!m_toolManager
->ownsToolWindow(w
)) //If it's already owned, this is a single-instance widget, so don't move it
99 m_toolManager
->addToolWindow(w
, area
, reference
, index
, geometry
);
101 m_toolManager
->bringToFront(w
);
106 void CDockableContainer::SetDefaultLayoutCallback(std::function
<void(CDockableContainer
*)> callback
)
108 m_defaultLayoutCallback
= callback
;
111 void CDockableContainer::SetMenu(CAbstractMenu
* pAbstractMenu
)
113 m_pMenu
= pAbstractMenu
;
116 void CDockableContainer::SetSplitterSizes(QWidget
* widget
, QList
<int> sizes
)
118 m_toolManager
->resizeSplitter(widget
, sizes
);
121 QVariantMap
CDockableContainer::GetState() const
126 QVariantMap stateMap
;
127 for (auto sw
: m_spawned
)
129 CDockableContainer::WidgetInstance
& w
= sw
.second
;
130 if (m_toolManager
->areaOf(w
.m_widget
))
132 QVariantMap toolData
;
133 toolData
.insert("class", w
.m_spawnName
);
134 IStateSerializable
* ssw
= qobject_cast
<IStateSerializable
*>(w
.m_widget
);
137 toolData
.insert("state", ssw
->GetState());
139 stateMap
[w
.m_widget
->objectName()] = toolData
;
142 result
["Windows"] = stateMap
;
143 result
["ToolsLayout"] = m_toolManager
->saveState();
148 void CDockableContainer::SetState(const QVariantMap
& state
)
152 m_startingLayout
= state
;
155 auto lock
= m_toolManager
->getNotifyLock(false);
156 m_toolManager
->hide();
157 m_toolManager
->clear();
159 QVariantMap openToolsMap
= state
.value("Windows").toMap();
160 for (QVariantMap::const_iterator iter
= openToolsMap
.begin(); iter
!= openToolsMap
.end(); ++iter
)
162 QString key
= iter
.key();
163 QVariantMap v
= iter
.value().toMap();
164 QString className
= v
.value("class").toString();
165 QVariantMap toolState
= v
.value("state", QVariantMap()).toMap();
167 QWidget
* w
= SpawnWidget(className
, key
);
168 IStateSerializable
* ssw
= qobject_cast
<IStateSerializable
*>(w
);
171 if (!toolState
.empty() && ssw
)
173 ssw
->SetState(toolState
);
178 m_toolManager
->restoreState(state
["ToolsLayout"]);
180 m_toolManager
->show();
181 m_startingLayout
= QVariantMap();
184 void CDockableContainer::OnWidgetDestroyed(QObject
* pObject
)
186 auto it
= m_spawned
.find(pObject
->objectName());
187 if (it
!= m_spawned
.end() && it
->second
.m_widget
== pObject
)
194 QString
CDockableContainer::CreateObjectName(QString title
) const
196 QString result
= title
;
197 while (m_spawned
.find(result
) != m_spawned
.end())
200 result
= QString::asprintf("%s#%d", title
.toStdString().c_str(), i
);
205 void CDockableContainer::showEvent(QShowEvent
* event
)
207 // Construct everything in the show event to ensure owner is fully constructed
213 QVariantMap config
= CEditorDialog::s_config
;
214 config
[QTWM_RELEASE_POLICY
] = rcpDelete
;
215 m_toolManager
= new QToolWindowManager(this, config
, s_dockingFactory
);
216 connect(m_toolManager
, &QToolWindowManager::updateTrackingTooltip
, [](const QString
& str
, const QPoint
& p
) { QTrackingTooltip::ShowTextTooltip(str
, p
); });
217 setLayout(new QVBoxLayout());
218 layout()->setContentsMargins(0, 0, 0, 0);
219 setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
220 layout()->addWidget(m_toolManager
);
221 if (!m_startingLayout
.isEmpty())
223 SetState(m_startingLayout
);
227 m_defaultLayoutCallback(this);
230 m_layoutChangedConnection
= connect(m_toolManager
, &QToolWindowManager::layoutChanged
, [=]() { OnLayoutChange(GetState()); BuildWindowMenu(); });
234 void CDockableContainer::BuildWindowMenu()
243 CAbstractMenu
* addMenu
= nullptr;
244 for (auto it
: m_registry
)
246 if (it
.second
.m_isInternal
)
253 addMenu
= m_pMenu
->CreateMenu("&Add Pane");
256 QString s
= it
.first
;
257 QAction
* action
= addMenu
->CreateAction(s
);
258 connect(action
, &QAction::triggered
, [=]() { return SpawnWidget(s
); });
261 QAction
* action
= m_pMenu
->CreateAction("&Reset layout");
262 connect(action
, &QAction::triggered
, [=] { ResetLayout(); });
264 int sec
= m_pMenu
->GetNextEmptySection();
266 foreach(QWidget
* q
, m_toolManager
->toolWindows())
268 QAction
* action
= m_pMenu
->CreateAction(q
->windowTitle(), sec
);
269 connect(action
, &QAction::triggered
, [=] { m_toolManager
->bringToFront(q
); });
273 void CDockableContainer::ResetLayout()
275 QToolWindowManager::QTWMNotifyLock lock
= m_toolManager
->getNotifyLock();
276 m_toolManager
->hide();
277 m_toolManager
->clear();
279 m_defaultLayoutCallback(this);
280 m_toolManager
->show();
283 CDockableContainer::FactoryInfo::FactoryInfo(std::function
<QWidget
*()> factory
, bool isUnique
, bool isInternal
) : m_factory(factory
), m_isUnique(isUnique
), m_isInternal(isInternal
)
287 CDockableContainer::WidgetInstance::WidgetInstance(QWidget
* widget
, QString spawnName
) : m_widget(widget
), m_spawnName(spawnName
)