Mercurial > minori
view include/gui/widgets/graph.h @ 327:b5d6c27c308f
anime: refactor Anime::SeriesSeason to Season class
ToLocalString has also been altered to take in both season
and year because lots of locales actually treat formatting
seasons differently! most notably is Russian which adds a
suffix at the end to notate seasons(??)
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Thu, 13 Jun 2024 01:49:18 -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_