File indexing completed on 2024-04-21 14:46:30
0001 /* 0002 SPDX-FileCopyrightText: 2011 Rafał Kułaga <rl.kulaga@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "legend.h" 0008 0009 #include "colorscheme.h" 0010 #include "kstarsdata.h" 0011 #include "skymap.h" 0012 #include "skyqpainter.h" 0013 #include "Options.h" 0014 0015 #include <QBrush> 0016 0017 namespace 0018 { 0019 const int symbolSize = 15; 0020 const int bRectWidth = 100; 0021 const int bRectHeight = 45; 0022 const int maxHScalePixels = 200; 0023 const int maxVScalePixels = 100; 0024 const int xSymbolSpacing = 100; 0025 const int ySymbolSpacing = 70; 0026 } 0027 0028 Legend::Legend(LEGEND_ORIENTATION orientation, LEGEND_POSITION pos) 0029 : m_SkyMap(SkyMap::Instance()), m_Orientation(orientation), 0030 m_Position(pos), m_PositionFloating(QPoint(0, 0)), m_cScheme(KStarsData::Instance()->colorScheme()), 0031 m_SymbolSize(symbolSize), m_BRectWidth(bRectWidth), m_BRectHeight(bRectHeight), 0032 m_MaxHScalePixels(maxHScalePixels), m_MaxVScalePixels(maxVScalePixels), m_XSymbolSpacing(xSymbolSpacing), 0033 m_YSymbolSpacing(ySymbolSpacing) 0034 { 0035 m_BgColor = m_cScheme->colorNamed("SkyColor"); 0036 } 0037 0038 Legend::~Legend() 0039 { 0040 if (m_Painter != nullptr && m_DeletePainter) 0041 { 0042 delete m_Painter; 0043 } 0044 } 0045 0046 QSize Legend::calculateSize() 0047 { 0048 int width = 0; 0049 int height = 0; 0050 0051 switch (m_Orientation) 0052 { 0053 case LO_HORIZONTAL: 0054 { 0055 switch (m_Type) 0056 { 0057 case LT_SCALE_ONLY: 0058 { 0059 width = 40 + m_MaxHScalePixels; 0060 height = 60; 0061 break; 0062 } 0063 0064 case LT_MAGNITUDES_ONLY: 0065 { 0066 width = 140; 0067 height = 70; 0068 break; 0069 } 0070 0071 case LT_SYMBOLS_ONLY: 0072 { 0073 width = 7 * m_XSymbolSpacing; 0074 height = 20 + m_SymbolSize + m_BRectHeight; 0075 break; 0076 } 0077 0078 case LT_SCALE_MAGNITUDES: 0079 { 0080 width = 160 + m_MaxHScalePixels; 0081 height = 70; 0082 break; 0083 } 0084 0085 case LT_FULL: 0086 { 0087 width = 7 * m_XSymbolSpacing; 0088 height = 20 + m_SymbolSize + m_BRectHeight + 70; 0089 break; 0090 } 0091 0092 default: 0093 break; // should never happen 0094 } 0095 } 0096 0097 break; 0098 0099 case LO_VERTICAL: 0100 { 0101 switch (m_Type) 0102 { 0103 case LT_SCALE_ONLY: 0104 { 0105 width = 120; 0106 height = 40 + m_MaxVScalePixels; 0107 break; 0108 } 0109 0110 case LT_MAGNITUDES_ONLY: 0111 { 0112 width = 140; 0113 height = 70; 0114 break; 0115 } 0116 0117 case LT_SYMBOLS_ONLY: 0118 { 0119 width = 120; 0120 height = 7 * m_YSymbolSpacing; 0121 break; 0122 } 0123 0124 case LT_SCALE_MAGNITUDES: 0125 { 0126 width = 120; 0127 height = 100 + m_MaxVScalePixels; 0128 break; 0129 } 0130 0131 case LT_FULL: 0132 { 0133 width = 120; 0134 height = 100 + 7 * m_YSymbolSpacing + m_MaxVScalePixels; 0135 break; 0136 } 0137 0138 default: 0139 break; // should never happen 0140 } 0141 0142 break; 0143 } 0144 0145 default: 0146 { 0147 return QSize(); 0148 } 0149 } 0150 0151 return QSize(width, height); 0152 } 0153 0154 void Legend::paintLegend(QPaintDevice *pd) 0155 { 0156 if (m_Painter) 0157 { 0158 delete m_Painter; 0159 } 0160 0161 m_Painter = new SkyQPainter(m_SkyMap, pd); 0162 m_DeletePainter = true; 0163 m_Painter->begin(); 0164 0165 paintLegend(m_Painter); 0166 0167 m_Painter->end(); 0168 } 0169 0170 void Legend::paintLegend(SkyQPainter *painter) 0171 { 0172 if (!m_DeletePainter) 0173 { 0174 m_Painter = painter; 0175 } 0176 0177 if (m_Position != LP_FLOATING) 0178 { 0179 m_PositionFloating = positionToDeviceCoord(painter->device()); 0180 } 0181 0182 m_Painter->translate(m_PositionFloating.x(), m_PositionFloating.y()); 0183 0184 m_Painter->setFont(m_Font); 0185 0186 QBrush backgroundBrush(m_BgColor, Qt::SolidPattern); 0187 QPen backgroundPen(m_cScheme->colorNamed("SNameColor")); 0188 backgroundPen.setStyle(Qt::SolidLine); 0189 0190 // set brush & pen 0191 m_Painter->setBrush(backgroundBrush); 0192 m_Painter->setPen(backgroundPen); 0193 0194 QSize size = calculateSize(); 0195 if (m_DrawFrame) 0196 { 0197 m_Painter->drawRect(1, 1, size.width(), size.height()); 0198 } 0199 0200 else 0201 { 0202 QPen noLinePen; 0203 noLinePen.setStyle(Qt::NoPen); 0204 0205 m_Painter->setPen(noLinePen); 0206 m_Painter->drawRect(1, 1, size.width(), size.height()); 0207 0208 m_Painter->setPen(backgroundPen); 0209 } 0210 0211 switch (m_Orientation) 0212 { 0213 case LO_HORIZONTAL: 0214 { 0215 switch (m_Type) 0216 { 0217 case LT_SCALE_ONLY: 0218 { 0219 paintScale(QPointF(20, 20)); 0220 break; 0221 } 0222 0223 case LT_MAGNITUDES_ONLY: 0224 { 0225 paintMagnitudes(QPointF(20, 20)); 0226 break; 0227 } 0228 0229 case LT_SYMBOLS_ONLY: 0230 { 0231 paintSymbols(QPointF(20, 20)); 0232 break; 0233 } 0234 0235 case LT_SCALE_MAGNITUDES: 0236 { 0237 paintMagnitudes(QPointF(20, 20)); 0238 paintScale(QPointF(150, 20)); 0239 break; 0240 } 0241 0242 case LT_FULL: 0243 { 0244 paintSymbols(QPointF(20, 20)); 0245 paintMagnitudes(QPointF(10, 40 + m_SymbolSize + m_BRectHeight)); 0246 paintScale(QPointF(200, 40 + m_SymbolSize + m_BRectHeight)); 0247 break; 0248 } 0249 0250 default: 0251 break; // should never happen 0252 } 0253 0254 break; 0255 } 0256 0257 case LO_VERTICAL: 0258 { 0259 switch (m_Type) 0260 { 0261 case LT_SCALE_ONLY: 0262 { 0263 paintScale(QPointF(20, 20)); 0264 break; 0265 } 0266 0267 case LT_MAGNITUDES_ONLY: 0268 { 0269 paintMagnitudes(QPointF(20, 20)); 0270 break; 0271 } 0272 0273 case LT_SYMBOLS_ONLY: 0274 { 0275 paintSymbols(QPointF(20, 20)); 0276 break; 0277 } 0278 0279 case LT_SCALE_MAGNITUDES: 0280 { 0281 paintMagnitudes(QPointF(7, 20)); 0282 paintScale(QPointF(20, 80)); 0283 break; 0284 } 0285 0286 case LT_FULL: 0287 { 0288 paintSymbols(QPointF(30, 20)); 0289 paintMagnitudes(QPointF(7, 30 + 7 * m_YSymbolSpacing)); 0290 paintScale(QPointF(20, 90 + 7 * m_YSymbolSpacing)); 0291 break; 0292 } 0293 0294 default: 0295 break; // should never happen 0296 } 0297 0298 break; 0299 } 0300 0301 default: 0302 break; // should never happen 0303 } 0304 } 0305 0306 void Legend::paintLegend(QPaintDevice *pd, LEGEND_TYPE type, LEGEND_POSITION pos) 0307 { 0308 LEGEND_TYPE prevType = m_Type; 0309 LEGEND_POSITION prevPos = m_Position; 0310 0311 m_Type = type; 0312 m_Position = pos; 0313 0314 paintLegend(pd); 0315 0316 m_Type = prevType; 0317 m_Position = prevPos; 0318 } 0319 0320 void Legend::paintLegend(SkyQPainter *painter, LEGEND_TYPE type, LEGEND_POSITION pos) 0321 { 0322 LEGEND_TYPE prevType = m_Type; 0323 LEGEND_POSITION prevPos = m_Position; 0324 0325 m_Type = type; 0326 m_Position = pos; 0327 0328 paintLegend(painter); 0329 0330 m_Type = prevType; 0331 m_Position = prevPos; 0332 } 0333 0334 void Legend::paintSymbols(QPointF pos) 0335 { 0336 qreal x = pos.x(); 0337 qreal y = pos.y(); 0338 0339 x += 30; 0340 0341 switch (m_Orientation) 0342 { 0343 case Legend::LO_HORIZONTAL: 0344 { 0345 // paint Open Cluster/Asterism symbol 0346 QString label1 = i18n("Open Cluster") + '\n' + i18n("Asterism"); 0347 paintSymbol(QPointF(x, y), 3, 1, 0, label1); 0348 x += m_XSymbolSpacing; 0349 0350 // paint Globular Cluster symbol 0351 paintSymbol(QPointF(x, y), 4, 1, 0, i18n("Globular Cluster")); 0352 x += m_XSymbolSpacing; 0353 0354 // paint Gaseous Nebula/Dark Nebula symbol 0355 QString label3 = i18n("Gaseous Nebula") + '\n' + i18n("Dark Nebula"); 0356 paintSymbol(QPointF(x, y), 5, 1, 0, label3); 0357 x += m_XSymbolSpacing; 0358 0359 // paint Planetary Nebula symbol 0360 paintSymbol(QPointF(x, y), 6, 1, 0, i18n("Planetary Nebula")); 0361 x += m_XSymbolSpacing; 0362 0363 // paint Supernova Remnant 0364 paintSymbol(QPointF(x, y), 7, 1, 0, i18n("Supernova Remnant")); 0365 x += m_XSymbolSpacing; 0366 0367 // paint Galaxy/Quasar 0368 QString label6 = i18n("Galaxy") + '\n' + i18n("Quasar"); 0369 paintSymbol(QPointF(x, y), 8, 0.5, 60, label6); 0370 x += m_XSymbolSpacing; 0371 0372 // paint Galaxy Cluster 0373 paintSymbol(QPointF(x, y), 14, 1, 0, i18n("Galactic Cluster")); 0374 0375 break; 0376 } 0377 0378 case Legend::LO_VERTICAL: 0379 { 0380 // paint Open Cluster/Asterism symbol 0381 QString label1 = i18n("Open Cluster") + '\n' + i18n("Asterism"); 0382 paintSymbol(QPointF(x, y), 3, 1, 0, label1); 0383 y += m_YSymbolSpacing; 0384 0385 // paint Globular Cluster symbol 0386 paintSymbol(QPointF(x, y), 4, 1, 0, i18n("Globular Cluster")); 0387 y += m_YSymbolSpacing; 0388 0389 // paint Gaseous Nebula/Dark Nebula symbol 0390 QString label3 = i18n("Gaseous Nebula") + '\n' + i18n("Dark Nebula"); 0391 paintSymbol(QPointF(x, y), 5, 1, 0, label3); 0392 y += m_YSymbolSpacing; 0393 0394 // paint Planetary Nebula symbol 0395 paintSymbol(QPointF(x, y), 6, 1, 0, i18n("Planetary Nebula")); 0396 y += m_YSymbolSpacing; 0397 0398 // paint Supernova Remnant 0399 paintSymbol(QPointF(x, y), 7, 1, 0, i18n("Supernova Remnant")); 0400 y += m_YSymbolSpacing; 0401 0402 // paint Galaxy/Quasar 0403 QString label6 = i18n("Galaxy") + '\n' + i18n("Quasar"); 0404 paintSymbol(QPointF(x, y), 8, 0.5, 60, label6); 0405 y += m_YSymbolSpacing; 0406 0407 // paint Galaxy Cluster 0408 paintSymbol(QPointF(x, y), 14, 1, 0, i18n("Galactic Cluster")); 0409 0410 break; 0411 } 0412 default: 0413 return; // should never happen 0414 } 0415 } 0416 0417 void Legend::paintSymbol(QPointF pos, int type, float e, float angle, QString label) 0418 { 0419 qreal x = pos.x(); 0420 qreal y = pos.y(); 0421 qreal bRectHalfWidth = (qreal)m_BRectWidth / 2; 0422 0423 // paint symbol 0424 m_Painter->drawDeepSkySymbol(pos, type, m_SymbolSize, e, angle); 0425 QRectF bRect(QPoint(x - bRectHalfWidth, y + m_SymbolSize), 0426 QPoint(x + bRectHalfWidth, y + m_SymbolSize + m_BRectHeight)); 0427 //m_Painter->drawRect(bRect); 0428 // paint label 0429 m_Painter->drawText(bRect, label, QTextOption(Qt::AlignHCenter)); 0430 } 0431 0432 void Legend::paintMagnitudes(QPointF pos) 0433 { 0434 qreal x = pos.x(); 0435 qreal y = pos.y(); 0436 0437 m_Painter->drawText(x, y, i18n("Star Magnitudes:")); 0438 y += 15; 0439 0440 for (int i = 1; i <= 9; i += 2) 0441 { 0442 m_Painter->drawPointSource(QPointF(x + i * 10, y), m_Painter->starWidth(i)); 0443 m_Painter->drawText(x + i * 10 - 4, y + 20, QString::number(i)); 0444 } 0445 } 0446 0447 void Legend::paintScale(QPointF pos) 0448 { 0449 qreal maxScalePixels; 0450 0451 switch (m_Orientation) 0452 { 0453 case LO_HORIZONTAL: 0454 { 0455 maxScalePixels = m_MaxHScalePixels; 0456 break; 0457 } 0458 0459 case LO_VERTICAL: 0460 { 0461 maxScalePixels = m_MaxVScalePixels; 0462 break; 0463 } 0464 0465 default: 0466 return; // should never happen 0467 } 0468 0469 qreal maxArcsec = maxScalePixels * 57.3 * 3600 / Options::zoomFactor(); 0470 0471 int deg = 0; 0472 int arcmin = 0; 0473 int arcsec = 0; 0474 0475 QString lab; 0476 if (maxArcsec >= 3600) 0477 { 0478 deg = maxArcsec / 3600; 0479 lab = QString::number(deg) + QString::fromWCharArray(L"\u00B0"); 0480 } 0481 0482 else if (maxArcsec >= 60) 0483 { 0484 arcmin = maxArcsec / 60; 0485 lab = QString::number(arcmin) + '\''; 0486 } 0487 0488 else 0489 { 0490 arcsec = maxArcsec; 0491 lab = QString::number(arcsec) + "\""; 0492 } 0493 0494 int actualArcsec = 3600 * deg + 60 * arcmin + arcsec; 0495 0496 qreal size = actualArcsec * Options::zoomFactor() / 57.3 / 3600; 0497 0498 qreal x = pos.x(); 0499 qreal y = pos.y(); 0500 0501 switch (m_Orientation) 0502 { 0503 case LO_HORIZONTAL: 0504 { 0505 m_Painter->drawText(pos, i18n("Chart Scale:")); 0506 y += 15; 0507 0508 m_Painter->drawLine(x, y, x + size, y); 0509 // paint line endings 0510 m_Painter->drawLine(x, y - 5, x, y + 5); 0511 m_Painter->drawLine(x + size, y - 5, x + size, y + 5); 0512 0513 // paint scale text 0514 QRectF bRect(QPoint(x, y), QPoint(x + size, y + 20)); 0515 m_Painter->drawText(bRect, lab, QTextOption(Qt::AlignHCenter)); 0516 0517 break; 0518 } 0519 0520 case LO_VERTICAL: 0521 { 0522 m_Painter->drawText(pos, i18n("Chart Scale:")); 0523 y += 10; 0524 x += 40; 0525 0526 m_Painter->drawLine(x, y, x, y + size); 0527 // paint line endings 0528 m_Painter->drawLine(x - 5, y, x + 5, y); 0529 m_Painter->drawLine(x - 5, y + size, x + 5, y + size); 0530 0531 // paint scale text 0532 QRectF bRect(QPoint(x + 5, y), QPoint(x + 20, y + size)); 0533 //m_Painter->drawRect(bRect); 0534 m_Painter->drawText(bRect, lab, QTextOption(Qt::AlignVCenter)); 0535 0536 break; 0537 } 0538 0539 default: 0540 return; // should never happen 0541 } 0542 } 0543 0544 QPoint Legend::positionToDeviceCoord(QPaintDevice *pd) 0545 { 0546 QSize legendSize = calculateSize(); 0547 0548 switch (m_Position) 0549 { 0550 case LP_UPPER_LEFT: // position: upper left corner 0551 { 0552 return QPoint(0, 0); 0553 } 0554 0555 case LP_UPPER_RIGHT: // position: upper right corner 0556 { 0557 return QPoint(pd->width() - legendSize.width(), 0); 0558 } 0559 0560 case LP_LOWER_LEFT: // position: lower left corner 0561 { 0562 return QPoint(0, pd->height() - legendSize.height()); 0563 } 0564 0565 case LP_LOWER_RIGHT: // position: lower right corner 0566 { 0567 return QPoint(pd->width() - legendSize.width(), pd->height() - legendSize.height()); 0568 } 0569 0570 default: // legend is floating 0571 { 0572 return QPoint(); 0573 } 0574 } 0575 } 0576 0577 Legend::Legend(const Legend &o) 0578 : m_Painter(nullptr), m_SkyMap(o.m_SkyMap), m_DeletePainter(o.m_DeletePainter), m_Type(o.m_Type), 0579 m_Orientation(o.m_Orientation), m_Position(o.m_Position), m_PositionFloating(o.m_PositionFloating), 0580 m_cScheme(o.m_cScheme), m_Font(o.m_Font), m_BgColor(o.m_BgColor), m_DrawFrame(o.m_DrawFrame), 0581 m_SymbolSize(o.m_SymbolSize), m_BRectWidth(o.m_BRectWidth), m_BRectHeight(o.m_BRectHeight), 0582 m_MaxHScalePixels(o.m_MaxHScalePixels), m_MaxVScalePixels(o.m_MaxVScalePixels), 0583 m_XSymbolSpacing(o.m_XSymbolSpacing), m_YSymbolSpacing(o.m_YSymbolSpacing) 0584 { 0585 } 0586 0587 Legend& Legend::operator=(const Legend &o) noexcept 0588 { 0589 m_SkyMap = o.m_SkyMap; 0590 m_DeletePainter = o.m_DeletePainter; 0591 m_Type = o.m_Type; 0592 m_Orientation = o.m_Orientation; 0593 m_Position = o.m_Position; 0594 m_PositionFloating = o.m_PositionFloating; 0595 m_cScheme = o.m_cScheme; 0596 m_Font = o.m_Font; 0597 m_BgColor = o.m_BgColor; 0598 m_DrawFrame = o.m_DrawFrame; 0599 m_SymbolSize = o.m_SymbolSize; 0600 m_BRectWidth = o.m_BRectWidth; 0601 m_BRectHeight = o.m_BRectHeight; 0602 m_MaxHScalePixels = o.m_MaxHScalePixels; 0603 m_MaxVScalePixels = o.m_MaxVScalePixels; 0604 m_XSymbolSpacing = o.m_XSymbolSpacing; 0605 m_YSymbolSpacing = o.m_YSymbolSpacing; 0606 return *this; 0607 }