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

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