mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
revisited selection
This commit is contained in:
parent
c91b7cb03c
commit
661a8c4da4
|
@ -84,3 +84,8 @@ void ChatLineContent::visibilityChanged(bool)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ChatLineContent::getText() const
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@ public:
|
||||||
virtual bool isOverSelection(QPointF scenePos) const;
|
virtual bool isOverSelection(QPointF scenePos) const;
|
||||||
virtual QString getSelectedText() const;
|
virtual QString getSelectedText() const;
|
||||||
|
|
||||||
|
virtual QString getText() const;
|
||||||
|
|
||||||
virtual qreal firstLineVOffset() const;
|
virtual qreal firstLineVOffset() const;
|
||||||
|
|
||||||
virtual QRectF boundingSceneRect() const = 0;
|
virtual QRectF boundingSceneRect() const = 0;
|
||||||
|
|
|
@ -57,6 +57,12 @@ ChatLog::ChatLog(QWidget* parent)
|
||||||
setViewportUpdateMode(SmartViewportUpdate);
|
setViewportUpdateMode(SmartViewportUpdate);
|
||||||
//setRenderHint(QPainter::TextAntialiasing);
|
//setRenderHint(QPainter::TextAntialiasing);
|
||||||
|
|
||||||
|
selGraphItem = new QGraphicsRectItem();
|
||||||
|
selGraphItem->setZValue(-10.0); //behind all items
|
||||||
|
selGraphItem->setBrush(QBrush(QColor(166,225,255)));
|
||||||
|
|
||||||
|
scene->addItem(selGraphItem);
|
||||||
|
|
||||||
// copy action
|
// copy action
|
||||||
copyAction = new QAction(this);
|
copyAction = new QAction(this);
|
||||||
copyAction->setShortcut(QKeySequence::Copy);
|
copyAction->setShortcut(QKeySequence::Copy);
|
||||||
|
@ -116,14 +122,17 @@ ChatMessage *ChatLog::addFileTransferMessage(const QString &sender, const ToxFil
|
||||||
|
|
||||||
void ChatLog::clearSelection()
|
void ChatLog::clearSelection()
|
||||||
{
|
{
|
||||||
if(selStartRow >= 0)
|
for(int i=selFirstRow; i<=selLastRow && i<lines.size() && i >= 0; ++i)
|
||||||
for(int r = qMin(selStartRow, selLastRow); r <= qMax(selLastRow, selStartRow) && r < lines.size(); ++r)
|
lines[i]->selectionCleared();
|
||||||
lines[r]->selectionCleared();
|
|
||||||
|
|
||||||
selStartRow = -1;
|
selGraphItem->hide();
|
||||||
selStartCol = -1;
|
|
||||||
|
selFirstRow = -1;
|
||||||
selLastRow = -1;
|
selLastRow = -1;
|
||||||
selLastCol = -1;
|
selClickedCol = -1;
|
||||||
|
selClickedRow = -1;
|
||||||
|
|
||||||
|
selectionMode = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect ChatLog::getVisibleRect() const
|
QRect ChatLog::getVisibleRect() const
|
||||||
|
@ -229,9 +238,6 @@ void ChatLog::mousePressEvent(QMouseEvent* ev)
|
||||||
void ChatLog::mouseReleaseEvent(QMouseEvent* ev)
|
void ChatLog::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
{
|
{
|
||||||
QGraphicsView::mouseReleaseEvent(ev);
|
QGraphicsView::mouseReleaseEvent(ev);
|
||||||
|
|
||||||
if(ev->button() == Qt::LeftButton)
|
|
||||||
selecting = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatLog::mouseMoveEvent(QMouseEvent* ev)
|
void ChatLog::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
@ -242,21 +248,21 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
|
||||||
if(ev->buttons() & Qt::LeftButton)
|
if(ev->buttons() & Qt::LeftButton)
|
||||||
{
|
{
|
||||||
if(!selecting && (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());
|
||||||
|
|
||||||
ChatLineContent* content = getContentFromPos(sceneClickPos);
|
ChatLineContent* content = getContentFromPos(sceneClickPos);
|
||||||
if(content)
|
if(content)
|
||||||
{
|
{
|
||||||
selStartRow = content->getRow();
|
selClickedRow = content->getRow();
|
||||||
selStartCol = content->getColumn();
|
selClickedCol = content->getColumn();
|
||||||
selLastRow = selStartRow;
|
selFirstRow = content->getRow();
|
||||||
selLastCol = selStartCol;
|
selLastRow = content->getRow();
|
||||||
|
|
||||||
content->selectionStarted(sceneClickPos);
|
content->selectionStarted(sceneClickPos);
|
||||||
|
|
||||||
selecting = true;
|
selectionMode = Precise;
|
||||||
|
|
||||||
// ungrab mouse grabber
|
// ungrab mouse grabber
|
||||||
if(scene->mouseGrabberItem())
|
if(scene->mouseGrabberItem())
|
||||||
|
@ -265,7 +271,7 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selecting && ev->pos() != lastPos)
|
if(selectionMode != None && ev->pos() != lastPos)
|
||||||
{
|
{
|
||||||
lastPos = ev->pos();
|
lastPos = ev->pos();
|
||||||
|
|
||||||
|
@ -273,47 +279,35 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev)
|
||||||
|
|
||||||
if(content)
|
if(content)
|
||||||
{
|
{
|
||||||
// TODO: turn this into a sane algo.
|
|
||||||
int row = content->getRow();
|
int row = content->getRow();
|
||||||
int col = content->getColumn();
|
int col = content->getColumn();
|
||||||
int firstRow = selStartRow;
|
|
||||||
|
|
||||||
// selection
|
if(row >= selClickedRow)
|
||||||
for(int r = qMin(firstRow, row + 1); r < qMax(row, firstRow); r++)
|
selLastRow = row;
|
||||||
lines[r]->selectAll();
|
|
||||||
|
|
||||||
if(row != selStartRow)
|
if(row <= selClickedRow)
|
||||||
for(int c = 0; c < col; c++)
|
selFirstRow = row;
|
||||||
lines[selStartRow]->selectAll();
|
|
||||||
|
if(row == selClickedRow && col == selClickedCol)
|
||||||
|
{
|
||||||
|
selectionMode = Precise;
|
||||||
|
|
||||||
if(row == selStartRow)
|
|
||||||
content->selectionMouseMove(scenePos);
|
content->selectionMouseMove(scenePos);
|
||||||
|
selGraphItem->hide();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lines[row]->selectAll();
|
selectionMode = Multi;
|
||||||
selStartCol = 0;
|
|
||||||
selLastCol = lines[row]->getColumnCount();
|
lines[selClickedRow]->selectionCleared();
|
||||||
|
|
||||||
|
QRectF selBBox;
|
||||||
|
selBBox = selBBox.united(lines[selFirstRow]->boundingSceneRect());
|
||||||
|
selBBox = selBBox.united(lines[selLastRow]->boundingSceneRect());
|
||||||
|
|
||||||
|
selGraphItem->setRect(selBBox);
|
||||||
|
selGraphItem->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// de-selection
|
|
||||||
if(row < selStartRow)
|
|
||||||
selLastRow = qMin(row, selLastRow);
|
|
||||||
else
|
|
||||||
selLastRow = qMax(row, selLastRow);
|
|
||||||
|
|
||||||
if(col < selStartCol)
|
|
||||||
selLastCol = qMin(col, selLastCol);
|
|
||||||
else
|
|
||||||
selLastCol = qMax(col, selLastCol);
|
|
||||||
|
|
||||||
for(int r = qMin(row, selLastRow); r < qMax(row, selLastRow + 1) && r < lines.size(); ++r)
|
|
||||||
if(r != row)
|
|
||||||
lines[r]->selectionCleared();
|
|
||||||
|
|
||||||
if(row == selStartRow)
|
|
||||||
for(int c = col + 1; c < lines[row]->getColumnCount() && c < selLastCol; ++c)
|
|
||||||
lines[row]->selectionCleared(c);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,17 +324,25 @@ ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const
|
||||||
|
|
||||||
bool ChatLog::isOverSelection(QPointF scenePos)
|
bool ChatLog::isOverSelection(QPointF scenePos)
|
||||||
{
|
{
|
||||||
ChatLineContent* content = getContentFromPos(scenePos);
|
if(selectionMode == Precise)
|
||||||
|
{
|
||||||
|
ChatLineContent* content = getContentFromPos(scenePos);
|
||||||
|
|
||||||
if(content)
|
if(content)
|
||||||
return content->isOverSelection(scenePos);
|
return content->isOverSelection(scenePos);
|
||||||
|
}
|
||||||
|
else if(selectionMode == Multi)
|
||||||
|
{
|
||||||
|
if(selGraphItem->rect().contains(scenePos))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ChatLog::useableWidth()
|
int ChatLog::useableWidth()
|
||||||
{
|
{
|
||||||
return width() - verticalScrollBar()->sizeHint().width();
|
return width() - verticalScrollBar()->sizeHint().width() - 10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatLog::reposition(int start, int end)
|
void ChatLog::reposition(int start, int end)
|
||||||
|
@ -411,19 +413,33 @@ void ChatLog::scrollToBottom()
|
||||||
|
|
||||||
QString ChatLog::getSelectedText() const
|
QString ChatLog::getSelectedText() const
|
||||||
{
|
{
|
||||||
QString ret;
|
if(selectionMode == Precise)
|
||||||
|
{
|
||||||
|
return lines[selClickedRow]->content[selClickedCol]->getSelectedText();
|
||||||
|
}
|
||||||
|
else if(selectionMode == Multi)
|
||||||
|
{
|
||||||
|
// build a nicely formatted message
|
||||||
|
QString out;
|
||||||
|
|
||||||
const int rowStart = qMin(selStartRow, selLastRow);
|
QString lastSender;
|
||||||
const int rowLast = qMax(selStartRow, selLastRow);
|
for(int i=selFirstRow; i<=selLastRow && i>=0 && i<lines.size(); ++i)
|
||||||
|
{
|
||||||
|
if(lastSender != lines[i]->content[0]->getText() && !lines[i]->content[0]->getText().isEmpty())
|
||||||
|
{
|
||||||
|
//author changed
|
||||||
|
out += lines[i]->content[0]->getText() + ":\n";
|
||||||
|
lastSender = lines[i]->content[0]->getText();
|
||||||
|
}
|
||||||
|
|
||||||
const int colStart = qMin(selStartCol, selLastCol);
|
out += lines[i]->content[1]->getText();
|
||||||
const int colLast = qMax(selStartCol, selLastCol);
|
out += "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
for(int r = rowStart; r <= rowLast && r < lines.size(); ++r)
|
return out;
|
||||||
for(int c = colStart; c <= colLast && c < lines[r]->getColumnCount(); ++c)
|
}
|
||||||
ret.append(lines[r]->content[c]->getSelectedText() + '\n');
|
|
||||||
|
|
||||||
return ret;
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatLog::showContextMenu(const QPoint& globalPos, const QPointF& scenePos)
|
void ChatLog::showContextMenu(const QPoint& globalPos, const QPointF& scenePos)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
class QGraphicsScene;
|
class QGraphicsScene;
|
||||||
|
class QGraphicsRectItem;
|
||||||
class ChatLine;
|
class ChatLine;
|
||||||
class ChatLineContent;
|
class ChatLineContent;
|
||||||
class ChatMessage;
|
class ChatMessage;
|
||||||
|
@ -72,6 +73,12 @@ protected:
|
||||||
virtual void resizeEvent(QResizeEvent *ev);
|
virtual void resizeEvent(QResizeEvent *ev);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum SelectionMode {
|
||||||
|
None,
|
||||||
|
Precise,
|
||||||
|
Multi,
|
||||||
|
};
|
||||||
|
|
||||||
QGraphicsScene* scene = nullptr;
|
QGraphicsScene* scene = nullptr;
|
||||||
QList<ChatLine*> lines;
|
QList<ChatLine*> lines;
|
||||||
QList<ChatLine*> visibleLines;
|
QList<ChatLine*> visibleLines;
|
||||||
|
@ -81,13 +88,14 @@ private:
|
||||||
int insertStartIndex = -1;
|
int insertStartIndex = -1;
|
||||||
|
|
||||||
// selection
|
// selection
|
||||||
int selStartRow = -1;
|
int selClickedRow = -1;
|
||||||
int selStartCol = -1;
|
int selClickedCol = -1;
|
||||||
|
int selFirstRow = -1;
|
||||||
int selLastRow = -1;
|
int selLastRow = -1;
|
||||||
int selLastCol = -1;
|
SelectionMode selectionMode = None;
|
||||||
bool selecting = false;
|
|
||||||
QPointF clickPos;
|
QPointF clickPos;
|
||||||
QPointF lastPos;
|
QPointF lastPos;
|
||||||
|
QGraphicsRectItem* selGraphItem = nullptr;
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
QAction* copyAction = nullptr;
|
QAction* copyAction = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user