Krita Source Code Documentation
Loading...
Searching...
No Matches
KisDockerHud.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Freya Lupen <penguinflyer2222@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "KisDockerHud.h"
8
9#include <QVBoxLayout>
10#include <QHBoxLayout>
11#include <QToolButton>
12#include <QComboBox>
13#include <QLabel>
14#include <QDockWidget>
15
16#include <kseparator.h>
17#include "KisMainWindow.h"
18#include "KisPart.h"
19#include "KisDlgListPicker.h"
21
22#include "kis_config.h"
23#include "kis_icon_utils.h"
24
25QHash<QString, QList<QString>> KisDockerHud::borrowedWidgetOwners = QHash<QString, QList<QString>>();
26
28{
29 QComboBox *dockerComboBox;
30 QVBoxLayout *dockerLayout;
31 QDockWidget* oldDockerParent {};
32 bool isBorrowing {false};
33 QLabel* dockerIOULabel {};
34 QToolButton* dockerMenu {};
35
36 QString borrowerName;
37 QString configId;
38
39 bool isShown {true};
40 bool isConnected {false};
41};
42
43KisDockerHud::KisDockerHud(QString borrowerName, QString configId)
44 : QWidget(),
45 m_d(new Private)
46{
47 this->setObjectName(configId + "DockerHud");
48 this->setAutoFillBackground(true); // so that it's not transparent
49
50 m_d->borrowerName = borrowerName;
51 m_d->configId = configId;
52
53 QVBoxLayout *layout = new QVBoxLayout();
54 QHBoxLayout *menuLayout = new QHBoxLayout();
55
56 // Put the docker config button before the combobox,
57 // so it cannot go offscreen in case of a wide widget.
58 m_d->dockerMenu = new QToolButton();
59 m_d->dockerMenu->setAutoRaise(true);
60 m_d->dockerMenu->setToolTip(i18n("Configure docker panel"));
61 connect(m_d->dockerMenu, SIGNAL(clicked()), this, SLOT(showDockerConfig()));
62 menuLayout->addWidget(m_d->dockerMenu);
63
64 m_d->dockerComboBox = new QComboBox();
65 menuLayout->addWidget(m_d->dockerComboBox);
66
67 layout->addLayout(menuLayout);
68 layout->addWidget(new KSeparator());
69 m_d->dockerLayout = new QVBoxLayout();
70 layout->addLayout(m_d->dockerLayout);
71 this->setLayout(layout);
72
73 m_d->dockerIOULabel = new QLabel(i18nc("%1 is the name of the widget", "Docker is open in %1. Close %1 to show here.", borrowerName));
74 m_d->dockerIOULabel->setWordWrap(true);
75 m_d->dockerIOULabel->setAlignment(Qt::AlignCenter);
76
78
80}
81
83{
84 delete m_d->dockerIOULabel;
85}
86
88{
89 if (m_d->isBorrowing) { // then return it
91 }
92
93 // If really visible, borrow it
94 if (this->isVisible() && m_d->isShown) {
96 }
97}
98
101
102
103 const QString dockerId = m_d->dockerComboBox->currentData().toString();
104 QDockWidget *docker = mainWindow->findChild<QDockWidget*>(dockerId);
105 if (docker == nullptr) {
106 return;
107 }
108
109 QList<QString> &owners = borrowedWidgetOwners[dockerId];
110
111 // If the docker is being borrowed by another widget, request its return
112 if (!owners.empty() && owners.last() != this->objectName()) {
113 KisDockerHud *prevOwner = mainWindow->findChild<KisDockerHud*>(owners.last());
114 prevOwner->returnDocker(true);
115 }
116
117 // Notify any waiting borrowers that we own it now
118 Q_FOREACH(QString waitingWidgetId, owners) {
119 KisDockerHud *waitingWidget = mainWindow->findChild<KisDockerHud*>(waitingWidgetId);
120 waitingWidget->showBorrowerLabel(m_d->borrowerName);
121 }
122
123 if (!owners.contains(this->objectName())) {
124 owners.append(this->objectName());
125 }
126
127 // Now actually borrow it.
128
129 m_d->oldDockerParent = docker;
130
131 // Animation dockers have playback controls and such in the titlebar,
132 // so we borrow those as well.
133 if (docker->objectName() == "AnimationCurvesDocker" || docker->objectName() == "TimelineDocker") {
134 KisUtilityTitleBar *titleBar = dynamic_cast<KisUtilityTitleBar*>(docker->titleBarWidget());
136 if (titleBar) {
137 QWidget *widgetArea = titleBar->widgetArea();
138 m_d->dockerLayout->addWidget(widgetArea);
139 }
140 }
141
142 m_d->dockerLayout->addWidget(docker->widget());
143 docker->setWidget(m_d->dockerIOULabel);
144
145 // Hack: somewhat fixes Animation Curves's titlebar being too tall
146 m_d->dockerLayout->setStretch(m_d->dockerLayout->count()-1, 1);
147
148 m_d->isBorrowing = true;
149}
150void KisDockerHud::returnDocker(bool beingTaken) {
151 QString dockerId = m_d->oldDockerParent->objectName();
152 QList<QString>* owners = &borrowedWidgetOwners[dockerId];
153
154 if (!owners->isEmpty()) {
155 const int idx = owners->indexOf(this->objectName());
156 const bool wasOwner = idx == owners->count()-1;
157 if (!beingTaken) {
158 owners->removeAt(idx); // we don't want it anymore
159 }
160
161 // If we don't own it, just remove our label
162 if (!wasOwner) {
164 return;
165 }
166 }
167
168 // If we own it, actually return it.
169
170 if (m_d->dockerLayout->count() == 2) {
171 // Return the animation dockers' titlebar widget as well
172 KisUtilityTitleBar *titleBar = dynamic_cast<KisUtilityTitleBar*>(m_d->oldDockerParent->titleBarWidget());
174 if (titleBar) {
175 titleBar->setWidgetArea(m_d->dockerLayout->takeAt(0)->widget());
176 }
177 }
178
179 QWidget* dockerInside = m_d->dockerLayout->takeAt(0)->widget();
180 m_d->oldDockerParent->setWidget(dockerInside);
181 dockerInside->setParent(m_d->oldDockerParent);
182
183 m_d->oldDockerParent = nullptr;
184 m_d->isBorrowing = false;
185
186 // If another borrower is in line, tell it to take it.
187 if (!beingTaken && !owners->empty()) {
189 KisDockerHud *newOwner = mainWindow->findChild<KisDockerHud*>(owners->last());
190 newOwner->borrowDocker();
191 }
192}
193
195{
196 QList<QString> currentDockerNames;
197 QList<QVariant> currentDockerIds;
198 for(int i = 0; i < m_d->dockerComboBox->count(); i++) {
199 currentDockerNames.append(m_d->dockerComboBox->itemText(i));
200 currentDockerIds.append(m_d->dockerComboBox->itemData(i));
201 }
202
204 const QList<QDockWidget*> dockers = mainWindow->dockWidgets();
205
206 QList<QString> dockerNames;
207 QList<QVariant> dockerIds;
208 Q_FOREACH(QDockWidget* docker, dockers) {
209 if (!currentDockerIds.contains(docker->objectName())) {
210 dockerNames.append(docker->windowTitle());
211 dockerIds.append(docker->objectName());
212 }
213 }
214
215 KisDlgListPicker config = KisDlgListPicker(i18nc("%1 is the name of the widget", "Configure %1 dockers", m_d->borrowerName),
216 i18n("Available dockers"), i18n("Current dockers"),
217 dockerNames, dockerIds, currentDockerNames, currentDockerIds, this);
218
219 if (config.exec() == QDialog::Accepted) {
221 const QString currentDocker = readCurrentDocker();
223 m_d->dockerComboBox->setCurrentIndex(m_d->dockerComboBox->findData(currentDocker, Qt::UserRole));
224
225 // If the current docker was removed from the list, use the first one.
226 if (m_d->dockerComboBox->currentData().isNull() && m_d->dockerComboBox->count() != 0) {
227 m_d->dockerComboBox->setCurrentIndex(0);
228 }
229 }
230}
231
233{
234 KisConfig(false).writeList(m_d->configId+"/dockerList", currentList);
235}
237{
238 m_d->dockerComboBox->clear();
239 const QList<QString> defaultDockers = QList<QString>({"BrushHudDocker", "KisLayerBox"});
240 const QList<QString> dockerList = KisConfig(true).readList(m_d->configId+"/dockerList", defaultDockers);
241
243 // for an ordered list
244 Q_FOREACH(QString objName, dockerList) {
245 QDockWidget *docker = mainWindow->findChild<QDockWidget*>(objName);
246 if (docker != nullptr) {
247 m_d->dockerComboBox->addItem(docker->windowTitle(), docker->objectName());
248 }
249 }
250}
251
253{
254 KisConfig(false).writeEntry(m_d->configId+"/currentDocker", m_d->dockerComboBox->currentData(Qt::UserRole));
255}
257{
258 return KisConfig(true).readEntry(m_d->configId+"/currentDocker", QString("BrushHudDocker"));
259}
260
261
263{
264 m_d->dockerMenu->setIcon(KisIconUtils::loadIcon("applications-system"));
265}
266
267void KisDockerHud::showEvent(QShowEvent *event)
268{
269 // In case we were loaded before the dockers were (as in the toolbar),
270 // try connecting to them here.
271 if (!m_d->isConnected) {
273 }
274
276
277 QWidget::showEvent(event);
278}
279
280void KisDockerHud::hideEvent(QHideEvent *event)
281{
283
284 QWidget::hideEvent(event);
285}
286
287void KisDockerHud::setIsShown(bool isShown)
288{
289 m_d->isShown = isShown;
290}
291
293{
294 if (KisPart::instance()->currentMainwindow() == nullptr) {
295 return;
296 }
297
299 m_d->dockerComboBox->setCurrentIndex(m_d->dockerComboBox->findData(readCurrentDocker()));
300 connect(m_d->dockerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(borrowOrReturnDocker()));
301 connect(m_d->dockerComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(writeCurrentDocker()));
302
303 m_d->isConnected = true;
304}
305
306void KisDockerHud::showBorrowerLabel(QString borrowerName)
307{
308 m_d->dockerIOULabel->setText(i18nc("%1 is the name of the widget",
309 "Docker is open in %1. Close %1 to show here.", borrowerName));
310 m_d->dockerLayout->addWidget(m_d->dockerIOULabel);
311 m_d->dockerLayout->setStretchFactor(m_d->dockerIOULabel, 1); // push the other widgets to the top
312 m_d->dockerIOULabel->show();
313}
314
316{
317 m_d->dockerIOULabel->hide();
318 m_d->dockerLayout->takeAt(0)->widget();
319 m_d->dockerIOULabel->setText(i18nc("%1 is the name of the widget",
320 "Docker is open in %1. Close %1 to show here.", m_d->borrowerName));
321}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void writeList(const QString &name, const QList< T > &value)
Definition kis_config.h:784
QList< T > readList(const QString &name, const QList< T > &defaultValue=QList< T >())
Definition kis_config.h:794
void writeEntry(const QString &name, const T &value)
Definition kis_config.h:779
T readEntry(const QString &name, const T &defaultValue=T())
Definition kis_config.h:789
QList< QVariant > getChosenData()
void hideEvent(QHideEvent *event) override
void showBorrowerLabel(QString borrowerName)
void returnDocker(bool beingTaken=false)
void showDockerConfig()
void writeDockerList(QList< QVariant >)
~KisDockerHud() override
const QScopedPointer< Private > m_d
void tryConnectToDockers()
void borrowDocker()
void borrowOrReturnDocker()
KisDockerHud(QString borrowerName, QString configId)
QString readCurrentDocker()
void setIsShown(bool isShown)
void showEvent(QShowEvent *event) override
static QHash< QString, QList< QString > > borrowedWidgetOwners
void slotUpdateIcons()
void hideBorrowerLabel()
void writeCurrentDocker()
void readDockerList()
Main window for Krita.
QList< QDockWidget * > dockWidgets() const
Return the list of dock widgets belonging to this main window.
static KisPart * instance()
Definition KisPart.cpp:131
KisMainWindow * currentMainwindow() const
Definition KisPart.cpp:483
A special utility titlebar with a title and controls, as well as a central area for adding frequently...
void setWidgetArea(QWidget *widgetArea)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
QIcon loadIcon(const QString &name)
QVBoxLayout * dockerLayout
QToolButton * dockerMenu
QDockWidget * oldDockerParent