1
2
3 #include "pane.h"
4
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "mainwindow.h"
8 #include "tenv.h"
9 #include "saveloadqsettings.h"
10
11 #include "toonzqt/gutil.h"
12
13 // TnzLib includes
14 #include "toonz/preferences.h"
15 #include "toonz/toonzfolders.h"
16 #include "toonz/tscenehandle.h"
17
18 // TnzCore includes
19 #include "tsystem.h"
20
21 // Qt includes
22 #include <QPainter>
23 #include <QStyleOptionDockWidget>
24 #include <QMouseEvent>
25 #include <QMainWindow>
26 #include <QSettings>
27 #include <QToolBar>
28 #include <QMap>
29 #include <QApplication>
30 #include <QFile>
31 #include <qdrawutil.h>
32 #include <assert.h>
33 #include <QDesktopWidget>
34 #include <QDialog>
35 #include <QLineEdit>
36
37 extern TEnv::StringVar EnvSafeAreaName;
38
39 //=============================================================================
40 // TPanel
41 //-----------------------------------------------------------------------------
42
TPanel(QWidget * parent,Qt::WindowFlags flags,TDockWidget::Orientation orientation)43 TPanel::TPanel(QWidget *parent, Qt::WindowFlags flags,
44 TDockWidget::Orientation orientation)
45 : TDockWidget(parent, flags)
46 , m_panelType("")
47 , m_isMaximizable(true)
48 , m_isMaximized(false)
49 , m_panelTitleBar(0)
50 , m_multipleInstancesAllowed(true) {
51 // setFeatures(QDockWidget::DockWidgetMovable |
52 // QDockWidget::DockWidgetFloatable);
53 // setFloating(false);
54 m_panelTitleBar = new TPanelTitleBar(this, orientation);
55 setTitleBarWidget(m_panelTitleBar);
56 // connect(m_panelTitleBar,SIGNAL(doubleClick()),this,SLOT(onDoubleClick()));
57 connect(m_panelTitleBar, SIGNAL(doubleClick(QMouseEvent *)), this,
58 SIGNAL(doubleClick(QMouseEvent *)));
59 connect(m_panelTitleBar, SIGNAL(closeButtonPressed()), this,
60 SLOT(onCloseButtonPressed()));
61 setOrientation(orientation);
62 }
63
64 //-----------------------------------------------------------------------------
65
~TPanel()66 TPanel::~TPanel() {
67 // On quitting, save the floating panel's geomtry and state in order to
68 // restore them when opening the floating panel next time
69 if (isFloating()) {
70 TFilePath savePath =
71 ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
72 QSettings settings(QString::fromStdWString(savePath.getWideString()),
73 QSettings::IniFormat);
74 settings.beginGroup("Panels");
75 settings.beginGroup(QString::fromStdString(m_panelType));
76 settings.setValue("geometry", geometry());
77 if (SaveLoadQSettings *persistent =
78 dynamic_cast<SaveLoadQSettings *>(widget()))
79 persistent->save(settings);
80 }
81 }
82
83 //-----------------------------------------------------------------------------
84
paintEvent(QPaintEvent * e)85 void TPanel::paintEvent(QPaintEvent *e) {
86 QPainter painter(this);
87
88 if (widget()) {
89 QRect dockRect = widget()->geometry();
90
91 dockRect.adjust(0, 0, -1, -1);
92 painter.fillRect(dockRect, m_bgcolor);
93 painter.setPen(Qt::black);
94 painter.drawRect(dockRect);
95 }
96
97 painter.end();
98 }
99
100 //-----------------------------------------------------------------------------
101
onCloseButtonPressed()102 void TPanel::onCloseButtonPressed() {
103 emit closeButtonPressed();
104
105 // Currently, Toonz panels that get closed indeed just remain hidden -
106 // ready to reappair if they are needed again. However, the user expects
107 // a new panel to be created - so we just reset the panel here.
108 // reset(); //Moved to panel invocation in floatingpanelcommand.cpp
109
110 // Also, remove widget from its dock layout control
111 if (parentLayout()) parentLayout()->removeWidget(this);
112 }
113
114 //-----------------------------------------------------------------------------
115 /*! activate the panel and set focus specified widget when mouse enters
116 */
enterEvent(QEvent * event)117 void TPanel::enterEvent(QEvent *event) {
118 // Only when Toonz application is active
119 QWidget *w = qApp->activeWindow();
120 if (w) {
121 // grab the focus, unless a line-edit is focused currently
122 QWidget *focusWidget = qApp->focusWidget();
123 if (focusWidget && dynamic_cast<QLineEdit *>(focusWidget)) {
124 event->accept();
125 return;
126 }
127
128 widgetFocusOnEnter();
129
130 // Some panels (e.g. Viewer, StudioPalette, Palette, ColorModel) are
131 // activated when mouse enters. Viewer is activatable only when being
132 // docked.
133 // Active windows will NOT switch when the current active window is dialog.
134 if (qobject_cast<QDialog *>(w) == 0 && isActivatableOnEnter())
135 activateWindow();
136 event->accept();
137 } else
138 event->accept();
139 }
140
141 //-----------------------------------------------------------------------------
142 /*! clear focus when mouse leaves
143 */
leaveEvent(QEvent * event)144 void TPanel::leaveEvent(QEvent *event) {
145 QWidget *focusWidget = qApp->focusWidget();
146 if (focusWidget && dynamic_cast<QLineEdit *>(focusWidget)) {
147 return;
148 }
149 widgetClearFocusOnLeave();
150 }
151
152 //-----------------------------------------------------------------------------
153 /*! load and restore previous geometry and state of the floating panel.
154 called from the function OpenFloatingPanel::getOrOpenFloatingPanel()
155 in floatingpanelcommand.cpp
156 */
restoreFloatingPanelState()157 void TPanel::restoreFloatingPanelState() {
158 TFilePath savePath = ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
159 QSettings settings(QString::fromStdWString(savePath.getWideString()),
160 QSettings::IniFormat);
161 settings.beginGroup("Panels");
162
163 if (!settings.childGroups().contains(QString::fromStdString(m_panelType)))
164 return;
165
166 settings.beginGroup(QString::fromStdString(m_panelType));
167
168 QRect geom = settings.value("geometry", saveGeometry()).toRect();
169 // check if it can be visible in the current screen
170 if (!(geom & QApplication::desktop()->availableGeometry(this)).isEmpty())
171 setGeometry(geom);
172 // load optional settings
173 if (SaveLoadQSettings *persistent =
174 dynamic_cast<SaveLoadQSettings *>(widget()))
175 persistent->load(settings);
176 }
177
178 //=============================================================================
179 // TPanelTitleBarButton
180 //-----------------------------------------------------------------------------
181
TPanelTitleBarButton(QWidget * parent,const QString & standardPixmapName)182 TPanelTitleBarButton::TPanelTitleBarButton(QWidget *parent,
183 const QString &standardPixmapName)
184 : QWidget(parent)
185 , m_standardPixmap(standardPixmapName)
186 , m_standardPixmapName(standardPixmapName)
187 , m_rollover(false)
188 , m_pressed(false)
189 , m_buttonSet(0)
190 , m_id(0) {
191 setFixedSize(m_standardPixmap.size());
192 }
193
194 //-----------------------------------------------------------------------------
195
TPanelTitleBarButton(QWidget * parent,const QPixmap & standardPixmap)196 TPanelTitleBarButton::TPanelTitleBarButton(QWidget *parent,
197 const QPixmap &standardPixmap)
198 : QWidget(parent)
199 , m_standardPixmap(standardPixmap)
200 , m_rollover(false)
201 , m_pressed(false)
202 , m_buttonSet(0)
203 , m_id(0) {
204 setFixedSize(m_standardPixmap.size() / m_standardPixmap.devicePixelRatio());
205 }
206
207 //-----------------------------------------------------------------------------
208
setButtonSet(TPanelTitleBarButtonSet * buttonSet,int id)209 void TPanelTitleBarButton::setButtonSet(TPanelTitleBarButtonSet *buttonSet,
210 int id) {
211 m_buttonSet = buttonSet;
212 m_id = id;
213 m_buttonSet->add(this);
214 }
215
216 //-----------------------------------------------------------------------------
217
setPressed(bool pressed)218 void TPanelTitleBarButton::setPressed(bool pressed) {
219 if (pressed != m_pressed) {
220 m_pressed = pressed;
221 update();
222 }
223 }
224
225 //-----------------------------------------------------------------------------
226
paintEvent(QPaintEvent * event)227 void TPanelTitleBarButton::paintEvent(QPaintEvent *event) {
228 // Set unique pressed colors if filename contains the following words:
229 QColor bgColor = getPressedColor();
230 if (m_standardPixmapName.contains("freeze", Qt::CaseInsensitive))
231 bgColor = getFreezeColor();
232 if (m_standardPixmapName.contains("preview", Qt::CaseInsensitive))
233 bgColor = getPreviewColor();
234
235 QPixmap panePixmap = recolorPixmap(svgToPixmap(m_standardPixmapName));
236 QPixmap panePixmapOff = compositePixmap(panePixmap, 0.8);
237 QPixmap panePixmapOver =
238 compositePixmap(panePixmap, 1, QSize(), 0, 0, getOverColor());
239 QPixmap panePixmapOn = compositePixmap(panePixmap, 1, QSize(), 0, 0, bgColor);
240
241 QPainter painter(this);
242 painter.drawPixmap(
243 0, 0,
244 m_pressed ? panePixmapOn : m_rollover ? panePixmapOver : panePixmapOff);
245 painter.end();
246 }
247
248 //-----------------------------------------------------------------------------
249
mouseMoveEvent(QMouseEvent * event)250 void TPanelTitleBarButton::mouseMoveEvent(QMouseEvent *event) {}
251
252 //-----------------------------------------------------------------------------
253
enterEvent(QEvent *)254 void TPanelTitleBarButton::enterEvent(QEvent *) {
255 if (!m_rollover) {
256 m_rollover = true;
257 if (!m_pressed) update();
258 }
259 }
260
261 //-----------------------------------------------------------------------------
262
leaveEvent(QEvent *)263 void TPanelTitleBarButton::leaveEvent(QEvent *) {
264 if (m_rollover) {
265 m_rollover = false;
266 if (!m_pressed) update();
267 }
268 }
269
270 //-----------------------------------------------------------------------------
271
mousePressEvent(QMouseEvent * e)272 void TPanelTitleBarButton::mousePressEvent(QMouseEvent *e) {
273 if (m_buttonSet) {
274 if (m_pressed) return;
275 m_buttonSet->select(this);
276 } else {
277 m_pressed = !m_pressed;
278 emit toggled(m_pressed);
279 update();
280 }
281 }
282
283 //=============================================================================
284 // TPanelTitleBarButtonForSafeArea
285 //-----------------------------------------------------------------------------
286
getSafeAreaNameList(QList<QString> & nameList)287 void TPanelTitleBarButtonForSafeArea::getSafeAreaNameList(
288 QList<QString> &nameList) {
289 TFilePath fp = TEnv::getConfigDir();
290 QString currentSafeAreaName = QString::fromStdString(EnvSafeAreaName);
291
292 std::string safeAreaFileName = "safearea.ini";
293
294 while (!TFileStatus(fp + safeAreaFileName).doesExist() && !fp.isRoot() &&
295 fp.getParentDir() != TFilePath())
296 fp = fp.getParentDir();
297
298 fp = fp + safeAreaFileName;
299
300 if (TFileStatus(fp).doesExist()) {
301 QSettings settings(toQString(fp), QSettings::IniFormat);
302
303 // find the current safearea name from the list
304 QStringList groups = settings.childGroups();
305 for (int g = 0; g < groups.size(); g++) {
306 settings.beginGroup(groups.at(g));
307 nameList.push_back(settings.value("name", "").toString());
308 settings.endGroup();
309 }
310 }
311 }
312
313 //-----------------------------------------------------------------------------
314
mousePressEvent(QMouseEvent * e)315 void TPanelTitleBarButtonForSafeArea::mousePressEvent(QMouseEvent *e) {
316 if (e->button() != Qt::RightButton) {
317 m_pressed = !m_pressed;
318 emit toggled(m_pressed);
319 update();
320 }
321 }
322
323 //-----------------------------------------------------------------------------
324
contextMenuEvent(QContextMenuEvent * e)325 void TPanelTitleBarButtonForSafeArea::contextMenuEvent(QContextMenuEvent *e) {
326 QMenu menu(this);
327
328 QList<QString> safeAreaNameList;
329 getSafeAreaNameList(safeAreaNameList);
330 for (int i = 0; i < safeAreaNameList.size(); i++) {
331 QAction *action = new QAction(safeAreaNameList.at(i), this);
332 action->setData(safeAreaNameList.at(i));
333 connect(action, SIGNAL(triggered()), this, SLOT(onSetSafeArea()));
334 if (safeAreaNameList.at(i) == QString::fromStdString(EnvSafeAreaName)) {
335 action->setCheckable(true);
336 action->setChecked(true);
337 }
338 menu.addAction(action);
339 }
340
341 menu.exec(e->globalPos());
342 }
343
344 //-----------------------------------------------------------------------------
345
onSetSafeArea()346 void TPanelTitleBarButtonForSafeArea::onSetSafeArea() {
347 QString safeAreaName = qobject_cast<QAction *>(sender())->data().toString();
348 // change safearea if the different one is selected
349 if (QString::fromStdString(EnvSafeAreaName) != safeAreaName) {
350 EnvSafeAreaName = safeAreaName.toStdString();
351 // emit sceneChanged without setting dirty flag
352 TApp::instance()->getCurrentScene()->notifySceneChanged(false);
353 }
354 }
355
356 //-----------------------------------------------------------------------------
357
358 //=============================================================================
359 // TPanelTitleBarButtonSet
360 //-----------------------------------------------------------------------------
361
TPanelTitleBarButtonSet()362 TPanelTitleBarButtonSet::TPanelTitleBarButtonSet() {}
363
~TPanelTitleBarButtonSet()364 TPanelTitleBarButtonSet::~TPanelTitleBarButtonSet() {}
365
add(TPanelTitleBarButton * button)366 void TPanelTitleBarButtonSet::add(TPanelTitleBarButton *button) {
367 m_buttons.push_back(button);
368 }
369
select(TPanelTitleBarButton * button)370 void TPanelTitleBarButtonSet::select(TPanelTitleBarButton *button) {
371 int i;
372 for (i = 0; i < (int)m_buttons.size(); i++)
373 m_buttons[i]->setPressed(button == m_buttons[i]);
374 emit selected(button->getId());
375 }
376
377 //=============================================================================
378 // PaneTitleBar
379 //-----------------------------------------------------------------------------
380
TPanelTitleBar(QWidget * parent,TDockWidget::Orientation orientation)381 TPanelTitleBar::TPanelTitleBar(QWidget *parent,
382 TDockWidget::Orientation orientation)
383 : QFrame(parent), m_closeButtonHighlighted(false) {
384 setMouseTracking(true);
385 setFocusPolicy(Qt::NoFocus);
386 }
387
388 //-----------------------------------------------------------------------------
389
minimumSizeHint() const390 QSize TPanelTitleBar::minimumSizeHint() const { return QSize(20, 18); }
391
392 //-----------------------------------------------------------------------------
393
paintEvent(QPaintEvent *)394 void TPanelTitleBar::paintEvent(QPaintEvent *) {
395 QPainter painter(this);
396 QRect rect = this->rect();
397
398 bool isPanelActive;
399
400 TPanel *dw = qobject_cast<TPanel *>(parentWidget());
401 Q_ASSERT(dw != 0);
402 // docked panel
403 if (!dw->isFloating()) {
404 isPanelActive = dw->widgetInThisPanelIsFocused();
405 qDrawBorderPixmap(&painter, rect, QMargins(3, 3, 3, 3),
406 (isPanelActive) ? m_activeBorderPm : m_borderPm);
407 }
408 // floating panel
409 else {
410 isPanelActive = isActiveWindow();
411 qDrawBorderPixmap(
412 &painter, rect, QMargins(3, 3, 3, 3),
413 (isPanelActive) ? m_floatActiveBorderPm : m_floatBorderPm);
414 }
415
416 if (dw->getOrientation() == TDockWidget::vertical) {
417 QString titleText = painter.fontMetrics().elidedText(
418 dw->windowTitle(), Qt::ElideRight, rect.width() - 50);
419
420 painter.setBrush(Qt::NoBrush);
421 painter.setPen(isPanelActive ? m_activeTitleColor : m_titleColor);
422 painter.drawText(QPointF(8, 13), titleText);
423 }
424
425 if (dw->isFloating()) {
426 QIcon paneCloseIcon = createQIcon("pane_close");
427 const static QPixmap closeButtonPixmap(
428 paneCloseIcon.pixmap(20, 18, QIcon::Normal, QIcon::Off));
429 const static QPixmap closeButtonPixmapOver(
430 paneCloseIcon.pixmap(20, 18, QIcon::Active));
431
432 QPoint closeButtonPos(rect.right() - 20, rect.top());
433
434 if (m_closeButtonHighlighted)
435 painter.drawPixmap(closeButtonPos, closeButtonPixmapOver);
436 else
437 painter.drawPixmap(closeButtonPos, closeButtonPixmap);
438 }
439
440 painter.end();
441 }
442
443 //-----------------------------------------------------------------------------
444
mousePressEvent(QMouseEvent * event)445 void TPanelTitleBar::mousePressEvent(QMouseEvent *event) {
446 TDockWidget *dw = static_cast<TDockWidget *>(parentWidget());
447
448 QPoint pos = event->pos();
449
450 if (dw->isFloating()) {
451 QRect rect = this->rect();
452 QRect closeButtonRect(rect.right() - 20, rect.top() + 1, 20, 18);
453 if (closeButtonRect.contains(pos) && dw->isFloating()) {
454 event->accept();
455 dw->hide();
456 m_closeButtonHighlighted = false;
457 emit closeButtonPressed();
458 return;
459 }
460 }
461 event->ignore();
462 }
463
464 //-----------------------------------------------------------------------------
465
mouseMoveEvent(QMouseEvent * event)466 void TPanelTitleBar::mouseMoveEvent(QMouseEvent *event) {
467 TDockWidget *dw = static_cast<TDockWidget *>(parentWidget());
468
469 if (dw->isFloating()) {
470 QPoint pos = event->pos();
471 QRect rect = this->rect();
472 QRect closeButtonRect(rect.right() - 18, rect.top() + 1, 18, 18);
473
474 if (closeButtonRect.contains(pos) && dw->isFloating())
475 m_closeButtonHighlighted = true;
476 else
477 m_closeButtonHighlighted = false;
478 }
479
480 update();
481 event->ignore();
482 }
483
484 //-----------------------------------------------------------------------------
485
mouseDoubleClickEvent(QMouseEvent * me)486 void TPanelTitleBar::mouseDoubleClickEvent(QMouseEvent *me) {
487 emit doubleClick(me);
488 me->ignore();
489 }
490
491 //-----------------------------------------------------------------------------
492
add(const QPoint & pos,QWidget * widget)493 void TPanelTitleBar::add(const QPoint &pos, QWidget *widget) {
494 m_buttons.push_back(std::make_pair(pos, widget));
495 }
496
497 //-----------------------------------------------------------------------------
498
resizeEvent(QResizeEvent * e)499 void TPanelTitleBar::resizeEvent(QResizeEvent *e) {
500 QWidget::resizeEvent(e);
501 int i;
502 for (i = 0; i < (int)m_buttons.size(); i++) {
503 QPoint p = m_buttons[i].first;
504 QWidget *w = m_buttons[i].second;
505 if (p.x() < 0) p.setX(p.x() + width());
506 w->move(p);
507 }
508 }
509
510 //=============================================================================
511 // TPanelFactory
512 //-----------------------------------------------------------------------------
513
TPanelFactory(QString panelType)514 TPanelFactory::TPanelFactory(QString panelType) : m_panelType(panelType) {
515 assert(tableInstance().count(panelType) == 0);
516 tableInstance()[m_panelType] = this;
517 }
518
519 //-----------------------------------------------------------------------------
520
~TPanelFactory()521 TPanelFactory::~TPanelFactory() { tableInstance().remove(m_panelType); }
522
523 //-----------------------------------------------------------------------------
524
tableInstance()525 QMap<QString, TPanelFactory *> &TPanelFactory::tableInstance() {
526 static QMap<QString, TPanelFactory *> table;
527 return table;
528 }
529
530 //-----------------------------------------------------------------------------
531
createPanel(QWidget * parent,QString panelType)532 TPanel *TPanelFactory::createPanel(QWidget *parent, QString panelType) {
533 TPanel *panel = 0;
534
535 QMap<QString, TPanelFactory *>::iterator it = tableInstance().find(panelType);
536 if (it == tableInstance().end()) {
537 TPanel *panel = new TPanel(parent);
538 panel->setPanelType(panelType.toStdString());
539 return panel;
540 } else {
541 TPanelFactory *factory = it.value();
542 TPanel *panel = factory->createPanel(parent);
543 panel->setPanelType(panelType.toStdString());
544 return panel;
545 }
546 }
547
548 //-----------------------------------------------------------------------------
549
createPanel(QWidget * parent)550 TPanel *TPanelFactory::createPanel(QWidget *parent) {
551 TPanel *panel = new TPanel(parent);
552 panel->setObjectName(getPanelType());
553 panel->setWindowTitle(getPanelType());
554 initialize(panel);
555 return panel;
556 }
557
558 //-----------------------------------------------------------------------------
559