view include/gui/widgets/graph.h @ 238:d2b7e974221e

CI/linux: install glib
author Paper <paper@paper.us.eu.org>
date Fri, 19 Jan 2024 11:17:42 -0500
parents 45a0967485f1
children 862d0d8619f6
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:
		std::unordered_map<T, unsigned long> map = {};

		QSize minimumSizeHint() const override {
			QFontMetrics metric(font());
			/* wtf?... */
			return QSize(100, metric.height() * map.size() + (2 * (map.size() - 2)));
		}

		/* helper functions */
		inline unsigned long GetTotal() {
			unsigned long count = 0;

			for (const auto& item : map)
				count += item.second;

			return count;
		}

		inline unsigned long GetTextWidth() {
			unsigned long ret = 0;
			QFontMetrics metric(font());

			for (const auto& item : map) {
				unsigned long width = metric.horizontalAdvance(QString::number(item.first), -1);
				if (width > ret)
					ret = width;
			}

			return ret;
		}

		void paintEvent(QPaintEvent* event) override {
			static constexpr int HORIZ_SPACING = 5;
			static constexpr int VERT_SPACING = 2;

			/* these are retrieved from the QPaintEvent */
			const QRect rect = event->rect();
			const int width = event->rect().width();
			const int x = rect.x();
			int y = rect.y();

			/* these are calculated from font metrics and such */
			const int total = GetTotal();
			const int text_width = GetTextWidth() + 10;
			const int each_height = QFontMetrics(font()).height();

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

			for (const auto& [key, value] : map) {
				painter.drawText(QRect(x, y, text_width, each_height), Qt::AlignVCenter, QString::number(key));

				/* only draw this if we actually have any data */
				if (total) {
					QPainterPath path;
					path.addRect(x + text_width + HORIZ_SPACING, y, (static_cast<double>(value)/total) * (width - text_width - HORIZ_SPACING), each_height);
					painter.fillPath(path, Qt::darkBlue);
					painter.drawPath(path);
				}

				y += each_height + VERT_SPACING;
			}
		}
};

#endif // __gui__widgets__graph_h