mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-26 08:33:54 -07:00
Add Utility Layouts and corresponding Widgets (#5177)
* Add FlowWidget class with flexible layout and scroll handling - Implemented FlowWidget class to organize widgets in a flow layout with scrollable options. - Integrated QScrollArea to handle overflow with configurable horizontal and vertical scroll policies. - Incorporated dynamic layout selection (FlowLayout, HorizontalFlowLayout, VerticalFlowLayout) based on scroll policy. * Add OverlapWidget and OverlapLayout for managing overlapping child widgets - Implemented the OverlapWidget class to manage child widgets in an overlapping manner, supporting configurable overlap percentage, maximum columns, maximum rows, and layout direction. - Introduced the OverlapLayout class, which arranges widgets with overlapping positions, allowing flexible stacking based on specified parameters. * Add OverlapControlWidget. * Delete FlowLayout items later to allow them to finish their event loop. * Allow OverlapWidgets to adjust their rows/columns on resize. * Clamp vertical FlowLayout to any available parent scrollAreas. * Implement margins and spacing for FlowLayouts. * Adjust/revert some things. * Address pull request comments (nullptr checks and additional comments, mostly.) * Reformat code so the linter will stop yelling at me. * Remove undefined methods from FlowLayouts. * Fix the build. * Revert FlowLayout::takeAt to index check. * Commits will continue until linter morale improves. * Fix various warnings in FlowLayout. * Fix various warnings in FlowLayout.h. * Fix various warnings in the FlowLayout classes. * Fix [[nodiscard]] warning. * Fix more warnings. * Final round of yellow squiggle fixing. * Linter formatting. * Refactor column/row calculation to be more readable. * Code style. * Address PR comments. * Combine if-statements. * Replace std::math functions with Qt equivalents. * Fix non-consts and QtMath. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
c8336df49d
commit
8ef92d26c5
18 changed files with 1832 additions and 42 deletions
|
|
@ -66,7 +66,7 @@ void CardInfoPictureWithTextOverlayWidget::setOutlineColor(const QColor &color)
|
|||
*/
|
||||
void CardInfoPictureWithTextOverlayWidget::setFontSize(const int size)
|
||||
{
|
||||
fontSize = size;
|
||||
fontSize = size > 0 ? size : 1;
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -109,48 +109,50 @@ void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
|||
|
||||
// Get the pixmap from the base class using the getter
|
||||
const QPixmap &pixmap = getResizedPixmap();
|
||||
if (!pixmap.isNull()) {
|
||||
// Calculate size and position for drawing
|
||||
const QSize scaledSize = pixmap.size().scaled(size(), Qt::KeepAspectRatio);
|
||||
const QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
||||
const QRect pixmapRect(topLeft, scaledSize);
|
||||
|
||||
// Prepare text wrapping
|
||||
const QFontMetrics fontMetrics(font);
|
||||
const int lineHeight = fontMetrics.height();
|
||||
const int textWidth = pixmapRect.width();
|
||||
QString wrappedText;
|
||||
|
||||
// Break the text into multiple lines to fit within the pixmap width
|
||||
QString currentLine;
|
||||
QStringList words = overlayText.split(' ');
|
||||
for (const QString &word : words) {
|
||||
if (fontMetrics.horizontalAdvance(currentLine + " " + word) > textWidth) {
|
||||
wrappedText += currentLine + '\n';
|
||||
currentLine = word;
|
||||
} else {
|
||||
if (!currentLine.isEmpty()) {
|
||||
currentLine += " ";
|
||||
}
|
||||
currentLine += word;
|
||||
}
|
||||
}
|
||||
wrappedText += currentLine;
|
||||
|
||||
// Calculate total text block height
|
||||
const int totalTextHeight = static_cast<int>(wrappedText.count('\n')) * lineHeight + lineHeight;
|
||||
|
||||
// Set up the text layout options
|
||||
QTextOption textOption;
|
||||
textOption.setAlignment(textAlignment);
|
||||
|
||||
// Create a text rectangle centered within the pixmap rect
|
||||
auto textRect = QRect(pixmapRect.left(), pixmapRect.top(), pixmapRect.width(), totalTextHeight);
|
||||
textRect.moveTop((pixmapRect.height() - totalTextHeight) / 2 + pixmapRect.top());
|
||||
|
||||
// Draw the outlined text
|
||||
drawOutlinedText(painter, textRect, wrappedText, textOption);
|
||||
if (pixmap.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate size and position for drawing
|
||||
const QSize scaledSize = pixmap.size().scaled(size(), Qt::KeepAspectRatio);
|
||||
const QPoint topLeft{(width() - scaledSize.width()) / 2, (height() - scaledSize.height()) / 2};
|
||||
const QRect pixmapRect(topLeft, scaledSize);
|
||||
|
||||
// Prepare text wrapping
|
||||
const QFontMetrics fontMetrics(font);
|
||||
const int lineHeight = fontMetrics.height();
|
||||
const int textWidth = pixmapRect.width();
|
||||
QString wrappedText;
|
||||
|
||||
// Break the text into multiple lines to fit within the pixmap width
|
||||
QString currentLine;
|
||||
QStringList words = overlayText.split(' ');
|
||||
for (const QString &word : words) {
|
||||
if (fontMetrics.horizontalAdvance(currentLine + " " + word) > textWidth) {
|
||||
wrappedText += currentLine + '\n';
|
||||
currentLine = word;
|
||||
} else {
|
||||
if (!currentLine.isEmpty()) {
|
||||
currentLine += " ";
|
||||
}
|
||||
currentLine += word;
|
||||
}
|
||||
}
|
||||
wrappedText += currentLine;
|
||||
|
||||
// Calculate total text block height
|
||||
const int totalTextHeight = static_cast<int>(wrappedText.count('\n')) * lineHeight + lineHeight;
|
||||
|
||||
// Set up the text layout options
|
||||
QTextOption textOption;
|
||||
textOption.setAlignment(textAlignment);
|
||||
|
||||
// Create a text rectangle centered within the pixmap rect
|
||||
auto textRect = QRect(pixmapRect.left(), pixmapRect.top(), pixmapRect.width(), totalTextHeight);
|
||||
textRect.moveTop((pixmapRect.height() - totalTextHeight) / 2 + pixmapRect.top());
|
||||
|
||||
// Draw the outlined text
|
||||
drawOutlinedText(painter, textRect, wrappedText, textOption);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* @file flow_widget.cpp
|
||||
* @brief Implementation of the FlowWidget class for organizing widgets in a flow layout within a scrollable area.
|
||||
*/
|
||||
|
||||
#include "flow_widget.h"
|
||||
|
||||
#include "../../../layouts/flow_layout.h"
|
||||
#include "../../../layouts/horizontal_flow_layout.h"
|
||||
#include "../../../layouts/vertical_flow_layout.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <qscrollarea.h>
|
||||
#include <qsizepolicy.h>
|
||||
|
||||
/**
|
||||
* @brief Constructs a FlowWidget with a scrollable layout.
|
||||
*
|
||||
* @param parent The parent widget of this FlowWidget.
|
||||
* @param horizontalPolicy The horizontal scroll bar policy for the scroll area.
|
||||
* @param verticalPolicy The vertical scroll bar policy for the scroll area.
|
||||
*/
|
||||
FlowWidget::FlowWidget(QWidget *parent,
|
||||
const Qt::ScrollBarPolicy horizontalPolicy,
|
||||
const Qt::ScrollBarPolicy verticalPolicy)
|
||||
: QWidget(parent)
|
||||
{
|
||||
// Main Widget and Layout
|
||||
this->setMinimumSize(0, 0);
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
main_layout = new QHBoxLayout();
|
||||
this->setLayout(main_layout);
|
||||
|
||||
// Flow Layout inside the scroll area
|
||||
container = new QWidget();
|
||||
|
||||
if (horizontalPolicy != Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
|
||||
flow_layout = new HorizontalFlowLayout(container);
|
||||
} else if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy != Qt::ScrollBarAlwaysOff) {
|
||||
flow_layout = new VerticalFlowLayout(container);
|
||||
} else {
|
||||
flow_layout = new FlowLayout(container, 0, 0, 0);
|
||||
}
|
||||
|
||||
container->setLayout(flow_layout);
|
||||
// The container should expand as much as possible, trusting the scrollArea to constrain it.
|
||||
container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
container->setMinimumSize(0, 0);
|
||||
|
||||
// Scroll Area, which should expand as much as possible, since it should be the only direct child widget.
|
||||
scrollArea = new QScrollArea();
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setMinimumSize(0, 0);
|
||||
scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
// Set scrollbar policies
|
||||
scrollArea->setHorizontalScrollBarPolicy(horizontalPolicy);
|
||||
scrollArea->setVerticalScrollBarPolicy(verticalPolicy);
|
||||
|
||||
// Use the FlowLayout container directly if we disable the ScrollArea
|
||||
if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
|
||||
main_layout->addWidget(container);
|
||||
} else {
|
||||
scrollArea->setWidget(container);
|
||||
main_layout->addWidget(scrollArea);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a widget to the flow layout within the FlowWidget.
|
||||
*
|
||||
* Adjusts the widget's size policy based on the scroll bar policies.
|
||||
*
|
||||
* @param widget_to_add The widget to add to the flow layout.
|
||||
*/
|
||||
void FlowWidget::addWidget(QWidget *widget_to_add) const
|
||||
{
|
||||
// Adjust size policy if scrollbars are disabled
|
||||
if (scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
|
||||
widget_to_add->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
|
||||
}
|
||||
if (scrollArea->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
|
||||
widget_to_add->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
|
||||
}
|
||||
|
||||
// Add the widget to the flow layout
|
||||
this->flow_layout->addWidget(widget_to_add);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all widgets from the flow layout.
|
||||
*
|
||||
* Deletes each widget and layout item, and recreates the flow layout if it was removed.
|
||||
*/
|
||||
void FlowWidget::clearLayout()
|
||||
{
|
||||
if (flow_layout != nullptr) {
|
||||
QLayoutItem *item;
|
||||
while ((item = flow_layout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater(); // Delete the widget
|
||||
delete item; // Delete the layout item
|
||||
}
|
||||
} else {
|
||||
if (scrollArea->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff &&
|
||||
scrollArea->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
|
||||
flow_layout = new HorizontalFlowLayout(container);
|
||||
} else if (scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff &&
|
||||
scrollArea->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff) {
|
||||
flow_layout = new VerticalFlowLayout(container);
|
||||
} else {
|
||||
flow_layout = new FlowLayout(container, 0, 0, 0);
|
||||
}
|
||||
this->container->setLayout(flow_layout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles resize events for the FlowWidget.
|
||||
*
|
||||
* Triggers layout recalculation and adjusts the scroll area content size.
|
||||
*
|
||||
* @param event The resize event containing the new size information.
|
||||
*/
|
||||
void FlowWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
// Trigger the layout to recalculate
|
||||
if (flow_layout != nullptr) {
|
||||
flow_layout->invalidate(); // Marks the layout as dirty and requires recalculation
|
||||
flow_layout->activate(); // Recalculate the layout based on the new size
|
||||
}
|
||||
|
||||
// Ensure the scroll area and its content adjust correctly
|
||||
if (scrollArea != nullptr) {
|
||||
if (scrollArea->widget() != nullptr) {
|
||||
scrollArea->widget()->adjustSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef FLOW_WIDGET_H
|
||||
#define FLOW_WIDGET_H
|
||||
#include "../../../layouts/flow_layout.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <qscrollarea.h>
|
||||
|
||||
class FlowWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlowWidget(QWidget *parent, Qt::ScrollBarPolicy horizontalPolicy, Qt::ScrollBarPolicy verticalPolicy);
|
||||
void addWidget(QWidget *widget_to_add) const;
|
||||
void clearLayout();
|
||||
|
||||
QScrollArea *scrollArea;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
QHBoxLayout *main_layout;
|
||||
FlowLayout *flow_layout;
|
||||
QWidget *container;
|
||||
};
|
||||
|
||||
#endif // FLOW_WIDGET_H
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#include "overlap_control_widget.h"
|
||||
|
||||
#include "overlap_widget.h"
|
||||
|
||||
OverlapControlWidget::OverlapControlWidget(int overlapPercentage,
|
||||
int maxColumns,
|
||||
int maxRows,
|
||||
Qt::Orientation direction,
|
||||
QWidget *parent)
|
||||
: QWidget(parent), overlapPercentage(overlapPercentage), maxColumns(maxColumns), maxRows(maxRows),
|
||||
direction(direction)
|
||||
{
|
||||
// Main Widget and Layout
|
||||
this->setMinimumSize(0, 100);
|
||||
// this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
// this->setStyleSheet("border: 10px solid red;");
|
||||
|
||||
layout = new QHBoxLayout(this);
|
||||
this->setLayout(layout);
|
||||
|
||||
card_size_slider = new QSlider(Qt::Horizontal);
|
||||
card_size_slider->setRange(1, 10); // Example range for scaling, adjust as needed
|
||||
|
||||
amount_of_items_to_overlap = new LabeledInput(this, tr("Cards to overlap:"));
|
||||
amount_of_items_to_overlap->addSpinBox(0, 999, 10);
|
||||
overlap_percentage_input = new LabeledInput(this, tr("Overlap percentage:"));
|
||||
overlap_percentage_input->addSpinBox(0, 100, 80);
|
||||
overlap_direction = new LabeledInput(this, tr("Overlap direction:"));
|
||||
overlap_direction->addDirectionComboBox();
|
||||
|
||||
layout->addWidget(card_size_slider);
|
||||
layout->addWidget(amount_of_items_to_overlap);
|
||||
layout->addWidget(overlap_percentage_input);
|
||||
layout->addWidget(overlap_direction);
|
||||
|
||||
// TODO probably connect this to the parent
|
||||
// connect(card_size_slider, &QSlider::valueChanged, display, &CardPicture::setScaleFactor);
|
||||
}
|
||||
|
||||
void OverlapControlWidget::connectOverlapWidget(OverlapWidget *overlap_widget)
|
||||
{
|
||||
connect(amount_of_items_to_overlap, &LabeledInput::spinBoxValueChanged, overlap_widget,
|
||||
&OverlapWidget::maxOverlapItemsChanged);
|
||||
connect(overlap_direction, &LabeledInput::directionComboBoxChanged, overlap_widget,
|
||||
&OverlapWidget::overlapDirectionChanged);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef OVERLAP_CONTROL_WIDGET_H
|
||||
#define OVERLAP_CONTROL_WIDGET_H
|
||||
#include "../display/labeled_input.h"
|
||||
#include "overlap_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QSlider>
|
||||
#include <QWidget>
|
||||
|
||||
class OverlapControlWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OverlapControlWidget(int overlapPercentage,
|
||||
int maxColumns,
|
||||
int maxRows,
|
||||
Qt::Orientation direction,
|
||||
QWidget *parent);
|
||||
void connectOverlapWidget(OverlapWidget *overlap_widget);
|
||||
|
||||
private:
|
||||
QHBoxLayout *layout;
|
||||
QSlider *card_size_slider;
|
||||
LabeledInput *amount_of_items_to_overlap;
|
||||
LabeledInput *overlap_percentage_input;
|
||||
LabeledInput *overlap_direction;
|
||||
int overlapPercentage;
|
||||
int maxColumns;
|
||||
int maxRows;
|
||||
Qt::Orientation direction;
|
||||
};
|
||||
|
||||
#endif // OVERLAP_CONTROL_WIDGET_H
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
#include "overlap_widget.h"
|
||||
|
||||
#include "../../../../../deck/deck_list_model.h"
|
||||
#include "../../../layouts/flow_layout.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
/**
|
||||
* @class OverlapWidget
|
||||
* @brief A widget for managing overlapping child widgets.
|
||||
*
|
||||
* The OverlapWidget class is a QWidget subclass that utilizes the OverlapLayout
|
||||
* to arrange its child widgets in an overlapping manner. This widget allows
|
||||
* configuration of overlap percentage, maximum columns, maximum rows, and layout
|
||||
* direction, making it suitable for displaying elements that can partially stack
|
||||
* over each other. The widget automatically manages resizing and re-layout of its
|
||||
* child widgets based on the available space and specified parameters.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Constructs an OverlapWidget with specified layout parameters.
|
||||
*
|
||||
* Initializes the OverlapWidget with the given overlap percentage, maximum number
|
||||
* of columns and rows, and layout direction. Sets size policies to ensure the widget
|
||||
* can expand as needed. A new OverlapLayout is created and assigned to manage the
|
||||
* layout of child widgets.
|
||||
*
|
||||
* @param overlapPercentage The percentage of overlap between child widgets (0-100).
|
||||
* @param maxColumns The maximum number of columns for the layout (0 for unlimited).
|
||||
* @param maxRows The maximum number of rows for the layout (0 for unlimited).
|
||||
* @param direction The orientation of the layout, either Qt::Horizontal or Qt::Vertical.
|
||||
* @param adjustOnResize If the overlap widgets should adjust its max columns/rows on resize to fit.
|
||||
* @param parent The parent widget of this OverlapWidget.
|
||||
*/
|
||||
OverlapWidget::OverlapWidget(QWidget *parent,
|
||||
const int overlapPercentage,
|
||||
const int maxColumns,
|
||||
const int maxRows,
|
||||
const Qt::Orientation direction,
|
||||
const bool adjustOnResize)
|
||||
: QWidget(parent), overlapPercentage(overlapPercentage), maxColumns(maxColumns), maxRows(maxRows),
|
||||
direction(direction), adjustOnResize(adjustOnResize)
|
||||
{
|
||||
this->setMinimumSize(0, 0);
|
||||
overlapLayout = new OverlapLayout(this, overlapPercentage, maxColumns, maxRows, direction);
|
||||
this->setLayout(overlapLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a widget to the overlap layout.
|
||||
*
|
||||
* This method appends the specified widget to the internal OverlapLayout, allowing
|
||||
* it to be arranged with the existing child widgets. The widget's visibility and
|
||||
* behavior will be managed by the layout.
|
||||
*
|
||||
* @param widgetToAdd A pointer to the QWidget to be added to the layout.
|
||||
*/
|
||||
void OverlapWidget::addWidget(QWidget *widgetToAdd) const
|
||||
{
|
||||
this->overlapLayout->addWidget(widgetToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all widgets from the layout and deletes them.
|
||||
*
|
||||
* This method removes all child widgets from the OverlapLayout, deleting both the
|
||||
* widget instances and their corresponding layout items. This ensures that the layout
|
||||
* is empty and can be reused or refreshed as needed.
|
||||
*/
|
||||
void OverlapWidget::clearLayout()
|
||||
{
|
||||
if (overlapLayout != nullptr) {
|
||||
QLayoutItem *item;
|
||||
while ((item = overlapLayout->takeAt(0)) != nullptr) {
|
||||
delete item->widget(); // Delete the widget
|
||||
delete item; // Delete the layout item
|
||||
}
|
||||
}
|
||||
|
||||
// If layout is null, create a new layout; otherwise, reuse the existing one
|
||||
if (overlapLayout == nullptr) {
|
||||
overlapLayout = new OverlapLayout(this, overlapPercentage, maxColumns, maxRows, direction);
|
||||
this->setLayout(overlapLayout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles resizing events for the widget.
|
||||
*
|
||||
* This overridden method is called when the widget is resized. It invokes layout
|
||||
* recalculation to ensure that the child widgets are correctly arranged based on the
|
||||
* new dimensions. It marks the layout as dirty and activates it to reflect the changes.
|
||||
*
|
||||
* @param event The resize event containing the new size information.
|
||||
*/
|
||||
void OverlapWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
// Trigger the layout to recalculate
|
||||
if (overlapLayout != nullptr) {
|
||||
overlapLayout->invalidate(); // Marks the layout as dirty and requires recalculation
|
||||
overlapLayout->activate(); // Recalculate the layout based on the new size
|
||||
}
|
||||
|
||||
if (adjustOnResize) {
|
||||
adjustMaxColumnsAndRows();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dynamically adjusts maxColumns and maxRows based on widget size and layout direction.
|
||||
*
|
||||
* This function calculates the maximum number of columns or rows that can fit within
|
||||
* the widget's width and height, depending on the layout direction. It then updates
|
||||
* the OverlapLayout with these calculated values to ensure the layout is optimized.
|
||||
*/
|
||||
void OverlapWidget::adjustMaxColumnsAndRows()
|
||||
{
|
||||
if (direction == Qt::Vertical) {
|
||||
// Calculate columns based on width for vertical layout
|
||||
const int calculatedColumns = overlapLayout->calculateMaxColumns();
|
||||
maxColumns = calculatedColumns;
|
||||
overlapLayout->setMaxColumns(calculatedColumns);
|
||||
|
||||
// Calculate rows based on total item count and columns
|
||||
const int calculatedRows = overlapLayout->calculateRowsForColumns(calculatedColumns);
|
||||
maxRows = calculatedRows;
|
||||
overlapLayout->setMaxRows(calculatedRows);
|
||||
} else {
|
||||
// Calculate rows based on height for horizontal layout
|
||||
const int calculatedRows = overlapLayout->calculateMaxRows();
|
||||
maxRows = calculatedRows;
|
||||
overlapLayout->setMaxRows(calculatedRows);
|
||||
|
||||
// Calculate columns based on total item count and rows
|
||||
const int calculatedColumns = overlapLayout->calculateColumnsForRows(calculatedRows);
|
||||
maxColumns = calculatedColumns;
|
||||
overlapLayout->setMaxColumns(calculatedColumns);
|
||||
}
|
||||
|
||||
overlapLayout->invalidate();
|
||||
overlapLayout->activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the maximum number of overlapping items based on new value.
|
||||
*
|
||||
* This method updates the maximum number of columns or rows for the overlap layout
|
||||
* based on the given new value. It adjusts the layout direction accordingly and
|
||||
* triggers a size adjustment for the widget, ensuring the layout reflects the changes.
|
||||
*
|
||||
* @param newValue The new maximum number of overlapping items allowed in the layout.
|
||||
*/
|
||||
void OverlapWidget::maxOverlapItemsChanged(const int newValue)
|
||||
{
|
||||
if (direction == Qt::Horizontal) {
|
||||
maxRows = 0;
|
||||
overlapLayout->setMaxRows(0);
|
||||
|
||||
maxColumns = newValue;
|
||||
overlapLayout->setMaxColumns(newValue);
|
||||
} else {
|
||||
maxRows = newValue;
|
||||
overlapLayout->setMaxRows(newValue);
|
||||
|
||||
maxColumns = 0;
|
||||
overlapLayout->setMaxColumns(0);
|
||||
}
|
||||
this->adjustSize();
|
||||
overlapLayout->invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Changes the layout direction based on the specified new direction.
|
||||
*
|
||||
* This method modifies the layout direction of the OverlapLayout based on the input
|
||||
* string. It updates the direction and triggers a size adjustment for the widget.
|
||||
* Valid inputs are "Qt::Horizontal" and "Qt::Vertical".
|
||||
*
|
||||
* @param newDirection The new layout direction as a QString.
|
||||
*/
|
||||
void OverlapWidget::overlapDirectionChanged(const QString &newDirection)
|
||||
{
|
||||
if (newDirection.compare("Qt::Horizontal", Qt::CaseInsensitive) == 0) {
|
||||
direction = Qt::Horizontal;
|
||||
overlapLayout->setDirection(direction);
|
||||
} else if (newDirection.compare("Qt::Vertical", Qt::CaseInsensitive) == 0) {
|
||||
direction = Qt::Vertical;
|
||||
overlapLayout->setDirection(direction);
|
||||
}
|
||||
this->adjustSize();
|
||||
overlapLayout->invalidate();
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef OVERLAP_WIDGET_H
|
||||
#define OVERLAP_WIDGET_H
|
||||
|
||||
#include "../../../layouts/overlap_layout.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class OverlapWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OverlapWidget(QWidget *parent,
|
||||
int overlapPercentage,
|
||||
int maxColumns,
|
||||
int maxRows,
|
||||
Qt::Orientation direction,
|
||||
bool adjustOnResize = false);
|
||||
void addWidget(QWidget *widgetToAdd) const;
|
||||
void clearLayout();
|
||||
void adjustMaxColumnsAndRows();
|
||||
|
||||
public slots:
|
||||
void maxOverlapItemsChanged(int newValue);
|
||||
void overlapDirectionChanged(const QString &newDirection);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
OverlapLayout *overlapLayout;
|
||||
int overlapPercentage;
|
||||
int maxColumns;
|
||||
int maxRows;
|
||||
Qt::Orientation direction;
|
||||
bool adjustOnResize = false;
|
||||
};
|
||||
|
||||
#endif // OVERLAP_WIDGET_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue