File indexing completed on 2024-04-14 05:45:53

0001 /*
0002     This file is part of the Okteta Gui library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2008-2009, 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "bytearrayrowcolumnrenderer_p.hpp"
0010 
0011 // lib
0012 #include "bytearraytableranges.hpp"
0013 #include "bytearraytablecursor.hpp"
0014 #include "bytearraytablelayout.hpp"
0015 #include "helper.hpp"
0016 #include <logging.hpp>
0017 // lib
0018 #include <abstractcolumnstylist.hpp>
0019 // Okteta core
0020 #include <Okteta/BookmarksConstIterator>
0021 #include <Okteta/Bookmark>
0022 #include <Okteta/CharCodec>
0023 #include <Okteta/ValueCodec>
0024 // KF
0025 #include <KColorScheme>
0026 // Qt
0027 #include <QPainter>
0028 #include <QFontMetrics>
0029 
0030 namespace Okteta {
0031 
0032 AbstractByteArrayView::CodingTypeId ByteArrayRowColumnRendererPrivate::codingIdofY(PixelY y) const
0033 {
0034     return
0035         (mVisibleCodings != AbstractByteArrayView::ValueAndCharCodings) ?
0036             (AbstractByteArrayView::CodingTypeId)mVisibleCodings :
0037         (y < mDigitHeight) ?
0038             AbstractByteArrayView::ValueCodingId :
0039             AbstractByteArrayView::CharCodingId;
0040 }
0041 
0042 PixelY ByteArrayRowColumnRendererPrivate::rowHeight() const
0043 {
0044     const int noOfCodings = (mVisibleCodings > 2) ? 2 : 1;
0045     return noOfCodings * mDigitHeight + DefaultRowSpacingHeight;
0046 }
0047 
0048 PixelY ByteArrayRowColumnRendererPrivate::yOfCodingId(AbstractByteArrayView::CodingTypeId codingId) const
0049 {
0050     PixelY result = (mVisibleCodings <= 2) ?                             0 :
0051                     (codingId == AbstractByteArrayView::ValueCodingId) ? 0 :
0052                                                                          mDigitHeight;
0053 
0054     return result;
0055 }
0056 
0057 void ByteArrayRowColumnRendererPrivate::set(AbstractByteArrayModel* byteArrayModel)
0058 {
0059     mByteArrayModel = byteArrayModel;
0060     mBookmarks = qobject_cast<Bookmarkable*>(byteArrayModel);
0061 }
0062 
0063 void ByteArrayRowColumnRendererPrivate::resetXBuffer()
0064 {
0065     delete [] mLinePosLeftPixelX;
0066     delete [] mLinePosRightPixelX;
0067 
0068     mLastLinePos = mLayout->noOfBytesPerLine() - 1;
0069     mLinePosLeftPixelX =  new PixelX[mLastLinePos + 1];
0070     mLinePosRightPixelX = new PixelX[mLastLinePos + 1];
0071 
0072     if (mLinePosLeftPixelX) {
0073         recalcX();
0074     }
0075 }
0076 
0077 void ByteArrayRowColumnRendererPrivate::setVisibleCodings(int visibleCodings)
0078 {
0079     mVisibleCodings = (AbstractByteArrayView::CodingTypes)(visibleCodings);
0080 }
0081 
0082 void ByteArrayRowColumnRendererPrivate::setFontMetrics(const QFontMetrics& fontMetrics)
0083 {
0084     mFontMetrics = fontMetrics;
0085 
0086     mDigitBaseLine = fontMetrics.ascent();
0087     mDigitHeight = fontMetrics.height();
0088     mDigitWidth = fontMetrics.maxWidth();
0089 
0090     // recalculate depend sizes
0091     recalcByteWidth();
0092 
0093     if (mLinePosLeftPixelX) {
0094         recalcX();
0095     }
0096 }
0097 
0098 bool ByteArrayRowColumnRendererPrivate::setSpacing(PixelX byteSpacingWidth, Size noOfGroupedBytes, PixelX groupSpacingWidth)
0099 {
0100     // no changes?
0101     if (mByteSpacingWidth == byteSpacingWidth && mNoOfGroupedBytes == noOfGroupedBytes && mGroupSpacingWidth == groupSpacingWidth) {
0102         return false;
0103     }
0104 
0105     mByteSpacingWidth = byteSpacingWidth;
0106     mNoOfGroupedBytes = noOfGroupedBytes;
0107     mGroupSpacingWidth = groupSpacingWidth;
0108 
0109     // recalculate depend sizes
0110     if (mLinePosLeftPixelX) {
0111         recalcX();
0112     }
0113 
0114     return true;
0115 }
0116 
0117 bool ByteArrayRowColumnRendererPrivate::setByteSpacingWidth(PixelX byteSpacingWidth)
0118 {
0119     // no changes?
0120     if (mByteSpacingWidth == byteSpacingWidth) {
0121         return false;
0122     }
0123 
0124     mByteSpacingWidth = byteSpacingWidth;
0125 
0126     // recalculate depend sizes
0127     if (mLinePosLeftPixelX) {
0128         recalcX();
0129     }
0130 
0131     return true;
0132 }
0133 
0134 bool ByteArrayRowColumnRendererPrivate::setNoOfGroupedBytes(Size noOfGroupedBytes)
0135 {
0136     // no changes?
0137     if (mNoOfGroupedBytes == noOfGroupedBytes) {
0138         return false;
0139     }
0140 
0141     mNoOfGroupedBytes = noOfGroupedBytes;
0142 
0143     if (mLinePosLeftPixelX) {
0144         recalcX();
0145     }
0146     return true;
0147 }
0148 
0149 bool ByteArrayRowColumnRendererPrivate::setGroupSpacingWidth(PixelX groupSpacingWidth)
0150 {
0151     // no changes?
0152     if (mGroupSpacingWidth == groupSpacingWidth) {
0153         return false;
0154     }
0155 
0156     mGroupSpacingWidth = groupSpacingWidth;
0157 
0158     // recalculate depend sizes
0159     if (mLinePosLeftPixelX) {
0160         recalcX();
0161     }
0162 
0163     return true;
0164 }
0165 
0166 void ByteArrayRowColumnRendererPrivate::setValueCodec(ValueCoding valueCoding, const ValueCodec* valueCodec)
0167 {
0168     mValueCoding = valueCoding;
0169     mValueCodec = valueCodec;
0170     mDecodedByteText.resize(mValueCodec->encodingWidth());
0171 
0172     // recalculate depend sizes
0173     recalcByteWidth();
0174 
0175     if (mLinePosLeftPixelX) {
0176         recalcX();
0177     }
0178 }
0179 
0180 bool ByteArrayRowColumnRendererPrivate::setBinaryGapWidth(PixelX binaryGapWidth)
0181 {
0182     // no changes?
0183     if (mBinaryGapWidth == binaryGapWidth) {
0184         return false;
0185     }
0186 
0187     mBinaryGapWidth = binaryGapWidth;
0188 
0189     // recalculate depend sizes
0190     recalcByteWidth();
0191 
0192     if (mLinePosLeftPixelX) {
0193         recalcX();
0194     }
0195     return true;
0196 }
0197 
0198 void ByteArrayRowColumnRendererPrivate::recalcByteWidth()
0199 {
0200     // use 0 as reference, using a fixed font should always yield same width
0201     mValueCodec->encode(&mDecodedByteText, 0, Byte(0));
0202     if (mValueCoding == BinaryCoding) {
0203         const int binaryHalfWidth = mFontMetrics.horizontalAdvance(mDecodedByteText.left(4));
0204         mBinaryHalfOffset = binaryHalfWidth + mBinaryGapWidth;
0205         mByteWidth = mBinaryHalfOffset + binaryHalfWidth;
0206     } else {
0207         mByteWidth = mFontMetrics.horizontalAdvance(mDecodedByteText);
0208     }
0209 }
0210 
0211 // perhaps sometimes there will be a grammar
0212 void ByteArrayRowColumnRendererPrivate::renderEditedByte(QPainter* painter, Byte byte, const QString& editBuffer)
0213 {
0214     const Character byteChar = mCharCodec->decode(byte);
0215 
0216     const QPalette& palette = mStylist->palette();
0217     KColorScheme colorScheme(palette.currentColorGroup(), KColorScheme::View);
0218     const KColorScheme::ForegroundRole foregroundRole =
0219         mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0220     const QBrush brush = colorScheme.foreground(foregroundRole);
0221     painter->fillRect(0, 0, byteWidth(), mDigitHeight, brush);
0222 
0223     const QBrush backgroundBrush = colorScheme.background();
0224     const QColor& charColor = backgroundBrush.color();
0225     renderCode(painter, editBuffer, charColor);
0226 }
0227 
0228 void ByteArrayRowColumnRendererPrivate::renderByteText(QPainter* painter,
0229                                                 Byte byte, Character byteChar, int codings,
0230                                                 const QColor& color) const
0231 {
0232     PixelY charBaseLine = mDigitBaseLine;
0233     if (codings & AbstractByteArrayView::ValueCodingId) {
0234         mValueCodec->encode(&mDecodedByteText, 0, byte);
0235         renderCode(painter, mDecodedByteText, color);
0236 
0237         charBaseLine += mDigitHeight;
0238     }
0239 
0240     if (codings & AbstractByteArrayView::CharCodingId) {
0241         // turn into a drawable String
0242         const QString text(byteChar.isUndefined() ?                       Character(mUndefinedChar) :
0243                            !(mShowingNonprinting || byteChar.isPrint()) ? Character(mSubstituteChar) :
0244                                                                           byteChar);
0245 
0246         painter->setPen(color);
0247         painter->drawText(0, charBaseLine, text);
0248     }
0249 }
0250 
0251 void ByteArrayRowColumnRendererPrivate::renderCode(QPainter* painter, const QString& code, const QColor& color) const
0252 {
0253     painter->setPen(color);
0254     if (mValueCoding == BinaryCoding) {
0255         // leave a gap in the middle
0256         painter->drawText(0, mDigitBaseLine, code.left(4));
0257         painter->drawText(mBinaryHalfOffset, mDigitBaseLine, code.right(4));
0258     } else {
0259         painter->drawText(0, mDigitBaseLine, code);
0260     }
0261 }
0262 
0263 void ByteArrayRowColumnRendererPrivate::recalcX()
0264 {
0265     Q_Q(ByteArrayRowColumnRenderer);
0266 
0267     const int spacingTrigger = noOfGroupedBytes() > 0 ? noOfGroupedBytes() - 1 : mLastLinePos + 1; // last ensures to never trigger the spacing
0268 
0269     PixelX newWidth = 0;
0270     Size groupedBytes = 0;
0271     PixelX* PX = mLinePosLeftPixelX;
0272     PixelX* PRX = mLinePosRightPixelX;
0273     LinePosition p = 0;
0274     for (; p <= mLastLinePos; ++PX, ++PRX, ++p, ++groupedBytes) {
0275         *PX = newWidth;
0276         newWidth += mByteWidth;
0277         *PRX = newWidth - 1;
0278 
0279         // is there a space behind the actual byte (if it is not the last)?
0280         if (groupedBytes == spacingTrigger) {
0281             newWidth += mGroupSpacingWidth;
0282             groupedBytes = -1;
0283         } else {
0284             newWidth += mByteSpacingWidth;
0285         }
0286     }
0287 
0288     q->setWidth(mLinePosRightPixelX[mLastLinePos] + 1);
0289 }
0290 
0291 // TODO: why are inlined functions not available as symbols when defined before their use
0292 // TODO: works not precisely for the byte rects but includes spacing and left and right
0293 /*inline*/ LinePosition ByteArrayRowColumnRendererPrivate::linePositionOfX(PixelX PX) const
0294 {
0295     Q_Q(const ByteArrayRowColumnRenderer);
0296 
0297     if (!mLinePosLeftPixelX) {
0298         return NoByteFound;
0299     }
0300 
0301     // translate
0302     PX -= q->x();
0303     // search backwards for the first byte that is equalleft to x
0304     for (LinePosition p = mLastLinePos; p >= 0; --p) {
0305         if (mLinePosLeftPixelX[p] <= PX) {
0306             return p;
0307         }
0308     }
0309 
0310     return 0; // NoByteFound;
0311 }
0312 
0313 LinePosition ByteArrayRowColumnRendererPrivate::magneticLinePositionOfX(PixelX PX) const
0314 {
0315     Q_Q(const ByteArrayRowColumnRenderer);
0316 
0317     if (!mLinePosLeftPixelX) {
0318         return NoByteFound;
0319     }
0320 
0321     // translate
0322     PX -= q->x();
0323     // search backwards for the first byte that is equalleft to x
0324     for (LinePosition p = mLastLinePos; p >= 0; --p) {
0325         if (mLinePosLeftPixelX[p] <= PX) {
0326             // are we close to the right?
0327             if (mLinePosRightPixelX[p] - PX < mDigitWidth / 2) { // TODO: perhaps cache also the middle xpos's
0328                 ++p;
0329             }
0330             return p;
0331         }
0332     }
0333 
0334     return 0; // NoByteFound;
0335 }
0336 
0337 LinePositionRange ByteArrayRowColumnRendererPrivate::linePositionsOfX(PixelX x, PixelX width) const
0338 {
0339     Q_Q(const ByteArrayRowColumnRenderer);
0340 
0341     if (!mLinePosLeftPixelX) {
0342         return LinePositionRange();
0343     }
0344 
0345     // translate
0346     x -= q->x();
0347     const PixelX rx = x + width - 1;
0348 
0349     LinePositionRange positions;
0350     // search backwards for the first byte that is equalleft to x
0351     for (LinePosition p = mLastLinePos; p >= 0; --p) {
0352         if (mLinePosLeftPixelX[p] <= rx) {
0353             positions.setEnd(p);
0354             for (; p >= 0; --p) {
0355                 if (mLinePosLeftPixelX[p] <= x) {
0356                     positions.setStart(p);
0357                     break;
0358                 }
0359             }
0360 
0361             break;
0362         }
0363     }
0364 
0365     return positions;
0366 }
0367 
0368 PixelX ByteArrayRowColumnRendererPrivate::xOfLinePosition(LinePosition linePosition) const
0369 {
0370     Q_Q(const ByteArrayRowColumnRenderer);
0371 
0372     return q->x() + (mLinePosLeftPixelX ? mLinePosLeftPixelX[linePosition] : 0);
0373 }
0374 
0375 PixelX ByteArrayRowColumnRendererPrivate::rightXOfLinePosition(LinePosition linePosition) const
0376 {
0377     Q_Q(const ByteArrayRowColumnRenderer);
0378 
0379     return q->x() + (mLinePosRightPixelX ? mLinePosRightPixelX[linePosition] : 0);
0380 }
0381 
0382 LinePosition ByteArrayRowColumnRendererPrivate::linePositionOfColumnX(PixelX PX) const
0383 {
0384     if (!mLinePosLeftPixelX) {
0385         return NoByteFound;
0386     }
0387 
0388     // search backwards for the first byte that is equalleft to x
0389     for (LinePosition p = mLastLinePos; p >= 0; --p) {
0390         if (mLinePosLeftPixelX[p] <= PX) {
0391             return p;
0392         }
0393     }
0394 
0395     return 0; // NoByteFound;
0396 }
0397 
0398 LinePositionRange ByteArrayRowColumnRendererPrivate::linePositionsOfColumnXs(PixelX pixelX, PixelX pixelWidth) const
0399 {
0400     if (!mLinePosLeftPixelX) {
0401         return LinePositionRange();
0402     }
0403 
0404     const PixelX rightPixelX = pixelX + pixelWidth - 1;
0405 
0406     LinePositionRange positions;
0407     // search backwards for the first byte that is equalleft to x
0408     for (LinePosition p = mLastLinePos; p >= 0; --p) {
0409         if (mLinePosLeftPixelX[p] <= rightPixelX) {
0410             const LinePosition endPos = p;
0411             positions.setEnd(p);
0412             for (p = 0; p <= endPos; ++p) {
0413                 if (mLinePosRightPixelX[p] >= pixelX) {
0414                     positions.setStart(p);
0415                     break;
0416                 }
0417             }
0418 
0419             break;
0420         }
0421     }
0422 
0423     return positions;
0424 }
0425 
0426 PixelX ByteArrayRowColumnRendererPrivate::columnXOfLinePosition(LinePosition linePosition) const
0427 {
0428     return mLinePosLeftPixelX ? mLinePosLeftPixelX[linePosition] : 0;
0429 }
0430 
0431 PixelX ByteArrayRowColumnRendererPrivate::columnRightXOfLinePosition(LinePosition linePosition) const
0432 {
0433     return mLinePosRightPixelX ? mLinePosRightPixelX[linePosition] : 0;
0434 }
0435 
0436 PixelXRange ByteArrayRowColumnRendererPrivate::xsOfLinePositionsInclSpaces(const LinePositionRange& linePositions) const
0437 {
0438     const PixelX x = (linePositions.start() > 0) ? rightXOfLinePosition(linePositions.nextBeforeStart()) + 1 :
0439                                                    xOfLinePosition(linePositions.start());
0440     const PixelX rightX = (linePositions.end() < mLastLinePos) ? xOfLinePosition(linePositions.nextBehindEnd()) - 1 :
0441                                                                  rightXOfLinePosition(linePositions.end());
0442     return PixelXRange(x, rightX);
0443 }
0444 
0445 PixelXRange ByteArrayRowColumnRendererPrivate::columnXsOfLinePositionsInclSpaces(const LinePositionRange& linePositions) const
0446 {
0447     const PixelX x = (linePositions.start() > 0) ? columnRightXOfLinePosition(linePositions.nextBeforeStart()) + 1 :
0448                                                    columnXOfLinePosition(linePositions.start());
0449     const PixelX rightX = (linePositions.end() < mLastLinePos) ? columnXOfLinePosition(linePositions.nextBehindEnd()) - 1 :
0450                                                                  columnRightXOfLinePosition(linePositions.end());
0451     return PixelXRange(x, rightX);
0452 }
0453 
0454 QRect ByteArrayRowColumnRendererPrivate::byteRect(Coord coord) const
0455 {
0456     Q_Q(const ByteArrayRowColumnRenderer);
0457 
0458     const PixelY lineHeight = q->lineHeight();
0459     const int x = xOfLinePosition(coord.pos());
0460     const int y = lineHeight * coord.line();
0461     const int w = mByteWidth;
0462     const int h = lineHeight;
0463     const QPoint point(x, y);
0464     const QSize size(w, h);
0465 
0466     const QRect result(point, size);
0467     return result;
0468 }
0469 
0470 QRect ByteArrayRowColumnRendererPrivate::byteRect(Coord coord, AbstractByteArrayView::CodingTypeId codingId) const
0471 {
0472     Q_Q(const ByteArrayRowColumnRenderer);
0473 
0474     const int x = xOfLinePosition(coord.pos());
0475     const int y = q->lineHeight() * coord.line() + yOfCodingId(codingId);
0476     const int w = mByteWidth;
0477     const int h = mDigitHeight;
0478     const QPoint point(x, y);
0479     const QSize size(w, h);
0480 
0481     const QRect result(point, size);
0482     return result;
0483 }
0484 
0485 void ByteArrayRowColumnRendererPrivate::prepareRendering(const PixelXRange& _Xs)
0486 {
0487     Q_Q(ByteArrayRowColumnRenderer);
0488 
0489     PixelXRange Xs(_Xs);
0490     q->restrictToXSpan(&Xs);
0491     // translate
0492     Xs.moveBy(-q->x());
0493 
0494     // store the values
0495     mRenderX = Xs.start();
0496     mRenderWidth = Xs.width();
0497 
0498     // get line linePositions to paint
0499     mRenderLinePositions = linePositionsOfColumnXs(mRenderX, mRenderWidth);
0500 }
0501 
0502 void ByteArrayRowColumnRendererPrivate::renderFirstLine(QPainter* painter, const PixelXRange& Xs, Line firstLineIndex)
0503 {
0504     prepareRendering(Xs);
0505 
0506     mRenderLine = firstLineIndex;
0507 
0508     renderLinePositions(painter, mRenderLine++, mRenderLinePositions);
0509 }
0510 
0511 void ByteArrayRowColumnRendererPrivate::renderNextLine(QPainter* painter)
0512 {
0513     renderLinePositions(painter, mRenderLine++, mRenderLinePositions);
0514 }
0515 
0516 void ByteArrayRowColumnRendererPrivate::renderLinePositions(QPainter* painter, Line lineIndex, const LinePositionRange& _linePositions)
0517 {
0518     // clear background
0519     const unsigned int blankFlag =
0520         (_linePositions.start() != 0 ? StartsBefore : 0) | (_linePositions.end() != mLastLinePos ? EndsLater : 0);
0521     const QBrush& backgroundBrush = mStylist->palette().brush(QPalette::Base);
0522 
0523     renderRange(painter, backgroundBrush, _linePositions, blankFlag);
0524 
0525     // no bytes to paint?
0526     if (!mLayout->hasContent(lineIndex)) {
0527         return;
0528     }
0529 
0530     // Go through the lines TODO: handle first and last line more effeciently
0531     // check for leading and trailing spaces
0532     const LinePositionRange existingLinePositions = mLayout->linePositions(lineIndex);
0533 
0534     LinePositionRange linePositions = _linePositions;
0535     linePositions.restrictTo(existingLinePositions);
0536     const int firstLinePosition = linePositions.start();
0537 
0538     // check for leading and trailing spaces
0539     AddressRange byteIndizes =
0540         AddressRange::fromWidth(mLayout->indexAtCoord(Coord(linePositions.start(), lineIndex)), linePositions.width());
0541 
0542     unsigned int selectionFlag = 0;
0543     unsigned int markingFlag = 0;
0544     AddressRange selectedRange;
0545     AddressRange markedRange;
0546     bool hasMarking = mRanges->hasMarking();
0547     bool hasSelection = mRanges->hasSelection();
0548 
0549 // qCDebug(LOG_OKTETA_GUI) << QString("painting linePositions (painter%1-%2L%3): ").arg(linePositions.start()).arg(linePositions.end()).arg(lineIndex)
0550 //         <<linePositions.start()<<"-"<<linePositions.start()
0551 //         <<" for byteIndizes "<<byteIndizes.start()<<"-"<<byteIndizes.start()<<endl;
0552     while (linePositions.isValid()) {
0553         LinePositionRange positionsPart = linePositions;  // set of linePositions to paint next
0554         AddressRange byteIndizesPart = byteIndizes;      // set of indizes to paint next
0555 
0556         if (hasMarking && markedRange.endsBefore(byteIndizesPart)) {
0557             hasMarking = getNextMarkedAddressRange(&markedRange, &markingFlag, byteIndizesPart);
0558         }
0559 
0560         if (hasSelection && selectedRange.endsBefore(byteIndizesPart)) {
0561             hasSelection = getNextSelectedAddressRange(&selectedRange, &selectionFlag, byteIndizesPart);
0562         }
0563 
0564         if (byteIndizesPart.start() == markedRange.start()) {
0565             byteIndizesPart.setEnd(markedRange.end());
0566             positionsPart.setEndByWidth(markedRange.width());
0567 
0568             if (positionsPart.start() == existingLinePositions.start()) {
0569                 markingFlag &= ~StartsBefore;
0570             }
0571             // TODO: hack: needed because otherwise the spacing will be plain
0572             else if ((positionsPart.start() == firstLinePosition) &&
0573                      selectedRange.includes(byteIndizesPart.start()) &&
0574                      (selectedRange.startsBefore(byteIndizesPart) ||
0575                       (selectionFlag & StartsBefore))) {
0576                 renderSelectionSpaceBehind(painter, firstLinePosition - 1);
0577             }
0578 
0579             if (positionsPart.end() == existingLinePositions.end()) {
0580                 markingFlag &= ~EndsLater;
0581             }
0582             // TODO: hack: needed because otherwise the spacing will be plain
0583             else if ((positionsPart.end() == linePositions.end()) &&
0584                      selectedRange.includes(byteIndizesPart.end()) &&
0585                      (selectedRange.endsBehind(byteIndizesPart) ||
0586                       (selectionFlag & EndsLater))) {
0587                 renderSelectionSpaceBehind(painter, positionsPart.end());
0588             }
0589 
0590             renderMarking(painter, positionsPart, byteIndizesPart.start(), markingFlag);
0591         } else if (selectedRange.includes(byteIndizesPart.start())) {
0592             if (selectedRange.startsBefore(byteIndizesPart)) {
0593                 selectionFlag |= StartsBefore;
0594             }
0595 
0596             const bool hasMarkingBeforeSelectionEnd = (hasMarking && markedRange.start() <= selectedRange.end());
0597 
0598             byteIndizesPart.setEnd(hasMarkingBeforeSelectionEnd ? markedRange.nextBeforeStart() : selectedRange.end());
0599             positionsPart.setEndByWidth(byteIndizesPart.width());
0600 
0601             if (hasMarkingBeforeSelectionEnd) {
0602                 selectionFlag |= EndsLater;
0603             }
0604             if (positionsPart.start() == existingLinePositions.start()) {
0605                 selectionFlag &= ~StartsBefore;
0606             }
0607             if (positionsPart.end() == existingLinePositions.end()) {
0608                 selectionFlag &= ~EndsLater;
0609             }
0610 
0611             renderSelection(painter, positionsPart, byteIndizesPart.start(), selectionFlag);
0612         } else {
0613             // calc end of plain text
0614             if (hasMarking) {
0615                 byteIndizesPart.setEnd(markedRange.nextBeforeStart());
0616             }
0617             if (hasSelection) {
0618                 byteIndizesPart.restrictEndTo(selectedRange.nextBeforeStart());
0619             }
0620 
0621             positionsPart.setEndByWidth(byteIndizesPart.width());
0622 
0623             renderPlain(painter, positionsPart, byteIndizesPart.start());
0624         }
0625 
0626         byteIndizes.setStartNextBehind(byteIndizesPart);
0627         linePositions.setStartNextBehind(positionsPart);
0628     }
0629 }
0630 
0631 void ByteArrayRowColumnRendererPrivate::renderPlain(QPainter* painter, const LinePositionRange& linePositions, Address byteIndex)
0632 {
0633     BookmarksConstIterator bit;
0634     Address nextBookmarkOffset = -1;
0635 
0636     const bool hasBookmarks = (mBookmarks != nullptr);
0637     if (hasBookmarks) {
0638         bit = mBookmarks->createBookmarksConstIterator();
0639         if (bit.findNextFrom(byteIndex)) {
0640             nextBookmarkOffset = bit.next().offset();
0641         }
0642     }
0643 
0644     const QPalette& palette = mStylist->palette();
0645     KColorScheme colorScheme(palette.currentColorGroup(), KColorScheme::View);
0646 
0647     // paint all the bytes affected
0648     for (LinePosition linePosition = linePositions.start(); linePosition <= linePositions.end(); ++linePosition, ++byteIndex) {
0649         const PixelX x = columnXOfLinePosition(linePosition);
0650 
0651         // draw the byte
0652         painter->translate(x, 0);
0653 
0654         if (byteIndex == nextBookmarkOffset) {
0655             renderBookmark(painter, colorScheme.background(KColorScheme::NeutralBackground));
0656 
0657             nextBookmarkOffset = bit.hasNext() ? bit.next().offset() : -1;// TODO )&& ( bit->offset() <= LastIndex );
0658         }
0659 
0660         const Byte byte = mByteArrayModel->byte(byteIndex);
0661         const Character byteChar = mCharCodec->decode(byte);
0662 
0663         const KColorScheme::ForegroundRole foregroundRole =
0664             mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0665         const QBrush brush = colorScheme.foreground(foregroundRole);
0666         const QColor& charColor = brush.color();// palette.text().color();//colorForChar(byteChar)
0667         renderByteText(painter, byte, byteChar, mVisibleCodings, charColor);
0668 
0669         painter->translate(-x, 0);
0670     }
0671 }
0672 
0673 void ByteArrayRowColumnRendererPrivate::renderSelection(QPainter* painter, const LinePositionRange& linePositions, Address byteIndex, int flag)
0674 {
0675     BookmarksConstIterator bit;
0676     Address nextBookmarkOffset = -1;
0677 
0678     const bool hasBookmarks = (mBookmarks != nullptr);
0679     if (hasBookmarks) {
0680         bit = mBookmarks->createBookmarksConstIterator();
0681         if (bit.findNextFrom(byteIndex)) {
0682             nextBookmarkOffset = bit.next().offset();
0683         }
0684     }
0685 
0686     const QPalette& palette = mStylist->palette();
0687     KColorScheme colorScheme(palette.currentColorGroup(), KColorScheme::Selection);
0688 
0689     renderRange(painter, colorScheme.background(), linePositions, flag);
0690 
0691     // paint all the bytes affected
0692     for (LinePosition linePosition = linePositions.start(); linePosition <= linePositions.end(); ++linePosition, ++byteIndex) {
0693         const PixelX x = columnXOfLinePosition(linePosition);
0694 
0695         // draw the byte
0696         painter->translate(x, 0);
0697 
0698         if (byteIndex == nextBookmarkOffset) {
0699             renderBookmark(painter, colorScheme.background(KColorScheme::NeutralBackground));
0700 
0701             nextBookmarkOffset = bit.hasNext() ? bit.next().offset() : -1;// TODO )&& ( bit->offset() <= LastIndex );
0702         }
0703 
0704         const Byte byte = mByteArrayModel->byte(byteIndex);
0705         const Character byteChar = mCharCodec->decode(byte);
0706 
0707         const KColorScheme::ForegroundRole foregroundRole =
0708             mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0709         const QBrush brush = colorScheme.foreground(foregroundRole);
0710         const QColor& charColor = brush.color();
0711         renderByteText(painter, byte, byteChar, mVisibleCodings, charColor);
0712 
0713         painter->translate(-x, 0);
0714     }
0715 }
0716 
0717 void ByteArrayRowColumnRendererPrivate::renderSelectionSpaceBehind(QPainter* painter, LinePosition linePosition)
0718 {
0719     const QPalette& palette = mStylist->palette();
0720     KColorScheme colorScheme(palette.currentColorGroup(), KColorScheme::Selection);
0721 
0722     renderSpaceBehind(painter, colorScheme.background(), linePosition);
0723 }
0724 
0725 void ByteArrayRowColumnRendererPrivate::renderMarking(QPainter* painter, const LinePositionRange& linePositions, Address byteIndex, int flag)
0726 {
0727     const QPalette& palette = mStylist->palette();
0728 
0729     renderRange(painter, palette.text(), linePositions, flag);
0730 
0731     const QColor& baseColor = palette.base().color();
0732     // paint all the bytes affected
0733     for (LinePosition p = linePositions.start(); p <= linePositions.end(); ++p, ++byteIndex) {
0734         const PixelX x = columnXOfLinePosition(p);
0735 
0736         // draw the byte
0737         painter->translate(x, 0);
0738         const Byte byte = mByteArrayModel->byte(byteIndex);
0739         const Character byteChar = mCharCodec->decode(byte);
0740         renderByteText(painter, byte, byteChar, mVisibleCodings, baseColor);
0741 
0742         painter->translate(-x, 0);
0743     }
0744 }
0745 
0746 void ByteArrayRowColumnRendererPrivate::renderBookmark(QPainter* painter, const QBrush& brush)
0747 {
0748     Q_Q(ByteArrayRowColumnRenderer);
0749 
0750     // TODO: think about how bookmarks should really be rendered
0751     painter->fillRect(1, 1, mByteWidth - 2, q->lineHeight() - 2, brush);
0752 }
0753 
0754 void ByteArrayRowColumnRendererPrivate::renderRange(QPainter* painter, const QBrush& brush, const LinePositionRange& linePositions, int flag)
0755 {
0756     Q_Q(ByteArrayRowColumnRenderer);
0757 
0758     const PixelX rangeX =
0759         (flag & StartsBefore) ? columnRightXOfLinePosition(linePositions.nextBeforeStart()) + 1 :
0760                                 columnXOfLinePosition(linePositions.start());
0761     const PixelX rangeW =
0762         ((flag & EndsLater) ? columnXOfLinePosition(linePositions.nextBehindEnd()) :
0763                               columnRightXOfLinePosition(linePositions.end()) + 1)
0764         - rangeX;
0765 
0766     painter->fillRect(rangeX, 0, rangeW, q->lineHeight(), brush);
0767 }
0768 
0769 void ByteArrayRowColumnRendererPrivate::renderSpaceBehind(QPainter* painter, const QBrush& brush, LinePosition linePosition)
0770 {
0771     Q_Q(ByteArrayRowColumnRenderer);
0772 
0773     const PixelX rangeX = columnRightXOfLinePosition(linePosition) + 1;
0774     const PixelX rangeW = columnXOfLinePosition(linePosition + 1) - rangeX;
0775 
0776     painter->fillRect(rangeX, 0, rangeW, q->lineHeight(), brush);
0777 }
0778 
0779 void ByteArrayRowColumnRendererPrivate::renderByte(QPainter* painter,
0780                                             Address byteIndex, AbstractByteArrayView::CodingTypeId codingId)
0781 {
0782     const Byte byte = (byteIndex > -1) ? mByteArrayModel->byte(byteIndex) : EmptyByte;
0783     const Character byteChar = mCharCodec->decode(byte);
0784 
0785     const QPalette& palette = mStylist->palette();
0786 
0787     KColorScheme::ColorSet colorSet = KColorScheme::View;
0788     if (byteIndex > -1) {
0789         if (mRanges->selectionIncludes(byteIndex)) {
0790             colorSet = KColorScheme::Selection;
0791         }
0792 //    else if( mRanges->markingIncludes(byteIndex) )
0793 //    {
0794 //      charColor = palette.base().color();
0795 //      brush = palette.text();
0796 //    }
0797     }
0798     KColorScheme colorScheme(palette.currentColorGroup(), colorSet);
0799 
0800     const QBrush backgroundBrush = colorScheme.background();
0801     painter->fillRect(0, 0, mByteWidth, mDigitHeight, backgroundBrush);
0802 
0803     if (mBookmarks && mBookmarks->containsBookmarkFor(byteIndex)) {
0804         const QBrush bookmarkBackgroundBrush = colorScheme.background(KColorScheme::NeutralBackground);
0805         painter->fillRect(1, 1, mByteWidth - 2, mDigitHeight - 2, bookmarkBackgroundBrush);
0806     }
0807 
0808     if (byteIndex > -1) {
0809         const KColorScheme::ForegroundRole foregroundRole =
0810             mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0811         const QBrush brush = colorScheme.foreground(foregroundRole);
0812         const QColor& charColor = brush.color();
0813 
0814         renderByteText(painter, byte, byteChar, codingId, charColor);
0815     }
0816 }
0817 
0818 // TODO: think about making framestyle a enum of a class ByteArrayColumnCursor
0819 void ByteArrayRowColumnRendererPrivate::renderFramedByte(QPainter* painter,
0820                                                   Address byteIndex, AbstractByteArrayView::CodingTypeId codingId,
0821                                                   ByteArrayRowColumnRenderer::FrameStyle frameStyle)
0822 {
0823     renderByte(painter, byteIndex, codingId);
0824 
0825     const Byte byte = (byteIndex > -1) ? mByteArrayModel->byte(byteIndex) : EmptyByte;
0826     const Character byteChar = mCharCodec->decode(byte);
0827 
0828     const bool isInSelection = (byteIndex > -1 && mRanges->selectionIncludes(byteIndex));
0829     const KColorScheme::ColorSet colorSet = isInSelection ? KColorScheme::Selection : KColorScheme::View;
0830 
0831     const QPalette& palette = mStylist->palette();
0832     KColorScheme colorScheme(palette.currentColorGroup(), colorSet);
0833     const KColorScheme::ForegroundRole foregroundRole =
0834         mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0835     const QBrush brush = colorScheme.foreground(foregroundRole);
0836     QPen pen(brush.color());
0837     pen.setJoinStyle(Qt::MiterJoin);
0838     painter->setPen(pen);
0839     if (frameStyle == ByteArrayRowColumnRenderer::Frame) {
0840         painter->drawRect(QRectF(0.5, 0.5, mByteWidth - 1, mDigitHeight - 1));
0841     } else if (frameStyle == ByteArrayRowColumnRenderer::Left) {
0842         painter->drawLine(QPointF(0.5, 0.5), QPointF(0.5, mDigitHeight - 0.5));
0843     } else {
0844         painter->drawLine(QPointF(mByteWidth - 0.5, 0), QPointF(mByteWidth - 0.5, mDigitHeight - 0.5));
0845     }
0846 }
0847 
0848 void ByteArrayRowColumnRendererPrivate::renderCursor(QPainter* painter, Address byteIndex, AbstractByteArrayView::CodingTypeId codingId)
0849 {
0850     Q_UNUSED(codingId)
0851     const Byte byte = (byteIndex > -1) ? mByteArrayModel->byte(byteIndex) : EmptyByte;
0852     const Character byteChar = mCharCodec->decode(byte);
0853 
0854     const bool isInSelection = (byteIndex > -1 && mRanges->selectionIncludes(byteIndex));
0855     const KColorScheme::ColorSet colorSet = isInSelection ? KColorScheme::Selection : KColorScheme::View;
0856 
0857     const QPalette& palette = mStylist->palette();
0858     KColorScheme colorScheme(palette.currentColorGroup(), colorSet);
0859     const KColorScheme::ForegroundRole foregroundRole =
0860         mByteTypeColored ? foregroundRoleForChar(byteChar) : KColorScheme::NormalText;
0861     const QBrush brush = colorScheme.foreground(foregroundRole);
0862     painter->fillRect(0, 0, mByteWidth, mDigitHeight, brush);
0863 
0864     if (byteIndex > -1) {
0865         const bool isBookmark = (byteIndex > -1 && mBookmarks && mBookmarks->containsBookmarkFor(byteIndex));
0866         const KColorScheme::BackgroundRole backgroundRole =
0867             isBookmark ? KColorScheme::NeutralBackground : KColorScheme::NormalBackground;
0868         const QBrush charBrush = colorScheme.background(backgroundRole);
0869         const QColor& charColor = charBrush.color();
0870         renderByteText(painter, byte, byteChar, codingId, charColor);
0871     }
0872 }
0873 
0874 bool ByteArrayRowColumnRendererPrivate::getNextSelectedAddressRange(AddressRange* _selection, unsigned int* _flag,
0875                                                              const AddressRange& range) const
0876 {
0877     const AddressRange* overlappingSelectedSection = mRanges->firstOverlappingSelection(range);
0878     if (!overlappingSelectedSection) {
0879         return false;
0880     }
0881 
0882     AddressRange selectedRange = *overlappingSelectedSection;
0883     unsigned int flag = 0;
0884 
0885     // does selectedRange start before asked range?
0886     if (selectedRange.startsBefore(range)) {
0887         selectedRange.setStart(range.start());
0888         flag |= StartsBefore;
0889     }
0890 
0891     // does selectedRange go on behind asked range?
0892     if (selectedRange.endsBehind(range)) {
0893         selectedRange.setEnd(range.end());
0894         flag |= EndsLater;
0895     }
0896 
0897     *_selection = selectedRange;
0898     *_flag = flag;
0899     return true;
0900 }
0901 
0902 bool ByteArrayRowColumnRendererPrivate::getNextMarkedAddressRange(AddressRange* _markedSection, unsigned int* _flag,
0903                                                            const AddressRange& range) const
0904 {
0905     const AddressRange* overlappingMarkedSection = mRanges->overlappingMarking(range);
0906     if (!overlappingMarkedSection) {
0907         return false;
0908     }
0909 
0910     unsigned int flag = 0;
0911     AddressRange markedRange = *overlappingMarkedSection;
0912 
0913     if (markedRange.startsBefore(range)) {
0914         markedRange.setStart(range.start());
0915         flag |= StartsBefore;
0916     }
0917 
0918     if (markedRange.endsBehind(range)) {
0919         markedRange.setEnd(range.end());
0920         flag |= EndsLater;
0921     }
0922 
0923     *_markedSection = markedRange;
0924     *_flag = flag;
0925     return true;
0926 }
0927 
0928 }