2702 lines
89 KiB
C++
2702 lines
89 KiB
C++
/****************************************************************************
|
|
* Copyright (c) 2020 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#ifndef _PreComp_
|
|
# include <QAction>
|
|
# include <QApplication>
|
|
# include <QBoxLayout>
|
|
# include <QComboBox>
|
|
# include <QDockWidget>
|
|
# include <QHeaderView>
|
|
# include <QKeyEvent>
|
|
# include <QMdiArea>
|
|
# include <QMenu>
|
|
# include <QPainter>
|
|
# include <QPointer>
|
|
# include <QSpacerItem>
|
|
# include <QSplitter>
|
|
# include <QTabBar>
|
|
# include <QTextStream>
|
|
# include <QTimerEvent>
|
|
# include <QToolTip>
|
|
# include <QTreeView>
|
|
# include <QScrollBar>
|
|
#endif
|
|
|
|
#include <QPainterPath>
|
|
#include <QPropertyAnimation>
|
|
|
|
#include <array>
|
|
#include <unordered_map>
|
|
|
|
#include "OverlayWidgets.h"
|
|
|
|
#include <Base/Tools.h>
|
|
#include <Base/Console.h>
|
|
#include <App/Application.h>
|
|
#include "Application.h"
|
|
#include "BitmapFactory.h"
|
|
#include "Clipping.h"
|
|
#include "ComboView.h"
|
|
#include "Command.h"
|
|
#include "Control.h"
|
|
#include "MainWindow.h"
|
|
#include "MDIView.h"
|
|
#include "NaviCube.h"
|
|
#include "OverlayManager.h"
|
|
#include "OverlayParams.h"
|
|
#include "TaskView/TaskView.h"
|
|
#include "Tree.h"
|
|
#include "TreeParams.h"
|
|
#include "propertyeditor/PropertyEditor.h"
|
|
|
|
FC_LOG_LEVEL_INIT("Dock", true, true);
|
|
|
|
using namespace Gui;
|
|
|
|
OverlayDragFrame *OverlayTabWidget::_DragFrame;
|
|
QDockWidget *OverlayTabWidget::_DragFloating;
|
|
QWidget *OverlayTabWidget::_Dragging;
|
|
OverlayTabWidget *OverlayTabWidget::_LeftOverlay;
|
|
OverlayTabWidget *OverlayTabWidget::_RightOverlay;
|
|
OverlayTabWidget *OverlayTabWidget::_TopOverlay;
|
|
OverlayTabWidget *OverlayTabWidget::_BottomOverlay;
|
|
|
|
static inline int widgetMinSize(const QWidget *widget, bool margin=false)
|
|
{
|
|
return widget->fontMetrics().ascent()
|
|
+ widget->fontMetrics().descent() + (margin?4:0);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlayProxyWidget::OverlayProxyWidget(OverlayTabWidget *tabOverlay)
|
|
:QWidget(tabOverlay->parentWidget()), owner(tabOverlay), _hintColor(QColor(50,50,50,150))
|
|
{
|
|
dockArea = owner->getDockArea();
|
|
timer.setSingleShot(true);
|
|
QObject::connect(&timer, &QTimer::timeout, this, &OverlayProxyWidget::onTimer);
|
|
setAttribute(Qt::WA_TransparentForMouseEvents, true);
|
|
}
|
|
|
|
bool OverlayProxyWidget::isActivated() const
|
|
{
|
|
return drawLine && isVisible();
|
|
}
|
|
|
|
OverlayProxyWidget::HitTest OverlayProxyWidget::hitTest(const QPoint &globalPt, bool delay)
|
|
{
|
|
if (!isVisible() || !owner->count())
|
|
return HitTest::HitNone;
|
|
|
|
auto pt = mapFromGlobal(globalPt);
|
|
|
|
QTabBar *tabbar = owner->tabBar();
|
|
if (tabbar->isVisible() && tabbar->tabAt(pt)>=0) {
|
|
ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
|
|
return HitTest::HitOuter;
|
|
}
|
|
|
|
HitTest hit = HitTest::HitNone;
|
|
QRect rect = this->getRect();
|
|
QSize s = this->size();
|
|
int hintSize = OverlayParams::getDockOverlayHintTriggerSize();
|
|
// if (owner->getState() == OverlayTabWidget::State::HintHidden)
|
|
// hintSize *= 2;
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() > 0 && pt.x() < hintSize)
|
|
hit = HitTest::HitOuter;
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() < s.width() && pt.x() > -hintSize)
|
|
hit = HitTest::HitOuter;
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() > 0 && pt.y() < hintSize)
|
|
hit = HitTest::HitOuter;
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() < s.height() && pt.y() > -hintSize)
|
|
hit = HitTest::HitOuter;
|
|
break;
|
|
}
|
|
if (rect.contains(pt)) {
|
|
hit = HitTest::HitInner;
|
|
ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
|
|
} else if (drawLine)
|
|
ToolTip::hideText();
|
|
|
|
if (owner->getState() == OverlayTabWidget::State::HintHidden) {
|
|
if (hit == HitTest::HitNone)
|
|
owner->setState(OverlayTabWidget::State::Normal);
|
|
else {
|
|
hit = HitTest::HitNone;
|
|
ToolTip::hideText();
|
|
}
|
|
}
|
|
if (hit != HitTest::HitNone) {
|
|
if (drawLine)
|
|
timer.stop();
|
|
else if (delay) {
|
|
if (!timer.isActive())
|
|
timer.start(OverlayParams::getDockOverlayHintDelay());
|
|
return hit;
|
|
} else {
|
|
timer.stop();
|
|
owner->setState(OverlayTabWidget::State::Hint);
|
|
drawLine = true;
|
|
update();
|
|
}
|
|
if(owner->getState() != OverlayTabWidget::State::Hidden
|
|
&& hit == HitTest::HitOuter
|
|
&& OverlayParams::getDockOverlayActivateOnHover()) {
|
|
if (owner->isVisible() && owner->tabBar()->isVisible()) {
|
|
QSize size = owner->tabBar()->size();
|
|
QPoint pt = owner->tabBar()->mapToGlobal(
|
|
QPoint(size.width(), size.height()));
|
|
QPoint pos = QCursor::pos();
|
|
switch(this->dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
if (pos.y() < pt.y())
|
|
return HitTest::HitNone;
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::BottomDockWidgetArea:
|
|
if (pos.x() < pt.x())
|
|
return HitTest::HitNone;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
owner->setState(OverlayTabWidget::State::Showing);
|
|
}
|
|
|
|
} else if (!drawLine) {
|
|
timer.stop();
|
|
} else if (delay) {
|
|
if (!timer.isActive())
|
|
timer.start(OverlayParams::getDockOverlayHintDelay());
|
|
} else {
|
|
timer.stop();
|
|
owner->setState(OverlayTabWidget::State::Normal);
|
|
drawLine = false;
|
|
ToolTip::hideText();
|
|
update();
|
|
}
|
|
return hit;
|
|
}
|
|
|
|
void OverlayProxyWidget::onTimer()
|
|
{
|
|
hitTest(QCursor::pos(), false);
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
void OverlayProxyWidget::enterEvent(QEvent *)
|
|
#else
|
|
void OverlayProxyWidget::enterEvent(QEnterEvent *)
|
|
#endif
|
|
{
|
|
if(!owner->count())
|
|
return;
|
|
|
|
if (!drawLine) {
|
|
if (!timer.isActive())
|
|
timer.start(OverlayParams::getDockOverlayHintDelay());
|
|
}
|
|
}
|
|
|
|
void OverlayProxyWidget::hideEvent(QHideEvent *)
|
|
{
|
|
drawLine = false;
|
|
}
|
|
|
|
void OverlayProxyWidget::onMousePress()
|
|
{
|
|
if(!owner->count())
|
|
return;
|
|
|
|
if (owner->getState() == OverlayTabWidget::State::HintHidden)
|
|
return;
|
|
|
|
owner->setState(OverlayTabWidget::State::Showing);
|
|
}
|
|
|
|
QBrush OverlayProxyWidget::hintColor() const
|
|
{
|
|
return _hintColor;
|
|
}
|
|
|
|
void OverlayProxyWidget::setHintColor(const QBrush &brush)
|
|
{
|
|
_hintColor = brush;
|
|
}
|
|
|
|
QRect OverlayProxyWidget::getRect() const
|
|
{
|
|
QRect rect = this->rect();
|
|
if (owner->isVisible() && owner->tabBar()->isVisible()) {
|
|
QSize size = owner->tabBar()->size();
|
|
QPoint pt = owner->tabBar()->mapToGlobal(
|
|
QPoint(size.width(), size.height()));
|
|
pt = this->mapFromGlobal(pt);
|
|
switch(this->dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
rect.setTop(pt.y());
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::BottomDockWidgetArea:
|
|
rect.setLeft(pt.x());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
switch(this->dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
if (int offset = OverlayParams::getDockOverlayHintLeftOffset())
|
|
rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
|
|
if (int length = OverlayParams::getDockOverlayHintLeftLength())
|
|
rect.setHeight(std::min(length, rect.height()));
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
if (int offset = OverlayParams::getDockOverlayHintRightOffset())
|
|
rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
|
|
if (int length = OverlayParams::getDockOverlayHintRightLength())
|
|
rect.setHeight(std::min(length, rect.height()));
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
if (int offset = OverlayParams::getDockOverlayHintTopOffset())
|
|
rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
|
|
if (int length = OverlayParams::getDockOverlayHintTopLength())
|
|
rect.setWidth(std::min(length, rect.width()));
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
if (int offset = OverlayParams::getDockOverlayHintBottomOffset())
|
|
rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
|
|
if (int length = OverlayParams::getDockOverlayHintBottomLength())
|
|
rect.setWidth(std::min(length, rect.width()));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rect;
|
|
}
|
|
|
|
void OverlayProxyWidget::paintEvent(QPaintEvent *)
|
|
{
|
|
if(!drawLine)
|
|
return;
|
|
QPainter painter(this);
|
|
painter.setOpacity(_hintColor.color().alphaF());
|
|
painter.setPen(Qt::transparent);
|
|
painter.setBrush(_hintColor);
|
|
|
|
QRect rect = this->getRect();
|
|
painter.drawRect(rect);
|
|
}
|
|
|
|
OverlayToolButton::OverlayToolButton(QWidget *parent)
|
|
:QToolButton(parent)
|
|
{
|
|
setCursor(Qt::ArrowCursor);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
OverlayTabWidget::OverlayTabWidget(QWidget *parent, Qt::DockWidgetArea pos)
|
|
:QTabWidget(parent), dockArea(pos)
|
|
{
|
|
// This is necessary to capture any focus lost from switching the tab,
|
|
// otherwise the lost focus will leak to the parent, i.e. MdiArea, which may
|
|
// cause unexpected Mdi sub window switching.
|
|
// setFocusPolicy(Qt::StrongFocus);
|
|
|
|
_imageScale = 0.0;
|
|
|
|
splitter = new OverlaySplitter(this);
|
|
|
|
_graphicsEffect = new OverlayGraphicsEffect(splitter);
|
|
splitter->setGraphicsEffect(_graphicsEffect);
|
|
|
|
_graphicsEffectTab = new OverlayGraphicsEffect(this);
|
|
_graphicsEffectTab->setEnabled(false);
|
|
tabBar()->setGraphicsEffect(_graphicsEffectTab);
|
|
|
|
Command *cmdHide = nullptr;
|
|
switch(pos) {
|
|
case Qt::LeftDockWidgetArea:
|
|
_LeftOverlay = this;
|
|
setTabPosition(QTabWidget::West);
|
|
splitter->setOrientation(Qt::Vertical);
|
|
cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleLeft");
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
_RightOverlay = this;
|
|
setTabPosition(QTabWidget::East);
|
|
splitter->setOrientation(Qt::Vertical);
|
|
cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleRight");
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
_TopOverlay = this;
|
|
setTabPosition(QTabWidget::North);
|
|
splitter->setOrientation(Qt::Horizontal);
|
|
cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleTop");
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
_BottomOverlay = this;
|
|
setTabPosition(QTabWidget::South);
|
|
splitter->setOrientation(Qt::Horizontal);
|
|
cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleBottom");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
proxyWidget = new OverlayProxyWidget(this);
|
|
proxyWidget->hide();
|
|
_setOverlayMode(proxyWidget,OverlayOption::Enable);
|
|
|
|
setOverlayMode(true);
|
|
hide();
|
|
|
|
actTransparent.setCheckable(true);
|
|
actTransparent.setData(QStringLiteral("OBTN Transparent"));
|
|
actTransparent.setParent(this);
|
|
addAction(&actTransparent);
|
|
|
|
actAutoHide.setData(QStringLiteral("OBTN AutoHide"));
|
|
|
|
actEditHide.setData(QStringLiteral("OBTN EditHide"));
|
|
|
|
actEditShow.setData(QStringLiteral("OBTN EditShow"));
|
|
|
|
actTaskShow.setData(QStringLiteral("OBTN TaskShow"));
|
|
|
|
actNoAutoMode.setData(QStringLiteral("OBTN NoAutoMode"));
|
|
|
|
actAutoMode.setData(QStringLiteral("OBTN AutoMode"));
|
|
actAutoMode.setParent(this);
|
|
autoModeMenu.hide();
|
|
autoModeMenu.setToolTipsVisible(true);
|
|
autoModeMenu.addAction(&actNoAutoMode);
|
|
autoModeMenu.addAction(&actAutoHide);
|
|
autoModeMenu.addAction(&actEditShow);
|
|
autoModeMenu.addAction(&actEditHide);
|
|
autoModeMenu.addAction(&actTaskShow);
|
|
addAction(&actAutoMode);
|
|
|
|
actOverlay.setData(QStringLiteral("OBTN Overlay"));
|
|
actOverlay.setParent(this);
|
|
addAction(&actOverlay);
|
|
|
|
if (cmdHide)
|
|
cmdHide->addTo(this);
|
|
|
|
retranslate();
|
|
refreshIcons();
|
|
|
|
connect(tabBar(), &QTabBar::tabBarClicked, this, &OverlayTabWidget::onCurrentChanged);
|
|
connect(tabBar(), &QTabBar::tabMoved, this, &OverlayTabWidget::onTabMoved);
|
|
tabBar()->installEventFilter(this);
|
|
|
|
timer.setSingleShot(true);
|
|
connect(&timer, &QTimer::timeout, this, &OverlayTabWidget::setupLayout);
|
|
|
|
repaintTimer.setSingleShot(true);
|
|
connect(&repaintTimer, &QTimer::timeout, this, &OverlayTabWidget::onRepaint);
|
|
|
|
_animator = new QPropertyAnimation(this, "animation", this);
|
|
_animator->setStartValue(0.0);
|
|
_animator->setEndValue(1.0);
|
|
connect(_animator, &QAbstractAnimation::stateChanged,
|
|
this, &OverlayTabWidget::onAnimationStateChanged);
|
|
}
|
|
|
|
void OverlayTabWidget::refreshIcons()
|
|
{
|
|
auto curStyleSheet =
|
|
App::GetApplication()
|
|
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow")
|
|
->GetASCII("StyleSheet", "None");
|
|
|
|
QPixmap pxAutoHide;
|
|
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/icons/overlay_light.svg"));
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
|
|
actTransparent.setIcon(BitmapFactory().pixmap("qss:overlay/icons/transparent_light.svg"));
|
|
pxAutoHide = BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
|
|
}
|
|
else {
|
|
actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/icons/overlay.svg"));
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode.svg"));
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow.svg"));
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide.svg"));
|
|
actTransparent.setIcon(BitmapFactory().pixmap("qss:overlay/icons/transparent.svg"));
|
|
pxAutoHide = BitmapFactory().pixmap("qss:overlay/icons/autohide.svg");
|
|
}
|
|
|
|
actAutoHide.setIcon(rotateAutoHideIcon(pxAutoHide, dockArea));
|
|
|
|
syncAutoMode();
|
|
}
|
|
|
|
void OverlayTabWidget::onAnimationStateChanged()
|
|
{
|
|
if (_animator->state() != QAbstractAnimation::Running) {
|
|
setAnimation(0);
|
|
if (_animator->startValue().toReal() == 0.0) {
|
|
hide();
|
|
OverlayManager::instance()->refresh();
|
|
}
|
|
if (_state == State::Showing)
|
|
setState(State::Normal);
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::setAnimation(qreal t)
|
|
{
|
|
if (t != _animation) {
|
|
_animation = t;
|
|
setupLayout();
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::startShow()
|
|
{
|
|
if (isVisible() || _state > State::Normal)
|
|
return;
|
|
int duration = OverlayParams::getDockOverlayAnimationDuration();
|
|
bool setmode = _state != State::Showing;
|
|
if (duration) {
|
|
_animator->setStartValue(1.0);
|
|
_animator->setEndValue(0.0);
|
|
_animator->setDuration(duration);
|
|
_animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
|
|
_animator->start();
|
|
}
|
|
else if (_state == State::Showing)
|
|
setState(State::Normal);
|
|
proxyWidget->hide();
|
|
show();
|
|
raise();
|
|
if (setmode)
|
|
setOverlayMode(overlaid);
|
|
}
|
|
|
|
QWidget *OverlayTabWidget::createTitleButton(QAction *action, int size)
|
|
{
|
|
auto button = new OverlayToolButton(nullptr);
|
|
button->setObjectName(action->data().toString());
|
|
button->setDefaultAction(action);
|
|
button->setAutoRaise(true);
|
|
button->setContentsMargins(0,0,0,0);
|
|
button->setFixedSize(size,size);
|
|
return button;
|
|
}
|
|
|
|
void OverlayTabWidget::startHide()
|
|
{
|
|
if (!isVisible()
|
|
|| _state > State::Normal
|
|
|| (_animator->state() == QAbstractAnimation::Running
|
|
&& _animator->startValue().toReal() == 0.0))
|
|
return;
|
|
int duration = OverlayParams::getDockOverlayAnimationDuration();
|
|
if (!duration)
|
|
hide();
|
|
else {
|
|
_animator->setStartValue(0.0);
|
|
_animator->setEndValue(1.0);
|
|
_animator->setDuration(duration);
|
|
_animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
|
|
_animator->start();
|
|
}
|
|
}
|
|
|
|
bool OverlayTabWidget::event(QEvent *ev)
|
|
{
|
|
switch(ev->type()) {
|
|
case QEvent::MouseButtonRelease:
|
|
if(mouseGrabber() == this) {
|
|
releaseMouse();
|
|
ev->accept();
|
|
return true;
|
|
}
|
|
break;
|
|
case QEvent::MouseMove:
|
|
case QEvent::ContextMenu:
|
|
if(QApplication::mouseButtons() == Qt::NoButton && mouseGrabber() == this) {
|
|
releaseMouse();
|
|
ev->accept();
|
|
return true;
|
|
}
|
|
break;
|
|
case QEvent::MouseButtonPress:
|
|
ev->accept();
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return QTabWidget::event(ev);
|
|
}
|
|
|
|
int OverlayTabWidget::testAlpha(const QPoint &_pos, int radiusScale)
|
|
{
|
|
if (!count() || (!isOverlaid() && !isTransparent()) || !isVisible())
|
|
return -1;
|
|
|
|
if (tabBar()->isVisible() && tabBar()->tabAt(tabBar()->mapFromGlobal(_pos))>=0)
|
|
return -1;
|
|
|
|
if (titleBar->isVisible() && titleBar->rect().contains(titleBar->mapFromGlobal(_pos)))
|
|
return -1;
|
|
|
|
if (!splitter->isVisible())
|
|
return 0;
|
|
|
|
auto pos = splitter->mapFromGlobal(_pos);
|
|
QSize size = splitter->size();
|
|
if (pos.x() < 0 || pos.y() < 0
|
|
|| pos.x() >= size.width()
|
|
|| pos.y() >= size.height())
|
|
{
|
|
if (this->rect().contains(this->mapFromGlobal(_pos)))
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
if (_image.isNull()) {
|
|
auto pixmap = splitter->grab();
|
|
_imageScale = pixmap.devicePixelRatio();
|
|
_image = pixmap.toImage();
|
|
}
|
|
|
|
int res = qAlpha(_image.pixel(pos*_imageScale));
|
|
int radius = OverlayParams::getDockOverlayAlphaRadius() * radiusScale;
|
|
if (res || radius<=0 )
|
|
return res;
|
|
|
|
radius *= _imageScale;
|
|
for (int i=-radius; i<radius; ++i) {
|
|
for (int j=-radius; j<radius; ++j) {
|
|
if (pos.x()+i < 0 || pos.y()+j < 0
|
|
|| pos.x()+i >= size.width()
|
|
|| pos.y()+j >= size.height())
|
|
continue;
|
|
res = qAlpha(_image.pixel(pos*_imageScale + QPoint(i,j)));
|
|
if (res)
|
|
return res;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void OverlayTabWidget::paintEvent(QPaintEvent *ev)
|
|
{
|
|
Base::StateLocker guard(repainting);
|
|
repaintTimer.stop();
|
|
if (!_image.isNull())
|
|
_image = QImage();
|
|
QTabWidget::paintEvent(ev);
|
|
}
|
|
|
|
void OverlayTabWidget::onRepaint()
|
|
{
|
|
Base::StateLocker guard(repainting);
|
|
repaintTimer.stop();
|
|
if (!_image.isNull())
|
|
_image = QImage();
|
|
splitter->repaint();
|
|
}
|
|
|
|
void OverlayTabWidget::scheduleRepaint()
|
|
{
|
|
if(!repainting
|
|
&& isVisible()
|
|
&& _graphicsEffect)
|
|
{
|
|
repaintTimer.start(100);
|
|
}
|
|
}
|
|
|
|
QColor OverlayTabWidget::effectColor() const
|
|
{
|
|
return _graphicsEffect->color();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectColor(const QColor &color)
|
|
{
|
|
_graphicsEffect->setColor(color);
|
|
_graphicsEffectTab->setColor(color);
|
|
}
|
|
|
|
int OverlayTabWidget::effectWidth() const
|
|
{
|
|
return _graphicsEffect->size().width();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectWidth(int s)
|
|
{
|
|
auto size = _graphicsEffect->size();
|
|
size.setWidth(s);
|
|
_graphicsEffect->setSize(size);
|
|
_graphicsEffectTab->setSize(size);
|
|
}
|
|
|
|
int OverlayTabWidget::effectHeight() const
|
|
{
|
|
return _graphicsEffect->size().height();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectHeight(int s)
|
|
{
|
|
auto size = _graphicsEffect->size();
|
|
size.setHeight(s);
|
|
_graphicsEffect->setSize(size);
|
|
_graphicsEffectTab->setSize(size);
|
|
}
|
|
|
|
qreal OverlayTabWidget::effectOffsetX() const
|
|
{
|
|
return _graphicsEffect->offset().x();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectOffsetX(qreal d)
|
|
{
|
|
auto offset = _graphicsEffect->offset();
|
|
offset.setX(d);
|
|
_graphicsEffect->setOffset(offset);
|
|
_graphicsEffectTab->setOffset(offset);
|
|
}
|
|
|
|
qreal OverlayTabWidget::effectOffsetY() const
|
|
{
|
|
return _graphicsEffect->offset().y();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectOffsetY(qreal d)
|
|
{
|
|
auto offset = _graphicsEffect->offset();
|
|
offset.setY(d);
|
|
_graphicsEffect->setOffset(offset);
|
|
_graphicsEffectTab->setOffset(offset);
|
|
}
|
|
|
|
qreal OverlayTabWidget::effectBlurRadius() const
|
|
{
|
|
return _graphicsEffect->blurRadius();
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectBlurRadius(qreal r)
|
|
{
|
|
_graphicsEffect->setBlurRadius(r);
|
|
_graphicsEffectTab->setBlurRadius(r);
|
|
}
|
|
|
|
bool OverlayTabWidget::effectEnabled() const
|
|
{
|
|
return _effectEnabled;
|
|
}
|
|
|
|
void OverlayTabWidget::setEffectEnabled(bool enable)
|
|
{
|
|
_effectEnabled = enable;
|
|
}
|
|
|
|
bool OverlayTabWidget::eventFilter(QObject *o, QEvent *ev)
|
|
{
|
|
if(ev->type() == QEvent::Resize && o == tabBar()) {
|
|
if (_state <= State::Normal)
|
|
timer.start(10);
|
|
}
|
|
return QTabWidget::eventFilter(o, ev);
|
|
}
|
|
|
|
void OverlayTabWidget::restore(ParameterGrp::handle handle)
|
|
{
|
|
if (!handle) {
|
|
hGrp = handle;
|
|
return;
|
|
}
|
|
if (!parentWidget())
|
|
return;
|
|
std::string widgets = handle->GetASCII("Widgets","");
|
|
for(auto &name : QString::fromUtf8(widgets.c_str()).split(QLatin1Char(','))) {
|
|
if(name.isEmpty())
|
|
continue;
|
|
OverlayManager::instance()->registerDockWidget(name, this);
|
|
auto dock = getMainWindow()->findChild<QDockWidget*>(name);
|
|
if(dock)
|
|
addWidget(dock, dock->windowTitle());
|
|
}
|
|
int width = handle->GetInt("Width", 0);
|
|
int height = handle->GetInt("Height", 0);
|
|
int offset1 = handle->GetInt("Offset1", 0);
|
|
int offset2 = handle->GetInt("Offset3", 0);
|
|
setOffset(QSize(offset1,offset2));
|
|
setSizeDelta(handle->GetInt("Offset2", 0));
|
|
if(width && height) {
|
|
QRect rect(0, 0, width, height);
|
|
switch(dockArea) {
|
|
case Qt::RightDockWidgetArea:
|
|
rect.moveRight(parentWidget()->size().width());
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
rect.moveBottom(parentWidget()->size().height());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
setRect(rect);
|
|
}
|
|
if (handle->GetBool("AutoHide", false))
|
|
setAutoMode(AutoMode::AutoHide);
|
|
else if (handle->GetBool("EditHide", false))
|
|
setAutoMode(AutoMode::EditHide);
|
|
else if (handle->GetBool("EditShow", false))
|
|
setAutoMode(AutoMode::EditShow);
|
|
else if (handle->GetBool("TaskShow", false))
|
|
setAutoMode(AutoMode::TaskShow);
|
|
else
|
|
setAutoMode(AutoMode::NoAutoMode);
|
|
|
|
setTransparent(handle->GetBool("Transparent", false));
|
|
|
|
_sizemap.clear();
|
|
std::string savedSizes = handle->GetASCII("Sizes","");
|
|
QList<int> sizes;
|
|
int idx = 0;
|
|
for(auto &size : QString::fromUtf8(savedSizes.c_str()).split(QLatin1Char(','))) {
|
|
sizes.append(size.toInt());
|
|
_sizemap[dockWidget(idx++)] = sizes.back();
|
|
}
|
|
|
|
FC_LOG("restore " << objectName().toUtf8().constData() << " " << savedSizes);
|
|
|
|
getSplitter()->setSizes(sizes);
|
|
hGrp = handle;
|
|
}
|
|
|
|
void OverlayTabWidget::saveTabs()
|
|
{
|
|
if(!hGrp)
|
|
return;
|
|
|
|
std::ostringstream os, os2;
|
|
_sizemap.clear();
|
|
auto sizes = splitter->sizes();
|
|
bool first = true;
|
|
for(int i=0,c=splitter->count(); i<c; ++i) {
|
|
auto dock = dockWidget(i);
|
|
if (!dock)
|
|
continue;
|
|
if(dock->objectName().size()) {
|
|
os << dock->objectName().toUtf8().constData() << ",";
|
|
if (first)
|
|
first = false;
|
|
else
|
|
os2 << ",";
|
|
os2 << sizes[i];
|
|
}
|
|
_sizemap[dock] = sizes[i];
|
|
}
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetASCII("Widgets", os.str().c_str());
|
|
hGrp->SetASCII("Sizes", os2.str().c_str());
|
|
FC_LOG("save " << objectName().toUtf8().constData() << " " << os2.str());
|
|
}
|
|
|
|
void OverlayTabWidget::onTabMoved(int from, int to)
|
|
{
|
|
QWidget *w = splitter->widget(from);
|
|
splitter->insertWidget(to,w);
|
|
saveTabs();
|
|
}
|
|
|
|
void OverlayTabWidget::setTitleBar(QWidget *w)
|
|
{
|
|
titleBar = w;
|
|
}
|
|
|
|
void OverlayTabWidget::changeEvent(QEvent *e)
|
|
{
|
|
QTabWidget::changeEvent(e);
|
|
if (e->type() == QEvent::LanguageChange)
|
|
retranslate();
|
|
}
|
|
|
|
void OverlayTabWidget::retranslate()
|
|
{
|
|
actTransparent.setToolTip(tr("Toggle transparent mode"));
|
|
actNoAutoMode.setText(tr("None"));
|
|
actNoAutoMode.setToolTip(tr("Turn off auto hide/show"));
|
|
actAutoHide.setText(tr("Auto hide"));
|
|
actAutoHide.setToolTip(tr("Auto hide docked widgets on leave"));
|
|
actEditHide.setText(tr("Hide on edit"));
|
|
actEditHide.setToolTip(tr("Auto hide docked widgets on editing"));
|
|
actEditShow.setText(tr("Show on edit"));
|
|
actEditShow.setToolTip(tr("Auto show docked widgets on editing"));
|
|
actTaskShow.setText(tr("Auto task"));
|
|
actTaskShow.setToolTip(tr("Auto show task view for any current task, and hide the view when there is no task."));
|
|
actOverlay.setToolTip(tr("Toggle overlay"));
|
|
syncAutoMode();
|
|
}
|
|
|
|
void OverlayTabWidget::syncAutoMode()
|
|
{
|
|
auto curStyleSheet =
|
|
App::GetApplication()
|
|
.GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow")
|
|
->GetASCII("StyleSheet", "None");
|
|
|
|
QAction* action = nullptr;
|
|
switch (autoMode) {
|
|
case AutoMode::AutoHide:
|
|
action = &actAutoHide;
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_lighter.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
action->setIcon(pxAutoHideMode);
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
|
|
}
|
|
else {
|
|
QPixmap pxAutoHideMode = BitmapFactory().pixmap("qss:overlay/icons/autohide.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
action->setIcon(pxAutoHideMode);
|
|
actNoAutoMode.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
|
|
actTaskShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
|
|
actEditShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
|
|
actEditHide.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
|
|
}
|
|
break;
|
|
case AutoMode::EditShow:
|
|
action = &actEditShow;
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
QPixmap pxEditShowMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/editshow_lighter.svg");
|
|
action->setIcon(pxEditShowMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
|
|
}
|
|
else {
|
|
QPixmap pxEditShowMode = BitmapFactory().pixmap("qss:overlay/icons/editshow.svg");
|
|
action->setIcon(pxEditShowMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actNoAutoMode.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
|
|
actTaskShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
|
|
actEditHide.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
|
|
}
|
|
break;
|
|
case AutoMode::TaskShow:
|
|
action = &actTaskShow;
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
QPixmap pxTaskShowMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/taskshow_lighter.svg");
|
|
action->setIcon(pxTaskShowMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
|
|
}
|
|
else {
|
|
QPixmap pxTaskShowMode = BitmapFactory().pixmap("qss:overlay/icons/taskshow.svg");
|
|
action->setIcon(pxTaskShowMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actNoAutoMode.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
|
|
actEditShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actEditHide.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
|
|
}
|
|
break;
|
|
case AutoMode::EditHide:
|
|
action = &actEditHide;
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
QPixmap pxEditHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/edithide_lighter.svg");
|
|
action->setIcon(pxEditHideMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
|
|
}
|
|
else {
|
|
QPixmap pxEditHideMode = BitmapFactory().pixmap("qss:overlay/icons/edithide.svg");
|
|
action->setIcon(pxEditHideMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actNoAutoMode.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
|
|
actEditShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actTaskShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
|
|
}
|
|
break;
|
|
default:
|
|
action = &actNoAutoMode;
|
|
if (isStyleSheetDark(curStyleSheet)) {
|
|
QPixmap pxNoAutoMode = BitmapFactory().pixmap("qss:overlay/icons/mode_lighter.svg");
|
|
action->setIcon(pxNoAutoMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
|
|
actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
|
|
}
|
|
else {
|
|
QPixmap pxNoAutoMode = BitmapFactory().pixmap("qss:overlay/icons/mode.svg");
|
|
action->setIcon(pxNoAutoMode);
|
|
QPixmap pxAutoHideMode =
|
|
BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
|
|
pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
|
|
actTaskShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
|
|
actEditShow.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
|
|
actAutoHide.setIcon(pxAutoHideMode);
|
|
actEditHide.setIcon(
|
|
BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
|
|
}
|
|
break;
|
|
}
|
|
actAutoMode.setIcon(action->icon());
|
|
if (action == &actNoAutoMode) {
|
|
actAutoMode.setToolTip(tr("Select auto show/hide mode"));
|
|
}
|
|
else {
|
|
actAutoMode.setToolTip(action->toolTip());
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::onAction(QAction *action)
|
|
{
|
|
if (action == &actAutoMode) {
|
|
action = autoModeMenu.exec(QCursor::pos());
|
|
if (action == &actNoAutoMode)
|
|
setAutoMode(AutoMode::NoAutoMode);
|
|
else if (action == &actAutoHide)
|
|
setAutoMode(AutoMode::AutoHide);
|
|
else if (action == &actEditShow)
|
|
setAutoMode(AutoMode::EditShow);
|
|
else if (action == &actTaskShow)
|
|
setAutoMode(AutoMode::TaskShow);
|
|
else if (action == &actEditHide)
|
|
setAutoMode(AutoMode::EditHide);
|
|
return;
|
|
}
|
|
else if(action == &actOverlay) {
|
|
OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleActive);
|
|
return;
|
|
} else if(action == &actTransparent) {
|
|
if(hGrp) {
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetBool("Transparent", actTransparent.isChecked());
|
|
}
|
|
}
|
|
OverlayManager::instance()->refresh(this);
|
|
}
|
|
|
|
void OverlayTabWidget::setState(State state)
|
|
{
|
|
if (_state == state)
|
|
return;
|
|
switch(state) {
|
|
case State::Normal:
|
|
if (_state == State::Hidden) {
|
|
// Only unhide through State::Showing, not State::Normal
|
|
return;
|
|
}
|
|
else if (_state == State::Showing) {
|
|
_state = state;
|
|
return;
|
|
}
|
|
// fall through
|
|
case State::Showing:
|
|
_state = state;
|
|
hide();
|
|
if (dockArea == Qt::RightDockWidgetArea)
|
|
setTabPosition(East);
|
|
else if (dockArea == Qt::BottomDockWidgetArea)
|
|
setTabPosition(South);
|
|
if (this->count() == 1)
|
|
tabBar()->hide();
|
|
_graphicsEffectTab->setEnabled(false);
|
|
titleBar->show();
|
|
splitter->show();
|
|
if (state == State::Showing)
|
|
OverlayManager::instance()->refresh(this);
|
|
break;
|
|
case State::Hint:
|
|
if (_state == State::HintHidden || _state == State::Hidden)
|
|
break;
|
|
_state = state;
|
|
if (this->count() && OverlayParams::getDockOverlayHintTabBar()) {
|
|
tabBar()->setToolTip(proxyWidget->toolTip());
|
|
tabBar()->show();
|
|
titleBar->hide();
|
|
splitter->hide();
|
|
_graphicsEffectTab->setEnabled(true);
|
|
show();
|
|
raise();
|
|
proxyWidget->raise();
|
|
if (dockArea == Qt::RightDockWidgetArea)
|
|
setTabPosition(West);
|
|
else if (dockArea == Qt::BottomDockWidgetArea)
|
|
setTabPosition(North);
|
|
OverlayManager::instance()->refresh(this);
|
|
}
|
|
break;
|
|
case State::HintHidden:
|
|
if (_state != State::Hidden)
|
|
_state = state;
|
|
proxyWidget->hide();
|
|
hide();
|
|
_graphicsEffectTab->setEnabled(true);
|
|
break;
|
|
case State::Hidden:
|
|
startHide();
|
|
_state = state;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool OverlayTabWidget::checkAutoHide() const
|
|
{
|
|
if(autoMode == AutoMode::AutoHide)
|
|
return true;
|
|
|
|
if(OverlayParams::getDockOverlayAutoView()) {
|
|
auto view = getMainWindow()->activeWindow();
|
|
if (!view) return true;
|
|
if(!view->onHasMsg("CanPan")
|
|
&& view->parentWidget()
|
|
&& view->parentWidget()->isMaximized())
|
|
return true;
|
|
}
|
|
|
|
if(autoMode == AutoMode::EditShow) {
|
|
return !Application::Instance->editDocument()
|
|
&& (!Control().taskPanel() || Control().taskPanel()->isEmpty(false));
|
|
}
|
|
|
|
if(autoMode == AutoMode::EditHide && Application::Instance->editDocument())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void OverlayTabWidget::leaveEvent(QEvent*)
|
|
{
|
|
if (titleBar && QWidget::mouseGrabber() == titleBar)
|
|
return;
|
|
OverlayManager::instance()->refresh();
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
void OverlayTabWidget::enterEvent(QEvent*)
|
|
#else
|
|
void OverlayTabWidget::enterEvent(QEnterEvent*)
|
|
#endif
|
|
{
|
|
revealTime = QTime();
|
|
OverlayManager::instance()->refresh();
|
|
}
|
|
|
|
void OverlayTabWidget::setRevealTime(const QTime &time)
|
|
{
|
|
revealTime = time;
|
|
}
|
|
|
|
void OverlayTabWidget::_setOverlayMode(QWidget *widget, OverlayOption option)
|
|
{
|
|
if(!widget)
|
|
return;
|
|
|
|
#if QT_VERSION>QT_VERSION_CHECK(5,12,2) && QT_VERSION < QT_VERSION_CHECK(5,12,6)
|
|
// Work around Qt bug https://bugreports.qt.io/browse/QTBUG-77006
|
|
widget->setStyleSheet(OverlayManager::instance()->getStyleSheet());
|
|
#endif
|
|
|
|
if (qobject_cast<QScrollBar*>(widget)) {
|
|
auto parent = widget->parentWidget();
|
|
if (parent) {
|
|
parent = parent->parentWidget();
|
|
if (qobject_cast<PropertyEditor::PropertyEditor*>(parent)) {
|
|
auto scrollArea = static_cast<QAbstractScrollArea*>(parent);
|
|
if (scrollArea->verticalScrollBar() == widget) {
|
|
if (!OverlayParams::getDockOverlayHidePropertyViewScrollBar()
|
|
|| option == OverlayOption::Disable)
|
|
widget->setStyleSheet(QString());
|
|
else {
|
|
static QString _style = QStringLiteral("*{width:0}");
|
|
widget->setStyleSheet(_style);
|
|
}
|
|
}
|
|
}
|
|
auto treeView = qobject_cast<TreeWidget*>(parent);
|
|
if (treeView) {
|
|
auto scrollArea = static_cast<QAbstractScrollArea*>(parent);
|
|
if (scrollArea->verticalScrollBar() == widget) {
|
|
if (!TreeParams::getHideScrollBar() || option == OverlayOption::Disable)
|
|
widget->setStyleSheet(QString());
|
|
else {
|
|
static QString _style = QStringLiteral("*{width:0}");
|
|
widget->setStyleSheet(_style);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (treeView) {
|
|
auto header = treeView->header();
|
|
if (!TreeParams::getHideHeaderView() || option==OverlayOption::Disable)
|
|
header->setStyleSheet(QString());
|
|
else {
|
|
static QString _style = QStringLiteral(
|
|
"QHeaderView:section {"
|
|
"height: 0px;"
|
|
"background-color: transparent;"
|
|
"padding: 0px;"
|
|
"border: transparent;}");
|
|
header->setStyleSheet(_style);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto tabbar = qobject_cast<QTabBar*>(widget);
|
|
if(tabbar) {
|
|
if(!tabbar->autoHide() || tabbar->count()>1) {
|
|
if(!OverlayManager::instance()->getHideTab())
|
|
tabbar->setVisible(true);
|
|
else
|
|
tabbar->setVisible(option == OverlayOption::Disable
|
|
|| (option == OverlayOption::ShowTab && tabbar->count()>1));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!qobject_cast<QScrollArea*>(widget)
|
|
|| !qobject_cast<Dialog::Clipping*>(widget->parentWidget())) {
|
|
if(option != OverlayOption::Disable) {
|
|
widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint);
|
|
} else {
|
|
widget->setWindowFlags(widget->windowFlags() & ~Qt::FramelessWindowHint);
|
|
}
|
|
widget->setAttribute(Qt::WA_NoSystemBackground, option != OverlayOption::Disable);
|
|
widget->setAttribute(Qt::WA_TranslucentBackground, option != OverlayOption::Disable);
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::setOverlayMode(QWidget *widget, OverlayOption option)
|
|
{
|
|
if(!widget || (qobject_cast<QDialog*>(widget)
|
|
&& !qobject_cast<Dialog::Clipping*>(widget))
|
|
|| qobject_cast<TaskView::TaskBox*>(widget))
|
|
return;
|
|
|
|
if(widget != tabBar()) {
|
|
if(OverlayParams::getDockOverlayAutoMouseThrough()
|
|
&& option == OverlayOption::ShowTab) {
|
|
widget->setMouseTracking(true);
|
|
}
|
|
}
|
|
|
|
_setOverlayMode(widget, option);
|
|
|
|
if(qobject_cast<QComboBox*>(widget)) {
|
|
// do not set child QAbstractItemView of QComboBox, otherwise the drop down box
|
|
// won't be shown
|
|
return;
|
|
}
|
|
for(auto child : widget->children())
|
|
setOverlayMode(qobject_cast<QWidget*>(child), option);
|
|
}
|
|
|
|
void OverlayTabWidget::setTransparent(bool enable)
|
|
{
|
|
if(actTransparent.isChecked() == enable)
|
|
return;
|
|
if(hGrp) {
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetBool("Transparent", enable);
|
|
}
|
|
actTransparent.setChecked(enable);
|
|
OverlayManager::instance()->refresh(this);
|
|
}
|
|
|
|
bool OverlayTabWidget::isTransparent() const
|
|
{
|
|
if (!actTransparent.isChecked())
|
|
return false;
|
|
if(OverlayParams::getDockOverlayAutoView()) {
|
|
auto view = getMainWindow()->activeWindow();
|
|
if (!view) return false;
|
|
if(!view->onHasMsg("CanPan")
|
|
&& view->parentWidget()
|
|
&& view->parentWidget()->isMaximized())
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool OverlayTabWidget::isOverlaid(QueryOption option) const
|
|
{
|
|
if (option != QueryOption::QueryOverlay
|
|
&& currentTransparent != isTransparent())
|
|
return option == QueryOption::TransparencyChanged;
|
|
return overlaid;
|
|
}
|
|
|
|
void OverlayTabWidget::setAutoMode(AutoMode mode)
|
|
{
|
|
if (autoMode == mode)
|
|
return;
|
|
autoMode = mode;
|
|
|
|
if (hGrp) {
|
|
bool autohide = false, editshow = false, edithide = false, taskshow = false;
|
|
switch (mode) {
|
|
case AutoMode::AutoHide:
|
|
autohide = true;
|
|
break;
|
|
case AutoMode::EditShow:
|
|
editshow = true;
|
|
break;
|
|
case AutoMode::EditHide:
|
|
edithide = true;
|
|
break;
|
|
case AutoMode::TaskShow:
|
|
taskshow = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetBool("AutoHide", autohide);
|
|
hGrp->SetBool("EditShow", editshow);
|
|
hGrp->SetBool("EditHide", edithide);
|
|
hGrp->SetBool("TaskShow", taskshow);
|
|
}
|
|
syncAutoMode();
|
|
OverlayManager::instance()->refresh(this);
|
|
}
|
|
|
|
QDockWidget *OverlayTabWidget::currentDockWidget() const
|
|
{
|
|
int index = -1;
|
|
for(int size : splitter->sizes()) {
|
|
++index;
|
|
if(size>0)
|
|
return dockWidget(index);
|
|
}
|
|
return dockWidget(currentIndex());
|
|
}
|
|
|
|
QDockWidget *OverlayTabWidget::dockWidget(int index) const
|
|
{
|
|
if(index < 0 || index >= splitter->count())
|
|
return nullptr;
|
|
return qobject_cast<QDockWidget*>(splitter->widget(index));
|
|
}
|
|
|
|
void OverlayTabWidget::updateSplitterHandles()
|
|
{
|
|
if (overlaid || _state > State::Normal)
|
|
return;
|
|
for (int i=0, c=splitter->count(); i<c; ++i) {
|
|
auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
|
|
if (handle)
|
|
handle->showTitle(true);
|
|
}
|
|
}
|
|
|
|
bool OverlayTabWidget::onEscape()
|
|
{
|
|
if (getState() == OverlayTabWidget::State::Hint
|
|
|| getState() == OverlayTabWidget::State::Hidden) {
|
|
setState(OverlayTabWidget::State::HintHidden);
|
|
return true;
|
|
}
|
|
if (!isVisible())
|
|
return false;
|
|
if (titleBar->isVisible() && titleBar->underMouse()) {
|
|
titleBar->hide();
|
|
return true;
|
|
}
|
|
for (int i=0, c=splitter->count(); i<c; ++i) {
|
|
auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
|
|
if (handle->isVisible() && handle->underMouse()) {
|
|
handle->showTitle(false);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void OverlayTabWidget::setOverlayMode(bool enable)
|
|
{
|
|
overlaid = enable;
|
|
|
|
if(!isVisible() || !count())
|
|
return;
|
|
|
|
touched = false;
|
|
|
|
if (_state <= State::Normal) {
|
|
titleBar->setVisible(!enable || OverlayManager::instance()->isMouseTransparent());
|
|
for (int i=0, c=splitter->count(); i<c; ++i) {
|
|
auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
|
|
if (handle)
|
|
handle->showTitle(!enable);
|
|
}
|
|
}
|
|
|
|
QString stylesheet;
|
|
stylesheet = OverlayManager::instance()->getStyleSheet();
|
|
currentTransparent = isTransparent();
|
|
|
|
OverlayOption option;
|
|
if(!enable && isTransparent()) {
|
|
option = OverlayOption::ShowTab;
|
|
} else if (enable
|
|
&& !isTransparent()
|
|
&& (autoMode == AutoMode::EditShow || autoMode == AutoMode::AutoHide)) {
|
|
option = OverlayOption::Disable;
|
|
} else {
|
|
option = enable?OverlayOption::Enable:OverlayOption::Disable;
|
|
}
|
|
setProperty("transparent", option != OverlayOption::Disable);
|
|
|
|
proxyWidget->setStyleSheet(stylesheet);
|
|
this->setStyleSheet(stylesheet);
|
|
setOverlayMode(this, option);
|
|
|
|
_graphicsEffect->setEnabled(effectEnabled() && (enable || isTransparent()));
|
|
|
|
if (_state == State::Hint && OverlayParams::getDockOverlayHintTabBar()) {
|
|
tabBar()->setToolTip(proxyWidget->toolTip());
|
|
tabBar()->show();
|
|
} else if (OverlayParams::getDockOverlayHideTabBar() || count()==1) {
|
|
tabBar()->hide();
|
|
} else {
|
|
tabBar()->setToolTip(QString());
|
|
tabBar()->setVisible(!enable || !OverlayManager::instance()->getHideTab());
|
|
}
|
|
|
|
setRect(rectOverlay);
|
|
}
|
|
|
|
const QRect &OverlayTabWidget::getRect()
|
|
{
|
|
return rectOverlay;
|
|
}
|
|
|
|
bool OverlayTabWidget::getAutoHideRect(QRect &rect) const
|
|
{
|
|
rect = rectOverlay;
|
|
int hintWidth = OverlayParams::getDockOverlayHintSize();
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
if (_TopOverlay->isVisible() && _TopOverlay->_state <= State::Normal)
|
|
rect.setTop(std::max(rect.top(), _TopOverlay->rectOverlay.bottom()));
|
|
if (dockArea == Qt::RightDockWidgetArea)
|
|
rect.setLeft(rect.left() + std::max(rect.width()-hintWidth,0));
|
|
else
|
|
rect.setRight(rect.right() - std::max(rect.width()-hintWidth,0));
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::BottomDockWidgetArea:
|
|
if (_LeftOverlay->isVisible() && _LeftOverlay->_state <= State::Normal)
|
|
rect.setLeft(std::max(rect.left(),_LeftOverlay->rectOverlay.right()));
|
|
if (dockArea == Qt::TopDockWidgetArea)
|
|
rect.setBottom(rect.bottom() - std::max(rect.height()-hintWidth,0));
|
|
else {
|
|
rect.setTop(rect.top() + std::max(rect.height()-hintWidth,0));
|
|
if (_RightOverlay->isVisible() && _RightOverlay->_state <= State::Normal) {
|
|
QPoint offset = getMainWindow()->getMdiArea()->pos();
|
|
rect.setRight(std::min(rect.right(), _RightOverlay->x()-offset.x()));
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return _state != State::Showing && overlaid && checkAutoHide();
|
|
}
|
|
|
|
void OverlayTabWidget::setOffset(const QSize &ofs)
|
|
{
|
|
if(offset != ofs) {
|
|
offset = ofs;
|
|
if(hGrp) {
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetInt("Offset1", ofs.width());
|
|
hGrp->SetInt("Offset3", ofs.height());
|
|
}
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::setSizeDelta(int delta)
|
|
{
|
|
if(sizeDelta != delta) {
|
|
if(hGrp) {
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetInt("Offset2", delta);
|
|
}
|
|
sizeDelta = delta;
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::setRect(QRect rect)
|
|
{
|
|
if(busy || !parentWidget() || !getMainWindow() || !getMainWindow()->getMdiArea())
|
|
return;
|
|
|
|
if (rect.width() == 0)
|
|
rect.setWidth(OverlayParams::getDockOverlayMinimumSize()*3);
|
|
if (rect.height() == 0)
|
|
rect.setHeight(OverlayParams::getDockOverlayMinimumSize()*3);
|
|
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
rect.moveLeft(0);
|
|
if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
|
|
rect.setWidth(OverlayParams::getDockOverlayMinimumSize());
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
|
|
rect.setLeft(rect.right()-OverlayParams::getDockOverlayMinimumSize());
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
rect.moveTop(0);
|
|
if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
|
|
rect.setHeight(OverlayParams::getDockOverlayMinimumSize());
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
|
|
rect.setTop(rect.bottom()-OverlayParams::getDockOverlayMinimumSize());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(hGrp && rect.size() != rectOverlay.size()) {
|
|
Base::StateLocker lock(_saving);
|
|
hGrp->SetInt("Width", rect.width());
|
|
hGrp->SetInt("Height", rect.height());
|
|
}
|
|
rectOverlay = rect;
|
|
|
|
QPoint offset = getMainWindow()->getMdiArea()->pos();
|
|
|
|
if(getAutoHideRect(rect) || _state == State::Hint || _state == State::Hidden) {
|
|
QRect rectHint = rect;
|
|
if (_state != State::Hint && _state != State::Hidden)
|
|
startHide();
|
|
else if (count() && OverlayParams::getDockOverlayHintTabBar()) {
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
if (dockArea == Qt::LeftDockWidgetArea)
|
|
rect.setWidth(tabBar()->width());
|
|
else
|
|
rect.setLeft(rect.left() + rect.width() - tabBar()->width());
|
|
rect.setHeight(std::max(rect.height(),
|
|
tabBar()->y() + tabBar()->sizeHint().height() + 5));
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
case Qt::TopDockWidgetArea:
|
|
if (dockArea == Qt::TopDockWidgetArea)
|
|
rect.setHeight(tabBar()->height());
|
|
else
|
|
rect.setTop(rect.top() + rect.height() - tabBar()->height());
|
|
rect.setWidth(std::max(rect.width(),
|
|
tabBar()->x() + tabBar()->sizeHint().width() + 5));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
setGeometry(rect.translated(offset));
|
|
}
|
|
proxyWidget->setGeometry(rectHint.translated(offset));
|
|
if (count()) {
|
|
proxyWidget->show();
|
|
proxyWidget->raise();
|
|
} else
|
|
proxyWidget->hide();
|
|
|
|
} else {
|
|
setGeometry(rectOverlay.translated(offset));
|
|
|
|
for(int i=0, count=splitter->count(); i<count; ++i)
|
|
splitter->widget(i)->show();
|
|
|
|
if(!isVisible() && count()) {
|
|
proxyWidget->hide();
|
|
startShow();
|
|
}
|
|
}
|
|
}
|
|
|
|
void OverlayTabWidget::addWidget(QDockWidget *dock, const QString &title)
|
|
{
|
|
if (!getMainWindow() || !getMainWindow()->getMdiArea())
|
|
return;
|
|
|
|
OverlayManager::instance()->registerDockWidget(dock->objectName(), this);
|
|
|
|
OverlayManager::setFocusView();
|
|
getMainWindow()->removeDockWidget(dock);
|
|
|
|
auto titleWidget = dock->titleBarWidget();
|
|
if(titleWidget && titleWidget->objectName()==QStringLiteral("OverlayTitle")) {
|
|
// replace the title bar with an invisible widget to hide it. The
|
|
// OverlayTabWidget uses its own title bar for all docks.
|
|
auto w = new QWidget();
|
|
w->setObjectName(QStringLiteral("OverlayTitle"));
|
|
dock->setTitleBarWidget(w);
|
|
w->hide();
|
|
titleWidget->deleteLater();
|
|
}
|
|
|
|
dock->show();
|
|
splitter->addWidget(dock);
|
|
auto dummyWidget = new QWidget(this);
|
|
addTab(dummyWidget, title);
|
|
connect(dock, &QObject::destroyed, dummyWidget, &QObject::deleteLater);
|
|
|
|
dock->setFeatures(dock->features() & ~QDockWidget::DockWidgetFloatable);
|
|
if(count() == 1) {
|
|
QRect rect = dock->geometry();
|
|
QSize sizeMain = getMainWindow()->getMdiArea()->size();
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
if (rect.width() > sizeMain.width()/3)
|
|
rect.setWidth(sizeMain.width()/3);
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::BottomDockWidgetArea:
|
|
if (rect.height() > sizeMain.height()/3)
|
|
rect.setHeight(sizeMain.height()/3);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
setRect(rect);
|
|
}
|
|
|
|
saveTabs();
|
|
}
|
|
|
|
int OverlayTabWidget::dockWidgetIndex(QDockWidget *dock) const
|
|
{
|
|
return splitter->indexOf(dock);
|
|
}
|
|
|
|
void OverlayTabWidget::removeWidget(QDockWidget *dock, QDockWidget *lastDock)
|
|
{
|
|
int index = dockWidgetIndex(dock);
|
|
if(index < 0)
|
|
return;
|
|
|
|
OverlayManager::instance()->unregisterDockWidget(dock->objectName(), this);
|
|
|
|
OverlayManager::setFocusView();
|
|
dock->show();
|
|
if(lastDock)
|
|
getMainWindow()->tabifyDockWidget(lastDock, dock);
|
|
else
|
|
getMainWindow()->addDockWidget(dockArea, dock);
|
|
|
|
auto w = this->widget(index);
|
|
removeTab(index);
|
|
w->deleteLater();
|
|
|
|
if(!count())
|
|
hide();
|
|
|
|
w = dock->titleBarWidget();
|
|
if(w && w->objectName() == QStringLiteral("OverlayTitle")) {
|
|
dock->setTitleBarWidget(nullptr);
|
|
w->deleteLater();
|
|
}
|
|
OverlayManager::instance()->setupTitleBar(dock);
|
|
|
|
dock->setFeatures(dock->features() | QDockWidget::DockWidgetFloatable);
|
|
|
|
setOverlayMode(dock, OverlayOption::Disable);
|
|
|
|
saveTabs();
|
|
}
|
|
|
|
void OverlayTabWidget::resizeEvent(QResizeEvent *ev)
|
|
{
|
|
QTabWidget::resizeEvent(ev);
|
|
if (_state <= State::Normal)
|
|
timer.start(10);
|
|
}
|
|
|
|
void OverlayTabWidget::setupLayout()
|
|
{
|
|
if (_state > State::Normal)
|
|
return;
|
|
|
|
if(count() == 1)
|
|
tabSize = 0;
|
|
else {
|
|
int tsize;
|
|
if(dockArea==Qt::LeftDockWidgetArea || dockArea==Qt::RightDockWidgetArea)
|
|
tsize = tabBar()->width();
|
|
else
|
|
tsize = tabBar()->height();
|
|
tabSize = tsize;
|
|
}
|
|
int titleBarSize = widgetMinSize(this, true);
|
|
QRect rect, rectTitle;
|
|
switch(tabPosition()) {
|
|
case West:
|
|
rectTitle = QRect(tabSize, 0, this->width()-tabSize, titleBarSize);
|
|
rect = QRect(rectTitle.left(), rectTitle.bottom(),
|
|
rectTitle.width(), this->height()-rectTitle.height());
|
|
break;
|
|
case East:
|
|
rectTitle = QRect(0, 0, this->width()-tabSize, titleBarSize);
|
|
rect = QRect(rectTitle.left(), rectTitle.bottom(),
|
|
rectTitle.width(), this->height()-rectTitle.height());
|
|
break;
|
|
case North:
|
|
rectTitle = QRect(0, tabSize, titleBarSize, this->height()-tabSize);
|
|
rect = QRect(rectTitle.right(), rectTitle.top(),
|
|
this->width()-rectTitle.width(), rectTitle.height());
|
|
break;
|
|
case South:
|
|
rectTitle = QRect(0, 0, titleBarSize, this->height()-tabSize);
|
|
rect = QRect(rectTitle.right(), rectTitle.top(),
|
|
this->width()-rectTitle.width(), rectTitle.height());
|
|
break;
|
|
}
|
|
if (_animation != 0.0) {
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
rect.moveLeft(rect.left() - _animation * rect.width());
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
rect.moveLeft(rect.left() + _animation * rect.width());
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
rect.moveTop(rect.top() - _animation * rect.height());
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
rect.moveTop(rect.top() + _animation * rect.height());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
splitter->setGeometry(rect);
|
|
titleBar->setGeometry(rectTitle);
|
|
}
|
|
|
|
void OverlayTabWidget::setCurrent(QDockWidget *widget)
|
|
{
|
|
int index = dockWidgetIndex(widget);
|
|
if(index >= 0)
|
|
setCurrentIndex(index);
|
|
}
|
|
|
|
void OverlayTabWidget::onSplitterResize(int index)
|
|
{
|
|
const auto &sizes = splitter->sizes();
|
|
if (index >= 0 && index < sizes.count()) {
|
|
if (sizes[index] == 0) {
|
|
if (currentIndex() == index) {
|
|
bool done = false;
|
|
for (int i=index+1; i<sizes.count(); ++i) {
|
|
if (sizes[i] > 0) {
|
|
setCurrentIndex(i);
|
|
done = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!done) {
|
|
for (int i=index-1; i>=0 ;--i) {
|
|
if (sizes[i] > 0) {
|
|
setCurrentIndex(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
setCurrentIndex(index);
|
|
}
|
|
|
|
saveTabs();
|
|
}
|
|
|
|
void OverlayTabWidget::onCurrentChanged(int index)
|
|
{
|
|
setState(State::Showing);
|
|
|
|
auto sizes = splitter->sizes();
|
|
int i=0;
|
|
int size = splitter->orientation()==Qt::Vertical ?
|
|
height()-tabBar()->height() : width()-tabBar()->width();
|
|
for(auto &s : sizes) {
|
|
if(i++ == index)
|
|
s = size;
|
|
else
|
|
s = 0;
|
|
}
|
|
splitter->setSizes(sizes);
|
|
onSplitterResize(index);
|
|
saveTabs();
|
|
}
|
|
|
|
void OverlayTabWidget::onSizeGripMove(const QPoint &p)
|
|
{
|
|
if (!getMainWindow() || !getMainWindow()->getMdiArea())
|
|
return;
|
|
|
|
QPoint pos = mapFromGlobal(p) + this->pos();
|
|
QPoint offset = getMainWindow()->getMdiArea()->pos();
|
|
QRect rect = this->rectOverlay.translated(offset);
|
|
|
|
switch(dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
if (pos.x() - rect.left() < OverlayParams::getDockOverlayMinimumSize())
|
|
return;
|
|
rect.setRight(pos.x());
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
if (rect.right() - pos.x() < OverlayParams::getDockOverlayMinimumSize())
|
|
return;
|
|
rect.setLeft(pos.x());
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
if (pos.y() - rect.top() < OverlayParams::getDockOverlayMinimumSize())
|
|
return;
|
|
rect.setBottom(pos.y());
|
|
break;
|
|
default:
|
|
if (rect.bottom() - pos.y() < OverlayParams::getDockOverlayMinimumSize())
|
|
return;
|
|
rect.setTop(pos.y());
|
|
break;
|
|
}
|
|
this->setRect(rect.translated(-offset));
|
|
OverlayManager::instance()->refresh();
|
|
}
|
|
|
|
QLayoutItem *OverlayTabWidget::prepareTitleWidget(QWidget *widget, const QList<QAction*> &actions)
|
|
{
|
|
bool vertical = false;
|
|
QBoxLayout *layout = nullptr;
|
|
auto tabWidget = qobject_cast<OverlayTabWidget*>(widget->parentWidget());
|
|
if(!tabWidget) {
|
|
layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
|
|
} else {
|
|
switch(tabWidget->getDockArea()) {
|
|
case Qt::LeftDockWidgetArea:
|
|
layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
layout = new QBoxLayout(QBoxLayout::RightToLeft, widget);
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
layout = new QBoxLayout(QBoxLayout::TopToBottom, widget);
|
|
vertical = true;
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
layout = new QBoxLayout(QBoxLayout::BottomToTop, widget);
|
|
vertical = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
layout->addSpacing(5);
|
|
layout->setContentsMargins(1,1,1,1);
|
|
int buttonSize = widgetMinSize(widget);
|
|
auto spacer = new QSpacerItem(buttonSize,buttonSize,
|
|
vertical?QSizePolicy::Minimum:QSizePolicy::Expanding,
|
|
vertical?QSizePolicy::Expanding:QSizePolicy::Minimum);
|
|
layout->addSpacerItem(spacer);
|
|
|
|
for(auto action : actions)
|
|
layout->addWidget(OverlayTabWidget::createTitleButton(action, buttonSize));
|
|
|
|
if (tabWidget) {
|
|
auto grip = new OverlaySizeGrip(tabWidget, vertical);
|
|
QObject::connect(grip, &OverlaySizeGrip::dragMove,
|
|
tabWidget, &OverlayTabWidget::onSizeGripMove);
|
|
layout->addWidget(grip);
|
|
grip->raise();
|
|
}
|
|
|
|
return spacer;
|
|
}
|
|
|
|
bool OverlayTabWidget::isStyleSheetDark(std::string curStyleSheet)
|
|
{
|
|
if (curStyleSheet.find("dark") != std::string::npos
|
|
|| curStyleSheet.find("Dark") != std::string::npos) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
QPixmap OverlayTabWidget::rotateAutoHideIcon(QPixmap pxAutoHide, Qt::DockWidgetArea dockArea)
|
|
{
|
|
switch (dockArea) {
|
|
case Qt::LeftDockWidgetArea:
|
|
return pxAutoHide;
|
|
break;
|
|
case Qt::RightDockWidgetArea:
|
|
return pxAutoHide.transformed(QTransform().scale(-1, 1));
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
return pxAutoHide.transformed(QTransform().rotate(90));
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
return pxAutoHide.transformed(QTransform().rotate(-90));
|
|
break;
|
|
default:
|
|
return pxAutoHide;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlayTitleBar::OverlayTitleBar(QWidget * parent)
|
|
:QWidget(parent)
|
|
{
|
|
setFocusPolicy(Qt::ClickFocus);
|
|
setMouseTracking(true);
|
|
setCursor(Qt::OpenHandCursor);
|
|
}
|
|
|
|
void OverlayTitleBar::setTitleItem(QLayoutItem *item)
|
|
{
|
|
titleItem = item;
|
|
}
|
|
|
|
void OverlayTitleBar::paintEvent(QPaintEvent *)
|
|
{
|
|
if (!titleItem)
|
|
return;
|
|
|
|
QDockWidget *dock = qobject_cast<QDockWidget*>(parentWidget());
|
|
int vertical = false;
|
|
int flags = Qt::AlignCenter;
|
|
if (!dock) {
|
|
OverlayTabWidget *tabWidget = qobject_cast<OverlayTabWidget*>(parentWidget());
|
|
if (tabWidget) {
|
|
switch(tabWidget->getDockArea()) {
|
|
case Qt::TopDockWidgetArea:
|
|
vertical = true;
|
|
// fallthrough
|
|
case Qt::RightDockWidgetArea:
|
|
flags = Qt::AlignRight;
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
vertical = true;
|
|
// fallthrough
|
|
case Qt::LeftDockWidgetArea:
|
|
flags = Qt::AlignLeft;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dock = tabWidget->dockWidget(0);
|
|
}
|
|
}
|
|
if (!dock)
|
|
return;
|
|
|
|
QPainter painter(this);
|
|
if (qobject_cast<OverlayTabWidget*>(parentWidget()))
|
|
painter.fillRect(this->rect(), painter.background());
|
|
|
|
QRect r = titleItem->geometry();
|
|
if (vertical) {
|
|
r = r.transposed();
|
|
painter.translate(r.left(), r.top() + r.width());
|
|
painter.rotate(-90);
|
|
painter.translate(-r.left(), -r.top());
|
|
}
|
|
|
|
QString title;
|
|
if (OverlayManager::instance()->isMouseTransparent()) {
|
|
if (timerId == 0)
|
|
timerId = startTimer(500);
|
|
title = blink ? tr("Mouse pass through, ESC to stop") : dock->windowTitle();
|
|
} else {
|
|
if (timerId != 0) {
|
|
killTimer(timerId);
|
|
timerId = 0;
|
|
}
|
|
title = dock->windowTitle();
|
|
}
|
|
QString text = painter.fontMetrics().elidedText(
|
|
title, Qt::ElideRight, r.width());
|
|
painter.drawText(r, flags, text);
|
|
}
|
|
|
|
void OverlayTitleBar::timerEvent(QTimerEvent *ev)
|
|
{
|
|
if (timerId == ev->timerId()) {
|
|
update();
|
|
blink = !blink;
|
|
}
|
|
}
|
|
|
|
static inline bool
|
|
isNear(const QPoint &a, const QPoint &b, int tol = 16)
|
|
{
|
|
QPoint d = a - b;
|
|
return d.x()*d.x() + d.y()*d.y() < tol;
|
|
}
|
|
|
|
void OverlayTitleBar::endDrag()
|
|
{
|
|
if (OverlayTabWidget::_Dragging == this) {
|
|
OverlayTabWidget::_Dragging = nullptr;
|
|
setCursor(Qt::OpenHandCursor);
|
|
if (OverlayTabWidget::_DragFrame)
|
|
OverlayTabWidget::_DragFrame->hide();
|
|
if (OverlayTabWidget::_DragFloating)
|
|
OverlayTabWidget::_DragFrame->hide();
|
|
}
|
|
}
|
|
|
|
void OverlayTitleBar::mouseMoveEvent(QMouseEvent *me)
|
|
{
|
|
if (ignoreMouse) {
|
|
if (!(me->buttons() & Qt::LeftButton))
|
|
ignoreMouse = false;
|
|
else {
|
|
me->ignore();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (OverlayTabWidget::_Dragging != this && mouseMovePending && (me->buttons() & Qt::LeftButton)) {
|
|
if (isNear(dragOffset, me->pos()))
|
|
return;
|
|
mouseMovePending = false;
|
|
OverlayTabWidget::_Dragging = this;
|
|
}
|
|
|
|
if (OverlayTabWidget::_Dragging != this)
|
|
return;
|
|
|
|
if (!(me->buttons() & Qt::LeftButton)) {
|
|
endDrag();
|
|
return;
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
QPoint point = me->globalPos();
|
|
#else
|
|
QPoint point = me->globalPosition().toPoint();
|
|
#endif
|
|
|
|
OverlayManager::instance()->dragDockWidget(point,
|
|
parentWidget(),
|
|
dragOffset,
|
|
dragSize);
|
|
}
|
|
|
|
void OverlayTitleBar::mousePressEvent(QMouseEvent *me)
|
|
{
|
|
mouseMovePending = false;
|
|
QWidget *parent = parentWidget();
|
|
if (OverlayTabWidget::_Dragging || !parent || !getMainWindow() || me->button() != Qt::LeftButton)
|
|
return;
|
|
|
|
dragSize = parent->size();
|
|
OverlayTabWidget *tabWidget = qobject_cast<OverlayTabWidget*>(parent);
|
|
if (!tabWidget) {
|
|
if(QApplication::queryKeyboardModifiers() == Qt::ShiftModifier) {
|
|
ignoreMouse = true;
|
|
me->ignore();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
for (int s : tabWidget->getSplitter()->sizes()) {
|
|
if (!s)
|
|
continue;
|
|
if (tabWidget == OverlayTabWidget::_TopOverlay
|
|
|| tabWidget == OverlayTabWidget::_BottomOverlay) {
|
|
dragSize.setWidth(s + this->width());
|
|
dragSize.setHeight(tabWidget->height());
|
|
}
|
|
else {
|
|
dragSize.setHeight(s + this->height());
|
|
dragSize.setWidth(tabWidget->width());
|
|
}
|
|
}
|
|
}
|
|
ignoreMouse = false;
|
|
QSize mwSize = getMainWindow()->size();
|
|
dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
|
|
static_cast<long>(std::min(mwSize.width()/2, dragSize.width()))));
|
|
dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
|
|
static_cast<long>(std::min(mwSize.height()/2, dragSize.height()))));
|
|
|
|
dragOffset = me->pos();
|
|
setCursor(Qt::ClosedHandCursor);
|
|
mouseMovePending = true;
|
|
}
|
|
|
|
void OverlayTitleBar::mouseReleaseEvent(QMouseEvent *me)
|
|
{
|
|
if (ignoreMouse) {
|
|
me->ignore();
|
|
return;
|
|
}
|
|
|
|
setCursor(Qt::OpenHandCursor);
|
|
mouseMovePending = false;
|
|
if (OverlayTabWidget::_Dragging != this)
|
|
return;
|
|
|
|
if (me->button() != Qt::LeftButton)
|
|
return;
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
QPoint point = me->globalPos();
|
|
#else
|
|
QPoint point = me->globalPosition().toPoint();
|
|
#endif
|
|
|
|
OverlayTabWidget::_Dragging = nullptr;
|
|
OverlayManager::instance()->dragDockWidget(point,
|
|
parentWidget(),
|
|
dragOffset,
|
|
dragSize,
|
|
true);
|
|
if (OverlayTabWidget::_DragFrame)
|
|
OverlayTabWidget::_DragFrame->hide();
|
|
if (OverlayTabWidget::_DragFloating)
|
|
OverlayTabWidget::_DragFloating->hide();
|
|
}
|
|
|
|
void OverlayTitleBar::keyPressEvent(QKeyEvent *ke)
|
|
{
|
|
if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
|
|
endDrag();
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlayDragFrame::OverlayDragFrame(QWidget * parent)
|
|
:QWidget(parent)
|
|
{
|
|
}
|
|
|
|
void OverlayDragFrame::paintEvent(QPaintEvent *)
|
|
{
|
|
QPainter painter(this);
|
|
painter.drawRect(0, 0, this->width()-1, this->height()-1);
|
|
painter.setOpacity(0.3);
|
|
painter.setBrush(QBrush(Qt::blue));
|
|
painter.drawRect(0, 0, this->width()-1, this->height()-1);
|
|
}
|
|
|
|
QSize OverlayDragFrame::sizeHint() const
|
|
{
|
|
return size();
|
|
}
|
|
|
|
QSize OverlayDragFrame::minimumSizeHint() const
|
|
{
|
|
return minimumSize();
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlaySizeGrip::OverlaySizeGrip(QWidget * parent, bool vertical)
|
|
:QWidget(parent), vertical(vertical)
|
|
{
|
|
if (vertical) {
|
|
this->setFixedHeight(6);
|
|
this->setMinimumWidth(widgetMinSize(this,true));
|
|
this->setCursor(Qt::SizeVerCursor);
|
|
}
|
|
else {
|
|
this->setFixedWidth(6);
|
|
this->setMinimumHeight(widgetMinSize(this,true));
|
|
this->setCursor(Qt::SizeHorCursor);
|
|
}
|
|
setMouseTracking(true);
|
|
}
|
|
|
|
void OverlaySizeGrip::paintEvent(QPaintEvent*)
|
|
{
|
|
QPainter painter(this);
|
|
painter.setPen(Qt::transparent);
|
|
painter.setOpacity(0.5);
|
|
painter.setBrush(QBrush(Qt::black, Qt::Dense6Pattern));
|
|
QRect rect(this->rect());
|
|
painter.drawRect(rect);
|
|
}
|
|
|
|
void OverlaySizeGrip::mouseMoveEvent(QMouseEvent *me)
|
|
{
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
QPoint point = me->globalPos();
|
|
#else
|
|
QPoint point = me->globalPosition().toPoint();
|
|
#endif
|
|
|
|
if ((me->buttons() & Qt::LeftButton)) {
|
|
Q_EMIT dragMove(point);
|
|
}
|
|
}
|
|
|
|
void OverlaySizeGrip::mousePressEvent(QMouseEvent *)
|
|
{
|
|
}
|
|
|
|
void OverlaySizeGrip::mouseReleaseEvent(QMouseEvent *)
|
|
{
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlaySplitter::OverlaySplitter(QWidget *parent)
|
|
: QSplitter(parent)
|
|
{
|
|
}
|
|
|
|
QSplitterHandle * OverlaySplitter::createHandle()
|
|
{
|
|
auto widget = new OverlaySplitterHandle(this->orientation(), this);
|
|
widget->setObjectName(QStringLiteral("OverlaySplitHandle"));
|
|
QList<QAction*> actions;
|
|
actions.append(&widget->actFloat);
|
|
widget->setTitleItem(OverlayTabWidget::prepareTitleWidget(widget, actions));
|
|
return widget;
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlaySplitterHandle::OverlaySplitterHandle(Qt::Orientation orientation, QSplitter *parent)
|
|
: QSplitterHandle(orientation, parent)
|
|
{
|
|
setMouseTracking(true);
|
|
setFocusPolicy(Qt::ClickFocus);
|
|
retranslate();
|
|
refreshIcons();
|
|
QObject::connect(&actFloat, &QAction::triggered, this, &OverlaySplitterHandle::onAction);
|
|
timer.setSingleShot(true);
|
|
QObject::connect(&timer, &QTimer::timeout, this, &OverlaySplitterHandle::onTimer);
|
|
}
|
|
|
|
void OverlaySplitterHandle::refreshIcons()
|
|
{
|
|
actFloat.setIcon(BitmapFactory().pixmap("qss:overlay/icons/float.svg"));
|
|
}
|
|
|
|
void OverlaySplitterHandle::onTimer()
|
|
{
|
|
if (isVisible() && qApp->widgetAt(QCursor::pos()) != this)
|
|
showTitle(false);
|
|
}
|
|
|
|
void OverlaySplitterHandle::showEvent(QShowEvent *ev)
|
|
{
|
|
if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
|
|
&& qApp->widgetAt(QCursor::pos()) != this)
|
|
timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
|
|
QSplitterHandle::showEvent(ev);
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
void OverlaySplitterHandle::enterEvent(QEvent *ev)
|
|
#else
|
|
void OverlaySplitterHandle::enterEvent(QEnterEvent *ev)
|
|
#endif
|
|
{
|
|
timer.stop();
|
|
QSplitterHandle::enterEvent(ev);
|
|
}
|
|
|
|
void OverlaySplitterHandle::leaveEvent(QEvent *ev)
|
|
{
|
|
if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0)
|
|
timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
|
|
QSplitterHandle::leaveEvent(ev);
|
|
}
|
|
|
|
QSize OverlaySplitterHandle::sizeHint() const
|
|
{
|
|
QSize size = QSplitterHandle::sizeHint();
|
|
int minSize = widgetMinSize(this,true);
|
|
if (this->orientation() == Qt::Vertical)
|
|
size.setHeight(std::max(minSize, size.height()));
|
|
else
|
|
size.setWidth(std::max(minSize, size.width()));
|
|
return size;
|
|
}
|
|
|
|
void OverlaySplitterHandle::onAction()
|
|
{
|
|
auto action = qobject_cast<QAction*>(sender());
|
|
if(action == &actFloat) {
|
|
QDockWidget *dock = dockWidget();
|
|
if (dock)
|
|
OverlayManager::instance()->floatDockWidget(dock);
|
|
}
|
|
}
|
|
|
|
QDockWidget *OverlaySplitterHandle::dockWidget()
|
|
{
|
|
QSplitter *parent = splitter();
|
|
if (!parent)
|
|
return nullptr;
|
|
|
|
if (parent->handle(this->idx) != this) {
|
|
this->idx = -1;
|
|
for (int i=0, c=parent->count(); i<c; ++i) {
|
|
if (parent->handle(i) == this) {
|
|
this->idx = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return qobject_cast<QDockWidget*>(parent->widget(this->idx));
|
|
}
|
|
|
|
void OverlaySplitterHandle::retranslate()
|
|
{
|
|
actFloat.setToolTip(QObject::tr("Toggle floating window"));
|
|
}
|
|
|
|
void OverlaySplitterHandle::changeEvent(QEvent *e)
|
|
{
|
|
QSplitterHandle::changeEvent(e);
|
|
if (e->type() == QEvent::LanguageChange)
|
|
retranslate();
|
|
}
|
|
|
|
void OverlaySplitterHandle::setTitleItem(QLayoutItem *item)
|
|
{
|
|
titleItem = item;
|
|
}
|
|
|
|
void OverlaySplitterHandle::showTitle(bool enable)
|
|
{
|
|
if (_showTitle == enable)
|
|
return;
|
|
if (!enable)
|
|
unsetCursor();
|
|
else {
|
|
setCursor(this->orientation() == Qt::Horizontal
|
|
? Qt::SizeHorCursor : Qt::SizeVerCursor);
|
|
if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
|
|
&& qApp->widgetAt(QCursor::pos()) != this)
|
|
timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
|
|
}
|
|
_showTitle = enable;
|
|
for (auto child : findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly))
|
|
child->setVisible(enable);
|
|
update();
|
|
}
|
|
|
|
void OverlaySplitterHandle::paintEvent(QPaintEvent *e)
|
|
{
|
|
if (!_showTitle)
|
|
return;
|
|
|
|
if (!titleItem) {
|
|
QSplitterHandle::paintEvent(e);
|
|
return;
|
|
}
|
|
|
|
int flags = Qt::AlignCenter;
|
|
auto tabWidget = qobject_cast<OverlayTabWidget*>(
|
|
splitter() ? splitter()->parentWidget() : nullptr);
|
|
|
|
if (tabWidget) {
|
|
switch(tabWidget->getDockArea()) {
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
flags = Qt::AlignRight;
|
|
break;
|
|
case Qt::BottomDockWidgetArea:
|
|
case Qt::LeftDockWidgetArea:
|
|
flags = Qt::AlignLeft;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
QDockWidget *dock = dockWidget();
|
|
if (!dock) {
|
|
QSplitterHandle::paintEvent(e);
|
|
return;
|
|
}
|
|
|
|
QPainter painter(this);
|
|
painter.fillRect(this->rect(), painter.background());
|
|
|
|
QRect r = titleItem->geometry();
|
|
if (this->orientation() != Qt::Vertical) {
|
|
r = r.transposed();
|
|
painter.translate(r.left(), r.top() + r.width());
|
|
painter.rotate(-90);
|
|
painter.translate(-r.left(), -r.top());
|
|
}
|
|
QString text = painter.fontMetrics().elidedText(
|
|
dock->windowTitle(), Qt::ElideRight, r.width());
|
|
|
|
painter.drawText(r, flags, text);
|
|
}
|
|
|
|
void OverlaySplitterHandle::endDrag()
|
|
{
|
|
auto tabWidget = qobject_cast<OverlayTabWidget*>(splitter()->parentWidget());
|
|
if (tabWidget) {
|
|
dockWidget();
|
|
tabWidget->onSplitterResize(this->idx);
|
|
}
|
|
OverlayTabWidget::_Dragging = nullptr;
|
|
setCursor(this->orientation() == Qt::Horizontal
|
|
? Qt::SizeHorCursor : Qt::SizeVerCursor);
|
|
if (OverlayTabWidget::_DragFrame)
|
|
OverlayTabWidget::_DragFrame->hide();
|
|
if (OverlayTabWidget::_DragFloating)
|
|
OverlayTabWidget::_DragFloating->hide();
|
|
}
|
|
|
|
void OverlaySplitterHandle::keyPressEvent(QKeyEvent *ke)
|
|
{
|
|
if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
|
|
endDrag();
|
|
}
|
|
|
|
void OverlaySplitterHandle::mouseMoveEvent(QMouseEvent *me)
|
|
{
|
|
if (OverlayTabWidget::_Dragging != this)
|
|
return;
|
|
|
|
if (!(me->buttons() & Qt::LeftButton)) {
|
|
endDrag();
|
|
return;
|
|
}
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
QPoint point = me->globalPos();
|
|
#else
|
|
QPoint point = me->globalPosition().toPoint();
|
|
#endif
|
|
|
|
if (dragging == 1) {
|
|
OverlayTabWidget *overlay = qobject_cast<OverlayTabWidget*>(
|
|
splitter()->parentWidget());
|
|
QPoint pos = me->pos();
|
|
if (overlay) {
|
|
switch(overlay->getDockArea()) {
|
|
case Qt::LeftDockWidgetArea:
|
|
case Qt::RightDockWidgetArea:
|
|
if (pos.x() < 0 || pos.x() > overlay->width())
|
|
dragging = 2;
|
|
break;
|
|
case Qt::TopDockWidgetArea:
|
|
case Qt::BottomDockWidgetArea:
|
|
if (pos.y() < 0 || pos.y() > overlay->height())
|
|
dragging = 2;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (dragging == 1) {
|
|
QPoint offset = parentWidget()->mapFromGlobal(point) - dragOffset;
|
|
moveSplitter(this->orientation() == Qt::Horizontal ? offset.x() : offset.y());
|
|
return;
|
|
}
|
|
setCursor(Qt::ClosedHandCursor);
|
|
}
|
|
|
|
OverlayManager::instance()->dragDockWidget(point,
|
|
dockWidget(),
|
|
dragOffset,
|
|
dragSize);
|
|
}
|
|
|
|
void OverlaySplitterHandle::mousePressEvent(QMouseEvent *me)
|
|
{
|
|
if (OverlayTabWidget::_Dragging || !getMainWindow() || me->button() != Qt::LeftButton)
|
|
return;
|
|
|
|
OverlayTabWidget::_Dragging = this;
|
|
dragging = 1;
|
|
dragOffset = me->pos();
|
|
auto dock = dockWidget();
|
|
if (dock) {
|
|
dragSize = dock->size();
|
|
dock->show();
|
|
} else
|
|
dragSize = QSize();
|
|
|
|
QSize mwSize = getMainWindow()->size();
|
|
dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
|
|
static_cast<long>(std::min(mwSize.width()/2, dragSize.width()))));
|
|
dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
|
|
static_cast<long>(std::min(mwSize.height()/2, dragSize.height()))));
|
|
|
|
}
|
|
|
|
void OverlaySplitterHandle::mouseReleaseEvent(QMouseEvent *me)
|
|
{
|
|
if (OverlayTabWidget::_Dragging != this || me->button() != Qt::LeftButton)
|
|
return;
|
|
|
|
if (dragging == 1) {
|
|
endDrag();
|
|
return;
|
|
}
|
|
endDrag();
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
|
QPoint point = me->globalPos();
|
|
#else
|
|
QPoint point = me->globalPosition().toPoint();
|
|
#endif
|
|
|
|
OverlayManager::instance()->dragDockWidget(point,
|
|
dockWidget(),
|
|
dragOffset,
|
|
dragSize,
|
|
true);
|
|
// Warning! the handle itself maybe deleted after return from
|
|
// dragDockWidget().
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
OverlayGraphicsEffect::OverlayGraphicsEffect(QObject *parent) :
|
|
QGraphicsEffect(parent),
|
|
_enabled(false),
|
|
_size(1,1),
|
|
_blurRadius(2.0f),
|
|
_color(0, 0, 0, 80)
|
|
{
|
|
}
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
|
|
QT_END_NAMESPACE
|
|
|
|
void OverlayGraphicsEffect::draw(QPainter* painter)
|
|
{
|
|
// if nothing to show outside the item, just draw source
|
|
if (!_enabled || _blurRadius + _size.height() <= 0 || _blurRadius + _size.width() <= 0) {
|
|
drawSource(painter);
|
|
return;
|
|
}
|
|
|
|
PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect;
|
|
QPoint offset;
|
|
QPixmap px = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
|
|
|
|
// return if no source
|
|
if (px.isNull())
|
|
return;
|
|
|
|
#if 0
|
|
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
|
static int count;
|
|
getMainWindow()->showMessage(
|
|
QStringLiteral("dock overlay redraw %1").arg(count++));
|
|
}
|
|
#endif
|
|
|
|
QTransform restoreTransform = painter->worldTransform();
|
|
painter->setWorldTransform(QTransform());
|
|
|
|
// Calculate size for the background image
|
|
QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
|
|
tmp.setDevicePixelRatio(px.devicePixelRatioF());
|
|
tmp.fill(0);
|
|
QPainter tmpPainter(&tmp);
|
|
QPainterPath clip;
|
|
tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
|
|
if(_size.width() == 0 && _size.height() == 0)
|
|
tmpPainter.drawPixmap(QPoint(0, 0), px);
|
|
else {
|
|
// exclude splitter handles
|
|
auto splitter = qobject_cast<QSplitter*>(parent());
|
|
if (splitter) {
|
|
int i = -1;
|
|
for (int size : splitter->sizes()) {
|
|
++i;
|
|
if (!size)
|
|
continue;
|
|
QWidget *w = splitter->widget(i);
|
|
if (w->findChild<TaskView::TaskView*>())
|
|
continue;
|
|
QRect rect = w->geometry();
|
|
if (splitter->orientation() == Qt::Vertical)
|
|
clip.addRect(rect.x(), rect.y()+4,
|
|
rect.width(), rect.height()-4);
|
|
else
|
|
clip.addRect(rect.x()+4, rect.y(),
|
|
rect.width()-4, rect.height());
|
|
}
|
|
if (clip.isEmpty()) {
|
|
drawSource(painter);
|
|
return;
|
|
}
|
|
tmpPainter.setClipPath(clip);
|
|
}
|
|
|
|
for (int x=-_size.width();x<=_size.width();++x) {
|
|
for (int y=-_size.height();y<=_size.height();++y) {
|
|
if (x || y) {
|
|
tmpPainter.drawPixmap(QPoint(x, y), px);
|
|
tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tmpPainter.end();
|
|
|
|
// blur the alpha channel
|
|
QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
|
|
blurred.setDevicePixelRatio(px.devicePixelRatioF());
|
|
blurred.fill(0);
|
|
QPainter blurPainter(&blurred);
|
|
qt_blurImage(&blurPainter, tmp, blurRadius(), false, true);
|
|
blurPainter.end();
|
|
|
|
tmp = blurred;
|
|
|
|
// blacken the image...
|
|
tmpPainter.begin(&tmp);
|
|
tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
|
tmpPainter.fillRect(tmp.rect(), color());
|
|
tmpPainter.end();
|
|
|
|
// draw the blurred shadow...
|
|
painter->drawImage(QPointF(offset.x()+_offset.x(), offset.y()+_offset.y()), tmp);
|
|
|
|
// draw the actual pixmap...
|
|
painter->drawPixmap(offset, px, QRectF());
|
|
|
|
#if 0
|
|
QWidget *focus = qApp->focusWidget();
|
|
if (focus) {
|
|
QWidget *widget = qobject_cast<QWidget*>(this->parent());
|
|
if (auto *edit = qobject_cast<QPlainTextEdit*>(focus)) {
|
|
if (!edit->isReadOnly() && edit->isEnabled()) {
|
|
for(auto w=edit->parentWidget(); w; w=w->parentWidget()) {
|
|
if (w == widget) {
|
|
QRect r = edit->cursorRect();
|
|
QRect rect(edit->viewport()->mapTo(widget, r.topLeft()),
|
|
edit->viewport()->mapTo(widget, r.bottomRight()));
|
|
// painter->fillRect(rect, edit->textColor());
|
|
// painter->fillRect(rect, edit->currentCharFormat().foreground());
|
|
painter->fillRect(rect.translated(offset), Qt::white);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// restore world transform
|
|
painter->setWorldTransform(restoreTransform);
|
|
}
|
|
|
|
QRectF OverlayGraphicsEffect::boundingRectFor(const QRectF& rect) const
|
|
{
|
|
if (!_enabled)
|
|
return rect;
|
|
return rect.united(rect.adjusted(-_blurRadius - _size.width() + _offset.x(),
|
|
-_blurRadius - _size.height()+ _offset.y(),
|
|
_blurRadius + _size.width() + _offset.x(),
|
|
_blurRadius + _size.height() + _offset.y()));
|
|
}
|
|
|
|
#include "moc_OverlayWidgets.cpp"
|