File indexing completed on 2024-05-19 09:27:58
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 }