File indexing completed on 2024-04-14 15:52:52

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