view include/gui/widgets/graph.h @ 146:d8a61e7e2a36

dep/animia: move fd stuff to a new fd.cc, don't force the user to include windows.h
author Paper <mrpapersonic@gmail.com>
date Mon, 13 Nov 2023 13:52:58 -0500
parents b315f3759c56
children 03b444cbe55f
line wrap: on
line source

#ifndef __gui__widgets__graph_h
#define __gui__widgets__graph_h

/* This class is defined as a template, so that means everything gets defined here as well :) */

#include <QWidget>
#include <QDebug>
#include <QSize>
#include <QPaintEvent>
#include <QSize>
#include <QRect>
#include <QPainter>
#include <QPainterPath>
#include <QPen>
#include <algorithm>
#include <unordered_map>

template <typename T>
class Graph final : public QWidget {
	public:
		Graph(QWidget* parent = nullptr) : QWidget(parent) {};
		void AddItem(T key, unsigned long val) { map[key] = val; update(); updateGeometry(); };
		void Clear() { map.clear(); update(); updateGeometry(); };

	protected:
		static constexpr int SPACING = 5;
		inline unsigned long GetTotal() {
			unsigned long count = 0;
			for (const auto& item : map)
				count += item.second;
			return count;
		}
		QSize minimumSizeHint() const override {
			QFontMetrics metric(font());
			return QSize(100, metric.height() * map.size() + 2 * (map.size() - 2));
		};
		inline unsigned long GetTextWidth() {
			unsigned long ret = 0;
			QFontMetrics metric(font());
			for (const auto& item : map) {
				unsigned long width = metric.boundingRect(QString::number(item.first)).width();
				if (width > ret)
					ret = width;
			}
			return ret;
		}
		void paintEvent(QPaintEvent* event) override {
			const QRect rect = event->rect();
			const int height_of_each = QFontMetrics(font()).height();
			const int size = GetTotal();
			const int text_width = GetTextWidth();
			int current_y = rect.y();

			/* now we do the actual painting */
			QPainter painter(this);

			for (const auto& item : map) {
				painter.drawText(QRect(rect.x(), current_y, text_width, height_of_each), Qt::AlignRight | Qt::AlignVCenter, QString::number(item.first));

				if (size) {
					painter.save();

					QPen pen(Qt::transparent, 0);
					painter.setPen(pen);

					QPainterPath path;
					path.addRect(rect.x() + text_width + SPACING, current_y, (static_cast<double>(item.second)/size)*(rect.width() - text_width - SPACING), height_of_each);
					painter.fillPath(path, Qt::darkBlue);
					painter.drawPath(path);

					painter.restore();
				}
				current_y += height_of_each + 2;
			}
		};
		std::unordered_map<T, unsigned long> map = {};
};

#endif // __gui__widgets__graph_h