tahoma2d/toonz/sources/toonz/pane.cpp
Jeremy Bullock 4566353fe5
Konero tweaks (#42)
* Fix build with Clang 10

* System depend code deduplication

* Improve multi-layer style picker.

Allows clicking anywhere on a stroke in another layer to pick it -
not just the center.

Fixes #2843.

* Get actual pixel size instead of hard-coding to 1.0.

* Rehide features

* fix pegbar restoring

* gui tweaks

tweaks the gui, makes tpaneltitlebarbutton color states changable in stylesheets

* fix styleeditor chandle mouse event

allow handle to be grabbed properly without slipping

Co-authored-by: Rodney <rodney.baker@gmail.com>
Co-authored-by: Rozhuk Ivan <rozhuk.im@gmail.com>
Co-authored-by: Martin van Zijl <martin.vanzijl@gmail.com>
Co-authored-by: shun-iwasawa <shun.iwasawa@ghibli.jp>
Co-authored-by: Kite <konero@users.noreply.github.com>
2020-06-04 01:48:08 -06:00

589 lines
18 KiB
C++

#include "pane.h"
// Tnz6 includes
#include "tapp.h"
#include "mainwindow.h"
#include "tenv.h"
#include "saveloadqsettings.h"
#include "toonzqt/gutil.h"
// TnzLib includes
#include "toonz/preferences.h"
#include "toonz/toonzfolders.h"
#include "toonz/tscenehandle.h"
// TnzCore includes
#include "tsystem.h"
// Qt includes
#include <QPainter>
#include <QStyleOptionDockWidget>
#include <QMouseEvent>
#include <QMainWindow>
#include <QSettings>
#include <QToolBar>
#include <QMap>
#include <QApplication>
#include <QFile>
#include <qdrawutil.h>
#include <assert.h>
#include <QDesktopWidget>
#include <QDialog>
#include <QLineEdit>
extern TEnv::StringVar EnvSafeAreaName;
//=============================================================================
// TPanel
//-----------------------------------------------------------------------------
TPanel::TPanel(QWidget *parent, Qt::WindowFlags flags,
TDockWidget::Orientation orientation)
: TDockWidget(parent, flags)
, m_panelType("")
, m_isMaximizable(true)
, m_isMaximized(false)
, m_isActive(true)
, m_panelTitleBar(0)
, m_multipleInstancesAllowed(true) {
// setFeatures(QDockWidget::DockWidgetMovable |
// QDockWidget::DockWidgetFloatable);
// setFloating(false);
m_panelTitleBar = new TPanelTitleBar(this, orientation);
setTitleBarWidget(m_panelTitleBar);
// connect(m_panelTitleBar,SIGNAL(doubleClick()),this,SLOT(onDoubleClick()));
connect(m_panelTitleBar, SIGNAL(doubleClick(QMouseEvent *)), this,
SIGNAL(doubleClick(QMouseEvent *)));
connect(m_panelTitleBar, SIGNAL(closeButtonPressed()), this,
SLOT(onCloseButtonPressed()));
setOrientation(orientation);
}
//-----------------------------------------------------------------------------
TPanel::~TPanel() {
// On quitting, save the floating panel's geomtry and state in order to
// restore them when opening the floating panel next time
if (isFloating()) {
TFilePath savePath =
ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
QSettings settings(QString::fromStdWString(savePath.getWideString()),
QSettings::IniFormat);
settings.beginGroup("Panels");
settings.beginGroup(QString::fromStdString(m_panelType));
settings.setValue("geometry", geometry());
if (SaveLoadQSettings *persistent =
dynamic_cast<SaveLoadQSettings *>(widget()))
persistent->save(settings);
}
}
//-----------------------------------------------------------------------------
void TPanel::setActive(bool value) {
m_isActive = value;
if (m_panelTitleBar) {
m_panelTitleBar->setIsActive(m_isActive);
}
}
//-----------------------------------------------------------------------------
void TPanel::paintEvent(QPaintEvent *e) {
QPainter painter(this);
if (widget()) {
QRect dockRect = widget()->geometry();
dockRect.adjust(0, 0, -1, -1);
painter.fillRect(dockRect, m_bgcolor);
painter.setPen(Qt::black);
painter.drawRect(dockRect);
}
if (m_floating && !m_panelTitleBar->isVisible()) {
m_panelTitleBar->showTitleBar(true);
}
painter.end();
}
//-----------------------------------------------------------------------------
void TPanel::onCloseButtonPressed() {
emit closeButtonPressed();
// Currently, Toonz panels that get closed indeed just remain hidden -
// ready to reappair if they are needed again. However, the user expects
// a new panel to be created - so we just reset the panel here.
// reset(); //Moved to panel invocation in floatingpanelcommand.cpp
// Also, remove widget from its dock layout control
if (parentLayout()) parentLayout()->removeWidget(this);
}
//-----------------------------------------------------------------------------
/*! activate the panel and set focus specified widget when mouse enters
*/
void TPanel::enterEvent(QEvent *event) {
// Only when Toonz application is active
QWidget *w = qApp->activeWindow();
// if (m_floating) {
// m_panelTitleBar->showTitleBar(true);
//}
if (w) {
// grab the focus, unless a line-edit is focused currently
bool shouldSetFocus = true;
QWidget *focusWidget = qApp->focusWidget();
if (focusWidget) {
QLineEdit *lineEdit = dynamic_cast<QLineEdit *>(focusWidget);
if (lineEdit) {
shouldSetFocus = false;
}
}
if (shouldSetFocus) {
widgetFocusOnEnter();
}
// Some panels (e.g. Viewer, StudioPalette, Palette, ColorModel) are
// activated when mouse enters. Viewer is activatable only when being
// docked.
// Active windows will NOT switch when the current active window is dialog.
if (qobject_cast<QDialog *>(w) == 0 && isActivatableOnEnter())
activateWindow();
event->accept();
} else
event->accept();
}
//-----------------------------------------------------------------------------
/*! clear focus when mouse leaves
*/
void TPanel::leaveEvent(QEvent *event) { widgetClearFocusOnLeave(); }
//-----------------------------------------------------------------------------
/*! load and restore previous geometry and state of the floating panel.
called from the function OpenFloatingPanel::getOrOpenFloatingPanel()
in floatingpanelcommand.cpp
*/
void TPanel::restoreFloatingPanelState() {
TFilePath savePath = ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
QSettings settings(QString::fromStdWString(savePath.getWideString()),
QSettings::IniFormat);
settings.beginGroup("Panels");
if (!settings.childGroups().contains(QString::fromStdString(m_panelType)))
return;
settings.beginGroup(QString::fromStdString(m_panelType));
QRect geom = settings.value("geometry", saveGeometry()).toRect();
// check if it can be visible in the current screen
if (!(geom & QApplication::desktop()->availableGeometry(this)).isEmpty())
setGeometry(geom);
// load optional settings
if (SaveLoadQSettings *persistent =
dynamic_cast<SaveLoadQSettings *>(widget()))
persistent->load(settings);
}
//=============================================================================
// TPanelTitleBarButton
//-----------------------------------------------------------------------------
TPanelTitleBarButton::TPanelTitleBarButton(QWidget *parent,
const QString &standardPixmapName)
: QWidget(parent)
, m_standardPixmap(standardPixmapName)
, m_standardPixmapName(standardPixmapName)
, m_rollover(false)
, m_pressed(false)
, m_buttonSet(0)
, m_id(0) {
setFixedSize(m_standardPixmap.size());
}
//-----------------------------------------------------------------------------
TPanelTitleBarButton::TPanelTitleBarButton(QWidget *parent,
const QPixmap &standardPixmap)
: QWidget(parent)
, m_standardPixmap(standardPixmap)
, m_rollover(false)
, m_pressed(false)
, m_buttonSet(0)
, m_id(0) {
setFixedSize(m_standardPixmap.size() / m_standardPixmap.devicePixelRatio());
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::setButtonSet(TPanelTitleBarButtonSet *buttonSet,
int id) {
m_buttonSet = buttonSet;
m_id = id;
m_buttonSet->add(this);
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::setPressed(bool pressed) {
if (pressed != m_pressed) {
m_pressed = pressed;
update();
}
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::paintEvent(QPaintEvent *event) {
QPainter painter(this);
// create color states for the button
QPixmap standard_pm(m_standardPixmap.size());
QPixmap rollover_pm(m_standardPixmap.size());
QPixmap pressed_pm(m_standardPixmap.size());
standard_pm.fill(Qt::transparent);
rollover_pm.fill(QColor(getRolloverColor()));
pressed_pm.fill(QColor(getPressedColor()));
// set unique colors if filename contains string
if (m_standardPixmapName.contains("freeze", Qt::CaseInsensitive)) {
pressed_pm.fill(QColor(getFreezeColor()));
}
if (m_standardPixmapName.contains("preview", Qt::CaseInsensitive)) {
pressed_pm.fill(QColor(getPreviewColor()));
}
// compose the state colors
painter.drawPixmap(
0, 0, m_pressed ? pressed_pm : m_rollover ? rollover_pm : standard_pm);
// compose the icon
painter.drawPixmap(0, 0, m_standardPixmap);
painter.end();
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::mouseMoveEvent(QMouseEvent *event) {}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::enterEvent(QEvent *) {
if (!m_rollover) {
m_rollover = true;
if (!m_pressed) update();
}
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::leaveEvent(QEvent *) {
if (m_rollover) {
m_rollover = false;
if (!m_pressed) update();
}
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButton::mousePressEvent(QMouseEvent *e) {
if (m_buttonSet) {
if (m_pressed) return;
m_buttonSet->select(this);
} else {
m_pressed = !m_pressed;
emit toggled(m_pressed);
update();
}
}
//=============================================================================
// TPanelTitleBarButtonForSafeArea
//-----------------------------------------------------------------------------
void TPanelTitleBarButtonForSafeArea::getSafeAreaNameList(
QList<QString> &nameList) {
TFilePath fp = TEnv::getConfigDir();
QString currentSafeAreaName = QString::fromStdString(EnvSafeAreaName);
std::string safeAreaFileName = "safearea.ini";
while (!TFileStatus(fp + safeAreaFileName).doesExist() && !fp.isRoot() &&
fp.getParentDir() != TFilePath())
fp = fp.getParentDir();
fp = fp + safeAreaFileName;
if (TFileStatus(fp).doesExist()) {
QSettings settings(toQString(fp), QSettings::IniFormat);
// find the current safearea name from the list
QStringList groups = settings.childGroups();
for (int g = 0; g < groups.size(); g++) {
settings.beginGroup(groups.at(g));
nameList.push_back(settings.value("name", "").toString());
settings.endGroup();
}
}
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButtonForSafeArea::mousePressEvent(QMouseEvent *e) {
if (e->button() != Qt::RightButton) {
m_pressed = !m_pressed;
emit toggled(m_pressed);
update();
}
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButtonForSafeArea::contextMenuEvent(QContextMenuEvent *e) {
QMenu menu(this);
QList<QString> safeAreaNameList;
getSafeAreaNameList(safeAreaNameList);
for (int i = 0; i < safeAreaNameList.size(); i++) {
QAction *action = new QAction(safeAreaNameList.at(i), this);
action->setData(safeAreaNameList.at(i));
connect(action, SIGNAL(triggered()), this, SLOT(onSetSafeArea()));
if (safeAreaNameList.at(i) == QString::fromStdString(EnvSafeAreaName)) {
action->setCheckable(true);
action->setChecked(true);
}
menu.addAction(action);
}
menu.exec(e->globalPos());
}
//-----------------------------------------------------------------------------
void TPanelTitleBarButtonForSafeArea::onSetSafeArea() {
QString safeAreaName = qobject_cast<QAction *>(sender())->data().toString();
// change safearea if the different one is selected
if (QString::fromStdString(EnvSafeAreaName) != safeAreaName) {
EnvSafeAreaName = safeAreaName.toStdString();
// emit sceneChanged without setting dirty flag
TApp::instance()->getCurrentScene()->notifySceneChanged(false);
}
}
//-----------------------------------------------------------------------------
//=============================================================================
// TPanelTitleBarButtonSet
//-----------------------------------------------------------------------------
TPanelTitleBarButtonSet::TPanelTitleBarButtonSet() {}
TPanelTitleBarButtonSet::~TPanelTitleBarButtonSet() {}
void TPanelTitleBarButtonSet::add(TPanelTitleBarButton *button) {
m_buttons.push_back(button);
}
void TPanelTitleBarButtonSet::select(TPanelTitleBarButton *button) {
int i;
for (i = 0; i < (int)m_buttons.size(); i++)
m_buttons[i]->setPressed(button == m_buttons[i]);
emit selected(button->getId());
}
//=============================================================================
// PaneTitleBar
//-----------------------------------------------------------------------------
TPanelTitleBar::TPanelTitleBar(QWidget *parent,
TDockWidget::Orientation orientation)
: QFrame(parent), m_isActive(true), m_closeButtonHighlighted(false) {
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::setIsActive(bool value) {
if (m_isActive == value) return;
m_isActive = value;
}
//-----------------------------------------------------------------------------
QSize TPanelTitleBar::minimumSizeHint() const { return QSize(20, 18); }
//-----------------------------------------------------------------------------
void TPanelTitleBar::paintEvent(QPaintEvent *) {
QPainter painter(this);
QRect rect = this->rect();
bool isPanelActive;
TPanel *dw = qobject_cast<TPanel *>(parentWidget());
Q_ASSERT(dw != 0);
// docked panel
if (!dw->isFloating()) {
isPanelActive = dw->widgetInThisPanelIsFocused();
qDrawBorderPixmap(&painter, rect, QMargins(3, 3, 3, 3),
(isPanelActive) ? m_activeBorderPm : m_borderPm);
}
// floating panel
else {
isPanelActive = isActiveWindow();
qDrawBorderPixmap(
&painter, rect, QMargins(3, 3, 3, 3),
(isPanelActive) ? m_floatActiveBorderPm : m_floatBorderPm);
}
if (dw->getOrientation() == TDockWidget::vertical) {
QString titleText = painter.fontMetrics().elidedText(
dw->windowTitle(), Qt::ElideRight, rect.width() - 50);
painter.setBrush(Qt::NoBrush);
painter.setPen(isPanelActive ? m_activeTitleColor : m_titleColor);
painter.drawText(QPointF(10, 15), titleText);
}
if (dw->isFloating()) {
const static QPixmap closeButtonPixmap(
svgToPixmap(":/Resources/pane_close.svg", QSize(18, 18)));
const static QPixmap closeButtonPixmapOver(
svgToPixmap(":/Resources/pane_close_rollover.svg", QSize(18, 18)));
QPoint closeButtonPos(rect.right() - 18, rect.top() + 1);
if (m_closeButtonHighlighted)
painter.drawPixmap(closeButtonPos, closeButtonPixmapOver);
else
painter.drawPixmap(closeButtonPos, closeButtonPixmap);
}
painter.end();
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::mousePressEvent(QMouseEvent *event) {
TDockWidget *dw = static_cast<TDockWidget *>(parentWidget());
QPoint pos = event->pos();
if (dw->isFloating()) {
QRect rect = this->rect();
QRect closeButtonRect(rect.right() - 18, rect.top() + 1, 18, 18);
if (closeButtonRect.contains(pos) && dw->isFloating()) {
event->accept();
dw->hide();
m_closeButtonHighlighted = false;
emit closeButtonPressed();
return;
}
}
event->ignore();
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::mouseMoveEvent(QMouseEvent *event) {
TDockWidget *dw = static_cast<TDockWidget *>(parentWidget());
if (dw->isFloating()) {
QPoint pos = event->pos();
QRect rect = this->rect();
QRect closeButtonRect(rect.right() - 18, rect.top() + 1, 18, 18);
if (closeButtonRect.contains(pos) && dw->isFloating())
m_closeButtonHighlighted = true;
else
m_closeButtonHighlighted = false;
}
update();
event->ignore();
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::mouseDoubleClickEvent(QMouseEvent *me) {
emit doubleClick(me);
me->ignore();
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::add(const QPoint &pos, QWidget *widget) {
m_buttons.push_back(std::make_pair(pos, widget));
}
//-----------------------------------------------------------------------------
void TPanelTitleBar::resizeEvent(QResizeEvent *e) {
QWidget::resizeEvent(e);
int i;
for (i = 0; i < (int)m_buttons.size(); i++) {
QPoint p = m_buttons[i].first;
QWidget *w = m_buttons[i].second;
if (p.x() < 0) p.setX(p.x() + width());
w->move(p);
}
}
//=============================================================================
// TPanelFactory
//-----------------------------------------------------------------------------
TPanelFactory::TPanelFactory(QString panelType) : m_panelType(panelType) {
assert(tableInstance().count(panelType) == 0);
tableInstance()[m_panelType] = this;
}
//-----------------------------------------------------------------------------
TPanelFactory::~TPanelFactory() { tableInstance().remove(m_panelType); }
//-----------------------------------------------------------------------------
QMap<QString, TPanelFactory *> &TPanelFactory::tableInstance() {
static QMap<QString, TPanelFactory *> table;
return table;
}
//-----------------------------------------------------------------------------
TPanel *TPanelFactory::createPanel(QWidget *parent, QString panelType) {
TPanel *panel = 0;
QMap<QString, TPanelFactory *>::iterator it = tableInstance().find(panelType);
if (it == tableInstance().end()) {
TPanel *panel = new TPanel(parent);
panel->setPanelType(panelType.toStdString());
return panel;
} else {
TPanelFactory *factory = it.value();
TPanel *panel = factory->createPanel(parent);
panel->setPanelType(panelType.toStdString());
return panel;
}
}
//-----------------------------------------------------------------------------
TPanel *TPanelFactory::createPanel(QWidget *parent) {
TPanel *panel = new TPanel(parent);
panel->setObjectName(getPanelType());
panel->setWindowTitle(getPanelType());
initialize(panel);
return panel;
}
//-----------------------------------------------------------------------------