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 }