1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

More pleasant multi-line selection, refactoring

This commit is contained in:
krepa098 2015-01-14 19:43:52 +01:00
parent 3be99ae663
commit 13746f5c38
2 changed files with 68 additions and 28 deletions

View File

@ -35,6 +35,16 @@ T clamp(T x, T min, T max)
return x; return x;
} }
auto compareSmaller = [](const ChatLine::Ptr lhs, const qreal rhs) -> bool
{
return lhs->boundingSceneRect().top() < rhs;
};
auto compareGreater = [](const qreal lhs, const ChatLine::Ptr rhs) -> bool
{
return lhs < rhs->boundingSceneRect().bottom();
};
ChatLog::ChatLog(QWidget* parent) ChatLog::ChatLog(QWidget* parent)
: QGraphicsView(parent) : QGraphicsView(parent)
{ {
@ -120,6 +130,9 @@ ChatLog::ChatLog(QWidget* parent)
void ChatLog::clearSelection() void ChatLog::clearSelection()
{ {
if(selectionMode == None)
return;
for(int i=selFirstRow; i<=selLastRow; ++i) for(int i=selFirstRow; i<=selLastRow; ++i)
lines[i]->selectionCleared(); lines[i]->selectionCleared();
@ -275,6 +288,7 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
if(selectionMode == None && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) if(selectionMode == None && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance())
{ {
QPointF sceneClickPos = mapToScene(clickPos.toPoint()); QPointF sceneClickPos = mapToScene(clickPos.toPoint());
ChatLine::Ptr line = findLineByYPos(scenePos.y());
ChatLineContent* content = getContentFromPos(sceneClickPos); ChatLineContent* content = getContentFromPos(sceneClickPos);
if(content) if(content)
@ -292,23 +306,31 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
if(scene->mouseGrabberItem()) if(scene->mouseGrabberItem())
scene->mouseGrabberItem()->ungrabMouse(); scene->mouseGrabberItem()->ungrabMouse();
} }
else if(line.get())
{
selClickedRow = line->getRowIndex();
selFirstRow = selClickedRow;
selLastRow = selClickedRow;
selectionMode = Multi;
}
} }
if(selectionMode != None) if(selectionMode != None)
{ {
ChatLineContent* content = getContentFromPos(scenePos); ChatLineContent* content = getContentFromPos(scenePos);
ChatLine::Ptr line = findLineByYPos(scenePos.y());
if(!content && !line.get())
return;
int row;
if(content) if(content)
{ {
int row = content->getRow(); row = content->getRow();
int col = content->getColumn(); int col = content->getColumn();
if(row >= selClickedRow)
selLastRow = row;
if(row <= selClickedRow)
selFirstRow = row;
if(row == selClickedRow && col == selClickedCol) if(row == selClickedRow && col == selClickedCol)
{ {
selectionMode = Precise; selectionMode = Precise;
@ -316,36 +338,48 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
content->selectionMouseMove(scenePos); content->selectionMouseMove(scenePos);
selGraphItem->hide(); selGraphItem->hide();
} }
else else if(col != selClickedCol)
{ {
selectionMode = Multi; selectionMode = Multi;
lines[selClickedRow]->selectionCleared(); lines[selClickedRow]->selectionCleared();
updateMultiSelectionRect();
} }
} }
else if(line.get())
{
row = line->getRowIndex();
if(row != selClickedRow)
{
selectionMode = Multi;
lines[selClickedRow]->selectionCleared();
}
}
if(row >= selClickedRow)
selLastRow = row;
if(row <= selClickedRow)
selFirstRow = row;
updateMultiSelectionRect();
} }
} }
} }
//Much faster than QGraphicsScene::itemAt()!
ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const
{ {
if(lines.empty()) if(lines.empty())
return nullptr; return nullptr;
//Much faster than QGraphicsScene::itemAt()!
//the first visible line //the first visible line
auto lowerBound = std::upper_bound(lines.cbegin(), lines.cend(), scenePos.y(), [](const qreal lhs, const ChatLine::Ptr rhs) auto lowerBound = std::upper_bound(lines.cbegin(), lines.cend(), scenePos.y(), compareGreater);
{
return lhs < rhs->boundingSceneRect().bottom();
});
//the last visible line //the last visible line
auto upperBound = std::lower_bound(lines.cbegin(), lines.cend(), scenePos.y(), [](const ChatLine::Ptr lhs, const qreal rhs) auto upperBound = std::lower_bound(lines.cbegin(), lines.cend(), scenePos.y(), compareSmaller);
{
return lhs->boundingSceneRect().top() < rhs;
});
//find content //find content
for(auto itr = lowerBound; itr != upperBound; ++itr) for(auto itr = lowerBound; itr != upperBound; ++itr)
@ -587,16 +621,10 @@ void ChatLog::checkVisibility()
return; return;
// find first visible line // find first visible line
auto lowerBound = std::upper_bound(lines.cbegin(), lines.cend(), getVisibleRect().top(), [](const qreal lhs, const ChatLine::Ptr rhs) auto lowerBound = std::upper_bound(lines.cbegin(), lines.cend(), getVisibleRect().top(), compareGreater);
{
return lhs < rhs->boundingSceneRect().bottom();
});
// find last visible line // find last visible line
auto upperBound = std::lower_bound(lines.cbegin(), lines.cend(), getVisibleRect().bottom(), [](const ChatLine::Ptr lhs, const qreal rhs) auto upperBound = std::lower_bound(lines.cbegin(), lines.cend(), getVisibleRect().bottom(), compareSmaller);
{
return lhs->boundingSceneRect().top() < rhs;
});
// set visibilty // set visibilty
QList<ChatLine::Ptr> newVisibleLines; QList<ChatLine::Ptr> newVisibleLines;
@ -688,6 +716,16 @@ void ChatLog::updateTypingNotification()
notification->layout(useableWidth(), QPointF(0.0, posY)); notification->layout(useableWidth(), QPointF(0.0, posY));
} }
ChatLine::Ptr ChatLog::findLineByYPos(qreal yPos) const
{
auto lowerBound = std::upper_bound(lines.cbegin(), lines.cend(), yPos, compareGreater);
if(lowerBound != lines.cend())
return *lowerBound;
return ChatLine::Ptr();
}
QRectF ChatLog::calculateSceneRect() const QRectF ChatLog::calculateSceneRect() const
{ {
qreal bottom = (lines.empty() ? 0.0 : lines.last()->boundingSceneRect().bottom()); qreal bottom = (lines.empty() ? 0.0 : lines.last()->boundingSceneRect().bottom());

View File

@ -79,6 +79,8 @@ protected:
void updateMultiSelectionRect(); void updateMultiSelectionRect();
void updateTypingNotification(); void updateTypingNotification();
ChatLine::Ptr findLineByYPos(qreal yPos) const;
private slots: private slots:
void onSelectionTimerTimeout(); void onSelectionTimerTimeout();
@ -101,7 +103,7 @@ private:
ChatLine::Ptr typingNotification; ChatLine::Ptr typingNotification;
// selection // selection
int selClickedRow = -1; int selClickedRow = -1; //These 4 are only valid while selectionMode != None
int selClickedCol = -1; int selClickedCol = -1;
int selFirstRow = -1; int selFirstRow = -1;
int selLastRow = -1; int selLastRow = -1;