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