So your problem is you can either use the drag or the select mode. So you will either have to use drag and implement selection, or use the select mode and implement dragging, or implement both.
The big question is whether your mouseMoveEvent is being called while you are dragging. If so, it is not that hard to calculate how close you are to the edges of the window, and if you are within a given threshold, let's say 20 pixels, you either scroll or scale the view.
Determining how fast you scroll is so easy I wouldn't even call it an algorithm. Just set a scrollSpeed variable to like 21, and when you cursor is within 20 pixels of a border, just scroll by (scrollSpeed - distanceFromBorder). This way if your mouse is 18 pixels away from the border, your will scroll by 3 pixels, if it is 2 pixels from the border, you will scroll by 19 pixels.
Providing a working code sample would take too much time, you should be able to do it yourself, provided mouseMoveEvent is being called while dragging.
edit:
OK, found some time, here is some very basic and potentially flawed example, enough to get you started. What it does is it tracks the cursor position relative to the center of the view, and once the cursor is within a certain distance of a border (scrollThreshold value) it give you two numbers, ranging from 0 to scrollThreshold depending on how close to the border you are, the closer you are the bigger values you will get, then you simply scroll by PLUS/MINUS those values depending in which region of the view you are in and the direction you want to scroll in.
@
//header
class MGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
MGraphicsView(QGraphicsScene* parent);
protected:
void mouseMoveEvent(QMouseEvent *event);
};
//CPP
float scrollThreshold = 30;
void clamp(QPointF &value)
{
if ((value.x() > scrollThreshold) || (value.x() < 0)) value.rx() = 0;
else value.rx() = qAbs(value.x() - scrollThreshold);
if ((value.y() > scrollThreshold) || (value.y() < 0)) value.ry() = 0;
else value.ry() = qAbs(value.y() - scrollThreshold);;
}
MGraphicsView::MGraphicsView(QGraphicsScene *parent) : QGraphicsView(parent)
{
setDragMode(QGraphicsView::RubberBandDrag);
}
void MGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
QGraphicsView::mouseMoveEvent(event);
QPointF loc = event->posF();
QPointF d;
if ((loc.x() <= rect().center().x()) && (loc.y() <= rect().center().y()))
{
//top left
d.setX(frameGeometry().left() + loc.x());
d.setY(loc.y());
clamp(d);
if (d.x() || d.y()) scrollContentsBy(d.x()/2, d.y()/2);
repaint();
}
else if ((loc.x() <= rect().center().x()) && (loc.y() > rect().center().y()))
{
//bottom left
d.setX(frameGeometry().left() + loc.x());
d.setY(frameGeometry().bottom() - loc.y() - scrollThreshold);
clamp(d);
if (d.x() || d.y()) scrollContentsBy(d.x()/2, -(d.y()/2));
repaint();
}
else if ((loc.x() > rect().center().x()) && (loc.y() > rect().center().y()))
{
//bottom right
d.setX(frameGeometry().right() - loc.x());
d.setY(frameGeometry().bottom() - loc.y() - scrollThreshold);
clamp(d);
if (d.x() || d.y()) scrollContentsBy(-(d.x()/2), -(d.y()/2));
repaint();
}
else
{
//top right
d.setX(frameGeometry().right() - loc.x());
d.setY(loc.y());
clamp(d);
if (d.x() || d.y()) scrollContentsBy(-(d.x()/2), d.y()/2);
repaint();
}
}@
It does work a little buggy for me. It scrolls correctly but I get painting artefacts and corruption and even thou it scrolls the item remain in the same location after refresh. Don't know if it is a bug in Qt (I wasn't even able to subclass QGraphicsView in 4.8, compiler gave me a ton of errors, with 4.7.4 it is OK) or flaw in this hasty implementation. It should get you started though.