* move message_log_widget to game

* move files

* update headers

* fix cmakelists

* oracle fixes

* split implementation out to cpp

* fix recursive import

* fix main file

* format
This commit is contained in:
ebbit1q 2025-09-20 14:35:52 +02:00 committed by GitHub
parent f484c98152
commit 17dcaf9afa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
337 changed files with 728 additions and 721 deletions

View file

@ -0,0 +1,101 @@
#include "banner_widget.h"
#include "../../../pixel_map_generator.h"
#include <QLinearGradient>
#include <QMouseEvent>
#include <QPainter>
#include <QVBoxLayout>
BannerWidget::BannerWidget(QWidget *parent, const QString &text, Qt::Orientation orientation, int transparency)
: QWidget(parent), gradientOrientation(orientation), transparency(qBound(0, transparency, 100))
{
auto layout = new QHBoxLayout(this);
iconLabel = new QLabel(this);
iconLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
// Create the banner label and set properties
bannerLabel = new QLabel(text, this);
bannerLabel->setAlignment(Qt::AlignCenter);
bannerLabel->setStyleSheet("font-size: 24px; font-weight: bold; color: white;");
layout->addWidget(iconLabel);
layout->addWidget(bannerLabel);
layout->addWidget(new QLabel(this)); // add dummy label to force text label to be centered
setLayout(layout);
// Set minimum height for the widget
setMinimumHeight(50);
connect(this, &BannerWidget::buddyVisibilityChanged, this, &BannerWidget::toggleBuddyVisibility);
updateDropdownIconState();
}
void BannerWidget::mousePressEvent(QMouseEvent *event)
{
QWidget::mousePressEvent(event);
if (clickable) {
emit buddyVisibilityChanged();
}
}
void BannerWidget::setText(const QString &text) const
{
bannerLabel->setText(text);
}
void BannerWidget::setClickable(bool _clickable)
{
clickable = _clickable;
updateDropdownIconState();
}
void BannerWidget::setBuddy(QWidget *_buddy)
{
buddy = _buddy;
updateDropdownIconState();
}
void BannerWidget::toggleBuddyVisibility() const
{
if (buddy) {
buddy->setVisible(!buddy->isVisible());
updateDropdownIconState();
}
}
void BannerWidget::updateDropdownIconState() const
{
if (clickable && buddy) {
iconLabel->setPixmap(DropdownIconPixmapGenerator::generatePixmap(24, !buddy->isHidden()));
} else {
// we cannot directly hide the iconLabel, since it's needed to center the text; set an empty image instead
iconLabel->setPixmap(QPixmap());
}
}
void BannerWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
// Calculate alpha based on transparency percentage
int alpha = (255 * transparency) / 100;
// Determine gradient direction
QLinearGradient gradient;
if (gradientOrientation == Qt::Vertical) {
gradient = QLinearGradient(rect().topLeft(), rect().bottomLeft());
} else {
gradient = QLinearGradient(rect().topLeft(), rect().topRight());
}
// Set neutral gradient colors with calculated transparency
gradient.setColorAt(0, QColor(200, 200, 200, alpha)); // Light grey with alpha
gradient.setColorAt(1, QColor(100, 100, 100, alpha / 1.5)); // Darker grey, slightly more transparent
// Fill the widget background with the gradient
painter.fillRect(rect(), gradient);
}

View file

@ -0,0 +1,43 @@
#ifndef BANNER_WIDGET_H
#define BANNER_WIDGET_H
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>
class BannerWidget : public QWidget
{
Q_OBJECT
public:
explicit BannerWidget(QWidget *parent,
const QString &text,
Qt::Orientation orientation = Qt::Vertical,
int transparency = 80);
void mousePressEvent(QMouseEvent *event) override;
void setText(const QString &text) const;
void setClickable(bool _clickable);
void setBuddy(QWidget *_buddy);
QString getText() const
{
return bannerLabel->text();
}
protected:
void paintEvent(QPaintEvent *event) override;
private:
QLabel *iconLabel;
QLabel *bannerLabel;
Qt::Orientation gradientOrientation;
int transparency; // Transparency percentage for the gradient
QWidget *buddy = nullptr;
bool clickable = true;
signals:
void buddyVisibilityChanged();
private slots:
void toggleBuddyVisibility() const;
void updateDropdownIconState() const;
};
#endif // BANNER_WIDGET_H

View file

@ -0,0 +1,56 @@
#include "bar_widget.h"
#include <QFontMetrics>
#include <QPainter>
BarWidget::BarWidget(QString label, int value, int total, QColor barColor, QWidget *parent)
: QWidget(parent), label(std::move(label)), value(value), total(total), barColor(barColor)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
QSize BarWidget::sizeHint() const
{
QFontMetrics metrics(font());
int labelHeight = metrics.height();
int valueHeight = metrics.height();
// Calculate the height dynamically based on the total
int barHeight = (total > 0) ? (value * 200 / total) : 20; // Scale height proportionally
int totalHeight = barHeight + labelHeight + valueHeight + 30; // Extra space for text
return QSize(60, totalHeight); // Allow width to expand
}
void BarWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
int widgetWidth = width();
int widgetHeight = height();
// Calculate bar dimensions
int barWidth = widgetWidth * 0.8; // Use 80% of the available width
int fullBarHeight = widgetHeight - 40; // Leave space for labels
int valueBarHeight = (total > 0) ? (value * fullBarHeight / total) : 0;
// Draw full bar background (gray)
painter.setBrush(QColor(200, 200, 200));
painter.drawRect((widgetWidth - barWidth) / 2, 10, barWidth, fullBarHeight);
// Draw the value-specific bar using the assigned color
painter.setBrush(barColor);
painter.drawRect((widgetWidth - barWidth) / 2, 10 + fullBarHeight - valueBarHeight, barWidth, valueBarHeight);
// Draw the CMC label
painter.setPen(Qt::white);
QRect textRect(0, widgetHeight - 30, widgetWidth, 20);
painter.drawText(textRect, Qt::AlignCenter, label);
// Draw the value count
painter.setPen(Qt::black);
QRect valueRect(0, 10, widgetWidth, 20);
painter.drawText(valueRect, Qt::AlignCenter, QString::number(value));
(void)event; // Suppress unused parameter warning
}

View file

@ -0,0 +1,27 @@
#ifndef BAR_WIDGET_H
#define BAR_WIDGET_H
#include <QColor>
#include <QString>
#include <QWidget>
class BarWidget : public QWidget
{
Q_OBJECT
public:
explicit BarWidget(QString label, int value, int total, QColor barColor = Qt::blue, QWidget *parent = nullptr);
QSize sizeHint() const override;
protected:
void paintEvent(QPaintEvent *event) override;
private:
QString label;
int value;
int total;
QColor barColor; // Store the bar color
};
#endif // BAR_WIDGET_H

View file

@ -0,0 +1,137 @@
#include "dynamic_font_size_label.h"
#define FONT_PRECISION (0.5)
#include <QDebug>
#include <QElapsedTimer>
DynamicFontSizeLabel::DynamicFontSizeLabel(QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f)
{
setIndent(0);
}
void DynamicFontSizeLabel::mousePressEvent(QMouseEvent *event)
{
Q_UNUSED(event)
emit clicked();
}
void DynamicFontSizeLabel::paintEvent(QPaintEvent *event)
{
// QElapsedTimer timer;
// timer.start();
QFont newFont = font();
float fontSize = getWidgetMaximumFontSize(this, this->text());
newFont.setPointSizeF(fontSize);
setFont(newFont);
// qDebug() << "Font size set to" << fontSize;
QLabel::paintEvent(event);
// LOG(true, "Paint delay" << ((float)timer.nsecsElapsed())/1000000.0 << " mS");
}
float DynamicFontSizeLabel::getWidgetMaximumFontSize(QWidget *widget, const QString &text)
{
QFont font = widget->font();
const QRect widgetRect = widget->contentsRect();
const float widgetWidth = widgetRect.width();
const float widgetHeight = widgetRect.height();
QRectF newFontSizeRect;
float currentSize = font.pointSizeF();
float step = currentSize / 2.0;
/* If too small, increase step */
if (step <= FONT_PRECISION) {
step = FONT_PRECISION * 4.0;
}
float lastTestedSize = currentSize;
float currentHeight = 0;
float currentWidth = 0;
if (text == "") {
return currentSize;
}
if (currentSize < 0) {
return 1;
}
/* Only stop when step is small enough and new size is smaller than QWidget */
while (step > FONT_PRECISION || (currentHeight > widgetHeight) || (currentWidth > widgetWidth)) {
/* Keep last tested value */
lastTestedSize = currentSize;
/* Test label with its font */
font.setPointSizeF(currentSize);
/* Use font metrics to test */
QFontMetricsF fm(font);
/* Check if widget is QLabel */
QLabel *label = qobject_cast<QLabel *>(widget);
if (label) {
newFontSizeRect =
fm.boundingRect(widgetRect, (label->wordWrap() ? Qt::TextWordWrap : 0) | label->alignment(), text);
} else {
newFontSizeRect = fm.boundingRect(widgetRect, 0, text);
}
currentHeight = newFontSizeRect.height();
currentWidth = newFontSizeRect.width();
/* If new font size is too big, decrease it */
if ((currentHeight > widgetHeight) || (currentWidth > widgetWidth)) {
// qDebug() << "-- contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect"
// << newFontSizeRect << "Tight" << text << currentSize;
currentSize -= step;
/* if step is small enough, keep it constant, so it converge to biggest font size */
if (step > FONT_PRECISION) {
step /= 2.0;
}
/* Do not allow negative size */
if (currentSize <= 0) {
break;
}
}
/* If new font size is smaller than maximum possible size, increase it */
else {
// qDebug() << "++ contentsRect()" << label->contentsRect() << "rect"<< label->rect() << " newFontSizeRect"
// << newFontSizeRect << "Tight" << text << currentSize;
currentSize += step;
}
}
return lastTestedSize;
}
void DynamicFontSizeLabel::setTextColor(QColor color)
{
if (color.isValid() && color != textColor) {
textColor = color;
setStyleSheet("color : " + color.name() + ";");
}
}
QColor DynamicFontSizeLabel::getTextColor()
{
return textColor;
}
void DynamicFontSizeLabel::setTextAndColor(const QString &text, QColor color)
{
setTextColor(color);
setText(text);
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizeLabel::minimumSizeHint() const
{
return QWidget::minimumSizeHint();
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizeLabel::sizeHint() const
{
return QWidget::sizeHint();
}

View file

@ -0,0 +1,41 @@
#ifndef DYNAMICFONTSIZELABEL_H
#define DYNAMICFONTSIZELABEL_H
#include <QColor>
#include <QLabel>
class DynamicFontSizeLabel : public QLabel
{
Q_OBJECT
public:
explicit DynamicFontSizeLabel(QWidget *parent = NULL, Qt::WindowFlags f = Qt::WindowFlags());
~DynamicFontSizeLabel()
{
}
static float getWidgetMaximumFontSize(QWidget *widget, const QString &text);
/* This method overwrite stylesheet */
void setTextColor(QColor color);
QColor getTextColor();
void setTextAndColor(const QString &text, QColor color = QColor::Invalid);
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *event);
QColor textColor;
// QWidget interface
protected:
void paintEvent(QPaintEvent *event);
// QWidget interface
public:
QSize minimumSizeHint() const;
QSize sizeHint() const;
};
#endif // DYNAMICFONTSIZELABEL_H

View file

@ -0,0 +1,80 @@
#include "dynamic_font_size_push_button.h"
#include "dynamic_font_size_label.h"
#include <QDebug>
#include <QPainter>
DynamicFontSizePushButton::DynamicFontSizePushButton(QWidget *parent) : QPushButton(parent)
{
}
void DynamicFontSizePushButton::paintEvent(QPaintEvent *event)
{
// Call the base class paintEvent to preserve any other painting behavior
QPushButton::paintEvent(event);
// Adjust the font size dynamically based on the text
QFont newFont = font();
float fontSize = DynamicFontSizeLabel::getWidgetMaximumFontSize(this, this->text());
newFont.setPointSizeF(fontSize);
setFont(newFont);
// Get painter for custom painting
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// Paint the background with a linear gradient (normal state)
QLinearGradient gradient(0, 0, 0, height());
if (isDown()) {
// Pressed state
gradient.setColorAt(0, QColor(128, 128, 128));
gradient.setColorAt(1, QColor(64, 64, 64));
} else if (underMouse()) {
// Hover state
gradient.setColorAt(0, QColor(96, 96, 96));
gradient.setColorAt(1, QColor(48, 48, 48));
} else {
// Normal state
gradient.setColorAt(0, QColor(64, 64, 64)); // start color
gradient.setColorAt(1, QColor(32, 32, 32)); // end color
}
painter.setBrush(gradient);
painter.setPen(Qt::NoPen); // No border
painter.drawRect(rect());
// Paint the button text
painter.setPen(QPen(textColor.isValid() ? textColor : QColor(255, 255, 255))); // Set text color
painter.drawText(rect(), Qt::AlignCenter, text());
}
void DynamicFontSizePushButton::setTextColor(QColor color)
{
if (color.isValid() && color != textColor) {
textColor = color;
update(); // Request a repaint to update the text color
}
}
void DynamicFontSizePushButton::setTextAndColor(const QString &text, QColor color)
{
setTextColor(color);
setText(text);
}
QColor DynamicFontSizePushButton::getTextColor()
{
return textColor;
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizePushButton::minimumSizeHint() const
{
return QWidget::minimumSizeHint();
}
/* Do not give any size hint as it it changes during paintEvent */
QSize DynamicFontSizePushButton::sizeHint() const
{
return QWidget::sizeHint();
}

View file

@ -0,0 +1,29 @@
#ifndef DYNAMICFONTSIZEPUSHBUTTON_H
#define DYNAMICFONTSIZEPUSHBUTTON_H
#include <QObject>
#include <QPushButton>
#include <QWidget>
class DynamicFontSizePushButton : public QPushButton
{
public:
explicit DynamicFontSizePushButton(QWidget *parent = NULL);
/* This method overwrite stylesheet */
void setTextColor(QColor color);
QColor getTextColor();
void setTextAndColor(const QString &text, QColor color = QColor::Invalid);
// QWidget interface
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent *event);
private:
QColor textColor;
};
#endif // DYNAMICFONTSIZEPUSHBUTTON_H

View file

@ -0,0 +1,39 @@
#include "labeled_input.h"
LabeledInput::LabeledInput(QWidget *parent, const QString &labelText) : QWidget(parent)
{
label = new QLabel(labelText, this);
layout = new QHBoxLayout(this);
layout->addWidget(label);
}
QSpinBox *LabeledInput::addSpinBox(const int minValue, const int maxValue, const int defaultValue)
{
auto *spinBox = new QSpinBox(this);
spinBox->setRange(minValue, maxValue);
spinBox->setValue(defaultValue);
layout->addWidget(spinBox);
connect(spinBox, SIGNAL(valueChanged(int)), this, SIGNAL(spinBoxValueChanged(int)));
return spinBox;
}
// Add a QComboBox (for arbitrary selections)
QComboBox *LabeledInput::addComboBox(const QStringList &items, const QString &defaultItem)
{
auto *comboBox = new QComboBox(this);
comboBox->addItems(items);
if (!defaultItem.isEmpty()) {
comboBox->setCurrentText(defaultItem);
}
layout->addWidget(comboBox);
return comboBox;
}
// Add a QComboBox specifically for Qt Directions
QComboBox *LabeledInput::addDirectionComboBox()
{
const QStringList directions = {"Qt::Horizontal", "Qt::Vertical"};
const auto comboBox = addComboBox(directions, "Qt::Vertical");
connect(comboBox, SIGNAL(currentTextChanged(QString)), this, SIGNAL(directionComboBoxChanged(QString)));
return comboBox;
}

View file

@ -0,0 +1,36 @@
#ifndef LABELED_INPUT_H
#define LABELED_INPUT_H
#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QWidget>
class LabeledInput final : public QWidget
{
Q_OBJECT
public:
explicit LabeledInput(QWidget *parent, const QString &labelText);
// Add a QSpinBox (for arbitrary numbers)
QSpinBox *addSpinBox(int minValue, int maxValue, int defaultValue = 0);
// Add a QComboBox (for arbitrary selections)
QComboBox *addComboBox(const QStringList &items, const QString &defaultItem = QString());
// Add a QComboBox specifically for Qt Directions
QComboBox *addDirectionComboBox();
signals:
void spinBoxValueChanged(int newValue); // Declare the valueChanged signal
void comboBoxValueChanged(int newValue);
void directionComboBoxChanged(QString newDirection);
private:
QLabel *label;
QHBoxLayout *layout;
};
#endif // LABELED_INPUT_H

View file

@ -0,0 +1,46 @@
#include "percent_bar_widget.h"
PercentBarWidget::PercentBarWidget(QWidget *parent, double initialValue) : QWidget(parent), valueToDisplay(initialValue)
{
setMinimumSize(50, 10);
}
void PercentBarWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
QRect rect = this->rect();
const int midX = rect.width() / 2;
const int height = rect.height();
// Draw background border (no fill)
painter.setPen(QPen(Qt::black, 1));
painter.setBrush(Qt::NoBrush);
painter.drawRect(rect.adjusted(0, 0, -1, -1)); // Avoid right/bottom overflow
const double halfWidth = rect.width() / 2.0;
const int barLength = static_cast<int>((qAbs(valueToDisplay) / 100.0) * halfWidth);
QRect fillRect;
if (valueToDisplay > 0.0) {
fillRect = QRect(midX, 0, barLength, height);
painter.fillRect(fillRect, Qt::green);
} else if (valueToDisplay < 0.0) {
fillRect = QRect(midX - barLength, 0, barLength, height);
painter.fillRect(fillRect, Qt::red);
}
// Draw center line at 0
painter.fillRect(midX - 1, 0, 3, height, Qt::white);
// Draw tick marks every 10%
const int tickHeight = 4;
for (int percent = -100; percent <= 100; percent += 10) {
int x = midX + static_cast<int>((percent / 100.0) * halfWidth);
painter.drawLine(x, height - tickHeight, x, height);
}
}

View file

@ -0,0 +1,33 @@
#ifndef PERCENT_BAR_WIDGET_H
#define PERCENT_BAR_WIDGET_H
#include <QColor>
#include <QPainter>
#include <QWidget>
class PercentBarWidget : public QWidget
{
Q_OBJECT
public:
explicit PercentBarWidget(QWidget *parent, double initialValue);
void setValue(double newValue)
{
valueToDisplay = qBound(-100.0, newValue, 100.0); // Clamp to [-100, 100]
update(); // Trigger repaint
}
double value() const
{
return valueToDisplay;
}
protected:
void paintEvent(QPaintEvent *event) override;
private:
double valueToDisplay; // Ranges from -100 to 100
};
#endif // PERCENT_BAR_WIDGET_H

View file

@ -0,0 +1,63 @@
#include "shadow_background_label.h"
#include <QPaintEvent>
#include <QPainter>
/**
* @class ShadowBackgroundLabel
* @brief A QLabel with a semi-transparent black shadowed background and rounded corners.
*
* This label provides a styled appearance with centered white text and a translucent
* rounded background, making it suitable for overlay or emphasis in a UI.
*/
ShadowBackgroundLabel::ShadowBackgroundLabel(QWidget *parent, const QString &text) : QLabel(parent)
{
setAttribute(Qt::WA_TranslucentBackground); // Allows transparency.
setText("<font color='white'>" + text + "</font>"); ///< Ensures the text is rendered in white.
setAlignment(Qt::AlignCenter); ///< Centers the text within the label.
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); ///< Ensures minimum size constraints.
}
/**
* @brief Handles resizing of the label.
*
* Ensures the label updates its appearance when resized by triggering a repaint.
*
* @param event The resize event containing new size information.
*/
void ShadowBackgroundLabel::resizeEvent(QResizeEvent *event)
{
QLabel::resizeEvent(event);
update(); // Repaint borders explicitly.
}
/**
* @brief Custom paint event for drawing the label's background.
*
* Renders a semi-transparent black rounded rectangle as the background
* and then delegates text rendering to QLabel.
*
* @param event The paint event for the widget.
*/
void ShadowBackgroundLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// Enable antialiasing for smoother edges.
painter.setRenderHint(QPainter::Antialiasing, true);
// Set semi-transparent black brush and disable border pen.
painter.setBrush(QColor(0, 0, 0, 128)); // Semi-transparent black.
painter.setPen(Qt::NoPen); // No border.
// Adjust the rectangle to account for margins.
QRect adjustedRect = this->rect();
int margin = contentsMargins().left(); // Assuming equal margins.
adjustedRect.adjust(margin, margin, -margin, -margin);
// Draw a rounded rectangle with a corner radius of 5.
painter.drawRoundedRect(adjustedRect, 5, 5);
// Delegate text rendering to QLabel.
QLabel::paintEvent(event);
}

View file

@ -0,0 +1,18 @@
#ifndef STYLEDLABEL_H
#define STYLEDLABEL_H
#include <QLabel>
class ShadowBackgroundLabel : public QLabel
{
Q_OBJECT
public:
explicit ShadowBackgroundLabel(QWidget *parent, const QString &text);
protected:
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override; // Custom painting logic
};
#endif // STYLEDLABEL_H