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