Make Windows attached to the Mainwindow snap to Windows they get near and move the mainwindow accordingly

This commit is contained in:
Thomas Frauendorfer 2008-02-29 18:23:06 +01:00
parent 553138578d
commit 989d699372
3 changed files with 157 additions and 96 deletions

View file

@ -92,35 +92,52 @@ BaseWindow::mouseMoveEvent (QMouseEvent *event)
}
QPoint
BaseWindow::snapWindow(QPoint pos, QWidgetList ignore)
BaseWindow::snapWindow(QPoint pos, AttachedWindowMap attached)
{
//TODO: make snapdistance configurable
qint32 snapdistance = 10;
qint32 left = pos.x ();
qint32 right = left + width ();
qint32 top = pos.y ();
qint32 bottom = top + height ();
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);
BaseWindow *b;
widgets.removeAt (widgets.indexOf (this));
// ignore attached widgets
// attached Widgets touch this window, and would create a strange movement
if (!attached.isEmpty ()) {
foreach (b, attached.keys ()) {
int i = widgets.indexOf (b);
if (i >= 0) {
widgets.removeAt (i);
}
}
}
bool vSnapped = false;
bool hSnapped = false;
attached.insert (this, QPoint (0,0));
BaseWindow *ref;
// equalizerwindow and playlistwindow have only process this method once
// the ugly part comes into play, because mainwindow also snaps to
// windows it's subwindows get near.
// We iterate over the moved window and all it's attached windows.
// if a attached window can snap to a window, we use the offset of
// this windows position to the mainwindow to calculate the position
// we have to move the mainwindow to.
//
// As soon as we have a horizontal an vertical postition where the
// windows can snap to, we stop further processing
// (vSnapped and hSnapped are used to keep track of that)
foreach (ref, attached.keys ()) {
qint32 left = pos.x () + attached[ref].x ();
qint32 right = left + ref->width ();
qint32 top = pos.y () + attached[ref].y ();
qint32 bottom = top + ref->height ();
QWidget *w;
// snap to left or right edge
bool snappedV = false;
bool snappedH = false;
foreach (w, widgets) {
if (w == this) {
continue;
}
if (!w->isVisible ()) {
continue;
}
@ -138,64 +155,103 @@ BaseWindow::snapWindow(QPoint pos, QWidgetList ignore)
// test if this widget can snap left or right to another widget
// and if it can, test if the tops or bottoms can also snap
if (!snappedV && (qAbs (w_left - right) < snapdistance)) {
pos.setX (w_left - width ());
snappedV = true;
if (snappedH) {
if (!vSnapped && (qAbs (w_left - right) < snapdistance)) {
pos.setX (w_left - ref->width () - attached[ref].x ());
vSnapped = true;
if (hSnapped) {
break;
}
if (qAbs (w_bottom - bottom) < snapdistance) {
pos.setY (w_bottom - height ());
pos.setY (w_bottom - ref->height () - attached[ref].y ());
hSnapped = true;
break;
} else if (qAbs (w_top - top) < snapdistance) {
pos.setY (w_top);
pos.setY (w_top - attached[ref].y ());
hSnapped = true;
break;
}
} else if (!snappedV && (qAbs (left - w_right) < snapdistance)) {
pos.setX (w_right);
snappedV = true;
if (snappedH) {
} else if (!vSnapped && (qAbs (left - w_right) < snapdistance)) {
pos.setX (w_right - attached[ref].x ());
vSnapped = true;
if (hSnapped) {
break;
}
if (qAbs (w_bottom - bottom) < snapdistance) {
pos.setY (w_bottom - height ());
pos.setY (w_bottom - ref->height () - attached[ref].y ());
hSnapped = true;
break;
} else if (qAbs (w_top - top) < snapdistance) {
pos.setY (w_top);
pos.setY (w_top - attached[ref].y ());
hSnapped = true;
break;
}
}
// test if this widget can snap to top or bottom of another widget
// and if it can, test if the left or right edges also can
if (!snappedH && (qAbs (top - w_bottom) < snapdistance)) {
pos.setY (w_bottom);
snappedH = true;
if (snappedV) {
if ((!hSnapped) && (qAbs (top - w_bottom) < snapdistance)) {
pos.setY (w_bottom - attached[ref].y ());
hSnapped = true;
if (vSnapped) {
break;
}
if (qAbs (w_left - left) < snapdistance) {
pos.setX (w_left);
pos.setX (w_left - attached[ref].x ());
vSnapped = true;
break;
} else if (qAbs (w_right - right) < snapdistance) {
pos.setX (w_right - width ());
pos.setX (w_right - ref->width () - attached[ref].x ());
vSnapped = true;
break;
}
} else if (!snappedH && (qAbs (w_top - bottom) < snapdistance)) {
pos.setY (w_top - height ());
snappedH = true;
if (snappedV) {
} else if ((!hSnapped) && (qAbs (w_top - bottom) < snapdistance)) {
pos.setY (w_top - ref->height () - attached[ref].y ());
hSnapped = true;
if (vSnapped) {
break;
}
if (qAbs (w_left - left) < snapdistance) {
pos.setX (w_left);
pos.setX (w_left - attached[ref].x ());
vSnapped = true;
break;
} else if (qAbs (w_right - right) < snapdistance) {
pos.setX (w_right - width ());
pos.setX (w_right - ref->width () - attached[ref].x ());
vSnapped = true;
break;
}
}
} // end foreach (w, widgets)
if (hSnapped && vSnapped) {
break;
}
} // end foreach (ref, attached)
return pos;
}
/*
if (!widgets.isEmpty ()) {
QPoint ret = testSnapWindow (this, pos, widgets);
// test is attached Windows can snap to a unattached window
if (((ret.x () == -1) || (ret.y () == -1)) && (!attached.isEmpty ())) {
QPoint tmp;
foreach (w, attached.keys ()) {
tmp = testSnapWindow (w, pos + attached[w], widgets);
if ((ret.x () == -1) && (tmp.x () > -1)) {
ret.setX (tmp.x () - attached[w].x ());
}
if ((ret.y () == -1) && (tmp.y () > -1)) {
ret.setY (tmp.y () - attached[w]. y());
}
ret = mergePoint (ret, tmp);
if ((ret.x () > -1) && (ret.y () > -1)) {
break;
}
}
}
// Subwindows didn't provide snap target for x and y axis:
ret = mergePoint (ret, pos);
return ret;
}
*/

View file

@ -18,11 +18,16 @@
#define __BASEWINDOW_H__
#include <QMainWindow>
#include <QPoint>
#include <QMap>
class QMouseEvent;
class QPoint;
class MainWindow;
class BaseWindow;
typedef QMap<BaseWindow *, QPoint> AttachedWindowMap;
class BaseWindow : public QMainWindow {
Q_OBJECT
@ -37,7 +42,7 @@ class BaseWindow : public QMainWindow {
void mouseReleaseEvent (QMouseEvent *event);
void mouseMoveEvent (QMouseEvent *event);
QPoint snapWindow (QPoint pos, QWidgetList ignore = QWidgetList());
QPoint snapWindow (QPoint pos, AttachedWindowMap attached = AttachedWindowMap());
QPoint m_diff;
};

View file

@ -132,12 +132,12 @@ 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));
// QWidgetList attached;
// QWidget *w;
// foreach (w, m_attachedWidgets.keys ()) {
// attached.append (w);
// }
move (snapWindow (event->globalPos() - m_diff, m_attachedWidgets));
}
}
@ -169,7 +169,7 @@ MainWindow::attachWidgets ()
if (w == this) {
continue;
}
if (w->inherits ("BaseWindow")) {
if ((w->inherits ("BaseWindow")) && (w->isVisible ())) {
widgets.append (qobject_cast<BaseWindow *> (w));
}
}