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:
parent
3be99ae663
commit
13746f5c38
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user