File indexing completed on 2024-05-12 05:44:25
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht ral@alwins-world.de * 0003 * https://kde.org/applications/development/org.kde.kdesvn * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0019 ***************************************************************************/ 0020 /* This file was part of KCachegrind. 0021 Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de> 0022 Adapted for the needs of kdesvn by Rajko Albrecht <ral@alwins-world.de> 0023 */ 0024 /* 0025 * A Widget for visualizing hierarchical metrics as areas. 0026 * The API is similar to QListView. 0027 */ 0028 0029 #include "drawparams.h" 0030 0031 #include <math.h> 0032 0033 #include <QFontDatabase> 0034 #include <QPainter> 0035 0036 // set this to 1 to enable debug output 0037 #define DEBUG_DRAWING 0 0038 #define MAX_FIELD 12 0039 0040 // 0041 // StoredDrawParams 0042 // 0043 StoredDrawParams::StoredDrawParams() 0044 : _backColor(Qt::white) 0045 , _selected(false) 0046 , _current(false) 0047 , _shaded(true) 0048 , _rotated(false) 0049 , _drawFrame(false) 0050 { 0051 // field array has size 0 0052 } 0053 0054 StoredDrawParams::StoredDrawParams(const QColor &c, bool selected, bool current) 0055 : _backColor(c) 0056 , _selected(selected) 0057 , _current(current) 0058 , _shaded(true) 0059 , _rotated(false) 0060 , _drawFrame(true) 0061 { 0062 // field array has size 0 0063 } 0064 0065 QString StoredDrawParams::text(int f) const 0066 { 0067 if ((f < 0) || (f >= _field.size())) { 0068 return QString(); 0069 } 0070 0071 return _field[f].text; 0072 } 0073 0074 QPixmap StoredDrawParams::pixmap(int f) const 0075 { 0076 if ((f < 0) || (f >= _field.size())) { 0077 return QPixmap(); 0078 } 0079 0080 return _field[f].pix; 0081 } 0082 0083 DrawParams::Position StoredDrawParams::position(int f) const 0084 { 0085 if ((f < 0) || (f >= _field.size())) { 0086 return Default; 0087 } 0088 0089 return _field[f].pos; 0090 } 0091 0092 int StoredDrawParams::maxLines(int f) const 0093 { 0094 if ((f < 0) || (f >= _field.size())) { 0095 return 0; 0096 } 0097 0098 return _field[f].maxLines; 0099 } 0100 0101 QFont StoredDrawParams::font() const 0102 { 0103 return QFontDatabase::systemFont(QFontDatabase::FixedFont); 0104 } 0105 0106 void StoredDrawParams::ensureField(int f) 0107 { 0108 static Field *def = nullptr; 0109 if (!def) { 0110 def = new Field(); 0111 def->pos = Default; 0112 def->maxLines = 0; 0113 } 0114 0115 if (f < 0 || f >= MAX_FIELD) { 0116 return; 0117 } 0118 0119 while (_field.size() < f + 1) { 0120 _field.append(*def); 0121 } 0122 } 0123 0124 void StoredDrawParams::setField(int f, const QString &t, const QPixmap &pm, Position p, int maxLines) 0125 { 0126 if (f < 0 || f >= MAX_FIELD) { 0127 return; 0128 } 0129 ensureField(f); 0130 0131 _field[f].text = t; 0132 _field[f].pix = pm; 0133 _field[f].pos = p; 0134 _field[f].maxLines = maxLines; 0135 } 0136 0137 void StoredDrawParams::setText(int f, const QString &t) 0138 { 0139 if (f < 0 || f >= MAX_FIELD) { 0140 return; 0141 } 0142 ensureField(f); 0143 0144 _field[f].text = t; 0145 } 0146 0147 void StoredDrawParams::setPixmap(int f, QPixmap pm) 0148 { 0149 if (f < 0 || f >= MAX_FIELD) { 0150 return; 0151 } 0152 ensureField(f); 0153 0154 _field[f].pix = pm; 0155 } 0156 0157 void StoredDrawParams::setPosition(int f, Position p) 0158 { 0159 if (f < 0 || f >= MAX_FIELD) { 0160 return; 0161 } 0162 ensureField(f); 0163 0164 _field[f].pos = p; 0165 } 0166 0167 void StoredDrawParams::setMaxLines(int f, int m) 0168 { 0169 if (f < 0 || f >= MAX_FIELD) { 0170 return; 0171 } 0172 ensureField(f); 0173 0174 _field[f].maxLines = m; 0175 } 0176 0177 // 0178 // RectDrawing 0179 // 0180 0181 RectDrawing::RectDrawing(const QRect &r) 0182 : _fm(nullptr) 0183 , _dp(nullptr) 0184 { 0185 setRect(r); 0186 } 0187 0188 RectDrawing::~RectDrawing() 0189 { 0190 delete _fm; 0191 delete _dp; 0192 } 0193 0194 DrawParams *RectDrawing::drawParams() 0195 { 0196 if (!_dp) { 0197 _dp = new StoredDrawParams(); 0198 } 0199 0200 return _dp; 0201 } 0202 0203 void RectDrawing::setDrawParams(DrawParams *dp) 0204 { 0205 if (_dp) { 0206 delete _dp; 0207 } 0208 _dp = dp; 0209 } 0210 0211 void RectDrawing::setRect(QRect r) 0212 { 0213 _rect = r; 0214 0215 _usedTopLeft = 0; 0216 _usedTopCenter = 0; 0217 _usedTopRight = 0; 0218 _usedBottomLeft = 0; 0219 _usedBottomCenter = 0; 0220 _usedBottomRight = 0; 0221 0222 _fontHeight = 0; 0223 } 0224 0225 QRect RectDrawing::remainingRect(DrawParams *dp) 0226 { 0227 if (!dp) { 0228 dp = drawParams(); 0229 } 0230 0231 if ((_usedTopLeft > 0) || (_usedTopCenter > 0) || (_usedTopRight > 0)) { 0232 if (dp->rotated()) { 0233 _rect.setLeft(_rect.left() + _fontHeight); 0234 } else { 0235 _rect.setTop(_rect.top() + _fontHeight); 0236 } 0237 } 0238 0239 if ((_usedBottomLeft > 0) || (_usedBottomCenter > 0) || (_usedBottomRight > 0)) { 0240 if (dp->rotated()) { 0241 _rect.setRight(_rect.right() - _fontHeight); 0242 } else { 0243 _rect.setBottom(_rect.bottom() - _fontHeight); 0244 } 0245 } 0246 return _rect; 0247 } 0248 0249 void RectDrawing::drawBack(QPainter *p, DrawParams *dp) 0250 { 0251 if (!dp) { 0252 dp = drawParams(); 0253 } 0254 if (_rect.width() <= 0 || _rect.height() <= 0) { 0255 return; 0256 } 0257 0258 QRect r = _rect; 0259 QColor normal = dp->backColor(); 0260 if (dp->selected()) { 0261 normal = normal.lighter(); 0262 } 0263 bool isCurrent = dp->current(); 0264 0265 if (dp->drawFrame() || isCurrent) { 0266 // 3D raised/sunken frame effect... 0267 QColor high = normal.lighter(); 0268 QColor low = normal.darker(); 0269 p->setPen(isCurrent ? low : high); 0270 p->drawLine(r.left(), r.top(), r.right(), r.top()); 0271 p->drawLine(r.left(), r.top(), r.left(), r.bottom()); 0272 p->setPen(isCurrent ? high : low); 0273 p->drawLine(r.right(), r.top(), r.right(), r.bottom()); 0274 p->drawLine(r.left(), r.bottom(), r.right(), r.bottom()); 0275 r.setRect(r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2); 0276 } 0277 if (r.width() <= 0 || r.height() <= 0) { 0278 return; 0279 } 0280 if (dp->shaded() && (r.width() > 0 && r.height() > 0)) { 0281 // adjustment for drawRect semantic in Qt4: decrement height/width 0282 r.setRect(r.x(), r.y(), r.width() - 1, r.height() - 1); 0283 0284 // some shading 0285 bool goDark = qGray(normal.rgb()) > 128; 0286 int rBase, gBase, bBase; 0287 normal.getRgb(&rBase, &gBase, &bBase); 0288 p->setBrush(Qt::NoBrush); 0289 0290 // shade parameters: 0291 int d = 7; 0292 double factor = 0.1, forth = 0.7, back1 = 0.9, toBack2 = .7, back2 = 0.97; 0293 0294 // coefficient corrections because of rectangle size 0295 int s = r.width(); 0296 if (s > r.height()) { 0297 s = r.height(); 0298 } 0299 if (s < 100) { 0300 forth -= .3 * (100 - s) / 100; 0301 back1 -= .2 * (100 - s) / 100; 0302 back2 -= .02 * (100 - s) / 100; 0303 } 0304 0305 // maximal color difference 0306 int rDiff = goDark ? -rBase / d : (255 - rBase) / d; 0307 int gDiff = goDark ? -gBase / d : (255 - gBase) / d; 0308 int bDiff = goDark ? -bBase / d : (255 - bBase) / d; 0309 0310 QColor shadeColor; 0311 while (factor < .95 && (r.width() >= 0 && r.height() >= 0)) { 0312 shadeColor.setRgb(qRound(rBase + factor * rDiff), qRound(gBase + factor * gDiff), qRound(bBase + factor * bDiff)); 0313 p->setPen(shadeColor); 0314 p->drawRect(r); 0315 r.setRect(r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2); 0316 factor = 1.0 - ((1.0 - factor) * forth); 0317 } 0318 0319 // and back (1st half) 0320 while (factor > toBack2 && (r.width() >= 0 && r.height() >= 0)) { 0321 shadeColor.setRgb(qRound(rBase + factor * rDiff), qRound(gBase + factor * gDiff), qRound(bBase + factor * bDiff)); 0322 p->setPen(shadeColor); 0323 p->drawRect(r); 0324 r.setRect(r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2); 0325 factor = 1.0 - ((1.0 - factor) / back1); 0326 } 0327 0328 // and back (2nd half) 0329 while (factor > .01 && (r.width() >= 0 && r.height() >= 0)) { 0330 shadeColor.setRgb(qRound(rBase + factor * rDiff), qRound(gBase + factor * gDiff), qRound(bBase + factor * bDiff)); 0331 p->setPen(shadeColor); 0332 p->drawRect(r); 0333 r.setRect(r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2); 0334 factor = factor * back2; 0335 } 0336 0337 normal = shadeColor; 0338 // for filling, width and height has to be incremented again 0339 r.setRect(r.x(), r.y(), r.width() + 1, r.height() + 1); 0340 } 0341 0342 // fill inside 0343 p->fillRect(r, normal); 0344 } 0345 0346 /* Helper for drawField 0347 * Find a line break position in a string, given a font and maximum width 0348 * 0349 * Returns the actually used width, and sets <breakPos> 0350 */ 0351 static int findBreak(int &breakPos, QString text, QFontMetrics *fm, int maxWidth) 0352 { 0353 int usedWidth; 0354 0355 // does full text fit? 0356 breakPos = text.length(); 0357 usedWidth = fm->horizontalAdvance(text); 0358 if (usedWidth < maxWidth) { 0359 return usedWidth; 0360 } 0361 0362 // now lower breakPos until best position is found. 0363 // first by binary search, resulting in a position a little bit too large 0364 int bottomPos = 0; 0365 while (qAbs(maxWidth - usedWidth) > 3 * fm->maxWidth()) { 0366 int halfPos = (bottomPos + breakPos) / 2; 0367 int halfWidth = fm->horizontalAdvance(text, halfPos); 0368 if (halfWidth < maxWidth) { 0369 bottomPos = halfPos; 0370 } else { 0371 breakPos = halfPos; 0372 usedWidth = halfWidth; 0373 } 0374 } 0375 0376 // final position by taking break boundaries into account. 0377 // possible break boundaries are changing char categories but not middle of "Aa" 0378 QChar::Category lastCat, cat; 0379 int pos = breakPos; 0380 lastCat = text[pos - 1].category(); 0381 // at minimum 2 chars before break 0382 while (pos > 2) { 0383 pos--; 0384 cat = text[pos - 1].category(); 0385 if (cat == lastCat) { 0386 continue; 0387 } 0388 0389 // "Aa" has not a possible break inbetween 0390 if ((cat == QChar::Letter_Uppercase) && (lastCat == QChar::Letter_Lowercase)) { 0391 lastCat = cat; 0392 continue; 0393 } 0394 lastCat = cat; 0395 0396 breakPos = pos; 0397 usedWidth = fm->horizontalAdvance(text, breakPos); 0398 if (usedWidth < maxWidth) { 0399 break; 0400 } 0401 } 0402 return usedWidth; 0403 } 0404 0405 /* Helper for drawField 0406 * Find last line break position in a string from backwards, 0407 * given a font and maximum width 0408 * 0409 * Returns the actually used width, and sets <breakPos> 0410 */ 0411 static int findBreakBackwards(int &breakPos, QString text, QFontMetrics *fm, int maxWidth) 0412 { 0413 int usedWidth; 0414 0415 // does full text fit? 0416 breakPos = 0; 0417 usedWidth = fm->horizontalAdvance(text); 0418 if (usedWidth < maxWidth) { 0419 return usedWidth; 0420 } 0421 0422 // now raise breakPos until best position is found. 0423 // first by binary search, resulting in a position a little bit too small 0424 int topPos = text.length(); 0425 while (qAbs(maxWidth - usedWidth) > 3 * fm->maxWidth()) { 0426 int halfPos = (breakPos + topPos) / 2; 0427 int halfWidth = fm->horizontalAdvance(text.mid(halfPos)); 0428 if (halfWidth < maxWidth) { 0429 breakPos = halfPos; 0430 usedWidth = halfWidth; 0431 } else { 0432 topPos = halfPos; 0433 } 0434 } 0435 0436 // final position by taking break boundaries into account. 0437 // possible break boundaries are changing char categories but not middle of "Aa" 0438 QChar::Category lastCat, cat; 0439 int pos = breakPos; 0440 lastCat = text[pos].category(); 0441 // at minimum 2 chars before break 0442 while (pos < text.length() - 2) { 0443 pos++; 0444 cat = text[pos].category(); 0445 if (cat == lastCat) { 0446 continue; 0447 } 0448 0449 // "Aa" has not a possible break inbetween 0450 if ((lastCat == QChar::Letter_Uppercase) && (cat == QChar::Letter_Lowercase)) { 0451 lastCat = cat; 0452 continue; 0453 } 0454 lastCat = cat; 0455 0456 breakPos = pos; 0457 usedWidth = fm->horizontalAdvance(text.mid(breakPos)); 0458 if (usedWidth < maxWidth) { 0459 break; 0460 } 0461 } 0462 return usedWidth; 0463 } 0464 0465 bool RectDrawing::drawField(QPainter *p, int f, DrawParams *dp) 0466 { 0467 if (!dp) { 0468 dp = drawParams(); 0469 } 0470 0471 if (!_fm) { 0472 _fm = new QFontMetrics(dp->font()); 0473 _fontHeight = _fm->height(); 0474 } 0475 0476 QRect r = _rect; 0477 0478 int h = _fontHeight; 0479 bool rotate = dp->rotated(); 0480 int width = (rotate ? r.height() : r.width()) - 4; 0481 int height = (rotate ? r.width() : r.height()); 0482 int lines = height / h; 0483 0484 // stop if there is no space available 0485 if (lines < 1) { 0486 return false; 0487 } 0488 0489 // calculate free space in first line (<unused>) 0490 int pos = dp->position(f); 0491 if (pos == DrawParams::Default) { 0492 switch (f % 4) { 0493 case 0: 0494 pos = DrawParams::TopLeft; 0495 break; 0496 case 1: 0497 pos = DrawParams::TopRight; 0498 break; 0499 case 2: 0500 pos = DrawParams::BottomRight; 0501 break; 0502 case 3: 0503 pos = DrawParams::BottomLeft; 0504 break; 0505 } 0506 } 0507 0508 int unused = 0; 0509 bool isBottom = false; 0510 bool isCenter = false; 0511 bool isRight = false; 0512 int *used = nullptr; 0513 switch (pos) { 0514 case DrawParams::TopLeft: 0515 used = &_usedTopLeft; 0516 if (_usedTopLeft == 0) { 0517 if (_usedTopCenter) { 0518 unused = (width - _usedTopCenter) / 2; 0519 } else { 0520 unused = width - _usedTopRight; 0521 } 0522 } 0523 break; 0524 0525 case DrawParams::TopCenter: 0526 isCenter = true; 0527 used = &_usedTopCenter; 0528 if (_usedTopCenter == 0) { 0529 if (_usedTopLeft > _usedTopRight) { 0530 unused = width - 2 * _usedTopLeft; 0531 } else { 0532 unused = width - 2 * _usedTopRight; 0533 } 0534 } 0535 break; 0536 0537 case DrawParams::TopRight: 0538 isRight = true; 0539 used = &_usedTopRight; 0540 if (_usedTopRight == 0) { 0541 if (_usedTopCenter) { 0542 unused = (width - _usedTopCenter) / 2; 0543 } else { 0544 unused = width - _usedTopLeft; 0545 } 0546 } 0547 break; 0548 0549 case DrawParams::BottomLeft: 0550 isBottom = true; 0551 used = &_usedBottomLeft; 0552 if (_usedBottomLeft == 0) { 0553 if (_usedBottomCenter) { 0554 unused = (width - _usedBottomCenter) / 2; 0555 } else { 0556 unused = width - _usedBottomRight; 0557 } 0558 } 0559 break; 0560 0561 case DrawParams::BottomCenter: 0562 isCenter = true; 0563 isBottom = true; 0564 used = &_usedBottomCenter; 0565 if (_usedBottomCenter == 0) { 0566 if (_usedBottomLeft > _usedBottomRight) { 0567 unused = width - 2 * _usedBottomLeft; 0568 } else { 0569 unused = width - 2 * _usedBottomRight; 0570 } 0571 } 0572 break; 0573 0574 case DrawParams::BottomRight: 0575 isRight = true; 0576 isBottom = true; 0577 used = &_usedBottomRight; 0578 if (_usedBottomRight == 0) { 0579 if (_usedBottomCenter) { 0580 unused = (width - _usedBottomCenter) / 2; 0581 } else { 0582 unused = width - _usedBottomLeft; 0583 } 0584 } 0585 break; 0586 } 0587 if (isBottom) { 0588 if ((_usedTopLeft > 0) || (_usedTopCenter > 0) || (_usedTopRight > 0)) { 0589 lines--; 0590 } 0591 } else if (!isBottom) { 0592 if ((_usedBottomLeft > 0) || (_usedBottomCenter > 0) || (_usedBottomRight > 0)) { 0593 lines--; 0594 } 0595 } 0596 if (lines < 1) { 0597 return false; 0598 } 0599 0600 int y = isBottom ? height - h : 0; 0601 0602 if (unused < 0) { 0603 unused = 0; 0604 } 0605 if (unused == 0) { 0606 // no space available in last line at this position 0607 y = isBottom ? (y - h) : (y + h); 0608 lines--; 0609 0610 if (lines < 1) { 0611 return false; 0612 } 0613 0614 // new line: reset used space 0615 if (isBottom) { 0616 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; 0617 } else { 0618 _usedTopLeft = _usedTopCenter = _usedTopRight = 0; 0619 } 0620 0621 unused = width; 0622 } 0623 0624 // stop as soon as possible when there is no space for "..." 0625 static int dotW = 0; 0626 if (!dotW) { 0627 dotW = _fm->horizontalAdvance(QLatin1String("...")); 0628 } 0629 if (width < dotW) { 0630 return false; 0631 } 0632 0633 // get text and pixmap now, only if we need to, because it is possible 0634 // that they are calculated on demand (and this can take some time) 0635 QString name = dp->text(f); 0636 if (name.isEmpty()) { 0637 return false; 0638 } 0639 QPixmap pix = dp->pixmap(f); 0640 0641 // check if pixmap can be drawn 0642 int pixW = pix.width(); 0643 int pixH = pix.height(); 0644 int pixY = 0; 0645 bool pixDrawn = true; 0646 if (pixW > 0) { 0647 pixW += 2; // X distance from pix 0648 if ((width < pixW + dotW) || (height < pixH)) { 0649 // do not draw 0650 pixW = 0; 0651 } else { 0652 pixDrawn = false; 0653 } 0654 } 0655 0656 // width of text and pixmap to be drawn 0657 int w = pixW + _fm->horizontalAdvance(name); 0658 0659 // if we have limited space at 1st line: 0660 // use it only if whole name does fit in last line... 0661 if ((unused < width) && (w > unused)) { 0662 y = isBottom ? (y - h) : (y + h); 0663 lines--; 0664 0665 if (lines < 1) { 0666 return false; 0667 } 0668 0669 // new line: reset used space 0670 if (isBottom) { 0671 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; 0672 } else { 0673 _usedTopLeft = _usedTopCenter = _usedTopRight = 0; 0674 } 0675 } 0676 0677 p->save(); 0678 p->setPen((qGray(dp->backColor().rgb()) > 100) ? Qt::black : Qt::white); 0679 p->setFont(dp->font()); 0680 if (rotate) { 0681 // p->translate(r.x()+2, r.y()+r.height()); 0682 p->translate(r.x(), r.y() + r.height() - 2); 0683 p->rotate(270); 0684 } else { 0685 p->translate(r.x() + 2, r.y()); 0686 } 0687 // adjust available lines according to maxLines 0688 int max = dp->maxLines(f); 0689 if ((max > 0) && (lines > max)) { 0690 lines = max; 0691 } 0692 /* loop over name parts to break up string depending on available width. 0693 * every char category change is supposed a possible break, 0694 * with the exception Uppercase=>Lowercase. 0695 * It is good enough for numbers, Symbols... 0696 * 0697 * If the text is to be written at the bottom, we start with the 0698 * end of the string (so everything is reverted) 0699 */ 0700 QString remaining; 0701 int origLines = lines; 0702 while (lines > 0) { 0703 // more than one line: search for line break 0704 if (w > width && lines > 1) { 0705 int breakPos; 0706 0707 if (!isBottom) { 0708 w = pixW + findBreak(breakPos, name, _fm, width - pixW); 0709 0710 remaining = name.mid(breakPos); 0711 // remove space on break point 0712 if (name[breakPos - 1].category() == QChar::Separator_Space) { 0713 name = name.left(breakPos - 1); 0714 } else { 0715 name = name.left(breakPos); 0716 } 0717 } else { // bottom 0718 w = pixW + findBreakBackwards(breakPos, name, _fm, width - pixW); 0719 0720 remaining = name.left(breakPos); 0721 // remove space on break point 0722 if (name[breakPos].category() == QChar::Separator_Space) { 0723 name = name.mid(breakPos + 1); 0724 } else { 0725 name = name.mid(breakPos); 0726 } 0727 } 0728 } else { 0729 remaining.clear(); 0730 } 0731 /* truncate and add ... if needed */ 0732 if (w > width) { 0733 name = _fm->elidedText(name, Qt::ElideRight, width - pixW); 0734 w = _fm->horizontalAdvance(name) + pixW; 0735 } 0736 0737 int x = 0; 0738 if (isCenter) { 0739 x = (width - w) / 2; 0740 } else if (isRight) { 0741 x = width - w; 0742 } 0743 if (!pixDrawn) { 0744 pixY = y + (h - pixH) / 2; // default: center vertically 0745 if (pixH > h) { 0746 pixY = isBottom ? y - (pixH - h) : y; 0747 } 0748 0749 p->drawPixmap(x, pixY, pix); 0750 0751 // for distance to next text 0752 pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2); 0753 pixDrawn = true; 0754 } 0755 p->drawText(x + pixW, y, width - pixW, h, Qt::AlignLeft, name); 0756 y = isBottom ? (y - h) : (y + h); 0757 lines--; 0758 0759 if (remaining.isEmpty()) { 0760 break; 0761 } 0762 name = remaining; 0763 w = pixW + _fm->horizontalAdvance(name); 0764 } 0765 0766 // make sure the pix stays visible 0767 if (pixDrawn && (pixY > 0)) { 0768 if (isBottom && (pixY < y)) { 0769 y = pixY; 0770 } 0771 if (!isBottom && (pixY > y)) { 0772 y = pixY; 0773 } 0774 } 0775 0776 if (origLines > lines) { 0777 // if only 1 line written, do not reset _used* vars 0778 if (lines - origLines > 1) { 0779 if (isBottom) { 0780 _usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0; 0781 } else { 0782 _usedTopLeft = _usedTopCenter = _usedTopRight = 0; 0783 } 0784 } 0785 0786 // take back one line 0787 y = isBottom ? (y + h) : (y - h); 0788 if (used) { 0789 *used = w; 0790 } 0791 } 0792 0793 // update free space 0794 if (!isBottom) { 0795 if (rotate) { 0796 _rect.setRect(r.x() + y, r.y(), r.width() - y, r.height()); 0797 } else { 0798 _rect.setRect(r.x(), r.y() + y, r.width(), r.height() - y); 0799 } 0800 } else { 0801 if (rotate) { 0802 _rect.setRect(r.x(), r.y(), y + h, r.height()); 0803 } else { 0804 _rect.setRect(r.x(), r.y(), r.width(), y + h); 0805 } 0806 } 0807 0808 p->restore(); 0809 0810 return true; 0811 }