Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "dialogview.h"
24 :
25 : #include <QQuickView>
26 : #include <QScreen>
27 :
28 : #ifdef Q_OS_MAC
29 : #include "internal/platform/macos/macoswindowlevelcontroller.h"
30 : #endif
31 :
32 : #include "log.h"
33 :
34 : using namespace Qt::Literals::StringLiterals;
35 :
36 : using namespace muse::uicomponents;
37 :
38 0 : DialogView::DialogView(QQuickItem* parent)
39 0 : : WindowView(parent)
40 : {
41 0 : setObjectName("DialogView");
42 0 : setRetCode(Ret::Code::Ok);
43 0 : }
44 :
45 0 : void DialogView::initView()
46 : {
47 0 : QQuickWindow::setDefaultAlphaBuffer(m_frameless);
48 :
49 0 : WindowView::initView();
50 :
51 0 : m_view->setFlags(Qt::Dialog);
52 0 : m_view->setIcon(QIcon(uiConfiguration()->appIconPath().toString()));
53 :
54 0 : if (m_frameless) {
55 0 : m_view->setColor(QColor(Qt::transparent));
56 : } else {
57 0 : auto updateBackgroundColor = [this]() {
58 0 : if (!m_view) {
59 0 : return;
60 : }
61 :
62 0 : QString bgColorStr = uiConfiguration()->currentTheme().values.value(ui::BACKGROUND_PRIMARY_COLOR).toString();
63 0 : m_view->setColor(QColor(bgColorStr));
64 0 : };
65 :
66 0 : uiConfiguration()->currentThemeChanged().onNotify(this, updateBackgroundColor);
67 :
68 0 : updateBackgroundColor();
69 : }
70 0 : }
71 :
72 0 : void DialogView::beforeOpen()
73 : {
74 0 : IF_ASSERT_FAILED(m_view) {
75 0 : return;
76 : }
77 :
78 : //! NOTE Set default title
79 0 : if (m_title.isEmpty()) {
80 0 : setTitle(application()->title());
81 : }
82 :
83 0 : m_view->setTitle(m_title);
84 0 : m_view->setFlag(Qt::FramelessWindowHint, m_frameless);
85 :
86 : #ifdef MUSE_MODULE_UI_DISABLE_MODALITY
87 : m_view->setModality(Qt::NonModal);
88 : #else
89 0 : m_view->setModality(m_modal ? Qt::ApplicationModal : Qt::NonModal);
90 : #endif
91 :
92 : //! NOTE ok will be if they call accept
93 0 : setRetCode(Ret::Code::Cancel);
94 :
95 0 : windowsController()->regWindow(m_view->winId());
96 : }
97 :
98 0 : void DialogView::onHidden()
99 : {
100 0 : WindowView::onHidden();
101 :
102 0 : windowsController()->unregWindow(m_view->winId());
103 0 : }
104 :
105 0 : void DialogView::afterShow()
106 : {
107 : #ifdef Q_OS_MAC
108 : if (m_alwaysAboveApp) {
109 : MacOSWindowLevelController::setAlwaysAboveApp(m_view);
110 : }
111 : #endif
112 0 : }
113 :
114 0 : void DialogView::updateGeometry()
115 : {
116 0 : QRect anchorRect = currentScreenGeometry();
117 :
118 0 : const QWindow* qMainWindow = mainWindow()->qWindow();
119 0 : bool mainWindowVisible = qMainWindow->isVisible();
120 0 : QRect referenceRect = qMainWindow->geometry();
121 :
122 0 : if (referenceRect.isEmpty() || !mainWindowVisible) {
123 0 : referenceRect = anchorRect;
124 : }
125 :
126 0 : QMargins frameMargins = m_view->frameMargins(); // actual window frame margins (title bar height etc.)
127 0 : QRect dlgRect = viewGeometry(); // content geometry
128 0 : dlgRect = dlgRect.marginsAdded(frameMargins);
129 :
130 : // position the dialog in the center of the main window
131 0 : dlgRect.moveLeft(referenceRect.x() + (referenceRect.width() - dlgRect.width()) / 2);
132 0 : dlgRect.moveTop(referenceRect.y() + (referenceRect.height() - dlgRect.height()) / 2);
133 :
134 : // try to move the dialog if it doesn't fit on the screen
135 :
136 0 : if (dlgRect.left() <= anchorRect.left()) {
137 0 : dlgRect.moveLeft(anchorRect.left());
138 : }
139 :
140 0 : if (dlgRect.top() <= anchorRect.top()) {
141 0 : dlgRect.moveTop(anchorRect.top());
142 : }
143 :
144 0 : if (dlgRect.right() >= anchorRect.right()) {
145 0 : dlgRect.moveRight(anchorRect.right());
146 : }
147 :
148 0 : if (dlgRect.bottom() >= anchorRect.bottom()) {
149 0 : dlgRect.moveBottom(anchorRect.bottom());
150 : }
151 :
152 : // if after moving the dialog does not fit on the screen, then adjust the size of the dialog
153 0 : if (!anchorRect.contains(dlgRect)) {
154 0 : dlgRect = anchorRect.intersected(dlgRect);
155 : }
156 :
157 0 : dlgRect = dlgRect.marginsRemoved(frameMargins);
158 :
159 0 : m_globalPos = dlgRect.topLeft();
160 :
161 0 : setContentWidth(dlgRect.width());
162 0 : setContentHeight(dlgRect.height());
163 0 : }
164 :
165 0 : QRect DialogView::viewGeometry() const
166 : {
167 0 : return QRect(m_globalPos.toPoint(), QSize(contentWidth(), contentHeight()));
168 : }
169 :
170 0 : QString DialogView::title() const
171 : {
172 0 : return m_title;
173 : }
174 :
175 0 : void DialogView::setTitle(QString title)
176 : {
177 0 : if (m_title == title) {
178 0 : return;
179 : }
180 :
181 0 : m_title = title;
182 0 : emit titleChanged(m_title);
183 :
184 0 : if (isOpened()) {
185 0 : m_view->setTitle(title);
186 : }
187 : }
188 :
189 0 : QString DialogView::objectId() const
190 : {
191 0 : return m_objectId;
192 : }
193 :
194 0 : void DialogView::setObjectId(QString objectId)
195 : {
196 0 : if (m_objectId == objectId) {
197 0 : return;
198 : }
199 :
200 0 : m_objectId = objectId;
201 0 : emit objectIdChanged(m_objectId);
202 : }
203 :
204 0 : bool DialogView::modal() const
205 : {
206 0 : return m_modal;
207 : }
208 :
209 0 : void DialogView::setModal(bool modal)
210 : {
211 0 : if (m_modal == modal) {
212 0 : return;
213 : }
214 :
215 0 : m_modal = modal;
216 0 : emit modalChanged(m_modal);
217 : }
218 :
219 0 : bool DialogView::frameless() const
220 : {
221 0 : return m_frameless;
222 : }
223 :
224 0 : void DialogView::setFrameless(bool frameless)
225 : {
226 0 : if (m_frameless == frameless) {
227 0 : return;
228 : }
229 :
230 0 : m_frameless = frameless;
231 0 : emit framelessChanged(m_frameless);
232 : }
233 :
234 0 : bool DialogView::resizable() const
235 : {
236 0 : return m_resizable;
237 : }
238 :
239 0 : void DialogView::setResizable(bool resizable)
240 : {
241 0 : if (m_resizable == resizable) {
242 0 : return;
243 : }
244 :
245 0 : m_resizable = resizable;
246 0 : emit resizableChanged(m_resizable);
247 :
248 0 : if (isOpened()) {
249 0 : updateSize(m_view->size());
250 : }
251 : }
252 :
253 0 : bool DialogView::alwaysAboveApp() const
254 : {
255 0 : return m_alwaysAboveApp;
256 : }
257 :
258 0 : void DialogView::setAlwaysAboveApp(bool alwaysAbove)
259 : {
260 0 : if (m_alwaysAboveApp == alwaysAbove) {
261 0 : return;
262 : }
263 :
264 0 : m_alwaysAboveApp = alwaysAbove;
265 0 : emit alwaysAboveAppChanged();
266 : }
267 :
268 0 : QVariantMap DialogView::ret() const
269 : {
270 0 : return m_ret;
271 : }
272 :
273 0 : void DialogView::setRet(QVariantMap ret)
274 : {
275 0 : if (m_ret == ret) {
276 0 : return;
277 : }
278 :
279 0 : m_ret = ret;
280 0 : emit retChanged(m_ret);
281 : }
282 :
283 0 : void DialogView::setRetCode(Ret::Code code)
284 : {
285 0 : QVariantMap ret;
286 0 : ret[u"errcode"_s] = static_cast<int>(code);
287 0 : setRet(ret);
288 0 : }
289 :
290 0 : void DialogView::show()
291 : {
292 0 : open();
293 0 : }
294 :
295 0 : void DialogView::hide()
296 : {
297 0 : close();
298 0 : }
299 :
300 0 : void DialogView::raise()
301 : {
302 0 : if (isOpened()) {
303 0 : m_view->raise();
304 : }
305 0 : }
306 :
307 0 : void DialogView::accept()
308 : {
309 0 : setRetCode(Ret::Code::Ok);
310 0 : close();
311 0 : }
312 :
313 0 : void DialogView::reject(int code)
314 : {
315 0 : if (code > 0) {
316 0 : setRetCode(static_cast<Ret::Code>(code));
317 : } else {
318 0 : setRetCode(Ret::Code::Cancel);
319 : }
320 :
321 0 : close();
322 0 : }
|