view include/gui/widgets/graph.h @ 337:a7d4e5107531

dep/animone: REFACTOR ALL THE THINGS 1: animone now has its own syntax divergent from anisthesia, making different platforms actually have their own sections 2: process names in animone are now called `comm' (this will probably break things). this is what its called in bsd/linux so I'm just going to use it everywhere 3: the X11 code now checks for the existence of a UTF-8 window title and passes it if available 4: ANYTHING THATS NOT LINUX IS 100% UNTESTED AND CAN AND WILL BREAK! I still actually need to test the bsd code. to be honest I'm probably going to move all of the bsds into separate files because they're all essentially different operating systems at this point
author Paper <paper@paper.us.eu.org>
date Wed, 19 Jun 2024 12:51:15 -0400
parents f31305b9f60a
children f81bed4e04ac
line wrap: on
line source

#ifndef MINORI_GUI_WIDGETS_GRAPH_H_
#define MINORI_GUI_WIDGETS_GRAPH_H_

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

#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
#include <QPen>
#include <QRect>
#include <QSize>
#include <QWidget>
#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 HORIZ_SPACING = 5;
	static constexpr int VERT_SPACING = 3;

	std::unordered_map<T, unsigned long> map = {};

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

	/* 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.boundingRect(QString::number(item.first)).width();
			if (width > ret)
				ret = width;
		}

		return ret;
	}

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

		for (const auto& item : map) {
			unsigned long width = metric.boundingRect(QString::number(item.second)).width();
			if (width > ret)
				ret = width;
		}

		return ret;
	}

	void paintEvent(QPaintEvent* event) override {
		/* these are retrieved from the QPaintEvent */
		const QRect rect = event->rect();
		const int width = 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();
		const int value_width = GetValueWidth();
		const int each_height = QFontMetrics(font()).height();

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

		for (const auto& [key, value] : map) {
			int offset = 0;

			painter.drawText(QRect(x, y, text_width, each_height), Qt::AlignVCenter | Qt::AlignRight,
			                 QString::number(key));

			offset += text_width + HORIZ_SPACING;

			/* only draw this if we actually have any data */
			if (total) {
				painter.save();

				QPen pen(painter.pen());
				pen.setStyle(Qt::NoPen);
				painter.setPen(pen);

				QPainterPath path;
				path.addRect(x + offset, y,
				             (static_cast<double>(value) / total) * (width - offset - HORIZ_SPACING - value_width), each_height);
				painter.fillPath(path, Qt::darkGreen);
				painter.drawPath(path);

				offset += (static_cast<double>(value) / total) * (width - offset - HORIZ_SPACING - value_width);

				painter.restore();
			}

			offset += HORIZ_SPACING;

			painter.drawText(QRect(x + offset, y, value_width, each_height), Qt::AlignVCenter | Qt::AlignLeft, QString::number(value));

			y += each_height + VERT_SPACING;
		}
	}
};

#endif // MINORI_GUI_WIDGETS_GRAPH_H_