From dab68263675422d923a0ccbd2b84e2e52ed7e157 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Thu, 31 Jul 2008 18:37:19 +0200 Subject: [PATCH] Inter- and intra-item selections now behave properly, except deactivating a global selection is still missing --- src/qtui/chatitem.cpp | 54 +++++++++++++++++++++------ src/qtui/chatitem.h | 6 ++- src/qtui/chatscene.cpp | 84 +++++++++++++++++++++++++++++++++++------- src/qtui/chatscene.h | 14 +++++-- 4 files changed, 129 insertions(+), 29 deletions(-) diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index 5d1bcb7a..286fd62c 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -36,6 +36,8 @@ ChatItem::ChatItem(const QPersistentModelIndex &index_, QGraphicsItem *parent) : _lines = 0; _selectionStart = -1; _selectionMode = NoSelection; + setAcceptHoverEvents(true); + setZValue(20); } ChatItem::~ChatItem() { @@ -138,11 +140,11 @@ void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q_UNUSED(option); Q_UNUSED(widget); if(!haveLayout()) updateLayout(); painter->setClipRect(boundingRect()); // no idea why QGraphicsItem clipping won't work - if(_selectionMode == FullSelection) { - painter->save(); - painter->fillRect(boundingRect(), QApplication::palette().brush(QPalette::Highlight)); - painter->restore(); - } // TODO: add selection format here + //if(_selectionMode == FullSelection) { + //painter->save(); + //painter->fillRect(boundingRect(), QApplication::palette().brush(QPalette::Highlight)); + //painter->restore(); + //} QVector formats; if(_selectionMode != NoSelection) { QTextLayout::FormatRange selectFmt; @@ -174,12 +176,22 @@ qint16 ChatItem::posToCursor(const QPointF &pos) { } void ChatItem::setFullSelection() { - _selectionMode = FullSelection; - update(); + if(_selectionMode != FullSelection) { + _selectionMode = FullSelection; + update(); + } } void ChatItem::clearSelection() { - _selectionMode = NoSelection; + if(_selectionMode != NoSelection) { + _selectionMode = NoSelection; + update(); + } +} + +void ChatItem::continueSelecting(const QPointF &pos) { + _selectionMode = PartialSelection; + _selectionEnd = posToCursor(pos); update(); } @@ -196,12 +208,14 @@ void ChatItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { void ChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if(contains(event->pos())) { - _selectionEnd = posToCursor(event->pos()); - update(); + qint16 end = posToCursor(event->pos()); + if(end != _selectionEnd) { + _selectionEnd = end; + update(); + } } else { setFullSelection(); - ungrabMouse(); - chatScene()->startGlobalSelection(this); + chatScene()->startGlobalSelection(this, event->pos()); } } @@ -217,6 +231,22 @@ void ChatItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { } } +void ChatItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { + //qDebug() << (void*)this << "entering"; + +} + +void ChatItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { + //qDebug() << (void*)this << "leaving"; + +} + +void ChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + //qDebug() << (void*)this << event->pos(); + +} + + /*************************************************************************************************/ ChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item) : item(_item) { diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index 3cf5a9b3..ddbffdbc 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -60,13 +60,17 @@ class ChatItem : public QGraphicsItem { // selection stuff, to be called by the scene void clearSelection(); void setFullSelection(); - void continueSelecting(); + void continueSelecting(const QPointF &pos); protected: virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); + private: qint16 posToCursor(const QPointF &pos); qreal computeHeight(); diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index f6a5e33a..797290d7 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -38,6 +38,7 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, QObject { _width = 0; _selectingItem = 0; + _isSelecting = false; connect(this, SIGNAL(sceneRectChanged(const QRectF &)), this, SLOT(rectChanged(const QRectF &))); connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(rowsInserted(const QModelIndex &, int, int))); @@ -141,28 +142,85 @@ void ChatScene::handlePositionChanged(qreal xpos) { update(qMin(oldx, xpos) - firstColHandle->width()/2, 0, qMax(oldx, xpos) + firstColHandle->width()/2, height()); } -void ChatScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - - QGraphicsScene::mouseMoveEvent(event); +void ChatScene::setSelectingItem(ChatItem *item) { + if(_selectingItem) _selectingItem->clearSelection(); + _selectingItem = item; } -void ChatScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { - - QGraphicsScene::mousePressEvent(event); +void ChatScene::startGlobalSelection(ChatItem *item, const QPointF &itemPos) { + _selectionStart = _selectionEnd = item->index().row(); + _selectionStartCol = _selectionMinCol = item->index().column(); + _isSelecting = true; + _lines[_selectionStart]->setSelected(true, (ChatLineModel::ColumnType)_selectionMinCol); + updateSelection(item->mapToScene(itemPos)); } -void ChatScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { +void ChatScene::updateSelection(const QPointF &pos) { + // This is somewhat hacky... we look at the contents item that is at the cursor's y position (ignoring x), since + // it has the full height. From this item, we can then determine the row index and hence the ChatLine. + ChatItem *contentItem = static_cast(itemAt(QPointF(secondColHandlePos + secondColHandle->width()/2, pos.y()))); + if(!contentItem) return; + + int curRow = contentItem->index().row(); + int curColumn; + if(pos.x() > secondColHandlePos + secondColHandle->width()/2) curColumn = ChatLineModel::ContentsColumn; + else if(pos.x() > firstColHandlePos) curColumn = ChatLineModel::SenderColumn; + else curColumn = ChatLineModel::TimestampColumn; + + ChatLineModel::ColumnType minColumn = (ChatLineModel::ColumnType)qMin(curColumn, _selectionStartCol); + if(minColumn != _selectionMinCol) { + _selectionMinCol = minColumn; + for(int l = qMin(_selectionStart, _selectionEnd); l <= qMax(_selectionStart, _selectionEnd); l++) { + _lines[l]->setSelected(true, minColumn); + } + } - QGraphicsScene::mouseReleaseEvent(event); -} + if(curRow > _selectionEnd && curRow > _selectionStart) { // select further towards bottom + for(int l = _selectionEnd + 1; l <= curRow; l++) { + _lines[l]->setSelected(true, minColumn); + } + } else if(curRow > _selectionEnd && curRow <= _selectionStart) { // deselect towards bottom + for(int l = _selectionEnd; l < curRow; l++) { + _lines[l]->setSelected(false); + } + } else if(curRow < _selectionEnd && curRow >= _selectionStart) { + for(int l = _selectionEnd; l > curRow; l--) { + _lines[l]->setSelected(false); + } + } else if(curRow < _selectionEnd && curRow < _selectionStart) { + for(int l = _selectionEnd - 1; l >= curRow; l--) { + _lines[l]->setSelected(true, minColumn); + } + } + _selectionEnd = curRow; -void ChatScene::setSelectingItem(ChatItem *item) { - if(_selectingItem) _selectingItem->clearSelection(); - _selectingItem = item; + if(curRow == _selectionStart && minColumn == ChatLineModel::ContentsColumn) { + _lines[curRow]->setSelected(false); + _isSelecting = false; + _selectingItem->continueSelecting(_selectingItem->mapFromScene(pos)); + } } -void ChatScene::startGlobalSelection(ChatItem *item) { +void ChatScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + if(_isSelecting && event->buttons() & Qt::LeftButton) { + updateSelection(event->scenePos()); + event->accept(); + } else { + QGraphicsScene::mouseMoveEvent(event); + } +} +void ChatScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { + qDebug() << "pressed"; + QGraphicsScene::mousePressEvent(event); +} +void ChatScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + if(_isSelecting) { + _isSelecting = false; + event->accept(); + } else { + QGraphicsScene::mouseReleaseEvent(event); + } } diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h index 7bfd6eb0..62a65f2d 100644 --- a/src/qtui/chatscene.h +++ b/src/qtui/chatscene.h @@ -23,6 +23,7 @@ #include #include +#include class AbstractUiMsg; class Buffer; @@ -45,10 +46,10 @@ class ChatScene : public QGraphicsScene { public slots: void setWidth(qreal); - // these are used by the chatitems to notify the scene + // these are used by the chatitems to notify the scene and manage selections void setSelectingItem(ChatItem *item); ChatItem *selectingItem() const { return _selectingItem; } - void startGlobalSelection(ChatItem *item); + void startGlobalSelection(ChatItem *item, const QPointF &itemPos); signals: void heightChanged(qreal height); @@ -66,6 +67,8 @@ class ChatScene : public QGraphicsScene { void handlePositionChanged(qreal xpos); private: + void updateSelection(const QPointF &pos); + QString _idString; qreal _width, _height; QAbstractItemModel *_model; @@ -74,7 +77,12 @@ class ChatScene : public QGraphicsScene { ColumnHandleItem *firstColHandle, *secondColHandle; qreal firstColHandlePos, secondColHandlePos; - ChatItem *_selectingItem; + ChatItem *_selectingItem, *_lastItem; + QSet _selectedItems; + int _selectionStartCol, _selectionMinCol; + int _selectionStart; + int _selectionEnd; + bool _isSelecting; }; #endif -- 2.20.1