| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							|  |  |  | #include "legend.h"
 | 
					
						
							|  |  |  | #include "statscolors.h"
 | 
					
						
							| 
									
										
										
										
											2021-01-02 10:25:04 +01:00
										 |  |  | #include "zvalues.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | #include <QFontMetrics>
 | 
					
						
							|  |  |  | #include <QPen>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const double legendBorderSize = 2.0; | 
					
						
							|  |  |  | static const double legendBoxBorderSize = 1.0; | 
					
						
							| 
									
										
										
										
											2021-01-03 12:49:26 +01:00
										 |  |  | static const double legendBoxBorderRadius = 4.0;	// radius of rounded corners
 | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | static const double legendBoxScale = 0.8;		// 1.0: text-height of the used font
 | 
					
						
							|  |  |  | static const double legendInternalBorderSize = 2.0; | 
					
						
							|  |  |  | static const QColor legendColor(0x00, 0x8e, 0xcc, 192); // Note: fourth argument is opacity
 | 
					
						
							|  |  |  | static const QColor legendBorderColor(Qt::black); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | Legend::Legend(StatsView &view, const std::vector<QString> &names) : | 
					
						
							| 
									
										
										
										
											2021-01-13 16:19:27 +01:00
										 |  |  | 	ChartRectItem(view, ChartZValue::Legend, | 
					
						
							|  |  |  | 		      QPen(legendBorderColor, legendBorderSize), QBrush(legendColor), legendBoxBorderRadius), | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	displayedItems(0), width(0.0), height(0.0), | 
					
						
							|  |  |  | 	font(QFont())	// Make configurable
 | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	entries.reserve(names.size()); | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	QFontMetrics fm(font); | 
					
						
							|  |  |  | 	fontHeight = fm.height(); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 	int idx = 0; | 
					
						
							|  |  |  | 	for (const QString &name: names) | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 		entries.emplace_back(name, idx++, (int)names.size(), fm); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | Legend::Entry::Entry(const QString &name, int idx, int numBins, const QFontMetrics &fm) : | 
					
						
							|  |  |  | 	name(name), | 
					
						
							|  |  |  | 	rectBrush(QBrush(binColor(idx, numBins))) | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	width = fm.height() + 2.0 * legendBoxBorderSize + fm.size(Qt::TextSingleLine, name).width(); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Legend::hide() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	ChartRectItem::resize(QSizeF(1,1)); | 
					
						
							|  |  |  | 	img->fill(Qt::transparent); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Legend::resize() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (entries.empty()) | 
					
						
							|  |  |  | 		return hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	QSizeF size = sceneSize(); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Silly heuristics: make the legend at most half as high and half as wide as the chart.
 | 
					
						
							|  |  |  | 	// Not sure if that makes sense - this might need some optimization.
 | 
					
						
							|  |  |  | 	int maxRows = static_cast<int>(size.height() / 2.0 - 2.0 * legendInternalBorderSize) / fontHeight; | 
					
						
							|  |  |  | 	if (maxRows <= 0) | 
					
						
							|  |  |  | 		return hide(); | 
					
						
							|  |  |  | 	int numColumns = ((int)entries.size() - 1) / maxRows + 1; | 
					
						
							|  |  |  | 	int numRows = ((int)entries.size() - 1) / numColumns + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	double x = legendInternalBorderSize; | 
					
						
							|  |  |  | 	displayedItems = 0; | 
					
						
							|  |  |  | 	for (int col = 0; col < numColumns; ++col) { | 
					
						
							|  |  |  | 		double y = legendInternalBorderSize; | 
					
						
							|  |  |  | 		double nextX = x; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (int row = 0; row < numRows; ++row) { | 
					
						
							|  |  |  | 			int idx = col * numRows + row; | 
					
						
							|  |  |  | 			if (idx >= (int)entries.size()) | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			entries[idx].pos = QPointF(x, y); | 
					
						
							|  |  |  | 			nextX = std::max(nextX, x + entries[idx].width); | 
					
						
							|  |  |  | 			y += fontHeight; | 
					
						
							|  |  |  | 			++displayedItems; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-01-03 00:54:52 +01:00
										 |  |  | 		x = nextX; | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 		width = nextX; | 
					
						
							|  |  |  | 		if (width >= size.width() / 2.0) // More than half the chart-width -> give up
 | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	width += legendInternalBorderSize; | 
					
						
							|  |  |  | 	height = 2 * legendInternalBorderSize + numRows * fontHeight; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 	ChartRectItem::resize(QSizeF(width, height)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Paint rectangles
 | 
					
						
							|  |  |  | 	painter->setPen(QPen(legendBorderColor, legendBoxBorderSize)); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 	for (int i = 0; i < displayedItems; ++i) { | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 		QPointF itemPos = entries[i].pos; | 
					
						
							|  |  |  | 		painter->setBrush(entries[i].rectBrush); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 		QRectF rect(itemPos, QSizeF(fontHeight, fontHeight)); | 
					
						
							|  |  |  | 		// Decrease box size by legendBoxScale factor
 | 
					
						
							|  |  |  | 		double delta = fontHeight * (1.0 - legendBoxScale) / 2.0; | 
					
						
							|  |  |  | 		rect = rect.adjusted(delta, delta, -delta, -delta); | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 		painter->drawRect(rect); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Paint labels
 | 
					
						
							|  |  |  | 	painter->setPen(darkLabelColor); // QPainter uses pen not brush for text!
 | 
					
						
							|  |  |  | 	painter->setFont(font); | 
					
						
							|  |  |  | 	for (int i = 0; i < displayedItems; ++i) { | 
					
						
							|  |  |  | 		QPointF itemPos = entries[i].pos; | 
					
						
							|  |  |  | 		itemPos.rx() += fontHeight + 2.0 * legendBoxBorderSize; | 
					
						
							|  |  |  | 		QRectF rect(itemPos, QSizeF(entries[i].width, fontHeight)); | 
					
						
							|  |  |  | 		painter->drawText(rect, entries[i].name); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-01-12 15:20:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// For now, place the legend in the top right corner.
 | 
					
						
							|  |  |  | 	QPointF pos(size.width() - width - 10.0, 10.0); | 
					
						
							|  |  |  | 	setPos(pos); | 
					
						
							| 
									
										
										
										
											2021-01-01 17:55:44 +01:00
										 |  |  | } |