File indexing completed on 2024-03-24 17:26:43

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