add splitter filters to ui

This commit is contained in:
2026-04-25 21:27:39 +02:00
parent b21fc352b4
commit 134f23d69b
4 changed files with 177 additions and 0 deletions

View File

@@ -3,16 +3,21 @@
#include <algorithm>
#include <cctype>
#include <map>
#include <set>
#include <string>
#include <QComboBox>
#include <QLabel>
#include <QListWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include "BeltSystem.h"
#include "Building.h"
#include "BuildingSystem.h"
#include "BuildingType.h"
#include "ItemType.h"
#include "Rotation.h"
#include "Simulation.h"
namespace
@@ -57,6 +62,18 @@ bool isBeltLike(BuildingType type)
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
@@ -67,6 +84,7 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
, m_sim(sim)
, m_config(config)
, m_singleId(kInvalidEntityId)
, m_splitterTile(0, 0)
{
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(8, 8, 8, 8);
@@ -76,18 +94,33 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
m_titleLabel = new QLabel(this);
m_recipeCombo = new QComboBox(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->setWordWrap(true);
m_filterAList->setMaximumHeight(100);
m_filterBList->setMaximumHeight(100);
m_layout->addWidget(m_titleLabel);
m_layout->addWidget(m_recipeCombo);
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);
connect(m_recipeCombo, qOverload<int>(&QComboBox::currentIndexChanged),
this, &SelectedBuildingPanel::onRecipeChanged);
connect(m_clearBeltBtn, &QPushButton::clicked,
this, &SelectedBuildingPanel::onClearBelt);
connect(m_filterAList, &QListWidget::itemChanged,
this, &SelectedBuildingPanel::onSplitterFilterChanged);
connect(m_filterBList, &QListWidget::itemChanged,
this, &SelectedBuildingPanel::onSplitterFilterChanged);
buildEmpty();
}
@@ -120,6 +153,10 @@ void SelectedBuildingPanel::buildEmpty()
m_titleLabel->hide();
m_recipeCombo->hide();
m_clearBeltBtn->hide();
m_filterALabel->hide();
m_filterAList->hide();
m_filterBLabel->hide();
m_filterBList->hide();
m_buffersLabel->hide();
}
@@ -189,6 +226,19 @@ void SelectedBuildingPanel::buildSingle(EntityId id)
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);
}
@@ -329,6 +379,10 @@ void SelectedBuildingPanel::buildMulti(const std::vector<EntityId>& ids)
m_singleId = kInvalidEntityId;
m_recipeCombo->hide();
m_clearBeltBtn->hide();
m_filterALabel->hide();
m_filterAList->hide();
m_filterBLabel->hide();
m_filterBList->hide();
m_buffersLabel->hide();
std::map<BuildingType, int> counts;
@@ -371,6 +425,94 @@ void SelectedBuildingPanel::onRecipeChanged(int comboIndex)
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()
{
std::vector<QPoint> tiles;