From 19407954ed9a602247af6bc3719aab4d6fe59509 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Mon, 11 Sep 2023 18:01:53 +0200 Subject: [PATCH] Object picker implemented --- mapeditor/mapsettings/abstractsettings.h | 6 +- mapeditor/mapview.cpp | 22 ++ mapeditor/mapview.h | 1 + mapeditor/playerparams.cpp | 50 +++- mapeditor/playerparams.h | 4 + mapeditor/playerparams.ui | 298 +++++++++++++---------- mapeditor/scenelayer.cpp | 77 ++++++ mapeditor/scenelayer.h | 33 ++- 8 files changed, 359 insertions(+), 132 deletions(-) diff --git a/mapeditor/mapsettings/abstractsettings.h b/mapeditor/mapsettings/abstractsettings.h index 827628778..9f7a53fbc 100644 --- a/mapeditor/mapsettings/abstractsettings.h +++ b/mapeditor/mapsettings/abstractsettings.h @@ -30,9 +30,9 @@ public: virtual void initialize(const CMap & map) = 0; virtual void update(CMap & map) = 0; - std::string getTownName(const CMap & map, int objectIdx); - std::string getHeroName(const CMap & map, int objectIdx); - std::string getMonsterName(const CMap & map, int objectIdx); + static std::string getTownName(const CMap & map, int objectIdx); + static std::string getHeroName(const CMap & map, int objectIdx); + static std::string getMonsterName(const CMap & map, int objectIdx); static JsonNode conditionToJson(const EventCondition & event); diff --git a/mapeditor/mapview.cpp b/mapeditor/mapview.cpp index 715dea10b..dc2650884 100644 --- a/mapeditor/mapview.cpp +++ b/mapeditor/mapview.cpp @@ -198,6 +198,9 @@ void MapView::mousePressEvent(QMouseEvent *event) auto * sc = static_cast(scene()); if(!sc || !controller->map()) return; + + if(sc->objectPickerView.isVisible()) + return; mouseStart = mapToScene(event->pos()); tileStart = tilePrev = int3(mouseStart.x() / 32, mouseStart.y() / 32, sc->level); @@ -338,6 +341,22 @@ void MapView::mouseReleaseEvent(QMouseEvent *event) if(rubberBand) rubberBand->hide(); + + if(sc->objectPickerView.isVisible()) + { + if(event->button() == Qt::RightButton) + sc->objectPickerView.discard(); + + if(event->button() == Qt::LeftButton) + { + mouseStart = mapToScene(event->pos()); + tileStart = tilePrev = int3(mouseStart.x() / 32, mouseStart.y() / 32, sc->level); + if(auto * pickedObject = sc->selectionObjectsView.selectObjectAt(tileStart.x, tileStart.y)) + sc->objectPickerView.select(pickedObject); + } + + return; + } switch(selectionTool) { @@ -547,6 +566,7 @@ MapScene::MapScene(int lvl): terrainView(this), objectsView(this), selectionObjectsView(this), + objectPickerView(this), isTerrainSelected(false), isObjectSelected(false) { @@ -562,6 +582,7 @@ std::list MapScene::getAbstractLayers() &objectsView, &gridView, &passabilityView, + &objectPickerView, &selectionTerrainView, &selectionObjectsView }; @@ -575,6 +596,7 @@ void MapScene::updateViews() objectsView.show(true); selectionTerrainView.show(true); selectionObjectsView.show(true); + objectPickerView.show(true); } void MapScene::terrainSelected(bool anythingSelected) diff --git a/mapeditor/mapview.h b/mapeditor/mapview.h index 009f40ac6..b5d8d0e1c 100644 --- a/mapeditor/mapview.h +++ b/mapeditor/mapview.h @@ -66,6 +66,7 @@ public: TerrainLayer terrainView; ObjectsLayer objectsView; SelectionObjectsLayer selectionObjectsView; + ObjectPickerLayer objectPickerView; signals: void selected(bool anything); diff --git a/mapeditor/playerparams.cpp b/mapeditor/playerparams.cpp index 9734f8f68..d72ae766c 100644 --- a/mapeditor/playerparams.cpp +++ b/mapeditor/playerparams.cpp @@ -11,6 +11,7 @@ #include "StdInc.h" #include "playerparams.h" #include "ui_playerparams.h" +#include "mapsettings/abstractsettings.h" #include "../lib/CTownHandler.h" #include "../lib/constants/StringConstants.h" @@ -87,7 +88,8 @@ PlayerParams::PlayerParams(MapController & ctrl, int playerId, QWidget *parent) { if(playerInfo.hasMainTown && playerInfo.posOfMainTown == town->pos) foundMainTown = townIndex; - const auto name = ctown->faction ? town->getObjectName() : town->getNameTranslated() + ", (random)"; + + const auto name = AbstractSettings::getTownName(*controller.map(), i); ui->mainTown->addItem(tr(name.c_str()), QVariant::fromValue(i)); ++townIndex; } @@ -186,3 +188,49 @@ void PlayerParams::on_playerColorCombo_activated(int index) } } + +void PlayerParams::on_townSelect_clicked() +{ + auto pred = [this](const CGObjectInstance * obj) -> bool + { + if(auto town = dynamic_cast(obj)) + return town->getOwner().getNum() == playerColor; + return false; + }; + + std::vector> pickers; + pickers.emplace_back(controller.scene(0)->objectPickerView); + if(controller.map()->twoLevel) + pickers.emplace_back(controller.scene(1)->objectPickerView); + + for(auto l : pickers) + { + l.get().highlight(pred); + l.get().update(); + QObject::connect(&l.get(), &ObjectPickerLayer::selectionMade, this, &PlayerParams::onTownPicked); + } + + dynamic_cast(parent()->parent()->parent()->parent())->hide(); +} + +void PlayerParams::onTownPicked(const CGObjectInstance * obj) +{ + dynamic_cast(parent()->parent()->parent()->parent())->show(); + + std::vector> pickers; + pickers.emplace_back(controller.scene(0)->objectPickerView); + if(controller.map()->twoLevel) + pickers.emplace_back(controller.scene(1)->objectPickerView); + + for(auto l : pickers) + { + l.get().clear(); + l.get().update(); + QObject::disconnect(&l.get(), &ObjectPickerLayer::selectionMade, this, &PlayerParams::onTownPicked); + } + + if(!obj) //discarded + return; + + +} diff --git a/mapeditor/playerparams.h b/mapeditor/playerparams.h index 2aaff5384..0faa030b1 100644 --- a/mapeditor/playerparams.h +++ b/mapeditor/playerparams.h @@ -28,6 +28,8 @@ public: PlayerInfo playerInfo; int playerColor; + + void onTownPicked(const CGObjectInstance *); private slots: void on_radioHuman_toggled(bool checked); @@ -46,6 +48,8 @@ private slots: void on_playerColorCombo_activated(int index); + void on_townSelect_clicked(); + private: Ui::PlayerParams *ui; diff --git a/mapeditor/playerparams.ui b/mapeditor/playerparams.ui index 811fd626e..d2947a2a2 100644 --- a/mapeditor/playerparams.ui +++ b/mapeditor/playerparams.ui @@ -6,7 +6,7 @@ 0 0 - 505 + 614 160 @@ -25,7 +25,7 @@ - + 0 @@ -49,136 +49,180 @@ - - - - - - 0 - 0 - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + CPU only + + + + + + + + 0 + 0 + + + + Human/CPU + + + + + + + Team + + + + + + + + 0 + 0 + + + + + - - - - - 0 - 0 - - - - Generate hero at main - - + + + + + + Color + + + + + + + + 0 + 0 + + + + + + + + Main town + + + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + (default) + + + + + + + + ... + + + + + + + + + + 0 + 0 + + + + Generate hero at main + + + + - - - - - 0 - 0 - - - - Random faction - - - - - - - Team - - - - - - - - 0 - 0 - - - - CPU only - - - - - - - - 0 - 0 - - - - Human/CPU - - - - - - - true - - - - 0 - 0 - - - - Qt::ClickFocus - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::NoSelection - - - - - - - - 0 - 0 - + + + + 0 - - (default) - + + + true + + + + 0 + 0 + + + + Qt::ClickFocus + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::NoSelection + + - - - - - - Main town - - - - - - - - 0 - 0 - - - - - - - - Color - - + + + + + 0 + 0 + + + + Random faction + + + + diff --git a/mapeditor/scenelayer.cpp b/mapeditor/scenelayer.cpp index 5b4076608..635667228 100644 --- a/mapeditor/scenelayer.cpp +++ b/mapeditor/scenelayer.cpp @@ -112,6 +112,83 @@ void PassabilityLayer::update() redraw(); } +ObjectPickerLayer::ObjectPickerLayer(MapSceneBase * s): AbstractLayer(s) +{ +} + +void ObjectPickerLayer::highlight(std::function predicate) +{ + if(!map) + return; + + for(int j = 0; j < map->height; ++j) + { + for(int i = 0; i < map->width; ++i) + { + auto tl = map->getTile(int3(i, j, scene->level)); + auto * obj = tl.topVisitableObj(); + if(!obj && !tl.blockingObjects.empty()) + obj = tl.blockingObjects.front(); + + if(obj && predicate(obj)) + possibleObjects.insert(obj); + } + } + + isActive = true; +} + +bool ObjectPickerLayer::isVisible() const +{ + return isShown && isActive; +} + +void ObjectPickerLayer::clear() +{ + possibleObjects.clear(); + isActive = false; +} + +void ObjectPickerLayer::update() +{ + if(!map) + return; + + pixmap.reset(new QPixmap(map->width * 32, map->height * 32)); + pixmap->fill(Qt::transparent); + if(isActive) + pixmap->fill(QColor(255, 255, 255, 128)); + + + QPainter painter(pixmap.get()); + painter.setCompositionMode(QPainter::CompositionMode_Source); + for(auto * obj : possibleObjects) + { + if(obj->pos.z != scene->level) + continue; + + for(auto & pos : obj->getBlockedPos()) + painter.fillRect(pos.x * 32, pos.y * 32, 32, 32, QColor(255, 211, 0, 64)); + } + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + redraw(); +} + +void ObjectPickerLayer::select(const CGObjectInstance * obj) +{ + if(obj && possibleObjects.count(obj)) + { + clear(); + emit selectionMade(obj); + } +} + +void ObjectPickerLayer::discard() +{ + clear(); + emit selectionMade(nullptr); +} + SelectionTerrainLayer::SelectionTerrainLayer(MapSceneBase * s): AbstractLayer(s) { } diff --git a/mapeditor/scenelayer.h b/mapeditor/scenelayer.h index 3d3cd6a3f..2b0a127fd 100644 --- a/mapeditor/scenelayer.h +++ b/mapeditor/scenelayer.h @@ -116,7 +116,7 @@ public: void update() override; - void draw(bool onlyDirty = true); //TODO: implement dirty + void draw(bool onlyDirty = true); void setDirty(int x, int y); void setDirty(const CGObjectInstance * object); @@ -127,6 +127,37 @@ private: }; +class ObjectPickerLayer: public AbstractLayer +{ + Q_OBJECT +public: + ObjectPickerLayer(MapSceneBase * s); + + void update() override; + bool isVisible() const; + + template + void highlight() + { + highlight([](const CGObjectInstance * o){ return dynamic_cast(o); }); + } + + void highlight(std::function predicate); + + void clear(); + + void select(const CGObjectInstance *); + void discard(); + +signals: + void selectionMade(const CGObjectInstance *); + +private: + bool isActive = false; + std::set possibleObjects; +}; + + class SelectionObjectsLayer: public AbstractLayer { Q_OBJECT