FreeCAD

Форк
0
/
OverlayWidgets.cpp 
2720 строк · 89.0 Кб
1
/****************************************************************************
2
 *   Copyright (c) 2020 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
3
 *                                                                          *
4
 *   This file is part of the FreeCAD CAx development system.               *
5
 *                                                                          *
6
 *   This library is free software; you can redistribute it and/or          *
7
 *   modify it under the terms of the GNU Library General Public            *
8
 *   License as published by the Free Software Foundation; either           *
9
 *   version 2 of the License, or (at your option) any later version.       *
10
 *                                                                          *
11
 *   This library  is distributed in the hope that it will be useful,       *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14
 *   GNU Library General Public License for more details.                   *
15
 *                                                                          *
16
 *   You should have received a copy of the GNU Library General Public      *
17
 *   License along with this library; see the file COPYING.LIB. If not,     *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,          *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                 *
20
 *                                                                          *
21
 ****************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
# include <QAction>
27
# include <QApplication>
28
# include <QBoxLayout>
29
# include <QComboBox>
30
# include <QDockWidget>
31
# include <QHeaderView>
32
# include <QKeyEvent>
33
# include <QMdiArea>
34
# include <QMenu>
35
# include <QPainter>
36
# include <QPointer>
37
# include <QSpacerItem>
38
# include <QSplitter>
39
# include <QTabBar>
40
# include <QTextStream>
41
# include <QTimerEvent>
42
# include <QToolTip>
43
# include <QTreeView>
44
# include <QScrollBar>
45
#endif
46

47
#include <QPainterPath>
48
#include <QPropertyAnimation>
49

50
#include <array>
51
#include <unordered_map>
52

53
#include "OverlayWidgets.h"
54

55
#include <Base/Tools.h>
56
#include <Base/Console.h>
57
#include <App/Application.h>
58
#include "Application.h"
59
#include "BitmapFactory.h"
60
#include "Clipping.h"
61
#include "ComboView.h"
62
#include "Command.h"
63
#include "Control.h"
64
#include "MainWindow.h"
65
#include "MDIView.h"
66
#include "NaviCube.h"
67
#include "OverlayManager.h"
68
#include "OverlayParams.h"
69
#include "TaskView/TaskView.h"
70
#include "Tree.h"
71
#include "TreeParams.h"
72
#include "propertyeditor/PropertyEditor.h"
73

74
FC_LOG_LEVEL_INIT("Dock", true, true);
75

76
using namespace Gui;
77

78
OverlayDragFrame *OverlayTabWidget::_DragFrame;
79
QDockWidget *OverlayTabWidget::_DragFloating;
80
QWidget *OverlayTabWidget::_Dragging;
81
OverlayTabWidget *OverlayTabWidget::_LeftOverlay;
82
OverlayTabWidget *OverlayTabWidget::_RightOverlay;
83
OverlayTabWidget *OverlayTabWidget::_TopOverlay;
84
OverlayTabWidget *OverlayTabWidget::_BottomOverlay;
85

86
static inline int widgetMinSize(const QWidget *widget, bool margin=false)
87
{
88
    return widget->fontMetrics().ascent()
89
        + widget->fontMetrics().descent() + (margin?4:0);
90
}
91

92
// -----------------------------------------------------------
93

94
OverlayProxyWidget::OverlayProxyWidget(OverlayTabWidget *tabOverlay)
95
    :QWidget(tabOverlay->parentWidget()), owner(tabOverlay), _hintColor(QColor(50,50,50,150))
96
{
97
    dockArea = owner->getDockArea();
98
    timer.setSingleShot(true);
99
    QObject::connect(&timer, &QTimer::timeout, this, &OverlayProxyWidget::onTimer);
100
    setAttribute(Qt::WA_TransparentForMouseEvents, true);
101
}
102

103
bool OverlayProxyWidget::isActivated() const
104
{
105
    return drawLine && isVisible();
106
}
107

108
OverlayProxyWidget::HitTest OverlayProxyWidget::hitTest(const QPoint &globalPt, bool delay)
109
{
110
    if (!isVisible() || !owner->count())
111
        return HitTest::HitNone;
112

113
    auto pt = mapFromGlobal(globalPt);
114

115
    QTabBar *tabbar = owner->tabBar();
116
    if (tabbar->isVisible() && tabbar->tabAt(pt)>=0) {
117
        ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
118
        return HitTest::HitOuter;
119
    }
120

121
    HitTest hit = HitTest::HitNone;
122
    QRect rect = this->getRect();
123
    QSize s = this->size();
124
    int hintSize = OverlayParams::getDockOverlayHintTriggerSize();
125
    // if (owner->getState() == OverlayTabWidget::State::HintHidden)
126
    //     hintSize *= 2;
127
    switch(dockArea) {
128
    case Qt::LeftDockWidgetArea:
129
        if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() > 0 && pt.x() < hintSize)
130
            hit = HitTest::HitOuter;
131
        break;
132
    case Qt::RightDockWidgetArea:
133
        if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() < s.width() && pt.x() > -hintSize)
134
            hit = HitTest::HitOuter;
135
        break;
136
    case Qt::TopDockWidgetArea:
137
        if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() > 0 && pt.y() < hintSize)
138
            hit = HitTest::HitOuter;
139
        break;
140
    case Qt::BottomDockWidgetArea:
141
        if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() < s.height() && pt.y() > -hintSize)
142
            hit = HitTest::HitOuter;
143
        break;
144
    }
145
    if (rect.contains(pt)) {
146
        hit = HitTest::HitInner;
147
        ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
148
    } else if (drawLine)
149
        ToolTip::hideText();
150

151
    if (owner->getState() == OverlayTabWidget::State::HintHidden) {
152
        if (hit == HitTest::HitNone)
153
            owner->setState(OverlayTabWidget::State::Normal);
154
        else {
155
            hit = HitTest::HitNone;
156
            ToolTip::hideText();
157
        }
158
    }
159
    if (hit != HitTest::HitNone) {
160
        if (drawLine)
161
            timer.stop();
162
        else if (delay) {
163
            if (!timer.isActive())
164
                timer.start(OverlayParams::getDockOverlayHintDelay());
165
            return hit;
166
        } else {
167
            timer.stop();
168
            owner->setState(OverlayTabWidget::State::Hint);
169
            drawLine = true;
170
            update();
171
        }
172

173
        auto view = getMainWindow()->activeWindow();
174
        auto overlayOnHoverAllowed = view && view->onHasMsg("AllowsOverlayOnHover");
175

176
        if(owner->getState() != OverlayTabWidget::State::Hidden
177
                && hit == HitTest::HitOuter
178
                && overlayOnHoverAllowed
179
                && OverlayParams::getDockOverlayActivateOnHover()) {
180
            if (owner->isVisible() && owner->tabBar()->isVisible()) {
181
                QSize size = owner->tabBar()->size();
182
                QPoint pt = owner->tabBar()->mapToGlobal(
183
                                QPoint(size.width(), size.height()));
184
                QPoint pos = QCursor::pos();
185
                switch(this->dockArea) {
186
                case Qt::LeftDockWidgetArea:
187
                case Qt::RightDockWidgetArea:
188
                    if (pos.y() < pt.y())
189
                        return HitTest::HitNone;
190
                    break;
191
                case Qt::TopDockWidgetArea:
192
                case Qt::BottomDockWidgetArea:
193
                    if (pos.x() < pt.x())
194
                        return HitTest::HitNone;
195
                    break;
196
                default:
197
                    break;
198
                }
199
            }
200
            owner->setState(OverlayTabWidget::State::Showing);
201
        }
202

203
    } else if (!drawLine) {
204
        timer.stop();
205
    } else if (delay) {
206
        if (!timer.isActive())
207
            timer.start(OverlayParams::getDockOverlayHintDelay());
208
    } else {
209
        timer.stop();
210
        owner->setState(OverlayTabWidget::State::Normal);
211
        drawLine = false;
212
        ToolTip::hideText();
213
        update();
214
    }
215
    return hit;
216
}
217

218
void OverlayProxyWidget::onTimer()
219
{
220
    hitTest(QCursor::pos(), false);
221
}
222

223
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
224
void OverlayProxyWidget::enterEvent(QEvent *)
225
#else
226
void OverlayProxyWidget::enterEvent(QEnterEvent *)
227
#endif
228
{
229
    if(!owner->count())
230
        return;
231

232
    if (!drawLine) {
233
        if (!timer.isActive())
234
            timer.start(OverlayParams::getDockOverlayHintDelay());
235
    }
236
}
237

238
void OverlayProxyWidget::hideEvent(QHideEvent *)
239
{
240
    drawLine = false;
241
}
242

243
void OverlayProxyWidget::onMousePress()
244
{
245
    if(!owner->count())
246
        return;
247

248
    if (owner->getState() == OverlayTabWidget::State::HintHidden)
249
        return;
250

251
    owner->setState(OverlayTabWidget::State::Showing);
252
}
253

254
QBrush OverlayProxyWidget::hintColor() const
255
{
256
    return _hintColor;
257
}
258

259
void OverlayProxyWidget::setHintColor(const QBrush &brush)
260
{
261
    _hintColor = brush;
262
}
263

264
QRect OverlayProxyWidget::getRect() const
265
{
266
    QRect rect = this->rect();
267
    if (owner->isVisible() && owner->tabBar()->isVisible()) {
268
        QSize size = owner->tabBar()->size();
269
        QPoint pt = owner->tabBar()->mapToGlobal(
270
                        QPoint(size.width(), size.height()));
271
        pt = this->mapFromGlobal(pt);
272
        switch(this->dockArea) {
273
            case Qt::LeftDockWidgetArea:
274
            case Qt::RightDockWidgetArea:
275
                rect.setTop(pt.y());
276
                break;
277
            case Qt::TopDockWidgetArea:
278
            case Qt::BottomDockWidgetArea:
279
                rect.setLeft(pt.x());
280
                break;
281
            default:
282
                break;
283
        }
284
    }
285
    switch(this->dockArea) {
286
        case Qt::LeftDockWidgetArea:
287
            if (int offset = OverlayParams::getDockOverlayHintLeftOffset())
288
                rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
289
            if (int length = OverlayParams::getDockOverlayHintLeftLength())
290
                 rect.setHeight(std::min(length, rect.height()));
291
            break;
292
        case Qt::RightDockWidgetArea:
293
            if (int offset = OverlayParams::getDockOverlayHintRightOffset())
294
                rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
295
            if (int length = OverlayParams::getDockOverlayHintRightLength())
296
                 rect.setHeight(std::min(length, rect.height()));
297
            break;
298
        case Qt::TopDockWidgetArea:
299
            if (int offset = OverlayParams::getDockOverlayHintTopOffset())
300
                rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
301
            if (int length = OverlayParams::getDockOverlayHintTopLength())
302
                 rect.setWidth(std::min(length, rect.width()));
303
            break;
304
        case Qt::BottomDockWidgetArea:
305
            if (int offset = OverlayParams::getDockOverlayHintBottomOffset())
306
                rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
307
            if (int length = OverlayParams::getDockOverlayHintBottomLength())
308
                 rect.setWidth(std::min(length, rect.width()));
309
            break;
310
        default:
311
            break;
312
    }
313
    return rect;
314
}
315

316
void OverlayProxyWidget::paintEvent(QPaintEvent *)
317
{
318
    if(!drawLine)
319
        return;
320
    QPainter painter(this);
321
    painter.setOpacity(_hintColor.color().alphaF());
322
    painter.setPen(Qt::transparent);
323
    painter.setBrush(_hintColor);
324

325
    QRect rect = this->getRect();
326
    painter.drawRect(rect);
327
}
328

329
OverlayToolButton::OverlayToolButton(QWidget *parent)
330
    :QToolButton(parent)
331
{
332
    setCursor(Qt::ArrowCursor);
333
}
334

335
// --------------------------------------------------------------------
336

337
OverlayTabWidget::OverlayTabWidget(QWidget *parent, Qt::DockWidgetArea pos)
338
    :QTabWidget(parent), dockArea(pos)
339
{
340
    // This is necessary to capture any focus lost from switching the tab,
341
    // otherwise the lost focus will leak to the parent, i.e. MdiArea, which may
342
    // cause unexpected Mdi sub window switching.
343
    // setFocusPolicy(Qt::StrongFocus);
344

345
    _imageScale = 0.0;
346

347
    splitter = new OverlaySplitter(this);
348

349
    _graphicsEffect = new OverlayGraphicsEffect(splitter);
350
    splitter->setGraphicsEffect(_graphicsEffect);
351

352
    _graphicsEffectTab = new OverlayGraphicsEffect(this);
353
    _graphicsEffectTab->setEnabled(false);
354
    tabBar()->setGraphicsEffect(_graphicsEffectTab);
355

356
    Command *cmdHide = nullptr;
357
    switch(pos) {
358
    case Qt::LeftDockWidgetArea:
359
        _LeftOverlay = this;
360
        setTabPosition(QTabWidget::West);
361
        splitter->setOrientation(Qt::Vertical);
362
        cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleLeft");
363
        break;
364
    case Qt::RightDockWidgetArea:
365
        _RightOverlay = this;
366
        setTabPosition(QTabWidget::East);
367
        splitter->setOrientation(Qt::Vertical);
368
        cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleRight");
369
        break;
370
    case Qt::TopDockWidgetArea:
371
        _TopOverlay = this;
372
        setTabPosition(QTabWidget::North);
373
        splitter->setOrientation(Qt::Horizontal);
374
        cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleTop");
375
        break;
376
    case Qt::BottomDockWidgetArea:
377
        _BottomOverlay = this;
378
        setTabPosition(QTabWidget::South);
379
        splitter->setOrientation(Qt::Horizontal);
380
        cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleBottom");
381
        break;
382
    default:
383
        break;
384
    }
385

386
    proxyWidget = new OverlayProxyWidget(this);
387
    proxyWidget->hide();
388
    _setOverlayMode(proxyWidget,OverlayOption::Enable);
389

390
    setOverlayMode(true);
391
    hide();
392

393
    actTransparent.setCheckable(true);
394
    actTransparent.setData(QStringLiteral("OBTN Transparent"));
395
    actTransparent.setParent(this);
396
    addAction(&actTransparent);
397

398
    actAutoHide.setData(QStringLiteral("OBTN AutoHide"));
399

400
    actEditHide.setData(QStringLiteral("OBTN EditHide"));
401

402
    actEditShow.setData(QStringLiteral("OBTN EditShow"));
403

404
    actTaskShow.setData(QStringLiteral("OBTN TaskShow"));
405

406
    actNoAutoMode.setData(QStringLiteral("OBTN NoAutoMode"));
407

408
    actAutoMode.setData(QStringLiteral("OBTN AutoMode"));
409
    actAutoMode.setParent(this);
410
    autoModeMenu.hide();
411
    autoModeMenu.setToolTipsVisible(true);
412
    autoModeMenu.addAction(&actNoAutoMode);
413
    autoModeMenu.addAction(&actAutoHide);
414
    autoModeMenu.addAction(&actEditShow);
415
    autoModeMenu.addAction(&actEditHide);
416
    autoModeMenu.addAction(&actTaskShow);
417
    addAction(&actAutoMode);
418

419
    actOverlay.setData(QStringLiteral("OBTN Overlay"));
420
    actOverlay.setParent(this);
421
    addAction(&actOverlay);
422

423
    if (cmdHide)
424
        cmdHide->addTo(this);
425

426
    retranslate();
427
    refreshIcons();
428

429
    connect(tabBar(), &QTabBar::tabBarClicked, this, &OverlayTabWidget::onCurrentChanged);
430
    connect(tabBar(), &QTabBar::tabMoved, this, &OverlayTabWidget::onTabMoved);
431
    tabBar()->installEventFilter(this);
432

433
    timer.setSingleShot(true);
434
    connect(&timer, &QTimer::timeout, this, &OverlayTabWidget::setupLayout);
435

436
    repaintTimer.setSingleShot(true);
437
    connect(&repaintTimer, &QTimer::timeout, this, &OverlayTabWidget::onRepaint);
438

439
    _animator = new QPropertyAnimation(this, "animation", this);
440
    _animator->setStartValue(0.0);
441
    _animator->setEndValue(1.0);
442
    connect(_animator, &QAbstractAnimation::stateChanged,
443
            this, &OverlayTabWidget::onAnimationStateChanged);
444
}
445

446
void OverlayTabWidget::refreshIcons()
447
{
448
    auto curStyleSheet =
449
        App::GetApplication()
450
            .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow")
451
            ->GetASCII("StyleSheet", "None");
452

453
    QPixmap pxAutoHide;
454

455
    if (isStyleSheetDark(curStyleSheet)) {
456
        actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/icons/overlay_light.svg"));
457
        actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
458
        actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
459
        actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
460
        actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
461
        actTransparent.setIcon(BitmapFactory().pixmap("qss:overlay/icons/transparent_light.svg"));
462
        pxAutoHide = BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
463
    }
464
    else {
465
        actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/icons/overlay.svg"));
466
        actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode.svg"));
467
        actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow.svg"));
468
        actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow.svg"));
469
        actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide.svg"));
470
        actTransparent.setIcon(BitmapFactory().pixmap("qss:overlay/icons/transparent.svg"));
471
        pxAutoHide = BitmapFactory().pixmap("qss:overlay/icons/autohide.svg");
472
    }
473

474
    actAutoHide.setIcon(rotateAutoHideIcon(pxAutoHide, dockArea));
475

476
    syncAutoMode();
477
}
478

479
void OverlayTabWidget::onAnimationStateChanged()
480
{
481
    if (_animator->state() != QAbstractAnimation::Running) {
482
        setAnimation(0);
483
        if (_animator->startValue().toReal() == 0.0) {
484
            hide();
485
            OverlayManager::instance()->refresh();
486
        }
487
        if (_state == State::Showing)
488
            setState(State::Normal);
489
    }
490
}
491

492
void OverlayTabWidget::setAnimation(qreal t)
493
{
494
    if (t != _animation) {
495
        _animation = t;
496
        setupLayout();
497
    }
498
}
499

500
void OverlayTabWidget::startShow()
501
{
502
    if (isVisible() || _state > State::Normal) {
503
        return;
504
    }
505

506
    int duration = OverlayParams::getDockOverlayAnimationDuration();
507
    bool setmode = _state != State::Showing;
508
    if (duration) {
509
        _animator->setStartValue(1.0);
510
        _animator->setEndValue(0.0);
511
        _animator->setDuration(duration);
512
        _animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
513
        _animator->start();
514
    }
515
    else if (_state == State::Showing)
516
        setState(State::Normal);
517
    proxyWidget->hide();
518
    show();
519
    raise();
520
    if (setmode)
521
        setOverlayMode(overlaid);
522
}
523

524
QWidget *OverlayTabWidget::createTitleButton(QAction *action, int size)
525
{
526
    auto button = new OverlayToolButton(nullptr);
527
    button->setObjectName(action->data().toString());
528
    button->setDefaultAction(action);
529
    button->setAutoRaise(true);
530
    button->setContentsMargins(0,0,0,0);
531
    button->setFixedSize(size,size);
532
    return button;
533
}
534

535
void OverlayTabWidget::startHide()
536
{
537
    if (!isVisible()
538
            || _state > State::Normal
539
            || (_animator->state() == QAbstractAnimation::Running
540
                && _animator->startValue().toReal() == 0.0))
541
        return;
542
    int duration = OverlayParams::getDockOverlayAnimationDuration();
543
    if (!duration)
544
        hide();
545
    else {
546
        _animator->setStartValue(0.0);
547
        _animator->setEndValue(1.0);
548
        _animator->setDuration(duration);
549
        _animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
550
        _animator->start();
551
    }
552
}
553

554
bool OverlayTabWidget::event(QEvent *ev)
555
{
556
    switch(ev->type()) {
557
    case QEvent::MouseButtonRelease:
558
        if(mouseGrabber() == this) {
559
            releaseMouse();
560
            ev->accept();
561
            return true;
562
        }
563
        break;
564
    case QEvent::MouseMove:
565
    case QEvent::ContextMenu:
566
        if(QApplication::mouseButtons() == Qt::NoButton && mouseGrabber() == this) {
567
            releaseMouse();
568
            ev->accept();
569
            return true;
570
        }
571
        break;
572
    case QEvent::MouseButtonPress:
573
        ev->accept();
574
        return true;
575
    default:
576
        break;
577
    }
578
    return QTabWidget::event(ev);
579
}
580

581
int OverlayTabWidget::testAlpha(const QPoint &_pos, int radiusScale)
582
{
583
    if (!count() || (!isOverlaid() && !isTransparent()) || !isVisible())
584
        return -1;
585

586
    if (tabBar()->isVisible() && tabBar()->tabAt(tabBar()->mapFromGlobal(_pos))>=0)
587
        return -1;
588

589
    if (titleBar->isVisible() && titleBar->rect().contains(titleBar->mapFromGlobal(_pos)))
590
        return -1;
591

592
    if (!splitter->isVisible())
593
        return 0;
594

595
    auto pos = splitter->mapFromGlobal(_pos);
596
    QSize size = splitter->size();
597
    if (pos.x() < 0 || pos.y() < 0
598
            || pos.x() >= size.width()
599
            || pos.y() >= size.height())
600
    {
601
        if (this->rect().contains(this->mapFromGlobal(_pos)))
602
            return 0;
603
        return -1;
604
    }
605

606
    if (_image.isNull()) {
607
        auto pixmap = splitter->grab();
608
        _imageScale = pixmap.devicePixelRatio();
609
        _image = pixmap.toImage();
610
    }
611

612
    int res = qAlpha(_image.pixel(pos*_imageScale));
613
    int radius = OverlayParams::getDockOverlayAlphaRadius() * radiusScale;
614
    if (res || radius<=0 )
615
        return res;
616

617
    radius *= _imageScale;
618
    for (int i=-radius; i<radius; ++i) {
619
        for (int j=-radius; j<radius; ++j) {
620
            if (pos.x()+i < 0 || pos.y()+j < 0
621
                    || pos.x()+i >= size.width()
622
                    || pos.y()+j >= size.height())
623
                continue;
624
            res = qAlpha(_image.pixel(pos*_imageScale + QPoint(i,j)));
625
            if (res)
626
                return res;
627
        }
628
    }
629
    return 0;
630
}
631

632
void OverlayTabWidget::paintEvent(QPaintEvent *ev)
633
{
634
    Base::StateLocker guard(repainting);
635
    repaintTimer.stop();
636
    if (!_image.isNull())
637
        _image = QImage();
638
    QTabWidget::paintEvent(ev);
639
}
640

641
void OverlayTabWidget::onRepaint()
642
{
643
    Base::StateLocker guard(repainting);
644
    repaintTimer.stop();
645
    if (!_image.isNull())
646
        _image = QImage();
647
    splitter->repaint();
648
}
649

650
void OverlayTabWidget::scheduleRepaint()
651
{
652
    if(!repainting
653
            && isVisible()
654
            && _graphicsEffect)
655
    {
656
        repaintTimer.start(100);
657
    }
658
}
659

660
QColor OverlayTabWidget::effectColor() const
661
{
662
    return _graphicsEffect->color();
663
}
664

665
void OverlayTabWidget::setEffectColor(const QColor &color)
666
{
667
    _graphicsEffect->setColor(color);
668
    _graphicsEffectTab->setColor(color);
669
}
670

671
int OverlayTabWidget::effectWidth() const
672
{
673
    return _graphicsEffect->size().width();
674
}
675

676
void OverlayTabWidget::setEffectWidth(int s)
677
{
678
    auto size = _graphicsEffect->size();
679
    size.setWidth(s);
680
    _graphicsEffect->setSize(size);
681
    _graphicsEffectTab->setSize(size);
682
}
683

684
int OverlayTabWidget::effectHeight() const
685
{
686
    return _graphicsEffect->size().height();
687
}
688

689
void OverlayTabWidget::setEffectHeight(int s)
690
{
691
    auto size = _graphicsEffect->size();
692
    size.setHeight(s);
693
    _graphicsEffect->setSize(size);
694
    _graphicsEffectTab->setSize(size);
695
}
696

697
qreal OverlayTabWidget::effectOffsetX() const
698
{
699
    return _graphicsEffect->offset().x();
700
}
701

702
void OverlayTabWidget::setEffectOffsetX(qreal d)
703
{
704
    auto offset = _graphicsEffect->offset();
705
    offset.setX(d);
706
    _graphicsEffect->setOffset(offset);
707
    _graphicsEffectTab->setOffset(offset);
708
}
709

710
qreal OverlayTabWidget::effectOffsetY() const
711
{
712
    return _graphicsEffect->offset().y();
713
}
714

715
void OverlayTabWidget::setEffectOffsetY(qreal d)
716
{
717
    auto offset = _graphicsEffect->offset();
718
    offset.setY(d);
719
    _graphicsEffect->setOffset(offset);
720
    _graphicsEffectTab->setOffset(offset);
721
}
722

723
qreal OverlayTabWidget::effectBlurRadius() const
724
{
725
    return _graphicsEffect->blurRadius();
726
}
727

728
void OverlayTabWidget::setEffectBlurRadius(qreal r)
729
{
730
    _graphicsEffect->setBlurRadius(r);
731
    _graphicsEffectTab->setBlurRadius(r);
732
}
733

734
bool OverlayTabWidget::effectEnabled() const
735
{
736
    return _effectEnabled;
737
}
738

739
void OverlayTabWidget::setEffectEnabled(bool enable)
740
{
741
    _effectEnabled = enable;
742
}
743

744
bool OverlayTabWidget::eventFilter(QObject *o, QEvent *ev)
745
{
746
    if(ev->type() == QEvent::Resize && o == tabBar()) {
747
        if (_state <= State::Normal)
748
            timer.start(10);
749
    }
750
    return QTabWidget::eventFilter(o, ev);
751
}
752

753
void OverlayTabWidget::restore(ParameterGrp::handle handle)
754
{
755
    if (!handle) {
756
        hGrp = handle;
757
        return;
758
    }
759
    if (!parentWidget())
760
        return;
761
    std::string widgets = handle->GetASCII("Widgets","");
762
    for(auto &name : QString::fromUtf8(widgets.c_str()).split(QLatin1Char(','))) {
763
        if(name.isEmpty())
764
            continue;
765
        OverlayManager::instance()->registerDockWidget(name, this);
766
        auto dock = getMainWindow()->findChild<QDockWidget*>(name);
767
        if(dock)
768
            addWidget(dock, dock->windowTitle());
769
    }
770
    int width = handle->GetInt("Width", 0);
771
    int height = handle->GetInt("Height", 0);
772
    int offset1 = handle->GetInt("Offset1", 0);
773
    int offset2 = handle->GetInt("Offset3", 0);
774
    setOffset(QSize(offset1,offset2));
775
    setSizeDelta(handle->GetInt("Offset2", 0));
776
    if(width && height) {
777
        QRect rect(0, 0, width, height);
778
        switch(dockArea) {
779
        case Qt::RightDockWidgetArea:
780
            rect.moveRight(parentWidget()->size().width());
781
            break;
782
        case Qt::BottomDockWidgetArea:
783
            rect.moveBottom(parentWidget()->size().height());
784
            break;
785
        default:
786
            break;
787
        }
788
        setRect(rect);
789
    }
790
    if (handle->GetBool("AutoHide", false))
791
        setAutoMode(AutoMode::AutoHide);
792
    else if (handle->GetBool("EditHide", false))
793
        setAutoMode(AutoMode::EditHide);
794
    else if (handle->GetBool("EditShow", false))
795
        setAutoMode(AutoMode::EditShow);
796
    else if (handle->GetBool("TaskShow", false))
797
        setAutoMode(AutoMode::TaskShow);
798
    else
799
        setAutoMode(AutoMode::NoAutoMode);
800

801
    setTransparent(handle->GetBool("Transparent", false));
802

803
    _sizemap.clear();
804
    std::string savedSizes = handle->GetASCII("Sizes","");
805
    QList<int> sizes;
806
    int idx = 0;
807
    for(auto &size : QString::fromUtf8(savedSizes.c_str()).split(QLatin1Char(','))) {
808
        sizes.append(size.toInt());
809
        _sizemap[dockWidget(idx++)] = sizes.back();
810
    }
811

812
    FC_LOG("restore " << objectName().toUtf8().constData() << " " << savedSizes);
813

814
    getSplitter()->setSizes(sizes);
815
    hGrp = handle;
816
}
817

818
void OverlayTabWidget::saveTabs()
819
{
820
    if(!hGrp)
821
        return;
822

823
    std::ostringstream os, os2;
824
    _sizemap.clear();
825
    auto sizes = splitter->sizes();
826
    bool first = true;
827
    for(int i=0,c=splitter->count(); i<c; ++i) {
828
        auto dock = dockWidget(i);
829
        if (!dock)
830
            continue;
831
        if(dock->objectName().size()) {
832
            os << dock->objectName().toUtf8().constData() << ",";
833
            if (first)
834
                first = false;
835
            else
836
                os2 << ",";
837
            os2 << sizes[i];
838
        }
839
        _sizemap[dock] = sizes[i];
840
    }
841
    Base::StateLocker lock(_saving);
842
    hGrp->SetASCII("Widgets", os.str().c_str());
843
    hGrp->SetASCII("Sizes", os2.str().c_str());
844
    FC_LOG("save " << objectName().toUtf8().constData() << " " << os2.str());
845
}
846

847
void OverlayTabWidget::onTabMoved(int from, int to)
848
{
849
    QWidget *w = splitter->widget(from);
850
    splitter->insertWidget(to,w);
851
    saveTabs();
852
}
853

854
void OverlayTabWidget::setTitleBar(QWidget *w)
855
{
856
    titleBar = w;
857
}
858

859
void OverlayTabWidget::changeEvent(QEvent *e)
860
{
861
    QTabWidget::changeEvent(e);
862
    if (e->type() == QEvent::LanguageChange)
863
        retranslate();
864
}
865

866
void OverlayTabWidget::retranslate()
867
{
868
    actTransparent.setToolTip(tr("Toggle transparent mode"));
869
    actNoAutoMode.setText(tr("None"));
870
    actNoAutoMode.setToolTip(tr("Turn off auto hide/show"));
871
    actAutoHide.setText(tr("Auto hide"));
872
    actAutoHide.setToolTip(tr("Auto hide docked widgets on leave"));
873
    actEditHide.setText(tr("Hide on edit"));
874
    actEditHide.setToolTip(tr("Auto hide docked widgets on editing"));
875
    actEditShow.setText(tr("Show on edit"));
876
    actEditShow.setToolTip(tr("Auto show docked widgets on editing"));
877
    actTaskShow.setText(tr("Auto task"));
878
    actTaskShow.setToolTip(tr("Auto show task view for any current task, and hide the view when there is no task."));
879
    actOverlay.setToolTip(tr("Toggle overlay"));
880
    syncAutoMode();
881
}
882

883
void OverlayTabWidget::syncAutoMode()
884
{
885
    auto curStyleSheet =
886
        App::GetApplication()
887
            .GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow")
888
            ->GetASCII("StyleSheet", "None");
889

890
    QAction* action = nullptr;
891
    switch (autoMode) {
892
        case AutoMode::AutoHide:
893
            action = &actAutoHide;
894
            if (isStyleSheetDark(curStyleSheet)) {
895
                QPixmap pxAutoHideMode =
896
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_lighter.svg");
897
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
898
                action->setIcon(pxAutoHideMode);
899
                actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
900
                actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
901
                actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
902
                actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
903
            }
904
            else {
905
                QPixmap pxAutoHideMode = BitmapFactory().pixmap("qss:overlay/icons/autohide.svg");
906
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
907
                action->setIcon(pxAutoHideMode);
908
                actNoAutoMode.setIcon(
909
                    BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
910
                actTaskShow.setIcon(
911
                    BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
912
                actEditShow.setIcon(
913
                    BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
914
                actEditHide.setIcon(
915
                    BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
916
            }
917
            break;
918
        case AutoMode::EditShow:
919
            action = &actEditShow;
920
            if (isStyleSheetDark(curStyleSheet)) {
921
                QPixmap pxEditShowMode =
922
                    BitmapFactory().pixmap("qss:overlay/icons/editshow_lighter.svg");
923
                action->setIcon(pxEditShowMode);
924
                QPixmap pxAutoHideMode =
925
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
926
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
927
                actAutoHide.setIcon(pxAutoHideMode);
928
                actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
929
                actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
930
                actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
931
            }
932
            else {
933
                QPixmap pxEditShowMode = BitmapFactory().pixmap("qss:overlay/icons/editshow.svg");
934
                action->setIcon(pxEditShowMode);
935
                QPixmap pxAutoHideMode =
936
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
937
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
938
                actAutoHide.setIcon(pxAutoHideMode);
939
                actNoAutoMode.setIcon(
940
                    BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
941
                actTaskShow.setIcon(
942
                    BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
943
                actEditHide.setIcon(
944
                    BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
945
            }
946
            break;
947
        case AutoMode::TaskShow:
948
            action = &actTaskShow;
949
            if (isStyleSheetDark(curStyleSheet)) {
950
                QPixmap pxTaskShowMode =
951
                    BitmapFactory().pixmap("qss:overlay/icons/taskshow_lighter.svg");
952
                action->setIcon(pxTaskShowMode);
953
                QPixmap pxAutoHideMode =
954
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
955
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
956
                actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
957
                actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
958
                actAutoHide.setIcon(pxAutoHideMode);
959
                actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
960
            }
961
            else {
962
                QPixmap pxTaskShowMode = BitmapFactory().pixmap("qss:overlay/icons/taskshow.svg");
963
                action->setIcon(pxTaskShowMode);
964
                QPixmap pxAutoHideMode =
965
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
966
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
967
                actNoAutoMode.setIcon(
968
                    BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
969
                actEditShow.setIcon(
970
                    BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
971
                actAutoHide.setIcon(pxAutoHideMode);
972
                actEditHide.setIcon(
973
                    BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
974
            }
975
            break;
976
        case AutoMode::EditHide:
977
            action = &actEditHide;
978
            if (isStyleSheetDark(curStyleSheet)) {
979
                QPixmap pxEditHideMode =
980
                    BitmapFactory().pixmap("qss:overlay/icons/edithide_lighter.svg");
981
                action->setIcon(pxEditHideMode);
982
                QPixmap pxAutoHideMode =
983
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
984
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
985
                actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/icons/mode_light.svg"));
986
                actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
987
                actAutoHide.setIcon(pxAutoHideMode);
988
                actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
989
            }
990
            else {
991
                QPixmap pxEditHideMode = BitmapFactory().pixmap("qss:overlay/icons/edithide.svg");
992
                action->setIcon(pxEditHideMode);
993
                QPixmap pxAutoHideMode =
994
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
995
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
996
                actNoAutoMode.setIcon(
997
                    BitmapFactory().pixmap("qss:overlay/icons/mode_lightgray.svg"));
998
                actEditShow.setIcon(
999
                    BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
1000
                actAutoHide.setIcon(pxAutoHideMode);
1001
                actTaskShow.setIcon(
1002
                    BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
1003
            }
1004
            break;
1005
        default:
1006
            action = &actNoAutoMode;
1007
            if (isStyleSheetDark(curStyleSheet)) {
1008
                QPixmap pxNoAutoMode = BitmapFactory().pixmap("qss:overlay/icons/mode_lighter.svg");
1009
                action->setIcon(pxNoAutoMode);
1010
                QPixmap pxAutoHideMode =
1011
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_light.svg");
1012
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
1013
                actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/taskshow_light.svg"));
1014
                actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/icons/editshow_light.svg"));
1015
                actAutoHide.setIcon(pxAutoHideMode);
1016
                actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/icons/edithide_light.svg"));
1017
            }
1018
            else {
1019
                QPixmap pxNoAutoMode = BitmapFactory().pixmap("qss:overlay/icons/mode.svg");
1020
                action->setIcon(pxNoAutoMode);
1021
                QPixmap pxAutoHideMode =
1022
                    BitmapFactory().pixmap("qss:overlay/icons/autohide_lightgray.svg");
1023
                pxAutoHideMode = rotateAutoHideIcon(pxAutoHideMode, dockArea);
1024
                actTaskShow.setIcon(
1025
                    BitmapFactory().pixmap("qss:overlay/icons/taskshow_lightgray.svg"));
1026
                actEditShow.setIcon(
1027
                    BitmapFactory().pixmap("qss:overlay/icons/editshow_lightgray.svg"));
1028
                actAutoHide.setIcon(pxAutoHideMode);
1029
                actEditHide.setIcon(
1030
                    BitmapFactory().pixmap("qss:overlay/icons/edithide_lightgray.svg"));
1031
            }
1032
            break;
1033
    }
1034
    actAutoMode.setIcon(action->icon());
1035
    if (action == &actNoAutoMode) {
1036
        actAutoMode.setToolTip(tr("Select auto show/hide mode"));
1037
    }
1038
    else {
1039
        actAutoMode.setToolTip(action->toolTip());
1040
    }
1041
}
1042

1043
void OverlayTabWidget::onAction(QAction *action)
1044
{
1045
    if (action == &actAutoMode) {
1046
        action = autoModeMenu.exec(QCursor::pos());
1047
        if (action == &actNoAutoMode)
1048
            setAutoMode(AutoMode::NoAutoMode);
1049
        else if (action == &actAutoHide)
1050
            setAutoMode(AutoMode::AutoHide);
1051
        else if (action == &actEditShow)
1052
            setAutoMode(AutoMode::EditShow);
1053
        else if (action == &actTaskShow)
1054
            setAutoMode(AutoMode::TaskShow);
1055
        else if (action == &actEditHide)
1056
            setAutoMode(AutoMode::EditHide);
1057
        return;
1058
    }
1059
    else if(action == &actOverlay) {
1060
        OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleActive);
1061
        return;
1062
    } else if(action == &actTransparent) {
1063
        if(hGrp) {
1064
            Base::StateLocker lock(_saving);
1065
            hGrp->SetBool("Transparent", actTransparent.isChecked());
1066
        }
1067
    }
1068
    OverlayManager::instance()->refresh(this);
1069
}
1070

1071
void OverlayTabWidget::setState(State state)
1072
{
1073
    if (_state == state)
1074
        return;
1075
    switch(state) {
1076
    case State::Normal:
1077
        if (_state == State::Hidden) {
1078
            // Only unhide through State::Showing, not State::Normal
1079
            return;
1080
        }
1081
        else if (_state == State::Showing) {
1082
            _state = state;
1083
            return;
1084
        }
1085
        // fall through
1086
    case State::Showing:
1087
        _state = state;
1088
        hide();
1089
        if (dockArea == Qt::RightDockWidgetArea)
1090
            setTabPosition(East);
1091
        else if (dockArea == Qt::BottomDockWidgetArea)
1092
            setTabPosition(South);
1093
        if (this->count() == 1)
1094
            tabBar()->hide();
1095
        _graphicsEffectTab->setEnabled(false);
1096
        titleBar->show();
1097
        splitter->show();
1098
        if (state == State::Showing)
1099
            OverlayManager::instance()->refresh(this);
1100
        break;
1101
    case State::Hint:
1102
        if (_state == State::HintHidden || _state == State::Hidden)
1103
            break;
1104
        _state = state;
1105
        if (this->count() && OverlayParams::getDockOverlayHintTabBar()) {
1106
            tabBar()->setToolTip(proxyWidget->toolTip());
1107
            tabBar()->show();
1108
            titleBar->hide();
1109
            splitter->hide();
1110
            _graphicsEffectTab->setEnabled(true);
1111
            show();
1112
            raise();
1113
            proxyWidget->raise();
1114
            if (dockArea == Qt::RightDockWidgetArea)
1115
                setTabPosition(West);
1116
            else if (dockArea == Qt::BottomDockWidgetArea)
1117
                setTabPosition(North);
1118
            OverlayManager::instance()->refresh(this);
1119
        }
1120
        break;
1121
    case State::HintHidden:
1122
        if (_state != State::Hidden)
1123
            _state = state;
1124
        proxyWidget->hide();
1125
        hide();
1126
        _graphicsEffectTab->setEnabled(true);
1127
        break;
1128
    case State::Hidden:
1129
        startHide();
1130
        _state = state;
1131
        break;
1132
    default:
1133
        break;
1134
    }
1135
}
1136

1137
bool OverlayTabWidget::checkAutoHide() const
1138
{
1139
    if (autoMode == AutoMode::AutoHide) {
1140
        return true;
1141
    }
1142

1143
    if (OverlayParams::getDockOverlayAutoView()) {
1144
        auto view = getMainWindow()->activeWindow();
1145

1146
        if (!view) {
1147
            return true;
1148
        }
1149

1150
        if (!view->onHasMsg("AllowsOverlayOnHover")) {
1151
            return true;
1152
        }
1153

1154
        if (!view->onHasMsg("CanPan")
1155
                && view->parentWidget()
1156
                && view->parentWidget()->isMaximized()) {
1157
            return true;
1158
        }
1159
    }
1160

1161
    if (autoMode == AutoMode::EditShow) {
1162
        return !Application::Instance->editDocument()
1163
            && (!Control().taskPanel() || Control().taskPanel()->isEmpty(false));
1164
    }
1165

1166
    if (autoMode == AutoMode::EditHide && Application::Instance->editDocument()) {
1167
        return true;
1168
    }
1169

1170
    return false;
1171
}
1172

1173
void OverlayTabWidget::leaveEvent(QEvent*)
1174
{
1175
    if (titleBar && QWidget::mouseGrabber() == titleBar)
1176
        return;
1177
    OverlayManager::instance()->refresh();
1178
}
1179

1180
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1181
void OverlayTabWidget::enterEvent(QEvent*)
1182
#else
1183
void OverlayTabWidget::enterEvent(QEnterEvent*)
1184
#endif
1185
{
1186
    revealTime = QTime();
1187
    OverlayManager::instance()->refresh();
1188
}
1189

1190
void OverlayTabWidget::setRevealTime(const QTime &time)
1191
{
1192
    revealTime = time;
1193
}
1194

1195
void OverlayTabWidget::_setOverlayMode(QWidget *widget, OverlayOption option)
1196
{
1197
    if(!widget)
1198
        return;
1199

1200
#if QT_VERSION>QT_VERSION_CHECK(5,12,2) && QT_VERSION < QT_VERSION_CHECK(5,12,6)
1201
    // Work around Qt bug https://bugreports.qt.io/browse/QTBUG-77006
1202
    widget->setStyleSheet(OverlayManager::instance()->getStyleSheet());
1203
#endif
1204

1205
    if (qobject_cast<QScrollBar*>(widget)) {
1206
        auto parent = widget->parentWidget();
1207
        if (parent) {
1208
            parent = parent->parentWidget();
1209
            if (qobject_cast<PropertyEditor::PropertyEditor*>(parent)) {
1210
                auto scrollArea = static_cast<QAbstractScrollArea*>(parent);
1211
                if (scrollArea->verticalScrollBar() == widget) {
1212
                    if (!OverlayParams::getDockOverlayHidePropertyViewScrollBar()
1213
                            || option == OverlayOption::Disable)
1214
                        widget->setStyleSheet(QString());
1215
                    else {
1216
                        static QString _style = QStringLiteral("*{width:0}");
1217
                        widget->setStyleSheet(_style);
1218
                    }
1219
                }
1220
            }
1221
            auto treeView = qobject_cast<TreeWidget*>(parent);
1222
            if (treeView) {
1223
                auto scrollArea = static_cast<QAbstractScrollArea*>(parent);
1224
                if (scrollArea->verticalScrollBar() == widget) {
1225
                    if (!TreeParams::getHideScrollBar() || option == OverlayOption::Disable)
1226
                        widget->setStyleSheet(QString());
1227
                    else {
1228
                        static QString _style = QStringLiteral("*{width:0}");
1229
                        widget->setStyleSheet(_style);
1230
                    }
1231
                }
1232
            }
1233

1234
            if (treeView) {
1235
                auto header = treeView->header();
1236
                if (!TreeParams::getHideHeaderView() || option==OverlayOption::Disable)
1237
                    header->setStyleSheet(QString());
1238
                else {
1239
                    static QString _style = QStringLiteral(
1240
                            "QHeaderView:section {"
1241
                              "height: 0px;"
1242
                              "background-color: transparent;"
1243
                              "padding: 0px;"
1244
                              "border: transparent;}");
1245
                    header->setStyleSheet(_style);
1246
                }
1247
            }
1248
        }
1249
    }
1250

1251
    auto tabbar = qobject_cast<QTabBar*>(widget);
1252
    if(tabbar) {
1253
        if(!tabbar->autoHide() || tabbar->count()>1) {
1254
            if(!OverlayManager::instance()->getHideTab())
1255
                tabbar->setVisible(true);
1256
            else
1257
                tabbar->setVisible(option == OverlayOption::Disable
1258
                        || (option == OverlayOption::ShowTab && tabbar->count()>1));
1259
            return;
1260
        }
1261
    }
1262

1263
    if (!qobject_cast<QScrollArea*>(widget)
1264
            || !qobject_cast<Dialog::Clipping*>(widget->parentWidget())) {
1265
        if(option != OverlayOption::Disable) {
1266
            widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint);
1267
        } else {
1268
            widget->setWindowFlags(widget->windowFlags() & ~Qt::FramelessWindowHint);
1269
        }
1270
        widget->setAttribute(Qt::WA_NoSystemBackground, option != OverlayOption::Disable);
1271
        widget->setAttribute(Qt::WA_TranslucentBackground, option != OverlayOption::Disable);
1272
    }
1273
}
1274

1275
void OverlayTabWidget::setOverlayMode(QWidget *widget, OverlayOption option)
1276
{
1277
    if(!widget || (qobject_cast<QDialog*>(widget)
1278
                        && !qobject_cast<Dialog::Clipping*>(widget))
1279
               || qobject_cast<TaskView::TaskBox*>(widget))
1280
        return;
1281

1282
    if(widget != tabBar()) {
1283
        if(OverlayParams::getDockOverlayAutoMouseThrough()
1284
                && option == OverlayOption::ShowTab) {
1285
            widget->setMouseTracking(true);
1286
        }
1287
    }
1288

1289
    _setOverlayMode(widget, option);
1290

1291
    if(qobject_cast<QComboBox*>(widget)) {
1292
        // do not set child QAbstractItemView of QComboBox, otherwise the drop down box
1293
        // won't be shown
1294
        return;
1295
    }
1296
    for(auto child : widget->children())
1297
        setOverlayMode(qobject_cast<QWidget*>(child), option);
1298
}
1299

1300
void OverlayTabWidget::setTransparent(bool enable)
1301
{
1302
    if(actTransparent.isChecked() == enable)
1303
        return;
1304
    if(hGrp) {
1305
        Base::StateLocker lock(_saving);
1306
        hGrp->SetBool("Transparent", enable);
1307
    }
1308
    actTransparent.setChecked(enable);
1309
    OverlayManager::instance()->refresh(this);
1310
}
1311

1312
bool OverlayTabWidget::isTransparent() const
1313
{
1314
    if (!actTransparent.isChecked())
1315
        return false;
1316
    if(OverlayParams::getDockOverlayAutoView()) {
1317
        auto view = getMainWindow()->activeWindow();
1318
        if (!view) return false;
1319
        if(!view->onHasMsg("CanPan")
1320
                && view->parentWidget()
1321
                && view->parentWidget()->isMaximized())
1322
            return false;
1323
    }
1324
    return true;
1325
}
1326

1327
bool OverlayTabWidget::isOverlaid(QueryOption option) const
1328
{
1329
    if (option != QueryOption::QueryOverlay
1330
            && currentTransparent != isTransparent())
1331
        return option == QueryOption::TransparencyChanged;
1332
    return overlaid;
1333
}
1334

1335
void OverlayTabWidget::setAutoMode(AutoMode mode)
1336
{
1337
    if (autoMode == mode)
1338
        return;
1339
    autoMode = mode;
1340

1341
    if (hGrp) {
1342
        bool autohide = false, editshow = false, edithide = false, taskshow = false;
1343
        switch (mode) {
1344
        case AutoMode::AutoHide:
1345
            autohide = true;
1346
            break;
1347
        case AutoMode::EditShow:
1348
            editshow = true;
1349
            break;
1350
        case AutoMode::EditHide:
1351
            edithide = true;
1352
            break;
1353
        case AutoMode::TaskShow:
1354
            taskshow = true;
1355
            break;
1356
        default:
1357
            break;
1358
        }
1359
        Base::StateLocker lock(_saving);
1360
        hGrp->SetBool("AutoHide", autohide);
1361
        hGrp->SetBool("EditShow", editshow);
1362
        hGrp->SetBool("EditHide", edithide);
1363
        hGrp->SetBool("TaskShow", taskshow);
1364
    }
1365
    syncAutoMode();
1366
    OverlayManager::instance()->refresh(this);
1367
}
1368

1369
QDockWidget *OverlayTabWidget::currentDockWidget() const
1370
{
1371
    int index = -1;
1372
    for(int size : splitter->sizes()) {
1373
        ++index;
1374
        if(size>0)
1375
            return dockWidget(index);
1376
    }
1377
    return dockWidget(currentIndex());
1378
}
1379

1380
QDockWidget *OverlayTabWidget::dockWidget(int index) const
1381
{
1382
    if(index < 0 || index >= splitter->count())
1383
        return nullptr;
1384
    return qobject_cast<QDockWidget*>(splitter->widget(index));
1385
}
1386

1387
void OverlayTabWidget::updateSplitterHandles()
1388
{
1389
    if (overlaid || _state > State::Normal)
1390
        return;
1391
    for (int i=0, c=splitter->count(); i<c; ++i) {
1392
        auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
1393
        if (handle)
1394
            handle->showTitle(true);
1395
    }
1396
}
1397

1398
bool OverlayTabWidget::onEscape()
1399
{
1400
    if (getState() == OverlayTabWidget::State::Hint
1401
            || getState() == OverlayTabWidget::State::Hidden) {
1402
        setState(OverlayTabWidget::State::HintHidden);
1403
        return true;
1404
    }
1405
    if (!isVisible())
1406
        return false;
1407
    if (titleBar->isVisible() && titleBar->underMouse()) {
1408
        titleBar->hide();
1409
        return true;
1410
    }
1411
    for (int i=0, c=splitter->count(); i<c; ++i) {
1412
        auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
1413
        if (handle->isVisible() && handle->underMouse()) {
1414
            handle->showTitle(false);
1415
            return true;
1416
        }
1417
    }
1418
    return false;
1419
}
1420

1421
void OverlayTabWidget::setOverlayMode(bool enable)
1422
{
1423
    overlaid = enable;
1424

1425
    if(!isVisible() || !count())
1426
        return;
1427

1428
    touched = false;
1429

1430
    if (_state <= State::Normal) {
1431
        titleBar->setVisible(!enable || OverlayManager::instance()->isMouseTransparent());
1432
        for (int i=0, c=splitter->count(); i<c; ++i) {
1433
            auto handle = qobject_cast<OverlaySplitterHandle*>(splitter->handle(i));
1434
            if (handle)
1435
                handle->showTitle(!enable);
1436
        }
1437
    }
1438

1439
    QString stylesheet;
1440
    stylesheet = OverlayManager::instance()->getStyleSheet();
1441
    currentTransparent = isTransparent();
1442

1443
    OverlayOption option;
1444
    if(!enable && isTransparent()) {
1445
        option = OverlayOption::ShowTab;
1446
    } else if (enable
1447
            && !isTransparent()
1448
            && (autoMode == AutoMode::EditShow || autoMode == AutoMode::AutoHide)) {
1449
        option = OverlayOption::Disable;
1450
    } else {
1451
        option = enable?OverlayOption::Enable:OverlayOption::Disable;
1452
    }
1453
    setProperty("transparent", option != OverlayOption::Disable);
1454

1455
    proxyWidget->setStyleSheet(stylesheet);
1456
    this->setStyleSheet(stylesheet);
1457
    setOverlayMode(this, option);
1458

1459
    _graphicsEffect->setEnabled(effectEnabled() && (enable || isTransparent()));
1460

1461
    if (_state == State::Hint && OverlayParams::getDockOverlayHintTabBar()) {
1462
        tabBar()->setToolTip(proxyWidget->toolTip());
1463
        tabBar()->show();
1464
    } else if (OverlayParams::getDockOverlayHideTabBar() || count()==1) {
1465
        tabBar()->hide();
1466
    } else {
1467
        tabBar()->setToolTip(QString());
1468
        tabBar()->setVisible(!enable || !OverlayManager::instance()->getHideTab());
1469
    }
1470

1471
    setRect(rectOverlay);
1472
}
1473

1474
const QRect &OverlayTabWidget::getRect()
1475
{
1476
    return rectOverlay;
1477
}
1478

1479
bool OverlayTabWidget::getAutoHideRect(QRect &rect) const
1480
{
1481
    rect = rectOverlay;
1482
    int hintWidth = OverlayParams::getDockOverlayHintSize();
1483
    switch(dockArea) {
1484
    case Qt::LeftDockWidgetArea:
1485
    case Qt::RightDockWidgetArea:
1486
        if (_TopOverlay->isVisible() && _TopOverlay->_state <= State::Normal)
1487
            rect.setTop(std::max(rect.top(), _TopOverlay->rectOverlay.bottom()));
1488
        if (dockArea == Qt::RightDockWidgetArea)
1489
            rect.setLeft(rect.left() + std::max(rect.width()-hintWidth,0));
1490
        else
1491
            rect.setRight(rect.right() - std::max(rect.width()-hintWidth,0));
1492
        break;
1493
    case Qt::TopDockWidgetArea:
1494
    case Qt::BottomDockWidgetArea:
1495
        if (_LeftOverlay->isVisible() && _LeftOverlay->_state <= State::Normal)
1496
            rect.setLeft(std::max(rect.left(),_LeftOverlay->rectOverlay.right()));
1497
        if (dockArea == Qt::TopDockWidgetArea)
1498
            rect.setBottom(rect.bottom() - std::max(rect.height()-hintWidth,0));
1499
        else {
1500
            rect.setTop(rect.top() + std::max(rect.height()-hintWidth,0));
1501
            if (_RightOverlay->isVisible() && _RightOverlay->_state <= State::Normal) {
1502
                QPoint offset = getMainWindow()->getMdiArea()->pos();
1503
                rect.setRight(std::min(rect.right(), _RightOverlay->x()-offset.x()));
1504
            }
1505
        }
1506
        break;
1507
    default:
1508
        break;
1509
    }
1510
    return _state != State::Showing && overlaid && checkAutoHide();
1511
}
1512

1513
void OverlayTabWidget::setOffset(const QSize &ofs)
1514
{
1515
    if(offset != ofs) {
1516
        offset = ofs;
1517
        if(hGrp) {
1518
            Base::StateLocker lock(_saving);
1519
            hGrp->SetInt("Offset1", ofs.width());
1520
            hGrp->SetInt("Offset3", ofs.height());
1521
        }
1522
    }
1523
}
1524

1525
void OverlayTabWidget::setSizeDelta(int delta)
1526
{
1527
    if(sizeDelta != delta) {
1528
        if(hGrp) {
1529
            Base::StateLocker lock(_saving);
1530
            hGrp->SetInt("Offset2", delta);
1531
        }
1532
        sizeDelta = delta;
1533
    }
1534
}
1535

1536
void OverlayTabWidget::setRect(QRect rect)
1537
{
1538
    if(busy || !parentWidget() || !getMainWindow() || !getMainWindow()->getMdiArea())
1539
        return;
1540

1541
    if (rect.width() == 0)
1542
        rect.setWidth(OverlayParams::getDockOverlayMinimumSize()*3);
1543
    if (rect.height() == 0)
1544
        rect.setHeight(OverlayParams::getDockOverlayMinimumSize()*3);
1545

1546
    switch(dockArea) {
1547
    case Qt::LeftDockWidgetArea:
1548
        rect.moveLeft(0);
1549
        if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
1550
            rect.setWidth(OverlayParams::getDockOverlayMinimumSize());
1551
        break;
1552
    case Qt::RightDockWidgetArea:
1553
        if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
1554
            rect.setLeft(rect.right()-OverlayParams::getDockOverlayMinimumSize());
1555
        break;
1556
    case Qt::TopDockWidgetArea:
1557
        rect.moveTop(0);
1558
        if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
1559
            rect.setHeight(OverlayParams::getDockOverlayMinimumSize());
1560
        break;
1561
    case Qt::BottomDockWidgetArea:
1562
        if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
1563
            rect.setTop(rect.bottom()-OverlayParams::getDockOverlayMinimumSize());
1564
        break;
1565
    default:
1566
        break;
1567
    }
1568

1569
    if (hGrp && rect.size() != rectOverlay.size()) {
1570
        Base::StateLocker lock(_saving);
1571
        hGrp->SetInt("Width", rect.width());
1572
        hGrp->SetInt("Height", rect.height());
1573
    }
1574
    rectOverlay = rect;
1575

1576
    QPoint offset = getMainWindow()->getMdiArea()->pos();
1577

1578
    if (getAutoHideRect(rect) || _state == State::Hint || _state == State::Hidden) {
1579
        QRect rectHint = rect;
1580
        if (_state != State::Hint && _state != State::Hidden)
1581
            startHide();
1582
        else if (count() && OverlayParams::getDockOverlayHintTabBar()) {
1583
            switch(dockArea) {
1584
            case Qt::LeftDockWidgetArea:
1585
            case Qt::RightDockWidgetArea:
1586
                if (dockArea == Qt::LeftDockWidgetArea)
1587
                    rect.setWidth(tabBar()->width());
1588
                else
1589
                    rect.setLeft(rect.left() + rect.width() - tabBar()->width());
1590
                rect.setHeight(std::max(rect.height(),
1591
                            tabBar()->y() + tabBar()->sizeHint().height() + 5));
1592
                break;
1593
            case Qt::BottomDockWidgetArea:
1594
            case Qt::TopDockWidgetArea:
1595
                if (dockArea == Qt::TopDockWidgetArea)
1596
                    rect.setHeight(tabBar()->height());
1597
                else
1598
                    rect.setTop(rect.top() + rect.height() - tabBar()->height());
1599
                rect.setWidth(std::max(rect.width(),
1600
                            tabBar()->x() + tabBar()->sizeHint().width() + 5));
1601
                break;
1602
            default:
1603
                break;
1604
            }
1605

1606
            setGeometry(rect.translated(offset));
1607
        }
1608
        proxyWidget->setGeometry(rectHint.translated(offset));
1609
        if (count()) {
1610
            proxyWidget->show();
1611
            proxyWidget->raise();
1612
        } else
1613
            proxyWidget->hide();
1614

1615
    } else {
1616
        setGeometry(rectOverlay.translated(offset));
1617

1618
        for (int i = 0, count = splitter->count(); i < count; ++i) {
1619
            splitter->widget(i)->show();
1620
        }
1621

1622
        if (!isVisible() && count()) {
1623
            proxyWidget->hide();
1624
            startShow();
1625
        }
1626
    }
1627
}
1628

1629
void OverlayTabWidget::addWidget(QDockWidget *dock, const QString &title)
1630
{
1631
    if (!getMainWindow() || !getMainWindow()->getMdiArea())
1632
        return;
1633

1634
    OverlayManager::instance()->registerDockWidget(dock->objectName(), this);
1635

1636
    OverlayManager::setFocusView();
1637
    getMainWindow()->removeDockWidget(dock);
1638

1639
    auto titleWidget = dock->titleBarWidget();
1640
    if(titleWidget && titleWidget->objectName()==QStringLiteral("OverlayTitle")) {
1641
        // replace the title bar with an invisible widget to hide it. The
1642
        // OverlayTabWidget uses its own title bar for all docks.
1643
        auto w = new QWidget();
1644
        w->setObjectName(QStringLiteral("OverlayTitle"));
1645
        dock->setTitleBarWidget(w);
1646
        w->hide();
1647
        titleWidget->deleteLater();
1648
    }
1649

1650
    dock->show();
1651
    splitter->addWidget(dock);
1652
    auto dummyWidget = new QWidget(this);
1653
    addTab(dummyWidget, title);
1654
    connect(dock, &QObject::destroyed, dummyWidget, &QObject::deleteLater);
1655

1656
    dock->setFeatures(dock->features() & ~QDockWidget::DockWidgetFloatable);
1657
    if(count() == 1) {
1658
        QRect rect = dock->geometry();
1659
        QSize sizeMain = getMainWindow()->getMdiArea()->size();
1660
        switch(dockArea) {
1661
        case Qt::LeftDockWidgetArea:
1662
        case Qt::RightDockWidgetArea:
1663
            if (rect.width() > sizeMain.width()/3)
1664
                rect.setWidth(sizeMain.width()/3);
1665
            break;
1666
        case Qt::TopDockWidgetArea:
1667
        case Qt::BottomDockWidgetArea:
1668
            if (rect.height() > sizeMain.height()/3)
1669
                rect.setHeight(sizeMain.height()/3);
1670
            break;
1671
        default:
1672
            break;
1673
        }
1674
        setRect(rect);
1675
    }
1676

1677
    saveTabs();
1678
}
1679

1680
int OverlayTabWidget::dockWidgetIndex(QDockWidget *dock) const
1681
{
1682
    return splitter->indexOf(dock);
1683
}
1684

1685
void OverlayTabWidget::removeWidget(QDockWidget *dock, QDockWidget *lastDock)
1686
{
1687
    int index = dockWidgetIndex(dock);
1688
    if(index < 0)
1689
        return;
1690

1691
    OverlayManager::instance()->unregisterDockWidget(dock->objectName(), this);
1692

1693
    OverlayManager::setFocusView();
1694
    dock->show();
1695
    if(lastDock)
1696
        getMainWindow()->tabifyDockWidget(lastDock, dock);
1697
    else
1698
        getMainWindow()->addDockWidget(dockArea, dock);
1699

1700
    auto w = this->widget(index);
1701
    removeTab(index);
1702
    w->deleteLater();
1703

1704
    if(!count())
1705
        hide();
1706

1707
    w = dock->titleBarWidget();
1708
    if(w && w->objectName() == QStringLiteral("OverlayTitle")) {
1709
        dock->setTitleBarWidget(nullptr);
1710
        w->deleteLater();
1711
    }
1712
    OverlayManager::instance()->setupTitleBar(dock);
1713

1714
    dock->setFeatures(dock->features() | QDockWidget::DockWidgetFloatable);
1715

1716
    setOverlayMode(dock, OverlayOption::Disable);
1717

1718
    saveTabs();
1719
}
1720

1721
void OverlayTabWidget::resizeEvent(QResizeEvent *ev)
1722
{
1723
    QTabWidget::resizeEvent(ev);
1724
    if (_state <= State::Normal)
1725
        timer.start(10);
1726
}
1727

1728
void OverlayTabWidget::setupLayout()
1729
{
1730
    if (_state > State::Normal)
1731
        return;
1732

1733
    if(count() == 1)
1734
        tabSize = 0;
1735
    else {
1736
        int tsize;
1737
        if(dockArea==Qt::LeftDockWidgetArea || dockArea==Qt::RightDockWidgetArea)
1738
            tsize = tabBar()->width();
1739
        else
1740
            tsize = tabBar()->height();
1741
        tabSize = tsize;
1742
    }
1743
    int titleBarSize = widgetMinSize(this, true);
1744
    QRect rect, rectTitle;
1745
    switch(tabPosition()) {
1746
    case West:
1747
        rectTitle = QRect(tabSize, 0, this->width()-tabSize, titleBarSize);
1748
        rect = QRect(rectTitle.left(), rectTitle.bottom(),
1749
                     rectTitle.width(), this->height()-rectTitle.height());
1750
        break;
1751
    case East:
1752
        rectTitle = QRect(0, 0, this->width()-tabSize, titleBarSize);
1753
        rect = QRect(rectTitle.left(), rectTitle.bottom(),
1754
                     rectTitle.width(), this->height()-rectTitle.height());
1755
        break;
1756
    case North:
1757
        rectTitle = QRect(0, tabSize, titleBarSize, this->height()-tabSize);
1758
        rect = QRect(rectTitle.right(), rectTitle.top(),
1759
                     this->width()-rectTitle.width(), rectTitle.height());
1760
        break;
1761
    case South:
1762
        rectTitle = QRect(0, 0, titleBarSize, this->height()-tabSize);
1763
        rect = QRect(rectTitle.right(), rectTitle.top(),
1764
                     this->width()-rectTitle.width(), rectTitle.height());
1765
        break;
1766
    }
1767
    if (_animation != 0.0) {
1768
        switch(dockArea) {
1769
        case Qt::LeftDockWidgetArea:
1770
            rect.moveLeft(rect.left() - _animation * rect.width());
1771
            break;
1772
        case Qt::RightDockWidgetArea:
1773
            rect.moveLeft(rect.left() + _animation * rect.width());
1774
            break;
1775
        case Qt::TopDockWidgetArea:
1776
            rect.moveTop(rect.top() - _animation * rect.height());
1777
            break;
1778
        case Qt::BottomDockWidgetArea:
1779
            rect.moveTop(rect.top() + _animation * rect.height());
1780
            break;
1781
        default:
1782
            break;
1783
        }
1784
    }
1785
    splitter->setGeometry(rect);
1786
    titleBar->setGeometry(rectTitle);
1787
}
1788

1789
void OverlayTabWidget::setCurrent(QDockWidget *widget)
1790
{
1791
    int index = dockWidgetIndex(widget);
1792
    if(index >= 0)
1793
        setCurrentIndex(index);
1794
}
1795

1796
void OverlayTabWidget::onSplitterResize(int index)
1797
{
1798
    const auto &sizes = splitter->sizes();
1799
    if (index >= 0 && index < sizes.count()) {
1800
        if (sizes[index] == 0) {
1801
            if (currentIndex() == index) {
1802
                bool done = false;
1803
                for (int i=index+1; i<sizes.count(); ++i) {
1804
                    if (sizes[i] > 0) {
1805
                        setCurrentIndex(i);
1806
                        done = true;
1807
                        break;
1808
                    }
1809
                }
1810
                if (!done) {
1811
                    for (int i=index-1; i>=0 ;--i) {
1812
                        if (sizes[i] > 0) {
1813
                            setCurrentIndex(i);
1814
                            break;
1815
                        }
1816
                    }
1817
                }
1818
            }
1819
        } else
1820
            setCurrentIndex(index);
1821
    }
1822

1823
    saveTabs();
1824
}
1825

1826
void OverlayTabWidget::onCurrentChanged(int index)
1827
{
1828
    setState(State::Showing);
1829

1830
    auto sizes = splitter->sizes();
1831
    int i=0;
1832
    int size = splitter->orientation()==Qt::Vertical ?
1833
                    height()-tabBar()->height() : width()-tabBar()->width();
1834
    for(auto &s : sizes) {
1835
        if(i++ == index)
1836
            s = size;
1837
        else
1838
            s = 0;
1839
    }
1840
    splitter->setSizes(sizes);
1841
    onSplitterResize(index);
1842
    saveTabs();
1843
}
1844

1845
void OverlayTabWidget::onSizeGripMove(const QPoint &p)
1846
{
1847
    if (!getMainWindow() || !getMainWindow()->getMdiArea())
1848
        return;
1849

1850
    QPoint pos = mapFromGlobal(p) + this->pos();
1851
    QPoint offset = getMainWindow()->getMdiArea()->pos();
1852
    QRect rect = this->rectOverlay.translated(offset);
1853

1854
    switch(dockArea) {
1855
    case Qt::LeftDockWidgetArea:
1856
        if (pos.x() - rect.left() < OverlayParams::getDockOverlayMinimumSize())
1857
            return;
1858
        rect.setRight(pos.x());
1859
        break;
1860
    case Qt::RightDockWidgetArea:
1861
        if (rect.right() - pos.x() < OverlayParams::getDockOverlayMinimumSize())
1862
            return;
1863
        rect.setLeft(pos.x());
1864
        break;
1865
    case Qt::TopDockWidgetArea:
1866
        if (pos.y() - rect.top() < OverlayParams::getDockOverlayMinimumSize())
1867
            return;
1868
        rect.setBottom(pos.y());
1869
        break;
1870
    default:
1871
        if (rect.bottom() - pos.y() < OverlayParams::getDockOverlayMinimumSize())
1872
            return;
1873
        rect.setTop(pos.y());
1874
        break;
1875
    }
1876
    this->setRect(rect.translated(-offset));
1877
    OverlayManager::instance()->refresh();
1878
}
1879

1880
QLayoutItem *OverlayTabWidget::prepareTitleWidget(QWidget *widget, const QList<QAction*> &actions)
1881
{
1882
    bool vertical = false;
1883
    QBoxLayout *layout = nullptr;
1884
    auto tabWidget = qobject_cast<OverlayTabWidget*>(widget->parentWidget());
1885
    if(!tabWidget) {
1886
        layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
1887
    } else {
1888
        switch(tabWidget->getDockArea()) {
1889
            case Qt::LeftDockWidgetArea:
1890
                layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
1891
                break;
1892
            case Qt::RightDockWidgetArea:
1893
                layout = new QBoxLayout(QBoxLayout::RightToLeft, widget);
1894
                break;
1895
            case Qt::TopDockWidgetArea:
1896
                layout = new QBoxLayout(QBoxLayout::TopToBottom, widget);
1897
                vertical = true;
1898
                break;
1899
            case Qt::BottomDockWidgetArea:
1900
                layout = new QBoxLayout(QBoxLayout::BottomToTop, widget);
1901
                vertical = true;
1902
                break;
1903
            default:
1904
                break;
1905
        }
1906
    }
1907

1908
    layout->addSpacing(5);
1909
    layout->setContentsMargins(1,1,1,1);
1910
    int buttonSize = widgetMinSize(widget);
1911
    auto spacer = new QSpacerItem(buttonSize,buttonSize,
1912
            vertical?QSizePolicy::Minimum:QSizePolicy::Expanding,
1913
            vertical?QSizePolicy::Expanding:QSizePolicy::Minimum);
1914
    layout->addSpacerItem(spacer);
1915

1916
    for(auto action : actions)
1917
        layout->addWidget(OverlayTabWidget::createTitleButton(action, buttonSize));
1918

1919
    if (tabWidget) {
1920
        auto grip = new OverlaySizeGrip(tabWidget, vertical);
1921
        QObject::connect(grip, &OverlaySizeGrip::dragMove,
1922
                tabWidget, &OverlayTabWidget::onSizeGripMove);
1923
        layout->addWidget(grip);
1924
        grip->raise();
1925
    }
1926

1927
    return spacer;
1928
}
1929

1930
bool OverlayTabWidget::isStyleSheetDark(std::string curStyleSheet)
1931
{
1932
    if (curStyleSheet.find("dark") != std::string::npos
1933
        || curStyleSheet.find("Dark") != std::string::npos) {
1934
        return true;
1935
    }
1936
    return false;
1937
}
1938

1939
QPixmap OverlayTabWidget::rotateAutoHideIcon(QPixmap pxAutoHide, Qt::DockWidgetArea dockArea)
1940
{
1941
    switch (dockArea) {
1942
        case Qt::LeftDockWidgetArea:
1943
            return pxAutoHide;
1944
            break;
1945
        case Qt::RightDockWidgetArea:
1946
            return pxAutoHide.transformed(QTransform().scale(-1, 1));
1947
            break;
1948
        case Qt::TopDockWidgetArea:
1949
            return pxAutoHide.transformed(QTransform().rotate(90));
1950
            break;
1951
        case Qt::BottomDockWidgetArea:
1952
            return pxAutoHide.transformed(QTransform().rotate(-90));
1953
            break;
1954
        default:
1955
            return pxAutoHide;
1956
            break;
1957
    }
1958
}
1959

1960
// -----------------------------------------------------------
1961

1962
OverlayTitleBar::OverlayTitleBar(QWidget * parent)
1963
    :QWidget(parent)
1964
{
1965
    setFocusPolicy(Qt::ClickFocus);
1966
    setMouseTracking(true);
1967
    setCursor(Qt::OpenHandCursor);
1968
}
1969

1970
void OverlayTitleBar::setTitleItem(QLayoutItem *item)
1971
{
1972
    titleItem = item;
1973
}
1974

1975
void OverlayTitleBar::paintEvent(QPaintEvent *)
1976
{
1977
    if (!titleItem)
1978
        return;
1979

1980
    QDockWidget *dock = qobject_cast<QDockWidget*>(parentWidget());
1981
    int vertical = false;
1982
    int flags = Qt::AlignCenter;
1983
    if (!dock) {
1984
        OverlayTabWidget *tabWidget = qobject_cast<OverlayTabWidget*>(parentWidget());
1985
        if (tabWidget) {
1986
            switch(tabWidget->getDockArea()) {
1987
            case Qt::TopDockWidgetArea:
1988
                vertical = true;
1989
            // fallthrough
1990
            case Qt::RightDockWidgetArea:
1991
                flags = Qt::AlignRight;
1992
                break;
1993
            case Qt::BottomDockWidgetArea:
1994
                vertical = true;
1995
            // fallthrough
1996
            case Qt::LeftDockWidgetArea:
1997
                flags = Qt::AlignLeft;
1998
                break;
1999
            default:
2000
                break;
2001
            }
2002
            dock = tabWidget->dockWidget(0);
2003
        }
2004
    }
2005
    if (!dock)
2006
        return;
2007

2008
    QPainter painter(this);
2009
    if (qobject_cast<OverlayTabWidget*>(parentWidget()))
2010
        painter.fillRect(this->rect(), painter.background());
2011

2012
    QRect r = titleItem->geometry();
2013
    if (vertical) {
2014
        r = r.transposed();
2015
        painter.translate(r.left(), r.top() + r.width());
2016
        painter.rotate(-90);
2017
        painter.translate(-r.left(), -r.top());
2018
    }
2019

2020
    QString title;
2021
    if (OverlayManager::instance()->isMouseTransparent()) {
2022
        if (timerId == 0)
2023
            timerId = startTimer(500);
2024
        title = blink ? tr("Mouse pass through, ESC to stop") : dock->windowTitle();
2025
    } else {
2026
        if (timerId != 0) {
2027
            killTimer(timerId);
2028
            timerId = 0;
2029
        }
2030
        title = dock->windowTitle();
2031
    }
2032
    QString text = painter.fontMetrics().elidedText(
2033
            title, Qt::ElideRight, r.width());
2034
    painter.drawText(r, flags, text);
2035
}
2036

2037
void OverlayTitleBar::timerEvent(QTimerEvent *ev)
2038
{
2039
    if (timerId == ev->timerId()) {
2040
        update();
2041
        blink = !blink;
2042
    }
2043
}
2044

2045
static inline bool
2046
isNear(const QPoint &a, const QPoint &b, int tol = 16)
2047
{
2048
    QPoint d = a - b;
2049
    return d.x()*d.x() + d.y()*d.y() < tol;
2050
}
2051

2052
void OverlayTitleBar::endDrag()
2053
{
2054
    if (OverlayTabWidget::_Dragging == this) {
2055
        OverlayTabWidget::_Dragging = nullptr;
2056
        setCursor(Qt::OpenHandCursor);
2057
        if (OverlayTabWidget::_DragFrame)
2058
            OverlayTabWidget::_DragFrame->hide();
2059
        if (OverlayTabWidget::_DragFloating)
2060
            OverlayTabWidget::_DragFrame->hide();
2061
    }
2062
}
2063

2064
void OverlayTitleBar::mouseMoveEvent(QMouseEvent *me)
2065
{
2066
    if (ignoreMouse) {
2067
        if (!(me->buttons() & Qt::LeftButton))
2068
            ignoreMouse = false;
2069
        else {
2070
            me->ignore();
2071
            return;
2072
        }
2073
    }
2074

2075
    if (OverlayTabWidget::_Dragging != this && mouseMovePending && (me->buttons() & Qt::LeftButton)) {
2076
        if (isNear(dragOffset, me->pos()))
2077
            return;
2078
        mouseMovePending = false;
2079
        OverlayTabWidget::_Dragging = this;
2080
    }
2081

2082
    if (OverlayTabWidget::_Dragging != this)
2083
        return;
2084

2085
    if (!(me->buttons() & Qt::LeftButton)) {
2086
        endDrag();
2087
        return;
2088
    }
2089

2090
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2091
    QPoint point = me->globalPos();
2092
#else
2093
    QPoint point = me->globalPosition().toPoint();
2094
#endif
2095

2096
    OverlayManager::instance()->dragDockWidget(point,
2097
                                               parentWidget(),
2098
                                               dragOffset,
2099
                                               dragSize);
2100
}
2101

2102
void OverlayTitleBar::mousePressEvent(QMouseEvent *me)
2103
{
2104
    mouseMovePending = false;
2105
    QWidget *parent = parentWidget();
2106
    if (OverlayTabWidget::_Dragging || !parent || !getMainWindow() || me->button() != Qt::LeftButton)
2107
        return;
2108

2109
    dragSize = parent->size();
2110
    OverlayTabWidget *tabWidget = qobject_cast<OverlayTabWidget*>(parent);
2111
    if (!tabWidget) {
2112
        if(QApplication::queryKeyboardModifiers() == Qt::ShiftModifier) {
2113
            ignoreMouse = true;
2114
            me->ignore();
2115
            return;
2116
        }
2117
    }
2118
    else {
2119
        for (int s : tabWidget->getSplitter()->sizes()) {
2120
            if (!s)
2121
                continue;
2122
            if (tabWidget == OverlayTabWidget::_TopOverlay
2123
                    || tabWidget == OverlayTabWidget::_BottomOverlay) {
2124
                dragSize.setWidth(s + this->width());
2125
                dragSize.setHeight(tabWidget->height());
2126
            }
2127
            else {
2128
                dragSize.setHeight(s + this->height());
2129
                dragSize.setWidth(tabWidget->width());
2130
            }
2131
        }
2132
    }
2133
    ignoreMouse = false;
2134
    QSize mwSize = getMainWindow()->size();
2135
    dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
2136
                               static_cast<long>(std::min(mwSize.width()/2, dragSize.width()))));
2137
    dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
2138
                               static_cast<long>(std::min(mwSize.height()/2, dragSize.height()))));
2139

2140
    dragOffset = me->pos();
2141
    setCursor(Qt::ClosedHandCursor);
2142
    mouseMovePending = true;
2143
}
2144

2145
void OverlayTitleBar::mouseReleaseEvent(QMouseEvent *me)
2146
{
2147
    if (ignoreMouse) {
2148
        me->ignore();
2149
        return;
2150
    }
2151

2152
    setCursor(Qt::OpenHandCursor);
2153
    mouseMovePending = false;
2154
    if (OverlayTabWidget::_Dragging != this)
2155
        return;
2156

2157
    if (me->button() != Qt::LeftButton)
2158
        return;
2159

2160
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2161
    QPoint point = me->globalPos();
2162
#else
2163
    QPoint point = me->globalPosition().toPoint();
2164
#endif
2165

2166
    OverlayTabWidget::_Dragging = nullptr;
2167
    OverlayManager::instance()->dragDockWidget(point,
2168
                                               parentWidget(),
2169
                                               dragOffset,
2170
                                               dragSize,
2171
                                               true);
2172
    if (OverlayTabWidget::_DragFrame)
2173
        OverlayTabWidget::_DragFrame->hide();
2174
    if (OverlayTabWidget::_DragFloating)
2175
        OverlayTabWidget::_DragFloating->hide();
2176
}
2177

2178
void OverlayTitleBar::keyPressEvent(QKeyEvent *ke)
2179
{
2180
    if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
2181
        endDrag();
2182
}
2183

2184

2185
// -----------------------------------------------------------
2186

2187
OverlayDragFrame::OverlayDragFrame(QWidget * parent)
2188
    :QWidget(parent)
2189
{
2190
}
2191

2192
void OverlayDragFrame::paintEvent(QPaintEvent *)
2193
{
2194
    QPainter painter(this);
2195
    painter.drawRect(0, 0, this->width()-1, this->height()-1);
2196
    painter.setOpacity(0.3);
2197
    painter.setBrush(QBrush(Qt::blue));
2198
    painter.drawRect(0, 0, this->width()-1, this->height()-1);
2199
}
2200

2201
QSize OverlayDragFrame::sizeHint() const
2202
{
2203
    return size();
2204
}
2205

2206
QSize OverlayDragFrame::minimumSizeHint() const
2207
{
2208
    return minimumSize();
2209
}
2210

2211
// -----------------------------------------------------------
2212

2213
OverlaySizeGrip::OverlaySizeGrip(QWidget * parent, bool vertical)
2214
    :QWidget(parent), vertical(vertical)
2215
{
2216
    if (vertical) {
2217
        this->setFixedHeight(6);
2218
        this->setMinimumWidth(widgetMinSize(this,true));
2219
        this->setCursor(Qt::SizeVerCursor);
2220
    }
2221
    else {
2222
        this->setFixedWidth(6);
2223
        this->setMinimumHeight(widgetMinSize(this,true));
2224
        this->setCursor(Qt::SizeHorCursor);
2225
    }
2226
    setMouseTracking(true);
2227
}
2228

2229
void OverlaySizeGrip::paintEvent(QPaintEvent*)
2230
{
2231
    QPainter painter(this);
2232
    painter.setPen(Qt::transparent);
2233
    painter.setOpacity(0.5);
2234
    painter.setBrush(QBrush(Qt::black, Qt::Dense6Pattern));
2235
    QRect rect(this->rect());
2236
    painter.drawRect(rect);
2237
}
2238

2239
void OverlaySizeGrip::mouseMoveEvent(QMouseEvent *me)
2240
{
2241
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2242
    QPoint point = me->globalPos();
2243
#else
2244
    QPoint point = me->globalPosition().toPoint();
2245
#endif
2246

2247
    if ((me->buttons() & Qt::LeftButton)) {
2248
        Q_EMIT dragMove(point);
2249
    }
2250
}
2251

2252
void OverlaySizeGrip::mousePressEvent(QMouseEvent *)
2253
{
2254
}
2255

2256
void OverlaySizeGrip::mouseReleaseEvent(QMouseEvent *)
2257
{
2258
}
2259

2260
// -----------------------------------------------------------
2261

2262
OverlaySplitter::OverlaySplitter(QWidget *parent)
2263
    : QSplitter(parent)
2264
{
2265
}
2266

2267
QSplitterHandle * OverlaySplitter::createHandle()
2268
{
2269
    auto widget = new OverlaySplitterHandle(this->orientation(), this);
2270
    widget->setObjectName(QStringLiteral("OverlaySplitHandle"));
2271
    QList<QAction*> actions;
2272
    actions.append(&widget->actFloat);
2273
    widget->setTitleItem(OverlayTabWidget::prepareTitleWidget(widget, actions));
2274
    return widget;
2275
}
2276

2277
// -----------------------------------------------------------
2278

2279
OverlaySplitterHandle::OverlaySplitterHandle(Qt::Orientation orientation, QSplitter *parent)
2280
    : QSplitterHandle(orientation, parent)
2281
{
2282
    setMouseTracking(true);
2283
    setFocusPolicy(Qt::ClickFocus);
2284
    retranslate();
2285
    refreshIcons();
2286
    QObject::connect(&actFloat, &QAction::triggered, this, &OverlaySplitterHandle::onAction);
2287
    timer.setSingleShot(true);
2288
    QObject::connect(&timer, &QTimer::timeout, this, &OverlaySplitterHandle::onTimer);
2289
}
2290

2291
void OverlaySplitterHandle::refreshIcons()
2292
{
2293
    actFloat.setIcon(BitmapFactory().pixmap("qss:overlay/icons/float.svg"));
2294
}
2295

2296
void OverlaySplitterHandle::onTimer()
2297
{
2298
    if (isVisible() && qApp->widgetAt(QCursor::pos()) != this)
2299
        showTitle(false);
2300
}
2301

2302
void OverlaySplitterHandle::showEvent(QShowEvent *ev)
2303
{
2304
    if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
2305
            && qApp->widgetAt(QCursor::pos()) != this)
2306
        timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
2307
    QSplitterHandle::showEvent(ev);
2308
}
2309

2310
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2311
void OverlaySplitterHandle::enterEvent(QEvent *ev)
2312
#else
2313
void OverlaySplitterHandle::enterEvent(QEnterEvent *ev)
2314
#endif
2315
{
2316
    timer.stop();
2317
    QSplitterHandle::enterEvent(ev);
2318
}
2319

2320
void OverlaySplitterHandle::leaveEvent(QEvent *ev)
2321
{
2322
    if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0)
2323
        timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
2324
    QSplitterHandle::leaveEvent(ev);
2325
}
2326

2327
QSize OverlaySplitterHandle::sizeHint() const
2328
{
2329
    QSize size = QSplitterHandle::sizeHint();
2330
    int minSize = widgetMinSize(this,true);
2331
    if (this->orientation() == Qt::Vertical)
2332
        size.setHeight(std::max(minSize, size.height()));
2333
    else
2334
        size.setWidth(std::max(minSize, size.width()));
2335
    return size;
2336
}
2337

2338
void OverlaySplitterHandle::onAction()
2339
{
2340
    auto action = qobject_cast<QAction*>(sender());
2341
    if(action == &actFloat) {
2342
        QDockWidget *dock = dockWidget();
2343
        if (dock)
2344
            OverlayManager::instance()->floatDockWidget(dock);
2345
    }
2346
}
2347

2348
QDockWidget *OverlaySplitterHandle::dockWidget()
2349
{
2350
    QSplitter *parent = splitter();
2351
    if (!parent)
2352
        return nullptr;
2353

2354
    if (parent->handle(this->idx) != this) {
2355
        this->idx = -1;
2356
        for (int i=0, c=parent->count(); i<c; ++i) {
2357
            if (parent->handle(i) == this) {
2358
                this->idx = i;
2359
                break;
2360
            }
2361
        }
2362
    }
2363
    return qobject_cast<QDockWidget*>(parent->widget(this->idx));
2364
}
2365

2366
void OverlaySplitterHandle::retranslate()
2367
{
2368
    actFloat.setToolTip(QObject::tr("Toggle floating window"));
2369
}
2370

2371
void OverlaySplitterHandle::changeEvent(QEvent *e)
2372
{
2373
    QSplitterHandle::changeEvent(e);
2374
    if (e->type() == QEvent::LanguageChange)
2375
        retranslate();
2376
}
2377

2378
void OverlaySplitterHandle::setTitleItem(QLayoutItem *item)
2379
{
2380
    titleItem = item;
2381
}
2382

2383
void OverlaySplitterHandle::showTitle(bool enable)
2384
{
2385
    if (_showTitle == enable)
2386
        return;
2387
    if (!enable)
2388
        unsetCursor();
2389
    else {
2390
        setCursor(this->orientation() == Qt::Horizontal
2391
                ?  Qt::SizeHorCursor : Qt::SizeVerCursor);
2392
        if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
2393
                && qApp->widgetAt(QCursor::pos()) != this)
2394
            timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
2395
    }
2396
    _showTitle = enable;
2397
    for (auto child : findChildren<QWidget*>(QString(), Qt::FindDirectChildrenOnly))
2398
        child->setVisible(enable);
2399
    update();
2400
}
2401

2402
void OverlaySplitterHandle::paintEvent(QPaintEvent *e)
2403
{
2404
    if (!_showTitle)
2405
        return;
2406

2407
    if (!titleItem) {
2408
        QSplitterHandle::paintEvent(e);
2409
        return;
2410
    }
2411

2412
    int flags = Qt::AlignCenter;
2413
    auto tabWidget = qobject_cast<OverlayTabWidget*>(
2414
            splitter() ? splitter()->parentWidget() : nullptr);
2415

2416
    if (tabWidget) {
2417
        switch(tabWidget->getDockArea()) {
2418
        case Qt::TopDockWidgetArea:
2419
        case Qt::RightDockWidgetArea:
2420
            flags = Qt::AlignRight;
2421
            break;
2422
        case Qt::BottomDockWidgetArea:
2423
        case Qt::LeftDockWidgetArea:
2424
            flags = Qt::AlignLeft;
2425
            break;
2426
        default:
2427
            break;
2428
        }
2429
    }
2430

2431
    QDockWidget *dock = dockWidget();
2432
    if (!dock) {
2433
        QSplitterHandle::paintEvent(e);
2434
        return;
2435
    }
2436

2437
    QPainter painter(this);
2438
    painter.fillRect(this->rect(), painter.background());
2439

2440
    QRect r = titleItem->geometry();
2441
    if (this->orientation() != Qt::Vertical) {
2442
        r = r.transposed();
2443
        painter.translate(r.left(), r.top() + r.width());
2444
        painter.rotate(-90);
2445
        painter.translate(-r.left(), -r.top());
2446
    }
2447
    QString text = painter.fontMetrics().elidedText(
2448
            dock->windowTitle(), Qt::ElideRight, r.width());
2449

2450
    painter.drawText(r, flags, text);
2451
}
2452

2453
void OverlaySplitterHandle::endDrag()
2454
{
2455
    auto tabWidget = qobject_cast<OverlayTabWidget*>(splitter()->parentWidget());
2456
    if (tabWidget) {
2457
        dockWidget();
2458
        tabWidget->onSplitterResize(this->idx);
2459
    }
2460
    OverlayTabWidget::_Dragging = nullptr;
2461
    setCursor(this->orientation() == Qt::Horizontal
2462
            ?  Qt::SizeHorCursor : Qt::SizeVerCursor);
2463
    if (OverlayTabWidget::_DragFrame)
2464
        OverlayTabWidget::_DragFrame->hide();
2465
    if (OverlayTabWidget::_DragFloating)
2466
        OverlayTabWidget::_DragFloating->hide();
2467
}
2468

2469
void OverlaySplitterHandle::keyPressEvent(QKeyEvent *ke)
2470
{
2471
    if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
2472
        endDrag();
2473
}
2474

2475
void OverlaySplitterHandle::mouseMoveEvent(QMouseEvent *me)
2476
{
2477
    if (OverlayTabWidget::_Dragging != this)
2478
        return;
2479

2480
    if (!(me->buttons() & Qt::LeftButton)) {
2481
        endDrag();
2482
        return;
2483
    }
2484

2485
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2486
    QPoint point = me->globalPos();
2487
#else
2488
    QPoint point = me->globalPosition().toPoint();
2489
#endif
2490

2491
    if (dragging == 1) {
2492
        OverlayTabWidget *overlay = qobject_cast<OverlayTabWidget*>(
2493
                splitter()->parentWidget());
2494
        QPoint pos = me->pos();
2495
        if (overlay) {
2496
            switch(overlay->getDockArea()) {
2497
            case Qt::LeftDockWidgetArea:
2498
            case Qt::RightDockWidgetArea:
2499
                if (pos.x() < 0 || pos.x() > overlay->width())
2500
                    dragging = 2;
2501
                break;
2502
            case Qt::TopDockWidgetArea:
2503
            case Qt::BottomDockWidgetArea:
2504
                if (pos.y() < 0 || pos.y() > overlay->height())
2505
                    dragging = 2;
2506
                break;
2507
            default:
2508
                break;
2509
            }
2510
        }
2511
        if (dragging == 1) {
2512
            QPoint offset = parentWidget()->mapFromGlobal(point) - dragOffset;
2513
            moveSplitter(this->orientation() == Qt::Horizontal ? offset.x() : offset.y());
2514
            return;
2515
        }
2516
        setCursor(Qt::ClosedHandCursor);
2517
    }
2518

2519
    OverlayManager::instance()->dragDockWidget(point,
2520
                                               dockWidget(),
2521
                                               dragOffset,
2522
                                               dragSize);
2523
}
2524

2525
void OverlaySplitterHandle::mousePressEvent(QMouseEvent *me)
2526
{
2527
    if (OverlayTabWidget::_Dragging || !getMainWindow() || me->button() != Qt::LeftButton)
2528
        return;
2529

2530
    OverlayTabWidget::_Dragging = this;
2531
    dragging = 1;
2532
    dragOffset = me->pos();
2533
    auto dock = dockWidget();
2534
    if (dock) {
2535
        dragSize = dock->size();
2536
        dock->show();
2537
    } else
2538
        dragSize = QSize();
2539

2540
    QSize mwSize = getMainWindow()->size();
2541
    dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
2542
                               static_cast<long>(std::min(mwSize.width()/2, dragSize.width()))));
2543
    dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
2544
                                static_cast<long>(std::min(mwSize.height()/2, dragSize.height()))));
2545

2546
}
2547

2548
void OverlaySplitterHandle::mouseReleaseEvent(QMouseEvent *me)
2549
{
2550
    if (OverlayTabWidget::_Dragging != this || me->button() != Qt::LeftButton)
2551
        return;
2552

2553
    if (dragging == 1) {
2554
        endDrag();
2555
        return;
2556
    }
2557
    endDrag();
2558

2559
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2560
    QPoint point = me->globalPos();
2561
#else
2562
    QPoint point = me->globalPosition().toPoint();
2563
#endif
2564

2565
    OverlayManager::instance()->dragDockWidget(point,
2566
                                               dockWidget(),
2567
                                               dragOffset,
2568
                                               dragSize,
2569
                                               true);
2570
    // Warning! the handle itself maybe deleted after return from
2571
    // dragDockWidget().
2572
}
2573

2574
// -----------------------------------------------------------
2575

2576
OverlayGraphicsEffect::OverlayGraphicsEffect(QObject *parent) :
2577
    QGraphicsEffect(parent),
2578
    _enabled(false),
2579
    _size(1,1),
2580
    _blurRadius(2.0f),
2581
    _color(0, 0, 0, 80)
2582
{
2583
}
2584

2585
QT_BEGIN_NAMESPACE
2586
  extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
2587
QT_END_NAMESPACE
2588

2589
void OverlayGraphicsEffect::draw(QPainter* painter)
2590
{
2591
    // if nothing to show outside the item, just draw source
2592
    if (!_enabled || _blurRadius + _size.height() <= 0 || _blurRadius + _size.width() <= 0) {
2593
        drawSource(painter);
2594
        return;
2595
    }
2596

2597
    PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect;
2598
    QPoint offset;
2599
    QPixmap px = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
2600

2601
    // return if no source
2602
    if (px.isNull())
2603
        return;
2604

2605
#if 0
2606
    if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
2607
        static int count;
2608
        getMainWindow()->showMessage(
2609
                QStringLiteral("dock overlay redraw %1").arg(count++));
2610
    }
2611
#endif
2612

2613
    QTransform restoreTransform = painter->worldTransform();
2614
    painter->setWorldTransform(QTransform());
2615

2616
    // Calculate size for the background image
2617
    QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
2618
    tmp.setDevicePixelRatio(px.devicePixelRatioF());
2619
    tmp.fill(0);
2620
    QPainter tmpPainter(&tmp);
2621
    QPainterPath clip;
2622
    tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
2623
    if(_size.width() == 0 && _size.height() == 0)
2624
        tmpPainter.drawPixmap(QPoint(0, 0), px);
2625
    else {
2626
        // exclude splitter handles
2627
        auto splitter = qobject_cast<QSplitter*>(parent());
2628
        if (splitter) {
2629
            int i = -1;
2630
            for (int size : splitter->sizes()) {
2631
                ++i;
2632
                if (!size)
2633
                    continue;
2634
                QWidget *w = splitter->widget(i);
2635
                if (w->findChild<TaskView::TaskView*>())
2636
                    continue;
2637
                QRect rect = w->geometry();
2638
                if (splitter->orientation() == Qt::Vertical)
2639
                    clip.addRect(rect.x(), rect.y()+4,
2640
                                rect.width(), rect.height()-4);
2641
                else
2642
                    clip.addRect(rect.x()+4, rect.y(),
2643
                                rect.width()-4, rect.height());
2644
            }
2645
            if (clip.isEmpty()) {
2646
                drawSource(painter);
2647
                return;
2648
            }
2649
            tmpPainter.setClipPath(clip);
2650
        }
2651

2652
        for (int x=-_size.width();x<=_size.width();++x) {
2653
            for (int y=-_size.height();y<=_size.height();++y) {
2654
                if (x || y) {
2655
                    tmpPainter.drawPixmap(QPoint(x, y), px);
2656
                    tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
2657
                }
2658
            }
2659
        }
2660
    }
2661
    tmpPainter.end();
2662

2663
    // blur the alpha channel
2664
    QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
2665
    blurred.setDevicePixelRatio(px.devicePixelRatioF());
2666
    blurred.fill(0);
2667
    QPainter blurPainter(&blurred);
2668
    qt_blurImage(&blurPainter, tmp, blurRadius(), false, true);
2669
    blurPainter.end();
2670

2671
    tmp = blurred;
2672

2673
    // blacken the image...
2674
    tmpPainter.begin(&tmp);
2675
    tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
2676
    tmpPainter.fillRect(tmp.rect(), color());
2677
    tmpPainter.end();
2678

2679
    // draw the blurred shadow...
2680
    painter->drawImage(QPointF(offset.x()+_offset.x(), offset.y()+_offset.y()), tmp);
2681

2682
    // draw the actual pixmap...
2683
    painter->drawPixmap(offset, px, QRectF());
2684

2685
#if 0
2686
    QWidget *focus = qApp->focusWidget();
2687
    if (focus) {
2688
        QWidget *widget = qobject_cast<QWidget*>(this->parent());
2689
        if (auto *edit = qobject_cast<QPlainTextEdit*>(focus)) {
2690
            if (!edit->isReadOnly() && edit->isEnabled()) {
2691
                for(auto w=edit->parentWidget(); w; w=w->parentWidget()) {
2692
                    if (w == widget) {
2693
                        QRect r = edit->cursorRect();
2694
                        QRect rect(edit->viewport()->mapTo(widget, r.topLeft()),
2695
                                edit->viewport()->mapTo(widget, r.bottomRight()));
2696
                        // painter->fillRect(rect, edit->textColor());
2697
                        // painter->fillRect(rect, edit->currentCharFormat().foreground());
2698
                        painter->fillRect(rect.translated(offset), Qt::white);
2699
                    }
2700
                }
2701
            }
2702
        }
2703
    }
2704
#endif
2705

2706
    // restore world transform
2707
    painter->setWorldTransform(restoreTransform);
2708
}
2709

2710
QRectF OverlayGraphicsEffect::boundingRectFor(const QRectF& rect) const
2711
{
2712
    if (!_enabled)
2713
        return rect;
2714
    return rect.united(rect.adjusted(-_blurRadius - _size.width() + _offset.x(),
2715
                                     -_blurRadius - _size.height()+ _offset.y(),
2716
                                     _blurRadius + _size.width() + _offset.x(),
2717
                                     _blurRadius + _size.height() + _offset.y()));
2718
}
2719

2720
#include "moc_OverlayWidgets.cpp"
2721

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.