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 }