add splitter filters to ui
This commit is contained in:
@@ -89,6 +89,22 @@ void BeltSystem::setSplitterFilters(QPoint tile,
|
|||||||
it->second.filterB = filterB;
|
it->second.filterB = filterB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<BeltSystem::SplitterInfo> BeltSystem::getSplitterInfo(QPoint tile) const
|
||||||
|
{
|
||||||
|
const std::map<std::pair<int, int>, SplitterTile>::const_iterator it =
|
||||||
|
m_splitters.find(key(tile));
|
||||||
|
if (it == m_splitters.end())
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return SplitterInfo{
|
||||||
|
it->second.outputA,
|
||||||
|
it->second.outputB,
|
||||||
|
it->second.filterA,
|
||||||
|
it->second.filterB
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Port interface
|
// Port interface
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -52,6 +52,15 @@ public:
|
|||||||
const std::vector<ItemType>& filterA,
|
const std::vector<ItemType>& filterA,
|
||||||
const std::vector<ItemType>& filterB);
|
const std::vector<ItemType>& filterB);
|
||||||
|
|
||||||
|
struct SplitterInfo
|
||||||
|
{
|
||||||
|
Rotation outputA;
|
||||||
|
Rotation outputB;
|
||||||
|
std::vector<ItemType> filterA;
|
||||||
|
std::vector<ItemType> filterB;
|
||||||
|
};
|
||||||
|
std::optional<SplitterInfo> getSplitterInfo(QPoint tile) const;
|
||||||
|
|
||||||
// -- Port interface (buildings <-> belts) --------------------------------
|
// -- Port interface (buildings <-> belts) --------------------------------
|
||||||
// port.tile = the belt tile adjacent to the building
|
// port.tile = the belt tile adjacent to the building
|
||||||
// port.direction = direction items flow on that tile
|
// port.direction = direction items flow on that tile
|
||||||
|
|||||||
@@ -3,16 +3,21 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QListWidget>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
#include "BeltSystem.h"
|
||||||
#include "Building.h"
|
#include "Building.h"
|
||||||
#include "BuildingSystem.h"
|
#include "BuildingSystem.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
|
#include "ItemType.h"
|
||||||
|
#include "Rotation.h"
|
||||||
#include "Simulation.h"
|
#include "Simulation.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -57,6 +62,18 @@ bool isBeltLike(BuildingType type)
|
|||||||
return type == BuildingType::Belt || type == BuildingType::Splitter;
|
return type == BuildingType::Belt || type == BuildingType::Splitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString rotationLabel(Rotation r)
|
||||||
|
{
|
||||||
|
switch (r)
|
||||||
|
{
|
||||||
|
case Rotation::North: return "North (↑)";
|
||||||
|
case Rotation::East: return "East (→)";
|
||||||
|
case Rotation::South: return "South (↓)";
|
||||||
|
case Rotation::West: return "West (←)";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@@ -67,6 +84,7 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
|||||||
, m_sim(sim)
|
, m_sim(sim)
|
||||||
, m_config(config)
|
, m_config(config)
|
||||||
, m_singleId(kInvalidEntityId)
|
, m_singleId(kInvalidEntityId)
|
||||||
|
, m_splitterTile(0, 0)
|
||||||
{
|
{
|
||||||
m_layout = new QVBoxLayout(this);
|
m_layout = new QVBoxLayout(this);
|
||||||
m_layout->setContentsMargins(8, 8, 8, 8);
|
m_layout->setContentsMargins(8, 8, 8, 8);
|
||||||
@@ -76,18 +94,33 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
|||||||
m_titleLabel = new QLabel(this);
|
m_titleLabel = new QLabel(this);
|
||||||
m_recipeCombo = new QComboBox(this);
|
m_recipeCombo = new QComboBox(this);
|
||||||
m_clearBeltBtn = new QPushButton("Clear Items", this);
|
m_clearBeltBtn = new QPushButton("Clear Items", this);
|
||||||
|
m_filterALabel = new QLabel(this);
|
||||||
|
m_filterAList = new QListWidget(this);
|
||||||
|
m_filterBLabel = new QLabel(this);
|
||||||
|
m_filterBList = new QListWidget(this);
|
||||||
m_buffersLabel = new QLabel(this);
|
m_buffersLabel = new QLabel(this);
|
||||||
m_buffersLabel->setWordWrap(true);
|
m_buffersLabel->setWordWrap(true);
|
||||||
|
|
||||||
|
m_filterAList->setMaximumHeight(100);
|
||||||
|
m_filterBList->setMaximumHeight(100);
|
||||||
|
|
||||||
m_layout->addWidget(m_titleLabel);
|
m_layout->addWidget(m_titleLabel);
|
||||||
m_layout->addWidget(m_recipeCombo);
|
m_layout->addWidget(m_recipeCombo);
|
||||||
m_layout->addWidget(m_clearBeltBtn);
|
m_layout->addWidget(m_clearBeltBtn);
|
||||||
|
m_layout->addWidget(m_filterALabel);
|
||||||
|
m_layout->addWidget(m_filterAList);
|
||||||
|
m_layout->addWidget(m_filterBLabel);
|
||||||
|
m_layout->addWidget(m_filterBList);
|
||||||
m_layout->addWidget(m_buffersLabel);
|
m_layout->addWidget(m_buffersLabel);
|
||||||
|
|
||||||
connect(m_recipeCombo, qOverload<int>(&QComboBox::currentIndexChanged),
|
connect(m_recipeCombo, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
this, &SelectedBuildingPanel::onRecipeChanged);
|
this, &SelectedBuildingPanel::onRecipeChanged);
|
||||||
connect(m_clearBeltBtn, &QPushButton::clicked,
|
connect(m_clearBeltBtn, &QPushButton::clicked,
|
||||||
this, &SelectedBuildingPanel::onClearBelt);
|
this, &SelectedBuildingPanel::onClearBelt);
|
||||||
|
connect(m_filterAList, &QListWidget::itemChanged,
|
||||||
|
this, &SelectedBuildingPanel::onSplitterFilterChanged);
|
||||||
|
connect(m_filterBList, &QListWidget::itemChanged,
|
||||||
|
this, &SelectedBuildingPanel::onSplitterFilterChanged);
|
||||||
|
|
||||||
buildEmpty();
|
buildEmpty();
|
||||||
}
|
}
|
||||||
@@ -120,6 +153,10 @@ void SelectedBuildingPanel::buildEmpty()
|
|||||||
m_titleLabel->hide();
|
m_titleLabel->hide();
|
||||||
m_recipeCombo->hide();
|
m_recipeCombo->hide();
|
||||||
m_clearBeltBtn->hide();
|
m_clearBeltBtn->hide();
|
||||||
|
m_filterALabel->hide();
|
||||||
|
m_filterAList->hide();
|
||||||
|
m_filterBLabel->hide();
|
||||||
|
m_filterBList->hide();
|
||||||
m_buffersLabel->hide();
|
m_buffersLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +226,19 @@ void SelectedBuildingPanel::buildSingle(EntityId id)
|
|||||||
m_clearBeltBtn->hide();
|
m_clearBeltBtn->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (b->type == BuildingType::Splitter)
|
||||||
|
{
|
||||||
|
m_splitterTile = b->anchor;
|
||||||
|
buildSplitterFilters(m_splitterTile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_filterALabel->hide();
|
||||||
|
m_filterAList->hide();
|
||||||
|
m_filterBLabel->hide();
|
||||||
|
m_filterBList->hide();
|
||||||
|
}
|
||||||
|
|
||||||
refreshBuffers(b);
|
refreshBuffers(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,6 +379,10 @@ void SelectedBuildingPanel::buildMulti(const std::vector<EntityId>& ids)
|
|||||||
m_singleId = kInvalidEntityId;
|
m_singleId = kInvalidEntityId;
|
||||||
m_recipeCombo->hide();
|
m_recipeCombo->hide();
|
||||||
m_clearBeltBtn->hide();
|
m_clearBeltBtn->hide();
|
||||||
|
m_filterALabel->hide();
|
||||||
|
m_filterAList->hide();
|
||||||
|
m_filterBLabel->hide();
|
||||||
|
m_filterBList->hide();
|
||||||
m_buffersLabel->hide();
|
m_buffersLabel->hide();
|
||||||
|
|
||||||
std::map<BuildingType, int> counts;
|
std::map<BuildingType, int> counts;
|
||||||
@@ -371,6 +425,94 @@ void SelectedBuildingPanel::onRecipeChanged(int comboIndex)
|
|||||||
m_sim->buildings().setRecipe(m_singleId, recipeId.toStdString());
|
m_sim->buildings().setRecipe(m_singleId, recipeId.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SelectedBuildingPanel::buildSplitterFilters(QPoint splitterTile)
|
||||||
|
{
|
||||||
|
const std::optional<BeltSystem::SplitterInfo> info =
|
||||||
|
m_sim->belts().getSplitterInfo(splitterTile);
|
||||||
|
if (!info.has_value())
|
||||||
|
{
|
||||||
|
m_filterALabel->hide();
|
||||||
|
m_filterAList->hide();
|
||||||
|
m_filterBLabel->hide();
|
||||||
|
m_filterBList->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> items = allItemIds();
|
||||||
|
|
||||||
|
auto populateList = [&](QListWidget* list, QLabel* label,
|
||||||
|
const QString& dirLabel,
|
||||||
|
const std::vector<ItemType>& filter)
|
||||||
|
{
|
||||||
|
label->setText(dirLabel + " filter (empty = all):");
|
||||||
|
list->blockSignals(true);
|
||||||
|
list->clear();
|
||||||
|
for (const std::string& itemId : items)
|
||||||
|
{
|
||||||
|
QListWidgetItem* row = new QListWidgetItem(
|
||||||
|
QString::fromStdString(itemId), list);
|
||||||
|
const bool checked = filter.empty()
|
||||||
|
? false
|
||||||
|
: std::find(filter.begin(), filter.end(),
|
||||||
|
ItemType{itemId}) != filter.end();
|
||||||
|
row->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
||||||
|
row->setFlags(row->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
}
|
||||||
|
list->blockSignals(false);
|
||||||
|
label->show();
|
||||||
|
list->show();
|
||||||
|
};
|
||||||
|
|
||||||
|
populateList(m_filterAList, m_filterALabel,
|
||||||
|
rotationLabel(info->outputA), info->filterA);
|
||||||
|
populateList(m_filterBList, m_filterBLabel,
|
||||||
|
rotationLabel(info->outputB), info->filterB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectedBuildingPanel::onSplitterFilterChanged()
|
||||||
|
{
|
||||||
|
if (m_singleId == kInvalidEntityId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto collectFilter = [](QListWidget* list) -> std::vector<ItemType>
|
||||||
|
{
|
||||||
|
std::vector<ItemType> filter;
|
||||||
|
for (int i = 0; i < list->count(); ++i)
|
||||||
|
{
|
||||||
|
const QListWidgetItem* row = list->item(i);
|
||||||
|
if (row->checkState() == Qt::Checked)
|
||||||
|
{
|
||||||
|
filter.push_back(ItemType{row->text().toStdString()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
m_sim->belts().setSplitterFilters(
|
||||||
|
m_splitterTile,
|
||||||
|
collectFilter(m_filterAList),
|
||||||
|
collectFilter(m_filterBList));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SelectedBuildingPanel::allItemIds() const
|
||||||
|
{
|
||||||
|
std::set<std::string> seen;
|
||||||
|
for (const RecipeDef& recipe : m_config->recipes.recipes)
|
||||||
|
{
|
||||||
|
for (const RecipeIngredient& ing : recipe.inputs)
|
||||||
|
{
|
||||||
|
seen.insert(ing.item);
|
||||||
|
}
|
||||||
|
for (const RecipeOutput& out : recipe.outputs)
|
||||||
|
{
|
||||||
|
seen.insert(out.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::vector<std::string>(seen.begin(), seen.end());
|
||||||
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::onClearBelt()
|
void SelectedBuildingPanel::onClearBelt()
|
||||||
{
|
{
|
||||||
std::vector<QPoint> tiles;
|
std::vector<QPoint> tiles;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Building.h"
|
#include "Building.h"
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
class Simulation;
|
class Simulation;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
class QListWidget;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QVBoxLayout;
|
class QVBoxLayout;
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ public slots:
|
|||||||
private slots:
|
private slots:
|
||||||
void onRecipeChanged(int comboIndex);
|
void onRecipeChanged(int comboIndex);
|
||||||
void onClearBelt();
|
void onClearBelt();
|
||||||
|
void onSplitterFilterChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void rebuild();
|
void rebuild();
|
||||||
@@ -41,8 +44,10 @@ private:
|
|||||||
void buildSingle(EntityId id);
|
void buildSingle(EntityId id);
|
||||||
void buildMulti(const std::vector<EntityId>& ids);
|
void buildMulti(const std::vector<EntityId>& ids);
|
||||||
void refreshBuffers(const Building* b);
|
void refreshBuffers(const Building* b);
|
||||||
|
void buildSplitterFilters(QPoint splitterTile);
|
||||||
const RecipeDef* findRecipe(const Building* b) const;
|
const RecipeDef* findRecipe(const Building* b) const;
|
||||||
const ShipDef* findShipDef(const std::string& id) const;
|
const ShipDef* findShipDef(const std::string& id) const;
|
||||||
|
std::vector<std::string> allItemIds() const;
|
||||||
|
|
||||||
Simulation* m_sim;
|
Simulation* m_sim;
|
||||||
const GameConfig* m_config;
|
const GameConfig* m_config;
|
||||||
@@ -52,8 +57,13 @@ private:
|
|||||||
QLabel* m_titleLabel;
|
QLabel* m_titleLabel;
|
||||||
QComboBox* m_recipeCombo;
|
QComboBox* m_recipeCombo;
|
||||||
QPushButton* m_clearBeltBtn;
|
QPushButton* m_clearBeltBtn;
|
||||||
|
QLabel* m_filterALabel;
|
||||||
|
QListWidget* m_filterAList;
|
||||||
|
QLabel* m_filterBLabel;
|
||||||
|
QListWidget* m_filterBList;
|
||||||
QLabel* m_buffersLabel;
|
QLabel* m_buffersLabel;
|
||||||
|
|
||||||
EntityId m_singleId;
|
EntityId m_singleId;
|
||||||
|
QPoint m_splitterTile;
|
||||||
std::string m_currentRecipeId;
|
std::string m_currentRecipeId;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user