|
|
|
/* This file is part of KCachegrind.
|
|
|
|
Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
|
|
|
|
Adapted for the needs of tdesvn by Rajko Albrecht <ral@alwins-world.de>
|
|
|
|
|
|
|
|
KCachegrind is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public
|
|
|
|
License as published by the Free Software Foundation, version 2.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A Widget for visualizing hierarchical metrics as areas.
|
|
|
|
* The API is similar to TQListView.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <tqtooltip.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include "drawparams.h"
|
|
|
|
|
|
|
|
|
|
|
|
// set this to 1 to enable debug output
|
|
|
|
#define DEBUG_DRAWING 0
|
|
|
|
#define MAX_FIELD 12
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// StoredDrawParams
|
|
|
|
//
|
|
|
|
StoredDrawParams::StoredDrawParams()
|
|
|
|
{
|
|
|
|
_selected = false;
|
|
|
|
_current = false;
|
|
|
|
_shaded = true;
|
|
|
|
_rotated = false;
|
|
|
|
|
|
|
|
_backColor = TQt::white;
|
|
|
|
|
|
|
|
// field array has size 0
|
|
|
|
}
|
|
|
|
|
|
|
|
StoredDrawParams::StoredDrawParams(TQColor c,
|
|
|
|
bool selected, bool current)
|
|
|
|
{
|
|
|
|
_backColor = c;
|
|
|
|
|
|
|
|
_selected = selected;
|
|
|
|
_current = current;
|
|
|
|
_shaded = true;
|
|
|
|
_rotated = false;
|
|
|
|
_drawFrame = true;
|
|
|
|
|
|
|
|
// field array has size 0
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString StoredDrawParams::text(int f) const
|
|
|
|
{
|
|
|
|
if ((f<0) || (f >= (int)_field.size()))
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
return _field[f].text;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPixmap StoredDrawParams::pixmap(int f) const
|
|
|
|
{
|
|
|
|
if ((f<0) || (f >= (int)_field.size()))
|
|
|
|
return TQPixmap();
|
|
|
|
|
|
|
|
return _field[f].pix;
|
|
|
|
}
|
|
|
|
|
|
|
|
DrawParams::Position StoredDrawParams::position(int f) const
|
|
|
|
{
|
|
|
|
if ((f<0) || (f >= (int)_field.size()))
|
|
|
|
return Default;
|
|
|
|
|
|
|
|
return _field[f].pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
int StoredDrawParams::maxLines(int f) const
|
|
|
|
{
|
|
|
|
if ((f<0) || (f >= (int)_field.size()))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return _field[f].maxLines;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQFont& StoredDrawParams::font() const
|
|
|
|
{
|
|
|
|
static TQFont* f = 0;
|
|
|
|
if (!f) f = new TQFont(TQApplication::font());
|
|
|
|
|
|
|
|
return *f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDrawParams::ensureField(int f)
|
|
|
|
{
|
|
|
|
static Field* def = 0;
|
|
|
|
if (!def) {
|
|
|
|
def = new Field();
|
|
|
|
def->pos = Default;
|
|
|
|
def->maxLines = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
|
|
|
|
if ((int)_field.size() < f+1) _field.resize(f+1, *def);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void StoredDrawParams::setField(int f, TQString t, TQPixmap pm,
|
|
|
|
Position p, int maxLines)
|
|
|
|
{
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
ensureField(f);
|
|
|
|
|
|
|
|
_field[f].text = t;
|
|
|
|
_field[f].pix = pm;
|
|
|
|
_field[f].pos = p;
|
|
|
|
_field[f].maxLines = maxLines;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDrawParams::setText(int f, TQString t)
|
|
|
|
{
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
ensureField(f);
|
|
|
|
|
|
|
|
_field[f].text = t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDrawParams::setPixmap(int f, TQPixmap pm)
|
|
|
|
{
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
ensureField(f);
|
|
|
|
|
|
|
|
_field[f].pix = pm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDrawParams::setPosition(int f, Position p)
|
|
|
|
{
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
ensureField(f);
|
|
|
|
|
|
|
|
_field[f].pos = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StoredDrawParams::setMaxLines(int f, int m)
|
|
|
|
{
|
|
|
|
if (f<0 || f>=MAX_FIELD) return;
|
|
|
|
ensureField(f);
|
|
|
|
|
|
|
|
_field[f].maxLines = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// RectDrawing
|
|
|
|
//
|
|
|
|
|
|
|
|
RectDrawing::RectDrawing(TQRect r)
|
|
|
|
{
|
|
|
|
_fm = 0;
|
|
|
|
_dp = 0;
|
|
|
|
setRect(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RectDrawing::~RectDrawing()
|
|
|
|
{
|
|
|
|
delete _fm;
|
|
|
|
delete _dp;
|
|
|
|
}
|
|
|
|
|
|
|
|
DrawParams* RectDrawing::drawParams()
|
|
|
|
{
|
|
|
|
if (!_dp)
|
|
|
|
_dp = new StoredDrawParams();
|
|
|
|
|
|
|
|
return _dp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RectDrawing::setDrawParams(DrawParams* dp)
|
|
|
|
{
|
|
|
|
if (_dp) delete _dp;
|
|
|
|
_dp = dp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RectDrawing::setRect(TQRect r)
|
|
|
|
{
|
|
|
|
_rect = r;
|
|
|
|
|
|
|
|
_usedTopLeft = 0;
|
|
|
|
_usedTopCenter = 0;
|
|
|
|
_usedTopRight = 0;
|
|
|
|
_usedBottomLeft = 0;
|
|
|
|
_usedBottomCenter = 0;
|
|
|
|
_usedBottomRight = 0;
|
|
|
|
|
|
|
|
_fontHeight = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect RectDrawing::remainingRect(DrawParams* dp)
|
|
|
|
{
|
|
|
|
if (!dp) dp = drawParams();
|
|
|
|
|
|
|
|
if ((_usedTopLeft >0) ||
|
|
|
|
(_usedTopCenter >0) ||
|
|
|
|
(_usedTopRight >0)) {
|
|
|
|
if (dp->rotated())
|
|
|
|
_rect.setLeft(_rect.left() + _fontHeight);
|
|
|
|
else
|
|
|
|
_rect.setTop(_rect.top() + _fontHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((_usedBottomLeft >0) ||
|
|
|
|
(_usedBottomCenter >0) ||
|
|
|
|
(_usedBottomRight >0)) {
|
|
|
|
if (dp->rotated())
|
|
|
|
_rect.setRight(_rect.right() - _fontHeight);
|
|
|
|
else
|
|
|
|
_rect.setBottom(_rect.bottom() - _fontHeight);
|
|
|
|
}
|
|
|
|
return _rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RectDrawing::drawBack(TQPainter* p, DrawParams* dp)
|
|
|
|
{
|
|
|
|
if (!dp) dp = drawParams();
|
|
|
|
if (_rect.width()<=0 || _rect.height()<=0) return;
|
|
|
|
|
|
|
|
TQRect r = _rect;
|
|
|
|
TQColor normal = dp->backColor();
|
|
|
|
if (dp->selected()) normal = normal.light();
|
|
|
|
bool isCurrent = dp->current();
|
|
|
|
|
|
|
|
if (dp->drawFrame() || isCurrent) {
|
|
|
|
// 3D raised/sunken frame effect...
|
|
|
|
TQColor high = normal.light();
|
|
|
|
TQColor low = normal.dark();
|
|
|
|
p->setPen( isCurrent ? low:high);
|
|
|
|
p->drawLine(r.left(), r.top(), r.right(), r.top());
|
|
|
|
p->drawLine(r.left(), r.top(), r.left(), r.bottom());
|
|
|
|
p->setPen( isCurrent ? high:low);
|
|
|
|
p->drawLine(r.right(), r.top(), r.right(), r.bottom());
|
|
|
|
p->drawLine(r.left(), r.bottom(), r.right(), r.bottom());
|
|
|
|
r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
|
|
|
|
}
|
|
|
|
if (r.width()<=0 || r.height()<=0) return;
|
|
|
|
|
|
|
|
if (dp->shaded()) {
|
|
|
|
// some shading
|
|
|
|
bool goDark = tqGray(normal.rgb())>128;
|
|
|
|
int rBase, gBase, bBase;
|
|
|
|
normal.rgb(&rBase, &gBase, &bBase);
|
|
|
|
p->setBrush(TQBrush::NoBrush);
|
|
|
|
|
|
|
|
// shade parameters:
|
|
|
|
int d = 7;
|
|
|
|
float factor = 0.1, forth=0.7, back1 =0.9, toBack2 = .7, back2 = 0.97;
|
|
|
|
|
|
|
|
// coefficient corrections because of rectangle size
|
|
|
|
int s = r.width();
|
|
|
|
if (s > r.height()) s = r.height();
|
|
|
|
if (s<100) {
|
|
|
|
forth -= .3 * (100-s)/100;
|
|
|
|
back1 -= .2 * (100-s)/100;
|
|
|
|
back2 -= .02 * (100-s)/100;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// maximal color difference
|
|
|
|
int rDiff = goDark ? -rBase/d : (255-rBase)/d;
|
|
|
|
int gDiff = goDark ? -gBase/d : (255-gBase)/d;
|
|
|
|
int bDiff = goDark ? -bBase/d : (255-bBase)/d;
|
|
|
|
|
|
|
|
TQColor shadeColor;
|
|
|
|
while (factor<.95) {
|
|
|
|
shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
|
|
|
|
(int)(gBase+factor*gDiff+.5),
|
|
|
|
(int)(bBase+factor*bDiff+.5));
|
|
|
|
p->setPen(shadeColor);
|
|
|
|
p->drawRect(r);
|
|
|
|
r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
|
|
|
|
if (r.width()<=0 || r.height()<=0) return;
|
|
|
|
factor = 1.0 - ((1.0 - factor) * forth);
|
|
|
|
}
|
|
|
|
|
|
|
|
// and back (1st half)
|
|
|
|
while (factor>toBack2) {
|
|
|
|
shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
|
|
|
|
(int)(gBase+factor*gDiff+.5),
|
|
|
|
(int)(bBase+factor*bDiff+.5));
|
|
|
|
p->setPen(shadeColor);
|
|
|
|
p->drawRect(r);
|
|
|
|
r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
|
|
|
|
if (r.width()<=0 || r.height()<=0) return;
|
|
|
|
factor = 1.0 - ((1.0 - factor) / back1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// and back (2nd half)
|
|
|
|
while ( factor>.01) {
|
|
|
|
shadeColor.setRgb((int)(rBase+factor*rDiff+.5),
|
|
|
|
(int)(gBase+factor*gDiff+.5),
|
|
|
|
(int)(bBase+factor*bDiff+.5));
|
|
|
|
p->setPen(shadeColor);
|
|
|
|
p->drawRect(r);
|
|
|
|
r.setRect(r.x()+1, r.y()+1, r.width()-2, r.height()-2);
|
|
|
|
if (r.width()<=0 || r.height()<=0) return;
|
|
|
|
|
|
|
|
factor = factor * back2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fill inside
|
|
|
|
p->setPen(TQPen::NoPen);
|
|
|
|
p->setBrush(normal);
|
|
|
|
p->drawRect(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RectDrawing::drawField(TQPainter* p, int f, DrawParams* dp)
|
|
|
|
{
|
|
|
|
if (!dp) dp = drawParams();
|
|
|
|
|
|
|
|
if (!_fm) {
|
|
|
|
_fm = new TQFontMetrics(dp->font());
|
|
|
|
_fontHeight = _fm->height();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQRect r = _rect;
|
|
|
|
|
|
|
|
if (0) kdDebug(90100) << "DrawField: Rect " << r.x() << "/" << r.y()
|
|
|
|
<< " - " << r.width() << "x" << r.height() << endl;
|
|
|
|
|
|
|
|
int h = _fontHeight;
|
|
|
|
bool rotate = dp->rotated();
|
|
|
|
int width = (rotate ? r.height() : r.width()) -4;
|
|
|
|
int height = (rotate ? r.width() : r.height());
|
|
|
|
int lines = height / h;
|
|
|
|
|
|
|
|
// stop if we have no space available
|
|
|
|
if (lines<1) return false;
|
|
|
|
|
|
|
|
// calculate free space in first line (<unused>)
|
|
|
|
int pos = dp->position(f);
|
|
|
|
if (pos == DrawParams::Default) {
|
|
|
|
switch(f%4) {
|
|
|
|
case 0: pos = DrawParams::TopLeft; break;
|
|
|
|
case 1: pos = DrawParams::TopRight; break;
|
|
|
|
case 2: pos = DrawParams::BottomRight; break;
|
|
|
|
case 3: pos = DrawParams::BottomLeft; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int unused = 0;
|
|
|
|
bool isBottom = false;
|
|
|
|
bool isCenter = false;
|
|
|
|
bool isRight = false;
|
|
|
|
int* used = 0;
|
|
|
|
switch(pos) {
|
|
|
|
case DrawParams::TopLeft:
|
|
|
|
used = &_usedTopLeft;
|
|
|
|
if (_usedTopLeft == 0) {
|
|
|
|
if (_usedTopCenter)
|
|
|
|
unused = (width - _usedTopCenter)/2;
|
|
|
|
else
|
|
|
|
unused = width - _usedTopRight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DrawParams::TopCenter:
|
|
|
|
isCenter = true;
|
|
|
|
used = &_usedTopCenter;
|
|
|
|
if (_usedTopCenter == 0) {
|
|
|
|
if (_usedTopLeft > _usedTopRight)
|
|
|
|
unused = width - 2 * _usedTopLeft;
|
|
|
|
else
|
|
|
|
unused = width - 2 * _usedTopRight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DrawParams::TopRight:
|
|
|
|
isRight = true;
|
|
|
|
used = &_usedTopRight;
|
|
|
|
if (_usedTopRight == 0) {
|
|
|
|
if (_usedTopCenter)
|
|
|
|
unused = (width - _usedTopCenter)/2;
|
|
|
|
else
|
|
|
|
unused = width - _usedTopLeft;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DrawParams::BottomLeft:
|
|
|
|
isBottom = true;
|
|
|
|
used = &_usedBottomLeft;
|
|
|
|
if (_usedBottomLeft == 0) {
|
|
|
|
if (_usedBottomCenter)
|
|
|
|
unused = (width - _usedBottomCenter)/2;
|
|
|
|
else
|
|
|
|
unused = width - _usedBottomRight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DrawParams::BottomCenter:
|
|
|
|
isCenter = true;
|
|
|
|
isBottom = true;
|
|
|
|
used = &_usedBottomCenter;
|
|
|
|
if (_usedBottomCenter == 0) {
|
|
|
|
if (_usedBottomLeft > _usedBottomRight)
|
|
|
|
unused = width - 2 * _usedBottomLeft;
|
|
|
|
else
|
|
|
|
unused = width - 2 * _usedBottomRight;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DrawParams::BottomRight:
|
|
|
|
isRight = true;
|
|
|
|
isBottom = true;
|
|
|
|
used = &_usedBottomRight;
|
|
|
|
if (_usedBottomRight == 0) {
|
|
|
|
if (_usedBottomCenter)
|
|
|
|
unused = (width - _usedBottomCenter)/2;
|
|
|
|
else
|
|
|
|
unused = width - _usedBottomLeft;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isBottom) {
|
|
|
|
if ((_usedTopLeft >0) ||
|
|
|
|
(_usedTopCenter >0) ||
|
|
|
|
(_usedTopRight >0))
|
|
|
|
lines--;
|
|
|
|
}
|
|
|
|
else if (!isBottom) {
|
|
|
|
if ((_usedBottomLeft >0) ||
|
|
|
|
(_usedBottomCenter >0) ||
|
|
|
|
(_usedBottomRight >0))
|
|
|
|
lines--;
|
|
|
|
}
|
|
|
|
if (lines<1) return false;
|
|
|
|
|
|
|
|
|
|
|
|
int y = isBottom ? height - h : 0;
|
|
|
|
|
|
|
|
if (unused < 0) unused = 0;
|
|
|
|
if (unused == 0) {
|
|
|
|
// no space available in last line at this position
|
|
|
|
y = isBottom ? (y-h) : (y+h);
|
|
|
|
lines--;
|
|
|
|
|
|
|
|
if (lines<1) return false;
|
|
|
|
|
|
|
|
// new line: reset used space
|
|
|
|
if (isBottom)
|
|
|
|
_usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
|
|
|
|
else
|
|
|
|
_usedTopLeft = _usedTopCenter = _usedTopRight = 0;
|
|
|
|
|
|
|
|
unused = width;
|
|
|
|
}
|
|
|
|
|
|
|
|
// stop as soon as possible when there's no space for "..."
|
|
|
|
static int dotW = 0;
|
|
|
|
if (!dotW) dotW = _fm->width("...");
|
|
|
|
if (width < dotW) return false;
|
|
|
|
|
|
|
|
// get text and pixmap now, only if we need to, because it is possible
|
|
|
|
// that they are calculated on demand (and this can take some time)
|
|
|
|
TQString name = dp->text(f);
|
|
|
|
if (name.isEmpty()) return 0;
|
|
|
|
TQPixmap pix = dp->pixmap(f);
|
|
|
|
|
|
|
|
// check if pixmap can be drawn
|
|
|
|
int pixW = pix.width();
|
|
|
|
int pixH = pix.height();
|
|
|
|
int pixY = 0;
|
|
|
|
bool pixDrawn = true;
|
|
|
|
if (pixW>0) {
|
|
|
|
pixW += 2; // X distance from pix
|
|
|
|
if ((width < pixW + dotW) || (height < pixH)) {
|
|
|
|
// don't draw
|
|
|
|
pixW = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pixDrawn = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// width of text and pixmap to be drawn
|
|
|
|
int w = pixW + _fm->width(name);
|
|
|
|
|
|
|
|
if (0) kdDebug(90100) << " For '" << name << "': Unused " << unused
|
|
|
|
<< ", StrW " << w << ", Width " << width << endl;
|
|
|
|
|
|
|
|
// if we have limited space at 1st line:
|
|
|
|
// use it only if whole name does fit in last line...
|
|
|
|
if ((unused < width) && (w > unused)) {
|
|
|
|
y = isBottom ? (y-h) : (y+h);
|
|
|
|
lines--;
|
|
|
|
|
|
|
|
if (lines<1) return false;
|
|
|
|
|
|
|
|
// new line: reset used space
|
|
|
|
if (isBottom)
|
|
|
|
_usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
|
|
|
|
else
|
|
|
|
_usedTopLeft = _usedTopCenter = _usedTopRight = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->save();
|
|
|
|
p->setPen( (tqGray(dp->backColor().rgb())>100) ? TQt::black : TQt::white);
|
|
|
|
p->setFont(dp->font());
|
|
|
|
if (rotate) {
|
|
|
|
//p->translate(r.x()+2, r.y()+r.height());
|
|
|
|
p->translate(r.x(), r.y()+r.height()-2);
|
|
|
|
p->rotate(270);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
p->translate(r.x()+2, r.y());
|
|
|
|
|
|
|
|
|
|
|
|
// adjust available lines according to maxLines
|
|
|
|
int max = dp->maxLines(f);
|
|
|
|
if ((max > 0) && (lines>max)) lines = max;
|
|
|
|
|
|
|
|
/* loop over name parts to break up string depending on available width.
|
|
|
|
* every char category change is supposed a possible break,
|
|
|
|
* with the exception Uppercase=>Lowercase.
|
|
|
|
* It's good enough for numbers, Symbols...
|
|
|
|
*
|
|
|
|
* If the text is to be written at the bottom, we start with the
|
|
|
|
* end of the string (so everything is reverted)
|
|
|
|
*/
|
|
|
|
TQString remaining;
|
|
|
|
int origLines = lines;
|
|
|
|
while (lines>0) {
|
|
|
|
|
|
|
|
if (w>width && lines>1) {
|
|
|
|
int lastBreakPos = name.length(), lastWidth = w;
|
|
|
|
int len = name.length();
|
|
|
|
TQChar::Category caOld, ca;
|
|
|
|
|
|
|
|
if (!isBottom) {
|
|
|
|
// start with comparing categories of last 2 chars
|
|
|
|
caOld = name[len-1].category();
|
|
|
|
while (len>2) {
|
|
|
|
len--;
|
|
|
|
ca = name[len-1].category();
|
|
|
|
if (ca != caOld) {
|
|
|
|
// "Aa" has no break between...
|
|
|
|
if (ca == TQChar::Letter_Uppercase &&
|
|
|
|
caOld == TQChar::Letter_Lowercase) {
|
|
|
|
caOld = ca;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
caOld = ca;
|
|
|
|
lastBreakPos = len;
|
|
|
|
w = pixW + _fm->width(name, len);
|
|
|
|
lastWidth = w;
|
|
|
|
if (w <= width) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w = lastWidth;
|
|
|
|
remaining = name.mid(lastBreakPos);
|
|
|
|
// remove space on break point
|
|
|
|
if (name[lastBreakPos-1].category() == TQChar::Separator_Space)
|
|
|
|
name = name.left(lastBreakPos-1);
|
|
|
|
else
|
|
|
|
name = name.left(lastBreakPos);
|
|
|
|
}
|
|
|
|
else { // bottom
|
|
|
|
int l = len;
|
|
|
|
caOld = name[l-len].category();
|
|
|
|
while (len>2) {
|
|
|
|
len--;
|
|
|
|
ca = name[l-len].category();
|
|
|
|
|
|
|
|
if (ca != caOld) {
|
|
|
|
// "Aa" has no break between...
|
|
|
|
if (caOld == TQChar::Letter_Uppercase &&
|
|
|
|
ca == TQChar::Letter_Lowercase) {
|
|
|
|
caOld = ca;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
caOld = ca;
|
|
|
|
lastBreakPos = len;
|
|
|
|
w = pixW + _fm->width(name.right(len));
|
|
|
|
lastWidth = w;
|
|
|
|
if (w <= width) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w = lastWidth;
|
|
|
|
remaining = name.left(l-lastBreakPos);
|
|
|
|
// remove space on break point
|
|
|
|
if (name[l-lastBreakPos].category() == TQChar::Separator_Space)
|
|
|
|
name = name.right(lastBreakPos-1);
|
|
|
|
else
|
|
|
|
name = name.right(lastBreakPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
remaining = TQString();
|
|
|
|
|
|
|
|
/* truncate and add ... if needed */
|
|
|
|
if (w>width) {
|
|
|
|
int len = name.length();
|
|
|
|
w += dotW;
|
|
|
|
while (len>2 && (w > width)) {
|
|
|
|
len--;
|
|
|
|
w = pixW + _fm->width(name, len) + dotW;
|
|
|
|
}
|
|
|
|
// stop drawing: we cannot draw 2 chars + "..."
|
|
|
|
if (w>width) break;
|
|
|
|
|
|
|
|
name = name.left(len) + "...";
|
|
|
|
}
|
|
|
|
|
|
|
|
int x = 0;
|
|
|
|
if (isCenter)
|
|
|
|
x = (width - w)/2;
|
|
|
|
else if (isRight)
|
|
|
|
x = width - w;
|
|
|
|
|
|
|
|
if (!pixDrawn) {
|
|
|
|
pixY = y+(h-pixH)/2; // default: center vertically
|
|
|
|
if (pixH > h) pixY = isBottom ? y-(pixH-h) : y;
|
|
|
|
|
|
|
|
p->drawPixmap( x, pixY, pix);
|
|
|
|
|
|
|
|
// for distance to next text
|
|
|
|
pixY = isBottom ? (pixY - h - 2) : (pixY + pixH + 2);
|
|
|
|
pixDrawn = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (0) kdDebug(90100) << " Drawing '" << name << "' at "
|
|
|
|
<< x+pixW << "/" << y << endl;
|
|
|
|
|
|
|
|
p->drawText( x+pixW, y,
|
|
|
|
width - pixW, h,
|
|
|
|
TQt::AlignLeft, name);
|
|
|
|
y = isBottom ? (y-h) : (y+h);
|
|
|
|
lines--;
|
|
|
|
|
|
|
|
if (remaining.isEmpty()) break;
|
|
|
|
name = remaining;
|
|
|
|
w = pixW + _fm->width(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure the pix stays visible
|
|
|
|
if (pixDrawn && (pixY>0)) {
|
|
|
|
if (isBottom && (pixY<y)) y = pixY;
|
|
|
|
if (!isBottom && (pixY>y)) y = pixY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (origLines > lines) {
|
|
|
|
// if only 1 line written, don't reset _used* vars
|
|
|
|
if (lines - origLines >1) {
|
|
|
|
if (isBottom)
|
|
|
|
_usedBottomLeft = _usedBottomCenter = _usedBottomRight = 0;
|
|
|
|
else
|
|
|
|
_usedTopLeft = _usedTopCenter = _usedTopRight = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// take back one line
|
|
|
|
y = isBottom ? (y+h) : (y-h);
|
|
|
|
if (used) *used = w;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update free space
|
|
|
|
if (!isBottom) {
|
|
|
|
if (rotate)
|
|
|
|
_rect.setRect(r.x()+y, r.y(), r.width()-y, r.height());
|
|
|
|
else
|
|
|
|
_rect.setRect(r.x(), r.y()+y, r.width(), r.height()-y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (rotate)
|
|
|
|
_rect.setRect(r.x(), r.y(), y+h, r.height());
|
|
|
|
else
|
|
|
|
_rect.setRect(r.x(), r.y(), r.width(), y+h);
|
|
|
|
}
|
|
|
|
|
|
|
|
p->restore();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|