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