1 /***************************************************************************
2 * Copyright (C) 2006-2021 by Ilya Kotov *
3 * forkotov02@ya.ru *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20
21 #include <QAction>
22 #include <QScreen>
23 #include <QWindow>
24 #include <QtDebug>
25 #include <QApplication>
26 #if (QT_VERSION < QT_VERSION_CHECK(5, 7, 0)) //qAsConst template
27 #include <qmmp/qmmp.h>
28 #endif
29 #include "dock.h"
30
31 Dock *Dock::m_instance = nullptr;
32
instance()33 Dock *Dock::instance()
34 {
35 if (!m_instance)
36 m_instance = new Dock();
37 return m_instance;
38 }
39
Dock(QObject * parent)40 Dock::Dock (QObject *parent)
41 : QObject (parent)
42 {
43 m_instance = this;
44 m_mainWidget = nullptr;
45 }
46
~Dock()47 Dock::~Dock()
48 {
49 m_instance = nullptr;
50 }
51
setMainWidget(QWidget * widget)52 void Dock::setMainWidget (QWidget *widget)
53 {
54 m_mainWidget = widget;
55 m_widgetList.prepend (widget);
56 m_dockedList.prepend (false);
57 }
58
snapDesktop(QPoint npos,QWidget * mv)59 QPoint Dock::snapDesktop(QPoint npos, QWidget* mv)
60 {
61 if(!mv->isVisible())
62 return npos;
63
64 QRect desktopRect = mv->window()->windowHandle()->screen()->availableGeometry();
65 int nx = abs (npos.x() - desktopRect.x()); //left-top
66 int ny = abs (npos.y() - desktopRect.y());
67
68 if(nx < 13)
69 npos.rx() = desktopRect.x();
70 if(ny < 13)
71 npos.ry() = desktopRect.y();
72
73 nx = abs (npos.x() + mv->width() - desktopRect.width() - desktopRect.x()); //right-bottom
74 ny = abs (npos.y() + mv->height() - desktopRect.height() - desktopRect.y());
75
76 if(nx < 13)
77 npos.rx() = desktopRect.width() - mv->width() + desktopRect.x();
78 if(ny < 13)
79 npos.ry() = desktopRect.height() - mv->height() + desktopRect.y();
80
81 return npos;
82 }
83
snap(QPoint npos,QWidget * mv,QWidget * st)84 QPoint Dock::snap (QPoint npos, QWidget* mv, QWidget* st)
85 {
86 int nx = npos.x() - st->x();
87 int ny = abs (npos.y() - st->y() + mv->height());
88
89 if (abs (nx) < 13 && ny < 13) //above
90 npos.rx() = st->x();
91 if (ny < 13 && nx > -mv->width() && nx < st->width())
92 npos.ry() = st->y() - mv->height();
93 nx = abs (npos.x() + mv->width() - st->x() - st->width());
94 if (nx < 13 && ny < 13)
95 npos.rx() = st->x() + st->width() - mv->width();
96
97 /***********/
98 nx = npos.x() - st->x();
99 ny = abs (npos.y() - st->y() - st->height());
100
101 if (abs (nx) < 13 && ny < 13) //near
102 npos.rx() = st->x();
103 if (ny < 13 && nx > -mv->width() && nx < st->width())
104 npos.ry() = st->y() + st->height();
105 nx = abs (npos.x() + mv->width() - st->x() - st->width());
106 if (nx < 13 && ny < 13)
107 npos.rx() = st->x() + st->width() - mv->width();
108 /**************/
109 nx = abs (npos.x() - st->x() + mv->width());
110 ny = npos.y() - st->y();
111
112 if (nx < 13 && abs (ny) < 13) //left
113 npos.ry() = st->y();
114 if (nx < 13 && ny > -mv->height() && ny < st->height())
115 npos.rx() = st->x() - mv->width();
116
117 ny = abs (npos.y() + mv->height() - st->y() - st->height());
118 if (nx < 13 && ny < 13)
119 npos.ry() = st->y() + st->height() - mv->height();
120 /*****************/
121 nx = abs (npos.x() - st->x() - st->width());
122 ny = npos.y() - st->y();
123
124 if (nx < 13 && abs (ny) < 13) //right
125 npos.ry() = st->y();
126 if (nx < 13 && ny > -mv->height() && ny < st->height())
127 npos.rx() = st->x() + st->width();
128
129 ny = abs (npos.y() + mv->height() - st->y() - st->height());
130 if (nx < 13 && ny < 13)
131 npos.ry() = st->y() + st->height() - mv->height();
132
133 return (npos);
134 }
135
addWidget(QWidget * widget)136 void Dock::addWidget (QWidget *widget)
137 {
138 m_widgetList.append (widget);
139 m_dockedList.append (false);
140 if(m_mainWidget)
141 widget->addActions(m_mainWidget->actions());
142 }
143
move(QWidget * mv,QPoint npos)144 void Dock::move (QWidget* mv, QPoint npos)
145 {
146 //QRect desktopRect = QApplication::desktop()->availableGeometry(m_mainWidget);
147
148 /*if(npos.y() < desktopRect.y())
149 npos.setY(desktopRect.y());*/
150
151 if (mv == m_mainWidget)
152 {
153
154 for (int i = 1; i<m_widgetList.size(); ++i)
155 {
156 if (!m_dockedList.at (i))
157 {
158 if (m_widgetList.at (i)->isVisible())
159 npos = snap (npos, mv, m_widgetList.at (i));
160 }
161 else
162 {
163 QPoint pos = npos + m_delta_list.at(i);
164 for (int j = 1; j<m_widgetList.size(); ++j)
165 {
166 if (!m_dockedList.at (j) && m_widgetList.at (j)->isVisible())
167 {
168 pos = snap (pos, m_widgetList.at (i), m_widgetList.at (j));
169 npos = pos - m_delta_list.at(i);
170 }
171 }
172 }
173 }
174 npos = snapDesktop(npos, mv);
175 for (int i = 1; i<m_widgetList.size(); ++i)
176 {
177 if (m_dockedList.at (i))
178 {
179 QPoint pos = npos + m_delta_list.at(i);
180 pos = snapDesktop(pos, m_widgetList.at(i));
181 m_widgetList.at (i)->move(pos);
182 npos = pos - m_delta_list.at(i);
183 }
184 }
185 mv->move (npos);
186 }
187 else
188 {
189 for (int i = 0; i<m_widgetList.size(); ++i)
190 {
191 m_dockedList[i] = false;
192 if (mv != m_widgetList.at (i) && !m_dockedList.at (i) && m_widgetList.at (i)->isVisible())
193 {
194 npos = snap (npos, mv, m_widgetList.at (i));
195 npos = snapDesktop(npos, mv);
196 }
197 }
198 mv->move (npos);
199 }
200 }
201
calculateDistances()202 void Dock::calculateDistances()
203 {
204 m_delta_list.clear();
205 for(const QWidget *w : qAsConst(m_widgetList))
206 {
207 if (w == m_mainWidget)
208 m_delta_list.append(QPoint(0,0));
209 else
210 m_delta_list.append(w->pos() - m_mainWidget->pos());
211 }
212 }
213
updateDock()214 void Dock::updateDock()
215 {
216 QWidget *mv = m_widgetList.at (0);
217 for (int j = 1; j<m_widgetList.size(); ++j)
218 {
219 QWidget *st = m_widgetList.at (j);
220 m_dockedList[j] = isDocked (mv, st);
221 }
222 for (int j = 1; j<m_widgetList.size(); ++j)
223 {
224 if (m_dockedList[j])
225 for (int i = 1; i<m_widgetList.size(); ++i)
226 {
227 if (!m_dockedList[i])
228 {
229 mv = m_widgetList.at (j);
230 QWidget *st = m_widgetList.at (i);
231 m_dockedList[i] = isDocked (mv, st);
232 }
233 }
234 }
235 }
236
isDocked(QWidget * mv,QWidget * st)237 bool Dock::isDocked (QWidget* mv, QWidget* st)
238 {
239 int nx = mv->x() - st->x();
240 int ny = abs (mv->y() - st->y() + mv->height());
241 if (ny < 2 && nx > -mv->width() && nx < st->width()) //above
242 return true;
243
244 /***********/
245 nx = mv->x() - st->x();
246 ny = abs (mv->y() - st->y() - st->height());
247 if (ny < 2 && nx > -mv->width() && nx < st->width()) //near
248 return true;
249
250 /**************/
251 nx = abs (mv->x() - st->x() + mv->width());
252 ny = mv->y() - st->y();
253 if (nx < 2 && ny > -mv->height() && ny < st->height()) //left
254 return true;
255
256 /*****************/
257 nx = abs (mv->x() - st->x() - st->width());
258 ny = mv->y() - st->y();
259 if (nx < 2 && ny > -mv->height() && ny < st->height()) //right
260 return true;
261 return false;
262 }
263
addActions(QList<QAction * > actions)264 void Dock::addActions (QList<QAction *> actions)
265 {
266 if(!m_mainWidget)
267 {
268 qFatal("Dock: main widget is null");
269 }
270 for (int i = 0; i<m_widgetList.size(); ++i)
271 m_widgetList.at (i)->addActions (actions);
272 }
273
isUnder(QWidget * upper,QWidget * nether,int dy)274 bool Dock::isUnder(QWidget* upper, QWidget* nether, int dy)
275 {
276 int nx = upper->x() - nether->x();
277 return abs (upper->y() + upper->height() -dy - nether->y()) < 2 &&
278 nx > -upper->width() && nx < nether->width();
279 }
280
align(QWidget * w,int dy)281 void Dock::align(QWidget* w, int dy)
282 {
283 for (int i = 0; i<m_dockedList.size(); ++i)
284 {
285 if (m_widgetList.at(i) != w && isUnder(w, m_widgetList.at(i), dy))
286 {
287 m_widgetList.at(i)->move(m_widgetList.at(i)->x(), m_widgetList.at(i)->y()+dy);
288 align(m_widgetList.at(i), dy);
289 }
290 }
291 }
292