mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-17 12:37:46 -07:00
[VDD] Fix minimum size by adding a compact mode to quickSettingsButtons (#6890)
* [VDD] Fix minimum size by adding a compact mode to quickSettingsButtons Took 17 minutes Took 5 seconds * Fix and use FlowWidget/FlowLayout Took 35 minutes Took 4 seconds * Set spacings. Took 12 minutes * Make VDE tools flow Took 1 hour 23 minutes Took 5 seconds * Squeeze and flow even more. Took 11 minutes * Make pushbutton compact. Took 54 minutes Took 7 seconds --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
762e742be0
commit
7153f7d4c1
21 changed files with 666 additions and 617 deletions
|
|
@ -20,12 +20,11 @@
|
|||
DrawProbabilityWidget::DrawProbabilityWidget(QWidget *parent, DeckListStatisticsAnalyzer *analyzer)
|
||||
: AbstractAnalyticsPanelWidget(parent, analyzer)
|
||||
{
|
||||
controls = new QWidget(this);
|
||||
controlLayout = new QHBoxLayout(controls);
|
||||
controlLayout->setContentsMargins(11, 0, 11, 0);
|
||||
controls = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
controls->setSpacing(4, 4);
|
||||
|
||||
labelPrefix = new QLabel(this);
|
||||
controlLayout->addWidget(labelPrefix);
|
||||
controls->addWidget(labelPrefix);
|
||||
|
||||
criteriaCombo = new QComboBox(this);
|
||||
// Give these things item-data so we can translate the actual user-facing strings
|
||||
|
|
@ -33,33 +32,32 @@ DrawProbabilityWidget::DrawProbabilityWidget(QWidget *parent, DeckListStatistics
|
|||
criteriaCombo->addItem(QString(), "type");
|
||||
criteriaCombo->addItem(QString(), "subtype");
|
||||
criteriaCombo->addItem(QString(), "cmc");
|
||||
controlLayout->addWidget(criteriaCombo);
|
||||
controls->addWidget(criteriaCombo);
|
||||
|
||||
exactnessCombo = new QComboBox(this);
|
||||
exactnessCombo->addItem(QString(), true); // At least
|
||||
exactnessCombo->addItem(QString(), false); // Exactly
|
||||
controlLayout->addWidget(exactnessCombo);
|
||||
controls->addWidget(exactnessCombo);
|
||||
|
||||
quantitySpin = new QSpinBox(this);
|
||||
quantitySpin->setRange(1, 60);
|
||||
controlLayout->addWidget(quantitySpin);
|
||||
controls->addWidget(quantitySpin);
|
||||
|
||||
labelMiddle = new QLabel(this);
|
||||
controlLayout->addWidget(labelMiddle);
|
||||
controls->addWidget(labelMiddle);
|
||||
|
||||
drawnSpin = new QSpinBox(this);
|
||||
drawnSpin->setRange(1, 60);
|
||||
drawnSpin->setValue(7);
|
||||
controlLayout->addWidget(drawnSpin);
|
||||
controls->addWidget(drawnSpin);
|
||||
|
||||
labelSuffix = new QLabel(this);
|
||||
controlLayout->addWidget(labelSuffix);
|
||||
controls->addWidget(labelSuffix);
|
||||
|
||||
labelPrefix->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
labelMiddle->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
labelSuffix->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
controlLayout->addStretch(1);
|
||||
layout->addWidget(controls);
|
||||
|
||||
// Table
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef COCKATRICE_DRAW_PROBABILITY_WIDGET_H
|
||||
#define COCKATRICE_DRAW_PROBABILITY_WIDGET_H
|
||||
|
||||
#include "../../../../layouts/flow_layout.h"
|
||||
#include "../../../general/layout_containers/flow_widget.h"
|
||||
#include "../../abstract_analytics_panel_widget.h"
|
||||
#include "../../deck_list_statistics_analyzer.h"
|
||||
#include "draw_probability_config.h"
|
||||
|
|
@ -31,8 +33,7 @@ private slots:
|
|||
private:
|
||||
DrawProbabilityConfig config;
|
||||
|
||||
QWidget *controls;
|
||||
QHBoxLayout *controlLayout;
|
||||
FlowWidget *controls;
|
||||
QLabel *labelPrefix;
|
||||
QLabel *labelMiddle;
|
||||
QLabel *labelSuffix;
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListStatisticsAnal
|
|||
layout = new QVBoxLayout(this);
|
||||
|
||||
// Controls
|
||||
controlContainer = new QWidget(this);
|
||||
controlLayout = new QHBoxLayout(controlContainer);
|
||||
controlContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
controlContainer->setSpacing(4, 4);
|
||||
addButton = new QPushButton(this);
|
||||
removeButton = new QPushButton(this);
|
||||
saveButton = new QPushButton(this);
|
||||
|
|
@ -32,11 +32,11 @@ DeckAnalyticsWidget::DeckAnalyticsWidget(QWidget *parent, DeckListStatisticsAnal
|
|||
includeSideboardCheckBox = new QCheckBox(this);
|
||||
includeSideboardCheckBox->setChecked(false);
|
||||
|
||||
controlLayout->addWidget(addButton);
|
||||
controlLayout->addWidget(removeButton);
|
||||
controlLayout->addWidget(saveButton);
|
||||
controlLayout->addWidget(loadButton);
|
||||
controlLayout->addWidget(includeSideboardCheckBox);
|
||||
controlContainer->addWidget(addButton);
|
||||
controlContainer->addWidget(removeButton);
|
||||
controlContainer->addWidget(saveButton);
|
||||
controlContainer->addWidget(loadButton);
|
||||
controlContainer->addWidget(includeSideboardCheckBox);
|
||||
|
||||
layout->addWidget(controlContainer);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef DECK_ANALYTICS_WIDGET_H
|
||||
#define DECK_ANALYTICS_WIDGET_H
|
||||
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
#include "abstract_analytics_panel_widget.h"
|
||||
#include "deck_list_statistics_analyzer.h"
|
||||
#include "resizable_panel.h"
|
||||
|
|
@ -51,8 +52,7 @@ private:
|
|||
void addPanelInstance(const QString &typeId, AbstractAnalyticsPanelWidget *panel, const QJsonObject &cfg = {});
|
||||
|
||||
QVBoxLayout *layout;
|
||||
QWidget *controlContainer;
|
||||
QHBoxLayout *controlLayout;
|
||||
FlowWidget *controlContainer;
|
||||
|
||||
QPushButton *addButton;
|
||||
QPushButton *removeButton;
|
||||
|
|
|
|||
|
|
@ -1,42 +1,52 @@
|
|||
/**
|
||||
* @file flow_widget.cpp
|
||||
* @brief Implementation of the FlowWidget class for organizing widgets in a flow layout within a scrollable area.
|
||||
* @brief Implementation of FlowWidget — a QWidget hosting a FlowLayout inside an
|
||||
* optional QScrollArea.
|
||||
*/
|
||||
|
||||
#include "flow_widget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QResizeEvent>
|
||||
#include <QScrollArea>
|
||||
#include <QSizePolicy>
|
||||
#include <QWidget>
|
||||
#include <qscrollarea.h>
|
||||
#include <qsizepolicy.h>
|
||||
|
||||
/**
|
||||
* @brief Constructs a FlowWidget with a scrollable layout.
|
||||
* @brief Constructs a FlowWidget.
|
||||
*
|
||||
* @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.
|
||||
* When both scroll policies are Qt::ScrollBarAlwaysOff the scroll area is
|
||||
* omitted entirely and the container is placed directly in the main layout.
|
||||
*
|
||||
* @param parent Parent widget.
|
||||
* @param _flowDirection Qt::Horizontal for row-wrapping, Qt::Vertical for column-wrapping.
|
||||
* @param horizontalPolicy Horizontal scroll-bar policy.
|
||||
* @param verticalPolicy Vertical scroll-bar policy.
|
||||
*/
|
||||
FlowWidget::FlowWidget(QWidget *parent,
|
||||
const Qt::Orientation _flowDirection,
|
||||
const Qt::ScrollBarPolicy horizontalPolicy,
|
||||
const Qt::ScrollBarPolicy verticalPolicy)
|
||||
: QWidget(parent), flowDirection(_flowDirection)
|
||||
: QWidget(parent), scrollArea(nullptr), flowDirection(_flowDirection)
|
||||
|
||||
{
|
||||
// Main Widget and Layout
|
||||
if (_flowDirection == Qt::Horizontal) {
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
setMinimumWidth(0);
|
||||
// Top-level size policy
|
||||
// Horizontal flow: expand horizontally, let height be determined by wrapping.
|
||||
// Vertical flow: expand vertically, let width be determined by wrapping.
|
||||
if (flowDirection == Qt::Horizontal) {
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
} else {
|
||||
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
setMinimumHeight(0);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(mainLayout);
|
||||
|
||||
if (horizontalPolicy != Qt::ScrollBarAlwaysOff || verticalPolicy != Qt::ScrollBarAlwaysOff) {
|
||||
// Scroll Area, which should expand as much as possible, since it should be the only direct child widget.
|
||||
const bool useScrollArea = (horizontalPolicy != Qt::ScrollBarAlwaysOff || verticalPolicy != Qt::ScrollBarAlwaysOff);
|
||||
|
||||
// Scroll area (optional)
|
||||
if (useScrollArea) {
|
||||
scrollArea = new QScrollArea(this);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setMinimumSize(0, 0);
|
||||
|
|
@ -48,39 +58,28 @@ FlowWidget::FlowWidget(QWidget *parent,
|
|||
scrollArea = nullptr;
|
||||
}
|
||||
|
||||
// Flow Layout inside the scroll area
|
||||
if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
|
||||
container = new QWidget(this);
|
||||
} else {
|
||||
container = new QWidget(scrollArea);
|
||||
}
|
||||
// Container widget (holds the FlowLayout)
|
||||
container = new QWidget(useScrollArea ? static_cast<QWidget *>(scrollArea) : this);
|
||||
|
||||
// The container should be willing to grow in both axes; its actual size is
|
||||
// governed by the FlowLayout's sizeHint / heightForWidth, not by a fixed policy.
|
||||
container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
container->setMinimumSize(0, 0);
|
||||
|
||||
flowLayout = new FlowLayout(container, flowDirection);
|
||||
|
||||
container->setLayout(flowLayout);
|
||||
// The container should expand as much as possible, trusting the scrollArea to constrain it.
|
||||
if (_flowDirection == Qt::Horizontal) {
|
||||
container->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
container->setMinimumWidth(0);
|
||||
} else {
|
||||
container->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
container->setMinimumHeight(0);
|
||||
}
|
||||
|
||||
// Use the FlowLayout container directly if we disable the ScrollArea
|
||||
if (horizontalPolicy == Qt::ScrollBarAlwaysOff && verticalPolicy == Qt::ScrollBarAlwaysOff) {
|
||||
mainLayout->addWidget(container);
|
||||
} else {
|
||||
if (useScrollArea) {
|
||||
scrollArea->setWidget(container);
|
||||
mainLayout->addWidget(scrollArea);
|
||||
} else {
|
||||
mainLayout->addWidget(container);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
|
@ -100,77 +99,74 @@ void FlowWidget::removeWidget(QWidget *widgetToRemove) const
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Clears all widgets from the flow layout.
|
||||
* @brief Removes all widgets from the flow layout and deletes them.
|
||||
*
|
||||
* Deletes each widget and layout item, and recreates the flow layout if it was removed.
|
||||
* If the layout pointer has somehow been lost it is recreated before returning.
|
||||
*/
|
||||
void FlowWidget::clearLayout()
|
||||
{
|
||||
if (flowLayout != nullptr) {
|
||||
if (flowLayout) {
|
||||
QLayoutItem *item;
|
||||
while ((item = flowLayout->takeAt(0)) != nullptr) {
|
||||
item->widget()->deleteLater(); // Delete the widget
|
||||
delete item; // Delete the layout item
|
||||
while ((item = flowLayout->takeAt(0))) {
|
||||
if (item->widget())
|
||||
item->widget()->deleteLater();
|
||||
delete item;
|
||||
}
|
||||
} else {
|
||||
// Defensive fallback: recreate the layout if it was deleted externally.
|
||||
flowLayout = new FlowLayout(container, flowDirection);
|
||||
container->setLayout(flowLayout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles resize events for the FlowWidget.
|
||||
* @brief Marks the flow layout as dirty so Qt recomputes item positions.
|
||||
*
|
||||
* Triggers layout recalculation and adjusts the scroll area content size.
|
||||
*
|
||||
* @param event The resize event containing the new size information.
|
||||
* We do NOT call adjustSize() or activate() here:
|
||||
* - adjustSize() would freeze geometry by calling setFixedSize internally.
|
||||
* - activate() called inside a resize event can cause synchronous re-entrancy.
|
||||
* Qt automatically calls setGeometry on the layout after a resize, so simply
|
||||
* invalidating is sufficient.
|
||||
*/
|
||||
void FlowWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
qCDebug(FlowWidgetSizeLog) << "resizeEvent:" << event->size();
|
||||
|
||||
qCDebug(FlowWidgetSizeLog) << event->size();
|
||||
|
||||
// Trigger the layout to recalculate
|
||||
if (flowLayout != nullptr) {
|
||||
flowLayout->invalidate(); // Marks the layout as dirty and requires recalculation
|
||||
flowLayout->activate(); // Recalculate the layout based on the new size
|
||||
}
|
||||
|
||||
// Ensure the scroll area and its content adjust correctly
|
||||
if (scrollArea != nullptr && scrollArea->widget() != nullptr) {
|
||||
qCDebug(FlowWidgetSizeLog) << "Got a scrollarea: " << scrollArea->widget()->size();
|
||||
scrollArea->widget()->adjustSize();
|
||||
} else {
|
||||
container->adjustSize();
|
||||
if (flowLayout) {
|
||||
flowLayout->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void FlowWidget::setSpacing(int hSpacing, int vSpacing)
|
||||
{
|
||||
flowLayout->setHorizontalMargin(hSpacing);
|
||||
flowLayout->setVerticalMargin(vSpacing);
|
||||
flowLayout->invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the minimum size for all widgets inside the FlowWidget to the maximum sizeHint of all of them.
|
||||
* @brief Sets every child widget's minimum size to the largest sizeHint in the layout.
|
||||
*
|
||||
* Useful for toolbars or button bars where all items should be the same size.
|
||||
*/
|
||||
void FlowWidget::setMinimumSizeToMaxSizeHint()
|
||||
{
|
||||
QSize maxSize(0, 0); // Initialize to a zero size
|
||||
QSize maxSize(0, 0);
|
||||
|
||||
// Iterate over all widgets in the flow layout to find the maximum sizeHint
|
||||
for (int i = 0; i < flowLayout->count(); ++i) {
|
||||
if (QLayoutItem *item = flowLayout->itemAt(i)) {
|
||||
if (QWidget *widget = item->widget()) {
|
||||
// Update the max size based on the sizeHint of each widget
|
||||
QSize widgetSizeHint = widget->sizeHint();
|
||||
maxSize.setWidth(qMax(maxSize.width(), widgetSizeHint.width()));
|
||||
maxSize.setHeight(qMax(maxSize.height(), widgetSizeHint.height()));
|
||||
}
|
||||
QLayoutItem *item = flowLayout->itemAt(i);
|
||||
if (item && item->widget()) {
|
||||
maxSize = maxSize.expandedTo(item->widget()->sizeHint());
|
||||
}
|
||||
}
|
||||
|
||||
// Set the minimum size for all widgets to the max sizeHint
|
||||
for (int i = 0; i < flowLayout->count(); ++i) {
|
||||
if (QLayoutItem *item = flowLayout->itemAt(i)) {
|
||||
if (QWidget *widget = item->widget()) {
|
||||
widget->setMinimumSize(maxSize);
|
||||
}
|
||||
QLayoutItem *item = flowLayout->itemAt(i);
|
||||
if (item && item->widget()) {
|
||||
item->widget()->setMinimumSize(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
/**
|
||||
* @file flow_widget.h
|
||||
* @ingroup UI
|
||||
* @brief TODO: Document this.
|
||||
* @brief A QWidget that wraps a FlowLayout inside an optional QScrollArea.
|
||||
*/
|
||||
|
||||
#ifndef FLOW_WIDGET_H
|
||||
#define FLOW_WIDGET_H
|
||||
|
||||
#include "../../../layouts/flow_layout.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLoggingCategory>
|
||||
#include <QScrollArea>
|
||||
#include <QWidget>
|
||||
#include <qscrollarea.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(FlowWidgetLog, "flow_widget", QtInfoMsg);
|
||||
inline Q_LOGGING_CATEGORY(FlowWidgetSizeLog, "flow_widget.size", QtInfoMsg);
|
||||
|
||||
class FlowWidget final : public QWidget
|
||||
class FlowWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -25,17 +26,20 @@ public:
|
|||
Qt::Orientation orientation,
|
||||
Qt::ScrollBarPolicy horizontalPolicy,
|
||||
Qt::ScrollBarPolicy verticalPolicy);
|
||||
|
||||
void addWidget(QWidget *widget_to_add) const;
|
||||
void insertWidgetAtIndex(QWidget *toInsert, int index);
|
||||
void removeWidget(QWidget *widgetToRemove) const;
|
||||
void clearLayout();
|
||||
|
||||
[[nodiscard]] int count() const;
|
||||
[[nodiscard]] QLayoutItem *itemAt(int index) const;
|
||||
|
||||
QScrollArea *scrollArea;
|
||||
QScrollArea *scrollArea; ///< Null when both scroll policies are AlwaysOff.
|
||||
|
||||
public slots:
|
||||
void setMinimumSizeToMaxSizeHint();
|
||||
void setSpacing(int hSpacing, int vSpacing);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
|
@ -47,4 +51,4 @@ private:
|
|||
QWidget *container;
|
||||
};
|
||||
|
||||
#endif // FLOW_WIDGET_H
|
||||
#endif // FLOW_WIDGET_H
|
||||
|
|
@ -35,19 +35,33 @@ void SettingsButtonWidget::setButtonIcon(QPixmap iconMap)
|
|||
button->setIcon(iconMap);
|
||||
}
|
||||
|
||||
void SettingsButtonWidget::setButtonText(const QString &buttonText)
|
||||
void SettingsButtonWidget::setButtonText(const QString &text)
|
||||
{
|
||||
// 🔓 unlock size constraints
|
||||
buttonText = text;
|
||||
|
||||
button->setMinimumSize(QSize(0, 0));
|
||||
button->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
|
||||
|
||||
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
button->setText(buttonText);
|
||||
|
||||
button->setText(text);
|
||||
button->setFixedHeight(32);
|
||||
button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
button->setMinimumWidth(button->sizeHint().width());
|
||||
button->setMinimumWidth(32); // icon-only fallback minimum
|
||||
}
|
||||
|
||||
void SettingsButtonWidget::setCompact(bool _compact)
|
||||
{
|
||||
compact = _compact;
|
||||
if (compact) {
|
||||
button->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
button->setFixedWidth(32);
|
||||
} else {
|
||||
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
button->setText(buttonText);
|
||||
button->setFixedWidth(QWIDGETSIZE_MAX); // release fixed width
|
||||
button->setMinimumWidth(32);
|
||||
button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsButtonWidget::togglePopup()
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ public:
|
|||
void removeSettingsWidget(QWidget *toRemove) const;
|
||||
void setButtonIcon(QPixmap iconMap);
|
||||
void setButtonText(const QString &buttonText);
|
||||
void setCompact(bool compact);
|
||||
bool isCompact() const
|
||||
{
|
||||
return compact;
|
||||
};
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
|
@ -34,6 +39,8 @@ private slots:
|
|||
private:
|
||||
QHBoxLayout *layout;
|
||||
QToolButton *button;
|
||||
QString buttonText;
|
||||
bool compact;
|
||||
|
||||
public:
|
||||
SettingsPopupWidget *popup;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
#include "compact_push_button.h"
|
||||
|
||||
CompactPushButton::CompactPushButton(QWidget *parent) : QPushButton(parent)
|
||||
{
|
||||
setCheckable(true);
|
||||
setFixedHeight(32);
|
||||
|
||||
// default sizing
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
connect(this, &QPushButton::clicked, this, [] {
|
||||
// your popup logic here
|
||||
});
|
||||
}
|
||||
|
||||
void CompactPushButton::setButtonText(const QString &text)
|
||||
{
|
||||
fullText = text;
|
||||
|
||||
if (!compact) {
|
||||
setText(fullText);
|
||||
}
|
||||
|
||||
updateGeometryState();
|
||||
}
|
||||
|
||||
void CompactPushButton::setButtonIcon(const QIcon &icon)
|
||||
{
|
||||
setIcon(icon);
|
||||
}
|
||||
|
||||
void CompactPushButton::setCompact(bool enabled)
|
||||
{
|
||||
compact = enabled;
|
||||
|
||||
if (compact) {
|
||||
setText(QString()); // icon only
|
||||
} else {
|
||||
setText(fullText);
|
||||
}
|
||||
|
||||
updateGeometryState();
|
||||
}
|
||||
|
||||
void CompactPushButton::updateGeometryState()
|
||||
{
|
||||
const int buttonHeight = 32;
|
||||
|
||||
setMinimumHeight(buttonHeight);
|
||||
setMaximumHeight(buttonHeight);
|
||||
|
||||
if (compact) {
|
||||
setMinimumWidth(buttonHeight);
|
||||
setMaximumWidth(buttonHeight);
|
||||
} else {
|
||||
setMinimumWidth(0);
|
||||
setMaximumWidth(QWIDGETSIZE_MAX);
|
||||
}
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
int CompactPushButton::expandedWidth() const
|
||||
{
|
||||
QFontMetrics fm(font());
|
||||
|
||||
return fm.horizontalAdvance(fullText) + 48; // icon + padding
|
||||
}
|
||||
|
||||
int CompactPushButton::compactWidth() const
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef COCKATRICE_COMPACT_PUSH_BUTTON_H
|
||||
#define COCKATRICE_COMPACT_PUSH_BUTTON_H
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
class CompactPushButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CompactPushButton(QWidget *parent = nullptr);
|
||||
|
||||
void setButtonText(const QString &text);
|
||||
|
||||
void setButtonIcon(const QIcon &icon);
|
||||
|
||||
void setCompact(bool enabled);
|
||||
|
||||
int expandedWidth() const;
|
||||
|
||||
int compactWidth() const;
|
||||
|
||||
private:
|
||||
void updateGeometryState();
|
||||
|
||||
private:
|
||||
QString fullText;
|
||||
bool compact = false;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_COMPACT_PUSH_BUTTON_H
|
||||
|
|
@ -5,16 +5,9 @@
|
|||
#include <QGroupBox>
|
||||
|
||||
VisualDatabaseDisplayFilterToolbarWidget::VisualDatabaseDisplayFilterToolbarWidget(VisualDatabaseDisplayWidget *_parent)
|
||||
: QWidget(_parent), visualDatabaseDisplay(_parent)
|
||||
: FlowWidget(_parent, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff),
|
||||
visualDatabaseDisplay(_parent)
|
||||
{
|
||||
filterContainerLayout = new QHBoxLayout(this);
|
||||
filterContainerLayout->setContentsMargins(11, 0, 11, 0);
|
||||
filterContainerLayout->setSpacing(2);
|
||||
setLayout(filterContainerLayout);
|
||||
filterContainerLayout->setAlignment(Qt::AlignLeft);
|
||||
|
||||
setMaximumHeight(80);
|
||||
|
||||
connect(this, &VisualDatabaseDisplayFilterToolbarWidget::searchModelChanged, visualDatabaseDisplay,
|
||||
&VisualDatabaseDisplayWidget::onSearchModelChanged);
|
||||
|
||||
|
|
@ -131,10 +124,18 @@ void VisualDatabaseDisplayFilterToolbarWidget::initialize()
|
|||
filterLayout->addWidget(quickFilterFormatLegalityWidget);
|
||||
|
||||
// put everything into main layout
|
||||
filterContainerLayout->addWidget(sortGroupBox);
|
||||
filterContainerLayout->addWidget(filterGroupBox);
|
||||
filterContainerLayout->addStretch();
|
||||
filterContainerLayout->addWidget(quickFilterSaveLoadWidget);
|
||||
addWidget(sortGroupBox);
|
||||
addWidget(filterGroupBox);
|
||||
auto *spacer = new QWidget(this);
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
spacer->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
addWidget(spacer);
|
||||
addWidget(quickFilterSaveLoadWidget);
|
||||
addWidget(quickFilterSaveLoadWidget);
|
||||
|
||||
// Force a layout pass so sizeHint() is accurate
|
||||
layout()->activate();
|
||||
fullWidthHint = sizeHint().width();
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterToolbarWidget::retranslateUi()
|
||||
|
|
@ -155,4 +156,25 @@ void VisualDatabaseDisplayFilterToolbarWidget::retranslateUi()
|
|||
quickFilterSubTypeWidget->setButtonText(tr("Sub Type"));
|
||||
quickFilterSetWidget->setButtonText(tr("Sets"));
|
||||
quickFilterFormatLegalityWidget->setButtonText(tr("Formats"));
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterToolbarWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
updateCompactMode(event->size().width());
|
||||
}
|
||||
|
||||
void VisualDatabaseDisplayFilterToolbarWidget::updateCompactMode(int availableWidth)
|
||||
{
|
||||
const bool compact = availableWidth < fullWidthHint;
|
||||
|
||||
const QList<SettingsButtonWidget *> filterButtons = {
|
||||
quickFilterSaveLoadWidget, quickFilterNameWidget, quickFilterMainTypeWidget,
|
||||
quickFilterSubTypeWidget, quickFilterSetWidget, quickFilterFormatLegalityWidget,
|
||||
};
|
||||
|
||||
for (auto *btn : filterButtons) {
|
||||
if (btn->isCompact() != compact) // only act on transitions
|
||||
btn->setCompact(compact);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
class VisualDatabaseDisplayWidget;
|
||||
|
||||
class VisualDatabaseDisplayFilterToolbarWidget : public QWidget
|
||||
class VisualDatabaseDisplayFilterToolbarWidget : public FlowWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
|
@ -32,7 +32,6 @@ private:
|
|||
QGroupBox *filterGroupBox;
|
||||
QLabel *filterByLabel;
|
||||
|
||||
QHBoxLayout *filterContainerLayout;
|
||||
SettingsButtonWidget *quickFilterSaveLoadWidget;
|
||||
VisualDatabaseDisplayFilterSaveLoadWidget *saveLoadWidget;
|
||||
SettingsButtonWidget *quickFilterNameWidget;
|
||||
|
|
@ -45,6 +44,12 @@ private:
|
|||
VisualDatabaseDisplaySetFilterWidget *setFilterWidget;
|
||||
SettingsButtonWidget *quickFilterFormatLegalityWidget;
|
||||
VisualDatabaseDisplayFormatLegalityFilterWidget *formatLegalityWidget;
|
||||
|
||||
int fullWidthHint = 0;
|
||||
void updateCompactMode(int availableWidth);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_VISUAL_DATABASE_DISPLAY_FILTER_TOOLBAR_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
|
|||
connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance(),
|
||||
&SettingsCache::setVisualDatabaseDisplayCardSize);
|
||||
|
||||
searchContainer = new QWidget(this);
|
||||
searchLayout = new QHBoxLayout(searchContainer);
|
||||
searchContainer->setLayout(searchLayout);
|
||||
searchContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
|
||||
searchEdit = new SearchLineEdit();
|
||||
searchEdit->setObjectName("searchEdit");
|
||||
|
|
@ -152,10 +150,10 @@ void VisualDatabaseDisplayWidget::initialize()
|
|||
filterContainer->initialize();
|
||||
filterContainer->setVisible(true);
|
||||
|
||||
searchLayout->addWidget(colorFilterWidget);
|
||||
searchLayout->addWidget(clearFilterWidget);
|
||||
searchLayout->addWidget(searchEdit);
|
||||
searchLayout->addWidget(displayModeButton);
|
||||
searchContainer->addWidget(colorFilterWidget);
|
||||
searchContainer->addWidget(clearFilterWidget);
|
||||
searchContainer->addWidget(searchEdit);
|
||||
searchContainer->addWidget(displayModeButton);
|
||||
|
||||
mainLayout->addWidget(searchContainer);
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,7 @@ protected slots:
|
|||
void onDisplayModeChanged(bool checked);
|
||||
|
||||
private:
|
||||
QWidget *searchContainer;
|
||||
QHBoxLayout *searchLayout;
|
||||
FlowWidget *searchContainer;
|
||||
SearchLineEdit *searchEdit;
|
||||
QPushButton *displayModeButton;
|
||||
FilterTreeModel *filterModel;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ VisualDeckDisplayOptionsWidget::VisualDeckDisplayOptionsWidget(QWidget *parent)
|
|||
sortCriteriaButton->addSettingsWidget(sortLabel);
|
||||
sortCriteriaButton->addSettingsWidget(sortByListWidget);
|
||||
|
||||
displayTypeButton = new QPushButton(this);
|
||||
displayTypeButton = new CompactPushButton(this);
|
||||
connect(displayTypeButton, &QPushButton::clicked, this, &VisualDeckDisplayOptionsWidget::updateDisplayType);
|
||||
|
||||
groupAndSortLayout->addWidget(groupByLabel);
|
||||
|
|
@ -91,7 +91,8 @@ void VisualDeckDisplayOptionsWidget::retranslateUi()
|
|||
sortByLabel->setText(tr("Sort by:"));
|
||||
sortLabel->setText(tr("Click and drag to change the sort order within the groups"));
|
||||
sortCriteriaButton->setToolTip(tr("Configure how cards are sorted within their groups"));
|
||||
displayTypeButton->setText(tr("Toggle Layout: Overlap"));
|
||||
displayTypeButton->setButtonText(tr("Toggle Layout: Overlap"));
|
||||
displayTypeButton->setButtonIcon(QPixmap("theme:icons/scales"));
|
||||
displayTypeButton->setToolTip(
|
||||
tr("Change how cards are displayed within zones (i.e. overlapped or fully visible.)"));
|
||||
}
|
||||
|
|
@ -115,11 +116,32 @@ void VisualDeckDisplayOptionsWidget::updateDisplayType()
|
|||
// Update UI and emit signal
|
||||
switch (currentDisplayType) {
|
||||
case DisplayType::Flat:
|
||||
displayTypeButton->setText(tr("Toggle Layout: Flat"));
|
||||
displayTypeButton->setButtonText(tr("Toggle Layout: Flat"));
|
||||
displayTypeButton->setButtonIcon(QPixmap("theme:icons/scroll"));
|
||||
break;
|
||||
case DisplayType::Overlap:
|
||||
displayTypeButton->setText(tr("Toggle Layout: Overlap"));
|
||||
displayTypeButton->setButtonText(tr("Toggle Layout: Overlap"));
|
||||
displayTypeButton->setButtonIcon(QPixmap("theme:icons/scales"));
|
||||
break;
|
||||
}
|
||||
emit displayTypeChanged(currentDisplayType);
|
||||
}
|
||||
|
||||
void VisualDeckDisplayOptionsWidget::updateCompactMode(bool mode)
|
||||
{
|
||||
displayTypeButton->setCompact(mode);
|
||||
}
|
||||
|
||||
int VisualDeckDisplayOptionsWidget::expandedWidth() const
|
||||
{
|
||||
return groupByLabel->sizeHint().width() + groupByComboBox->sizeHint().width() + sortByLabel->sizeHint().width() +
|
||||
sortCriteriaButton->sizeHint().width() + displayTypeButton->expandedWidth() +
|
||||
(groupAndSortLayout->spacing() * 4);
|
||||
}
|
||||
|
||||
int VisualDeckDisplayOptionsWidget::compactWidth() const
|
||||
{
|
||||
return groupByLabel->sizeHint().width() + groupByComboBox->sizeHint().width() + sortByLabel->sizeHint().width() +
|
||||
sortCriteriaButton->sizeHint().width() + displayTypeButton->compactWidth() +
|
||||
(groupAndSortLayout->spacing() * 4);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ public slots:
|
|||
* Called when the application language changes.
|
||||
*/
|
||||
void retranslateUi();
|
||||
void updateCompactMode(bool mode);
|
||||
int expandedWidth() const;
|
||||
int compactWidth() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
|
@ -108,7 +111,7 @@ private:
|
|||
DisplayType currentDisplayType = DisplayType::Overlap;
|
||||
|
||||
/// Button used to toggle the display layout.
|
||||
QPushButton *displayTypeButton;
|
||||
CompactPushButton *displayTypeButton;
|
||||
|
||||
/// Label for the group-by selector.
|
||||
QLabel *groupByLabel;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "../general/layout_containers/flow_widget.h"
|
||||
#include "../tabs/visual_deck_editor/tab_deck_editor_visual.h"
|
||||
#include "../tabs/visual_deck_editor/tab_deck_editor_visual_tab_widget.h"
|
||||
#include "../utility/compact_push_button.h"
|
||||
#include "visual_deck_display_options_widget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
|
@ -69,7 +70,13 @@ VisualDeckEditorWidget::VisualDeckEditorWidget(QWidget *parent,
|
|||
|
||||
void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
|
||||
{
|
||||
searchBar = new QLineEdit(this);
|
||||
searchContainer = new QWidget(this);
|
||||
searchContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
searchLayout = new QHBoxLayout(searchContainer);
|
||||
searchContainer->setLayout(searchLayout);
|
||||
|
||||
searchBar = new QLineEdit(searchContainer);
|
||||
searchContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
connect(searchBar, &QLineEdit::returnPressed, this, [=, this]() {
|
||||
if (!searchBar->hasFocus())
|
||||
return;
|
||||
|
|
@ -80,6 +87,8 @@ void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
|
|||
}
|
||||
});
|
||||
|
||||
searchLayout->addWidget(searchBar);
|
||||
|
||||
setFocusProxy(searchBar);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
|
|
@ -133,13 +142,16 @@ void VisualDeckEditorWidget::initializeSearchBarAndCompleter()
|
|||
});
|
||||
|
||||
// Search button functionality
|
||||
searchPushButton = new QPushButton(this);
|
||||
searchPushButton = new CompactPushButton(searchContainer);
|
||||
searchPushButton->setButtonIcon(QPixmap("theme:icons/search"));
|
||||
connect(searchPushButton, &QPushButton::clicked, this, [=, this]() {
|
||||
ExactCard card = CardDatabaseManager::query()->getCard({searchBar->text()});
|
||||
if (card) {
|
||||
emit cardAdditionRequested(card);
|
||||
}
|
||||
});
|
||||
|
||||
searchLayout->addWidget(searchPushButton);
|
||||
}
|
||||
|
||||
void VisualDeckEditorWidget::initializeDisplayOptionsWidget()
|
||||
|
|
@ -156,18 +168,14 @@ void VisualDeckEditorWidget::initializeDisplayOptionsWidget()
|
|||
void VisualDeckEditorWidget::initializeDisplayOptionsAndSearchWidget()
|
||||
{
|
||||
initializeSearchBarAndCompleter();
|
||||
|
||||
initializeDisplayOptionsWidget();
|
||||
|
||||
displayOptionsAndSearch = new QWidget(this);
|
||||
displayOptionsAndSearchLayout = new QHBoxLayout(displayOptionsAndSearch);
|
||||
displayOptionsAndSearchLayout->setContentsMargins(0, 0, 0, 0);
|
||||
displayOptionsAndSearchLayout->setAlignment(Qt::AlignLeft);
|
||||
displayOptionsAndSearch->setLayout(displayOptionsAndSearchLayout);
|
||||
displayOptionsAndSearch = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
|
||||
|
||||
displayOptionsAndSearchLayout->addWidget(displayOptionsWidget);
|
||||
displayOptionsAndSearchLayout->addWidget(searchBar);
|
||||
displayOptionsAndSearchLayout->addWidget(searchPushButton);
|
||||
// We split into two sub-widgets here so that the searchBar and button wrap together. At this point, we've done
|
||||
// pretty much all we can and have reached our minimum size.
|
||||
displayOptionsAndSearch->addWidget(displayOptionsWidget);
|
||||
displayOptionsAndSearch->addWidget(searchContainer); // Expanding — fills remainder of its row
|
||||
}
|
||||
|
||||
void VisualDeckEditorWidget::initializeScrollAreaAndZoneContainer()
|
||||
|
|
@ -205,7 +213,7 @@ void VisualDeckEditorWidget::connectDeckListModel()
|
|||
void VisualDeckEditorWidget::retranslateUi()
|
||||
{
|
||||
searchBar->setPlaceholderText(tr("Type a card name here for suggestions from the database..."));
|
||||
searchPushButton->setText(tr("Quick search and add card"));
|
||||
searchPushButton->setButtonText(tr("Quick search and add card"));
|
||||
searchPushButton->setToolTip(tr("Search for closest match in the database (with auto-suggestions) and add "
|
||||
"preferred printing to the deck on pressing enter"));
|
||||
|
||||
|
|
@ -214,6 +222,44 @@ void VisualDeckEditorWidget::retranslateUi()
|
|||
}
|
||||
}
|
||||
|
||||
void VisualDeckEditorWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
updateCompactMode();
|
||||
}
|
||||
|
||||
void VisualDeckEditorWidget::updateCompactMode()
|
||||
{
|
||||
const int spacing = displayOptionsAndSearch->layout()->spacing();
|
||||
|
||||
const int available = displayOptionsAndSearch->width();
|
||||
|
||||
const int searchExpanded =
|
||||
searchBar->sizeHint().width() + searchPushButton->expandedWidth() + searchLayout->spacing();
|
||||
|
||||
const int fullWidth = displayOptionsWidget->expandedWidth() + spacing + searchExpanded;
|
||||
|
||||
const int displayCompactWidth = displayOptionsWidget->compactWidth() + spacing + searchExpanded;
|
||||
|
||||
// everything expanded
|
||||
if (available >= fullWidth) {
|
||||
displayOptionsWidget->updateCompactMode(false);
|
||||
searchPushButton->setCompact(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// only display compact
|
||||
if (available >= displayCompactWidth) {
|
||||
displayOptionsWidget->updateCompactMode(true);
|
||||
searchPushButton->setCompact(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// both compact
|
||||
displayOptionsWidget->updateCompactMode(true);
|
||||
searchPushButton->setCompact(true);
|
||||
}
|
||||
|
||||
void VisualDeckEditorWidget::updatePlaceholderVisibility()
|
||||
{
|
||||
if (placeholderWidget) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "../cards/card_size_widget.h"
|
||||
#include "../general/layout_containers/overlap_control_widget.h"
|
||||
#include "../quick_settings/settings_button_widget.h"
|
||||
#include "../utility/compact_push_button.h"
|
||||
#include "visual_deck_editor_placeholder_widget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
|
@ -39,6 +40,7 @@ class VisualDeckEditorWidget : public QWidget
|
|||
public:
|
||||
explicit VisualDeckEditorWidget(QWidget *parent, DeckListModel *deckListModel, QItemSelectionModel *selectionModel);
|
||||
void retranslateUi();
|
||||
void updateCompactMode();
|
||||
void clearAllDisplayWidgets();
|
||||
|
||||
void setDeckList(const DeckList &_deckListModel);
|
||||
|
|
@ -82,19 +84,23 @@ protected slots:
|
|||
void onHover(const ExactCard &hoveredCard);
|
||||
void onCardClick(QMouseEvent *event, CardInfoPictureWithTextOverlayWidget *instance, QString zoneName);
|
||||
void decklistModelReset();
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
int expandedWidthAll = -1;
|
||||
int expandedWidthDisplayCompact = -1;
|
||||
DeckListModel *deckListModel;
|
||||
QItemSelectionModel *selectionModel;
|
||||
QVBoxLayout *mainLayout;
|
||||
CardDatabaseModel *cardDatabaseModel;
|
||||
CardDatabaseDisplayModel *cardDatabaseDisplayModel;
|
||||
CardCompleterProxyModel *proxyModel;
|
||||
QWidget *searchContainer;
|
||||
QHBoxLayout *searchLayout;
|
||||
QCompleter *completer;
|
||||
QWidget *displayOptionsAndSearch;
|
||||
QHBoxLayout *displayOptionsAndSearchLayout;
|
||||
FlowWidget *displayOptionsAndSearch;
|
||||
VisualDeckDisplayOptionsWidget *displayOptionsWidget;
|
||||
QPushButton *searchPushButton;
|
||||
CompactPushButton *searchPushButton;
|
||||
QScrollArea *scrollArea;
|
||||
QWidget *zoneContainer;
|
||||
QVBoxLayout *zoneContainerLayout;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue