You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/devices/base/device_group.cpp

363 lines
12 KiB

/***************************************************************************
* Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
* *
* This program 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; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "device_group.h"
#if !defined(NO_KDE)
# include <tqpainter.h>
# include <kglobal.h>
TQColor Device::statusColor(Status status)
{
switch (status.type()) {
case Status::Future: return TQt::blue;
case Status::InProduction: return TQt::green;
case Status::Mature:
case Status::NotRecommended: return TQColor("orange");
case Status::EOL: return TQt::red;
case Status::Unknown:
case Status::Nb_Types: break;
}
return TQt::black;
}
TQString coloredString(const TQString &text, TQColor color)
{
return TQString("<font color=\"") + color.name() + "\">" + text + "</font>";
}
TQString supportedString(bool supported)
{
return coloredString(supported ? i18n("Supported") : i18n("Unsupported"),
supported ? TQt::green : TQt::red);
}
class Tick {
public:
Tick() {}
Tick(double value, double oValue) {
s = KGlobal::locale()->formatNumber(value, 1);
min = oValue;
}
TQString s;
double min;
};
class TickMap : public TQMap<double, Tick>
{
public:
TickMap() {}
void add(double value, double oValue) {
insert(value, Tick(value, oValue), false);
(*this)[value].min = TQMIN((*this)[value].min, oValue);
}
};
TQPixmap drawGraph(const TQValueVector<Device::RangeBox> &boxes)
{
const uint w = 300, h = 200;
TQPixmap pixmap(w, h);
pixmap.fill(TQt::white);
TQPainter p(&pixmap);
TQFontMetrics f(p.font());
TickMap xTicks, yTicks;
xTicks.add(0.0, 0.0);
yTicks.add(0.0, 0.0);
for (uint i=0; i<boxes.count(); i++) {
// qDebug("box #%i: %f=[%f %f] %f=[%f %f]", i, boxes[i].start.x, boxes[i].start.yMin,
// boxes[i].start.yMax, boxes[i].end.x, boxes[i].end.yMin, boxes[i].end.yMax);
xTicks.add(boxes[i].start.x, boxes[i].start.yMin);
xTicks.add(boxes[i].start.x, boxes[i].start.yMax);
xTicks.add(boxes[i].end.x, boxes[i].end.yMin);
xTicks.add(boxes[i].end.x, boxes[i].end.yMax);
yTicks.add(boxes[i].start.yMin, boxes[i].start.x);
yTicks.add(boxes[i].start.yMax, boxes[i].start.x);
yTicks.add(boxes[i].end.yMin, boxes[i].end.x);
yTicks.add(boxes[i].end.yMax, boxes[i].end.x);
}
double xMax = 0.0, yMax = 0.0;
int xStart = 0;
int yStart = h-1 - f.lineSpacing();
TickMap::const_iterator it = xTicks.begin();
for (; it!=xTicks.end(); ++it) {
xStart = TQMAX(xStart, f.width(it.data().s));
xMax = TQMAX(xMax, it.key());
}
for (it = yTicks.begin(); it!=yTicks.end(); ++it)
yMax = TQMAX(yMax, it.key());
int xEnd = w-1 - f.width(xTicks[xMax].s)/2;
TQRect rect = f.boundingRect(yTicks[yMax].s);
int yEnd = rect.height()/2;
// draw boxes
p.setPen(TQt::lightGray);
p.setBrush(TQt::lightGray);
for (uint i=0; i<boxes.count(); i++) {
double ax = double(xEnd - xStart)/xMax;
double ay = double(yEnd - yStart)/yMax;
TQPointArray pa(4);
pa.setPoint(0, tqRound(ax*boxes[i].start.x), tqRound(ay*boxes[i].start.yMin));
pa.setPoint(1, tqRound(ax*boxes[i].end.x), tqRound(ay*boxes[i].end.yMin));
pa.setPoint(2, tqRound(ax*boxes[i].end.x), tqRound(ay*boxes[i].end.yMax));
pa.setPoint(3, tqRound(ax*boxes[i].start.x), tqRound(ay*boxes[i].start.yMax));
pa.translate(xStart, yStart);
p.drawPolygon(pa);
}
// draw axis
p.setPen(TQt::black);
p.drawLine(xStart, yStart, w-1, yStart);
p.drawLine(xStart, yStart, xStart, 0);
// draw ticks and lines
p.setPen(TQt::DotLine);
for (it = yTicks.begin(); it!=yTicks.end(); ++it) {
int y1 = yStart + tqRound(it.key()*(yEnd-yStart)/yMax);
TQRect rect = f.boundingRect(it.data().s);
p.drawText(xStart/2-rect.width()/2 , y1+rect.height()/2, it.data().s);
int xmin = xStart + tqRound(it.data().min*(xEnd-xStart)/xMax);
p.drawLine(xStart, y1, xmin, y1);
}
for (it = xTicks.begin(); it!=xTicks.end(); ++it) {
int x1 = xStart + tqRound(it.key()*(xEnd-xStart)/xMax);
TQRect rect = f.boundingRect(it.data().s);
p.drawText(x1-rect.width()/2, h-1, it.data().s);
int ymin = yStart + tqRound(it.data().min*(yEnd-yStart)/yMax);
p.drawLine(x1, yStart, x1, ymin);
}
return pixmap;
}
TQPixmap Device::vddGraph(const TQString &xLabel, const TQString &yLabel,
const TQValueVector<Device::RangeBox> &boxes)
{
uint sp = 10;
TQPixmap graph = drawGraph(boxes);
TQPainter p;
TQFontMetrics f(p.font());
TQPixmap pixmap(graph.width() + sp + f.width(xLabel), graph.height() + sp + f.lineSpacing());
pixmap.fill(TQt::white);
copyBlt(&pixmap, 0, f.lineSpacing() + sp, &graph, 0, 0, graph.width(), graph.height());
p.begin(&pixmap);
p.setPen(TQt::black);
p.drawText(0, f.lineSpacing(), yLabel);
p.drawText(pixmap.width()-1-f.width(xLabel), pixmap.height()-1, xLabel);
return pixmap;
}
const Device::Package *Device::barPackage(const char *name, const Device::Data &data)
{
for (uint i=0; i<data.packages().count(); i++)
for (uint k=0; k<data.packages()[i].types.count(); k++)
if ( Package::TYPE_DATA[data.packages()[i].types[k]].name==name ) return &data.packages()[i];
return 0;
}
TQPixmap Device::pinsGraph(const Device::Package &package)
{
TQPixmap pixmap;
TQPainter p;
TQFontMetrics fm(p.font());
uint nb = package.pins.count();
const int hspacing = 3, wspacing = 3, wmark = 10, wpin = 4;
int theight = fm.ascent() + (fm.ascent()%2==0 ? 1 : 0);
int height = hspacing + (nb/2)*(hspacing + theight);
int wnumber = fm.width("1");
wnumber = TQMAX(wnumber, fm.width(TQString::number(nb/2)));
wnumber = TQMAX(wnumber, fm.width(TQString::number(nb/2+1)));
wnumber = TQMAX(wnumber, fm.width(TQString::number(nb)));
int bwidth = 4*wspacing + 2*wnumber + wmark;
int lwidth = 0, rwidth = 0;
for (uint k=0; k<nb/2; k++) {
lwidth = TQMAX(lwidth, fm.width(package.pins[k]));
rwidth = TQMAX(rwidth, fm.width(package.pins[nb-k-1]));
}
int bx = lwidth + wspacing + wpin;
int width = bx + bwidth + wpin + wspacing + rwidth;
pixmap.resize(width, height);
pixmap.fill(TQt::white);
p.begin(&pixmap);
p.setPen(TQPen(TQt::black, 2));
p.drawRect(bx, 1, bwidth, height-1);
p.drawArc(bx+wspacing+wnumber+wspacing, -wmark/2+2, wmark, wmark, 0, -180*16);
for (uint k=0; k<nb/2; k++) {
int h = hspacing + theight/2 + k*(hspacing + theight);
p.drawLine(bx-wpin-1, h, bx, h);
p.drawLine(bx+bwidth, h, bx+bwidth+wpin, h);
h += theight/2;
TQString label = package.pins[k];
p.drawText(bx-wpin-wspacing-fm.width(label), h, label);
p.drawText(bx+bwidth+wpin+wspacing, h, package.pins[nb-k-1]);
uint pin = (k+1);
if ( pin==1 || pin==(nb/2) ) {
p.drawText(bx+wspacing, h, TQString::number(pin));
label = TQString::number(nb-k);
p.drawText(bx+bwidth-wspacing-fm.width(label), h, label);
}
}
p.end();
return pixmap;
}
TQString Device::htmlInfo(const Device::Data &data, const TQString &deviceHref, const TQString &documentHtml)
{
TQString doc;
// title
doc += "<h1>";
bool first = true;
FOR_EACH(Special, special) {
for (uint k=0; k<data.frequencyRanges().count(); k++) {
if ( data.frequencyRanges()[k].special!=special ) continue;
if (first) first = false;
else doc += " / ";
doc += data.fname(special);
break;
}
}
doc += "</h1>";
doc += "<table>";
TQString status = coloredString(data.status().label(), statusColor(data.status()));
doc += htmlTableRow(i18n("Status"), status);
if ( data.alternatives().count() ) {
TQString s;
for (uint i=0; i<data.alternatives().count(); i++) {
if ( i!=0 ) s += ", ";
if ( deviceHref.isEmpty() ) s += data.alternatives()[i].upper();
else {
TQString href = deviceHref.tqarg(data.alternatives()[i].upper());
s += TQString("<a href=\"%1\">%2</a>").tqarg(href).tqarg(data.alternatives()[i].upper());
}
}
doc += htmlTableRow(i18n("Alternatives"), s);
}
doc += documentHtml;
doc += "</table>";
doc += "<hr />";
doc += "<table>";
doc += data.group().informationHtml(data);
TQString s;
for (uint i=0; i<data.packages().count(); i++)
for (uint k=0; k<data.packages()[i].types.count(); k++)
s += i18n(Package::TYPE_DATA[data.packages()[i].types[k]].label) + TQString("[%1] ").tqarg(data.packages()[i].pins.count());
doc += htmlTableRow(i18n("Packaging"), s);
doc += "</table>";
return doc;
}
TQString Device::htmlPinDiagrams(const Device::Data &data, const TQString &imagePrefix, TQMimeSourceFactory *msf)
{
TQString doc;
// pins
const Package *package = 0;
for (uint i=0; Package::TYPE_DATA[i].name; i++) {
if ( Package::TYPE_DATA[i].tqshape!=Package::Bar ) continue;
package = barPackage(Package::TYPE_DATA[i].name, data);
if (package) break;
}
if (package) {
TQPixmap pix = pinsGraph(*package);
doc += "<table cellpadding=\"3\"><tr bgcolor=\"gray\"><th align=\"center\">";
for (uint k=0; k<package->types.count(); k++) {
if ( k!=0 ) doc += " ";
doc += i18n(Package::TYPE_DATA[package->types[k]].label);
doc += "(" + TQString::number(package->pins.count()) + ")";
}
doc += "</th></tr><tr><td align=\"center\">";
TQString label = data.name() + "_pins_graph.png";
doc += "<img src=\"" + imagePrefix + label + "\" />";
if (msf) msf->setPixmap(label, pix);
doc += "</td></tr></table>";
}
return doc;
}
TQString Device::htmlVoltageFrequencyGraphs(const Device::Data &data, const TQString &imagePrefix, TQMimeSourceFactory *msf)
{
TQString doc;
FOR_EACH(Special, special) {
for (uint k=0; k<data.frequencyRanges().count(); k++) {
const Device::FrequencyRange &fr = data.frequencyRanges()[k];
if ( fr.special!=special ) continue;
doc += "<h3>" + data.fname(special) + " - " + i18n("Temperature range: ") + fr.operatingCondition.label() + "</h3>";
TQString label = data.name() + "_" + data.fname(special) + "_"
+ fr.operatingCondition.key() + ".png";
doc += "<img src=\"" + imagePrefix + label + "\" />";
if (msf) msf->setPixmap(label, Device::vddGraph(i18n("F (MHz)"), i18n("Vdd (V)"), fr.vdds));
}
}
return doc;
}
TQPixmap Device::memoryGraph(const TQValueList<MemoryGraphData> &r)
{
TQValueList<MemoryGraphData> ranges = r;
TQPixmap pixmap;
TQPainter p;
TQFontMetrics fm(p.font());
// order
qHeapSort(ranges);
// add empty ranges
TQValueList<MemoryGraphData>::iterator it;
for (it=ranges.begin(); it!=ranges.end(); ) {
TQValueList<MemoryGraphData>::iterator prev = it;
++it;
if ( it==ranges.end() ) break;
if ( (*prev).endAddress+1==(*it).startAddress ) continue;
MemoryGraphData data;
data.startAddress = (*prev).endAddress + 1;
data.endAddress = (*it).startAddress-1;
ranges.insert(it, data);
}
// compute widths and total height
int theight = fm.ascent() + (fm.ascent()%2==0 ? 1 : 0);
int hspacing = 5;
int height = 1;
int w1 = 0, w2 = 0;
for (it=ranges.begin(); it!=ranges.end(); ++it) {
w1 = TQMAX(w1, fm.width((*it).start));
w1 = TQMAX(w1, fm.width((*it).end));
w2 = TQMAX(w2, fm.width((*it).label));
(*it).height = 2*hspacing + theight;
if ( (*it).startAddress!=(*it).endAddress ) (*it).height += 2*theight;
height += (*it).height;
}
int wspacing = 4;
int width = wspacing + w1 + wspacing + wspacing + w2;
pixmap.resize(width, height);
pixmap.fill(TQt::white);
p.begin(&pixmap);
int h = 0;
// draw ranges
for (it=ranges.begin(); it!=ranges.end(); ++it) {
p.setPen(TQPen(TQt::black, 1, TQt::DotLine));
p.drawLine(0,h, width-1,h);
p.setPen(TQPen(TQt::black, 1));
p.setBrush((*it).label.isEmpty() ? TQt::gray : TQt::white);
p.drawRect(0,h, wspacing+w1+wspacing,(*it).height+1);
int hmid = h+(*it).height/2+theight/2;
p.drawText(wspacing+w1+wspacing+wspacing,hmid, (*it).label);
if ( (*it).startAddress==(*it).endAddress ) p.drawText(wspacing,hmid, (*it).start);
else {
p.drawText(wspacing,h+theight, (*it).start);
p.drawText(wspacing,h+(*it).height-3, (*it).end);
}
h += (*it).height;
p.setPen(TQPen(TQt::black, 1, TQt::DotLine));
p.drawLine(0,h, width-1,h);
}
p.end();
return pixmap;
}
#endif