File indexing completed on 2025-01-05 05:14:52

0001 /*
0002 SPDX-FileCopyrightText: 2021 Hamed Masafi <hamed.masfi@gmail.com>
0003 
0004 SPDX-License-Identifier: GPL-3.0-or-later
0005 */
0006 
0007 #include "segmentsscrollbar.h"
0008 
0009 #include "gitglobal.h"
0010 #include "segmentconnector.h"
0011 #include "widgets/codeeditor.h"
0012 
0013 #include <QPaintEvent>
0014 #include <QPainter>
0015 #include <kommitwidgetsglobaloptions.h>
0016 
0017 SegmentsScrollBar::SegmentsScrollBar(QWidget *parent)
0018     : QWidget{parent}
0019 {
0020     setMouseTracking(true);
0021 }
0022 
0023 SegmentConnector *SegmentsScrollBar::segmentConnector() const
0024 {
0025     return mSegmentConnector;
0026 }
0027 
0028 void SegmentsScrollBar::setSegmentConnector(SegmentConnector *newSegmentConnector)
0029 {
0030     if (mSegmentConnector) {
0031         disconnect(newSegmentConnector, &SegmentConnector::segmentsChanged, this, &SegmentsScrollBar::reload);
0032         disconnect(newSegmentConnector, &SegmentConnector::sameSizeChanged, this, &SegmentsScrollBar::reload);
0033     }
0034     mSegmentConnector = newSegmentConnector;
0035     connect(newSegmentConnector, &SegmentConnector::segmentsChanged, this, &SegmentsScrollBar::reload);
0036     connect(newSegmentConnector, &SegmentConnector::sameSizeChanged, this, &SegmentsScrollBar::reload);
0037     update();
0038 }
0039 
0040 void SegmentsScrollBar::paintEvent(QPaintEvent *event)
0041 {
0042     QPainter painter(this);
0043     painter.fillRect(event->rect(), Qt::white);
0044 
0045     if (!Q_UNLIKELY(mSegmentConnector))
0046         return;
0047 
0048     painter.drawImage(0, 0, mSegmentsImage);
0049 
0050     auto leftArea = mSegmentConnector->left()->visibleLines();
0051     auto rightArea = mSegmentConnector->right()->visibleLines();
0052 
0053     QBrush br(Qt::gray);
0054 
0055     painter.fillRect(QRect{int(width() * .4), 0, int(width() * .2), height() - 1}, palette().base());
0056     painter.drawLine(width() * .4, 0, width() * .4, height() - 1);
0057     painter.drawLine(width() * .6, 0, width() * .6, height() - 1);
0058 
0059     painter.setOpacity(.3);
0060     paintSection(painter, Left, leftArea.first, leftArea.second, br, true);
0061     paintSection(painter, Right, rightArea.first, rightArea.second, br, true);
0062     painter.setOpacity(1);
0063     painter.drawRect(QRect{0, 0, width() - 1, height() - 1});
0064 }
0065 
0066 void SegmentsScrollBar::mouseMoveEvent(QMouseEvent *event)
0067 {
0068     QWidget::mouseMoveEvent(event);
0069     Q_EMIT hover(event->y(), static_cast<double>(event->y()) / static_cast<double>(height()));
0070 }
0071 
0072 void SegmentsScrollBar::resizeEvent(QResizeEvent *event)
0073 {
0074     Q_UNUSED(event)
0075     if (Q_LIKELY(mSegmentConnector))
0076         generateSegmentsImage();
0077 }
0078 
0079 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0080 void SegmentsScrollBar::enterEvent(QEvent *event)
0081 #else
0082 void SegmentsScrollBar::enterEvent(QEnterEvent *event)
0083 #endif
0084 {
0085     QWidget::enterEvent(event);
0086     Q_EMIT mouseEntered();
0087 }
0088 
0089 void SegmentsScrollBar::leaveEvent(QEvent *event)
0090 {
0091     QWidget::leaveEvent(event);
0092     Q_EMIT mouseLeaved();
0093 }
0094 
0095 void SegmentsScrollBar::reload()
0096 {
0097     leftCount = rightCount = 0;
0098     for (const auto &segment : qAsConst(mSegmentConnector->segments())) {
0099         if (mSegmentConnector->sameSize()) {
0100             auto m = qMax(segment->oldText.size(), segment->newText.size());
0101             leftCount += m;
0102             rightCount += m;
0103         } else {
0104             leftCount += segment->oldText.size();
0105             rightCount += segment->newText.size();
0106         }
0107     }
0108     update();
0109 }
0110 
0111 void SegmentsScrollBar::generateSegmentsImage()
0112 {
0113     mSegmentsImage = QImage{width(), height(), QImage::Format_ARGB32};
0114 
0115     mSegmentsImage.fill(Qt::white);
0116     QPainter painter{&mSegmentsImage};
0117 
0118     int countLeft{0};
0119     int countRight{0};
0120 
0121     for (const auto &segment : qAsConst(mSegmentConnector->segments())) {
0122         QBrush brush;
0123         switch (segment->type) {
0124         case Diff::SegmentType::OnlyOnLeft:
0125             brush = KommitWidgetsGlobalOptions::instance()->statucColor(Git::ChangeStatus::Removed);
0126             break;
0127         case Diff::SegmentType::OnlyOnRight:
0128             brush = KommitWidgetsGlobalOptions::instance()->statucColor(Git::ChangeStatus::Added);
0129             break;
0130         case Diff::SegmentType::SameOnBoth:
0131             brush = Qt::white;
0132             break;
0133         case Diff::SegmentType::DifferentOnBoth:
0134             brush = KommitWidgetsGlobalOptions::instance()->statucColor(Git::ChangeStatus::Modified);
0135             break;
0136         default:
0137             break;
0138         }
0139 
0140         paintSection(painter, Left, countLeft, segment->oldText.size(), brush);
0141         paintSection(painter, Right, countRight, segment->newText.size(), brush);
0142 
0143         if (mSegmentConnector->sameSize()) {
0144             auto m = qMax(segment->oldText.size(), segment->newText.size());
0145 
0146             paintSection(painter, Left, countLeft + segment->oldText.size(), m - segment->oldText.size(), Qt::darkGray);
0147             paintSection(painter, Right, countRight + segment->newText.size(), m - segment->newText.size(), Qt::darkGray);
0148 
0149             countLeft += m;
0150             countRight += m;
0151         } else {
0152             countLeft += segment->oldText.size();
0153             countRight += segment->newText.size();
0154         }
0155     }
0156     /*
0157         auto leftArea = mSegmentConnector->left()->visibleLines();
0158         auto rightArea = mSegmentConnector->right()->visibleLines();
0159 
0160         QBrush br(Qt::gray);
0161 
0162         painter.fillRect(QRect{int(width() * .4), 0, int(width() * .2), height() - 1}, palette().base());
0163         painter.drawLine(width() * .4, 0, width() * .4, height() - 1);
0164         painter.drawLine(width() * .6, 0, width() * .6, height() - 1);
0165 
0166         painter.setOpacity(.3);
0167         paintSection(painter, Left, leftArea.first, leftArea.second, br, true);
0168         paintSection(painter, Right, rightArea.first, rightArea.second, br, true);
0169         painter.setOpacity(1);
0170         painter.drawRect(QRect{0, 0, width() - 1, height() - 1});*/
0171 }
0172 
0173 void SegmentsScrollBar::paintSection(QPainter &painter, SegmentsScrollBar::Side side, int from, int len, const QBrush &brush, bool drawRect)
0174 {
0175     if (len <= 0)
0176         return;
0177     int w = width() * .4;
0178     int l = side == Left ? 0 : width() - w;
0179     int &c = side == Left ? leftCount : rightCount;
0180 
0181     QRect rc{l, static_cast<int>((from / (double)c) * height()) - 1, w, static_cast<int>((len / (double)c) * height())};
0182     painter.fillRect(rc, brush);
0183     if (drawRect)
0184         painter.drawRect(rc);
0185 }
0186 
0187 #include "moc_segmentsscrollbar.cpp"