Warning, file /plasma/oxygen/kstyle/oxygensplitterproxy.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //////////////////////////////////////////////////////////////////////////////
0002 // oxygensplitterproxy.cpp
0003 // Extended hit area for Splitters
0004 // -------------------
0005 //
0006 // SPDX-FileCopyrightText: 2011 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0007 //
0008 // Based on Bespin splitterproxy code
0009 // SPDX-FileCopyrightText: 2011 Thomas Luebking <thomas.luebking@web.de>
0010 //
0011 //
0012 // SPDX-License-Identifier: LGPL-2.0-only
0013 //////////////////////////////////////////////////////////////////////////////
0014 
0015 #include "oxygensplitterproxy.h"
0016 #include "oxygenstyleconfigdata.h"
0017 
0018 #include <QCoreApplication>
0019 #include <QDebug>
0020 #include <QPainter>
0021 
0022 namespace Oxygen
0023 {
0024 
0025 //____________________________________________________________________
0026 void SplitterFactory::setEnabled(bool value)
0027 {
0028     if (_enabled != value) {
0029         // store
0030         _enabled = value;
0031 
0032         // assign to existing splitters
0033         for (WidgetMap::iterator iter = _widgets.begin(); iter != _widgets.end(); ++iter) {
0034             if (iter.value())
0035                 iter.value().data()->setEnabled(value);
0036         }
0037     }
0038 }
0039 
0040 //____________________________________________________________________
0041 bool SplitterFactory::registerWidget(QWidget *widget)
0042 {
0043     // check widget type
0044     if (qobject_cast<QMainWindow *>(widget)) {
0045         WidgetMap::iterator iter(_widgets.find(widget));
0046         if (iter == _widgets.end() || !iter.value()) {
0047             widget->installEventFilter(&_addEventFilter);
0048             SplitterProxy *proxy(new SplitterProxy(widget, _enabled));
0049             widget->removeEventFilter(&_addEventFilter);
0050 
0051             widget->installEventFilter(proxy);
0052             _widgets.insert(widget, proxy);
0053 
0054         } else {
0055             widget->removeEventFilter(iter.value().data());
0056             widget->installEventFilter(iter.value().data());
0057         }
0058 
0059         return true;
0060 
0061     } else if (qobject_cast<QSplitterHandle *>(widget)) {
0062         QWidget *window(widget->window());
0063         WidgetMap::iterator iter(_widgets.find(window));
0064         if (iter == _widgets.end() || !iter.value()) {
0065             window->installEventFilter(&_addEventFilter);
0066             SplitterProxy *proxy(new SplitterProxy(window, _enabled));
0067             window->removeEventFilter(&_addEventFilter);
0068 
0069             widget->installEventFilter(proxy);
0070             _widgets.insert(window, proxy);
0071 
0072         } else {
0073             widget->removeEventFilter(iter.value().data());
0074             widget->installEventFilter(iter.value().data());
0075         }
0076 
0077         return true;
0078 
0079     } else
0080         return false;
0081 }
0082 
0083 //____________________________________________________________________
0084 void SplitterFactory::unregisterWidget(QWidget *widget)
0085 {
0086     WidgetMap::iterator iter(_widgets.find(widget));
0087     if (iter != _widgets.end()) {
0088         if (iter.value())
0089             iter.value().data()->deleteLater();
0090         _widgets.erase(iter);
0091     }
0092 }
0093 
0094 //____________________________________________________________________
0095 SplitterProxy::SplitterProxy(QWidget *parent, bool enabled)
0096     : QWidget(parent)
0097     , _enabled(enabled)
0098     , _timerId(0)
0099 {
0100     setAttribute(Qt::WA_TranslucentBackground, true);
0101     setAttribute(Qt::WA_OpaquePaintEvent, false);
0102     hide();
0103 }
0104 
0105 //____________________________________________________________________
0106 void SplitterProxy::setEnabled(bool value)
0107 {
0108     // make sure status has changed
0109     if (_enabled != value) {
0110         _enabled = value;
0111         if (_enabled)
0112             clearSplitter();
0113     }
0114 }
0115 
0116 //____________________________________________________________________
0117 bool SplitterProxy::eventFilter(QObject *object, QEvent *event)
0118 {
0119     // do nothing if disabled
0120     if (!_enabled)
0121         return false;
0122 
0123     // do nothing in case of mouse grab
0124     if (mouseGrabber())
0125         return false;
0126 
0127     switch (event->type()) {
0128     case QEvent::HoverEnter:
0129         if (!isVisible()) {
0130             // cast to splitter handle
0131             if (QSplitterHandle *handle = qobject_cast<QSplitterHandle *>(object)) {
0132                 setSplitter(handle);
0133             }
0134         }
0135 
0136         return false;
0137 
0138     case QEvent::HoverMove:
0139     case QEvent::HoverLeave:
0140         return isVisible() && object == _splitter.data();
0141 
0142     case QEvent::MouseMove:
0143     case QEvent::Timer:
0144     case QEvent::Move:
0145         return false;
0146 
0147     case QEvent::CursorChange:
0148         if (QWidget *window = qobject_cast<QMainWindow *>(object)) {
0149             if (window->cursor().shape() == Qt::SplitHCursor || window->cursor().shape() == Qt::SplitVCursor) {
0150                 setSplitter(window);
0151             }
0152         }
0153         return false;
0154 
0155     case QEvent::WindowDeactivate:
0156     case QEvent::MouseButtonRelease:
0157         clearSplitter();
0158         return false;
0159 
0160     default:
0161         return false;
0162     }
0163 }
0164 
0165 //____________________________________________________________________
0166 bool SplitterProxy::event(QEvent *event)
0167 {
0168     switch (event->type()) {
0169     case QEvent::MouseMove:
0170     case QEvent::MouseButtonPress:
0171     case QEvent::MouseButtonRelease: {
0172         // check splitter
0173         if (!_splitter)
0174             return false;
0175 
0176         event->accept();
0177 
0178         // grab on mouse press
0179         if (event->type() == QEvent::MouseButtonPress) {
0180             grabMouse();
0181             resize(1, 1);
0182         }
0183 
0184         // cast to mouse event
0185         QMouseEvent *mouseEvent(static_cast<QMouseEvent *>(event));
0186 
0187         // get relevant position to post mouse drag event to application
0188         if (event->type() == QEvent::MouseButtonPress) {
0189             // use hook, to make sure splitter is properly dragged
0190             QMouseEvent mouseEvent2(mouseEvent->type(), _hook, mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers());
0191 
0192             QCoreApplication::sendEvent(_splitter.data(), &mouseEvent2);
0193 
0194         } else {
0195             // map event position to current splitter and post.
0196             QMouseEvent mouseEvent2(mouseEvent->type(),
0197                                     _splitter.data()->mapFromGlobal(mouseEvent->globalPos()),
0198                                     mouseEvent->button(),
0199                                     mouseEvent->buttons(),
0200                                     mouseEvent->modifiers());
0201 
0202             QCoreApplication::sendEvent(_splitter.data(), &mouseEvent2);
0203         }
0204 
0205         // release grab on mouse-Release
0206         if (event->type() == QEvent::MouseButtonRelease && mouseGrabber() == this) {
0207             releaseMouse();
0208         }
0209 
0210         return true;
0211     }
0212 
0213     case QEvent::Timer:
0214         if (static_cast<QTimerEvent *>(event)->timerId() != _timerId) {
0215             return QWidget::event(event);
0216         }
0217 
0218         /*
0219         Fall through is intended.
0220         We somehow lost a QEvent::Leave before timeout. We fix it from here
0221         */
0222         Q_FALLTHROUGH();
0223 
0224     case QEvent::HoverLeave:
0225     case QEvent::Leave: {
0226         if (mouseGrabber() == this) {
0227             return true;
0228         }
0229 
0230         // reset splitter
0231         if (isVisible() && !rect().contains(mapFromGlobal(QCursor::pos()))) {
0232             clearSplitter();
0233         }
0234         return true;
0235     }
0236 
0237     default:
0238         return QWidget::event(event);
0239     }
0240 }
0241 
0242 //____________________________________________________________________
0243 void SplitterProxy::setSplitter(QWidget *widget)
0244 {
0245     // check if changed
0246     if (_splitter.data() == widget)
0247         return;
0248 
0249     // get cursor position
0250     const QPoint position(QCursor::pos());
0251 
0252     // store splitter and hook
0253     _splitter = widget;
0254     _hook = _splitter.data()->mapFromGlobal(position);
0255 
0256     // adjust rect
0257     QRect rect(0, 0, 2 * StyleConfigData::splitterProxyWidth(), 2 * StyleConfigData::splitterProxyWidth());
0258     rect.moveCenter(parentWidget()->mapFromGlobal(position));
0259     setGeometry(rect);
0260     setCursor(_splitter.data()->cursor().shape());
0261 
0262     // show
0263     raise();
0264     show();
0265 
0266     // timer used to automatically hide proxy in case leave events are lost
0267     if (!_timerId)
0268         _timerId = startTimer(150);
0269 }
0270 
0271 //____________________________________________________________________
0272 void SplitterProxy::clearSplitter(void)
0273 {
0274     // check if changed
0275     if (!_splitter)
0276         return;
0277 
0278     // release mouse
0279     if (mouseGrabber() == this)
0280         releaseMouse();
0281 
0282     // hide
0283     parentWidget()->setUpdatesEnabled(false);
0284     hide();
0285     parentWidget()->setUpdatesEnabled(true);
0286 
0287     // send hover event
0288     if (_splitter) {
0289         QHoverEvent hoverEvent(qobject_cast<QSplitterHandle *>(_splitter.data()) ? QEvent::HoverLeave : QEvent::HoverMove,
0290                                _splitter.data()->mapFromGlobal(QCursor::pos()),
0291                                _hook);
0292         QCoreApplication::sendEvent(_splitter.data(), &hoverEvent);
0293         _splitter.clear();
0294     }
0295 
0296     // kill timer if any
0297     if (_timerId) {
0298         killTimer(_timerId);
0299         _timerId = 0;
0300     }
0301 }
0302 }