diff --git a/src/basewindow.cpp b/src/basewindow.cpp index 728e212..3e008a1 100644 --- a/src/basewindow.cpp +++ b/src/basewindow.cpp @@ -15,6 +15,7 @@ */ #include "basewindow.h" +#include "mainwindow.h" #include #include @@ -25,10 +26,48 @@ BaseWindow::BaseWindow (QWidget *parent) : QMainWindow (parent) { } +bool +BaseWindow::touches (QWidget *widget) +{ + if (this == widget) { + return true; + } + + qint32 left = x (); + qint32 right = left + width (); + qint32 top = y (); + qint32 bottom = top + height (); + + qint32 w_left = widget->x (); + qint32 w_right = w_left + widget->width (); + qint32 w_top = widget->y (); + qint32 w_bottom = w_top + widget->height (); + + if (( (top <= w_bottom) && (bottom >= w_top) && + ((left == w_right || right == w_left)) ) || + ( (left <= w_right) && (right >= w_left) && + ((top == w_bottom) || (bottom == w_top) ) )) { + return true; + } + + return false; +} + +MainWindow * +BaseWindow::mw () +{ + //MainWindow is the only BaseWindow without a *parent + if (parent ()) { + return qobject_cast(parent ()); + } else { + return qobject_cast(this); + } +} + void BaseWindow::mousePressEvent (QMouseEvent *event) { - if (event->buttons () & Qt::LeftButton) { + if (event->button () == Qt::LeftButton) { m_diff = event->pos (); } } @@ -36,8 +75,9 @@ BaseWindow::mousePressEvent (QMouseEvent *event) void BaseWindow::mouseReleaseEvent (QMouseEvent *event) { - if (event->buttons () & Qt::LeftButton) { + if (event->button () == Qt::LeftButton) { m_diff = QPoint (0, 0); + mw ()->attachWidgets (); } } @@ -52,7 +92,7 @@ BaseWindow::mouseMoveEvent (QMouseEvent *event) } QPoint -BaseWindow::snapWindow(QPoint pos) +BaseWindow::snapWindow(QPoint pos, QWidgetList ignore) { //TODO: make snapdistance configurable qint32 snapdistance = 10; @@ -62,9 +102,18 @@ BaseWindow::snapWindow(QPoint pos) qint32 top = pos.y (); qint32 bottom = top + height (); - qDebug ("top: %i, bottom: %i, left: %i, right: %i", top, bottom, left, right); QWidgetList widgets = qApp->topLevelWidgets (); QWidget *w; + // ignore widgets, MainWindow needs this for attached Widgets + if (!ignore.isEmpty ()) { + foreach (w, ignore) { + int i = widgets.indexOf (w); + if (i >= 0) { + widgets.removeAt (i); + } + } + } + // snap to left or right edge bool snappedV = false; bool snappedH = false; diff --git a/src/basewindow.h b/src/basewindow.h index c73879b..a47deb6 100644 --- a/src/basewindow.h +++ b/src/basewindow.h @@ -21,20 +21,23 @@ class QMouseEvent; class QPoint; +class MainWindow; + class BaseWindow : public QMainWindow { Q_OBJECT public: BaseWindow (QWidget *parent); + + bool touches (QWidget *); + MainWindow * mw (); protected: void mousePressEvent (QMouseEvent *event); void mouseReleaseEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); - QPoint snapWindow (QPoint pos); - - private: + QPoint snapWindow (QPoint pos, QWidgetList ignore = QWidgetList()); QPoint m_diff; }; diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index d731909..c95a9bd 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include MainWindow::MainWindow (QWidget *parent) : BaseWindow (parent) @@ -125,6 +126,19 @@ MainWindow::raisePL (void) m_playlistwin->raise (); } +void +MainWindow::mouseMoveEvent (QMouseEvent *event) +{ + if ((event->buttons () & Qt::LeftButton) && !m_diff.isNull ()) { + QWidgetList ignore; + QWidget *w; + foreach (w, m_attachedWidgets.keys ()) { + ignore.append (w); + } + move (snapWindow (event->globalPos() - m_diff, ignore)); + } +} + void MainWindow::moveEvent (QMoveEvent *event) { @@ -133,12 +147,60 @@ MainWindow::moveEvent (QMoveEvent *event) // move all connected windows to their new position // at the moment connected windows can be m_playlistwin and m_equalizer - if (!m_connectedWidgets.isEmpty ()) { - QMap::const_iterator i - = m_connectedWidgets.constBegin (); - while (i != m_connectedWidgets.constEnd ()) { + if (!m_attachedWidgets.isEmpty ()) { + QMap::const_iterator i + = m_attachedWidgets.constBegin (); + while (i != m_attachedWidgets.constEnd ()) { i.key()->move (pos () + i.value ()); ++i; } } } + +void +MainWindow::attachWidgets () +{ + m_attachedWidgets.clear (); + QList widgets; + QWidget *w; + foreach (w, qApp->topLevelWidgets ()) { + if (w == this) { + continue; + } + if (w->inherits ("BaseWindow")) { + widgets.append (qobject_cast (w)); + } + } + // attach widgets that directly touch MainWindow + BaseWindow *b; + foreach (b, widgets) { + if (b->touches (this)) { + m_attachedWidgets[b] = b->pos ()- pos (); + } + } + // now attach the windows, that indirectly touch mainwindow through an + // attached window + // widgets isn't modified, even if it might be more efficent, because + // that might produce some ugly, hard to trace bugs (modifying the + // base of an iterater while it is in use) + if (!m_attachedWidgets.isEmpty ()) { + bool found = false; + BaseWindow *att; + do { + found = false; + foreach (att, m_attachedWidgets.keys ()) { + foreach (b, widgets) { + if (m_attachedWidgets.contains (b)) { + continue; + } + if (att->touches (b)) { + m_attachedWidgets[b] = b->pos ()- pos (); + found = true; + } + } + } + + } while (found); + } + +} diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h index f7eae43..63ab8ec 100644 --- a/src/mainwindow/mainwindow.h +++ b/src/mainwindow/mainwindow.h @@ -20,6 +20,7 @@ #include class QWidget; +class QMouseEvent; class MainDisplay; class ShadedDisplay; @@ -45,8 +46,11 @@ class MainWindow : public BaseWindow bool isTimemodeReverse(void) { QSettings s; return s.value("MainWindow/timemodereverse").toBool(); } void setTimemodeReverse(bool b) { QSettings s; return s.setValue("MainWindow/timemodereverse",b); } + void attachWidgets (); + public slots: void switchDisplay (); + void mouseMoveEvent (QMouseEvent *event); private: bool isShaded (void) { QSettings s; return s.value("MainWindow/shaded").toBool(); } @@ -56,7 +60,7 @@ class MainWindow : public BaseWindow EqualizerWindow *m_equalizer; PlaylistWindow *m_playlistwin; - QMap m_connectedWidgets; + QMap m_attachedWidgets; };