diff --git a/src/noggit/MapTile.h b/src/noggit/MapTile.h index 25e6ee46..5f82ce77 100644 --- a/src/noggit/MapTile.h +++ b/src/noggit/MapTile.h @@ -123,6 +123,8 @@ public: bool tile_is_being_reloaded() const { return _tile_is_being_reloaded; } + std::vector* get_uids() { return &uids; } + private: tile_mode _mode; bool _tile_is_being_reloaded; diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index ebf0bd29..40ae05be 100644 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -2262,6 +2262,18 @@ void MapView::doSelection (bool selectTerrainOnly) _world->remove_from_selection(hit); } } + else if (hit.which() == eEntry_MapChunk) + { + _world->range_add_to_selection(_cursor_pos, objectEditor->brushRadius(), false); + } + + } + else if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) + { + if (hit.which() == eEntry_MapChunk) + { + _world->range_add_to_selection(_cursor_pos, objectEditor->brushRadius(), true); + } } else { @@ -2365,6 +2377,9 @@ void MapView::draw_map() case editing_mode::holes: radius = holeTool->brushRadius(); break; + case editing_mode::object: + radius = objectEditor->brushRadius(); + break; } //! \note Select terrain below mouse, if no item selected or the item is map. @@ -2696,6 +2711,7 @@ void MapView::mouseMoveEvent (QMouseEvent* event) { terrainTool->moveVertices (_world.get(), -relative_movement.dy() / YSENS); } + } @@ -2729,7 +2745,9 @@ void MapView::mouseMoveEvent (QMouseEvent* event) case editing_mode::holes: holeTool->changeRadius(relative_movement.dx() / XSENS); break; - + case editing_mode::object: + objectEditor->changeRadius(relative_movement.dx() / XSENS); + break; } } @@ -2752,6 +2770,14 @@ void MapView::mouseMoveEvent (QMouseEvent* event) } } + if (leftMouse && (_mod_shift_down || _mod_ctrl_down)) + { + if (terrainMode == editing_mode::object) + { + doSelection(false); // Required for radius selection in Object mode + } + } + if (_display_mode == display_mode::in_2D && leftMouse && _mod_alt_down && _mod_shift_down) { strafing = ((relative_movement.dx() / XSENS) / -1) * 5.0f; diff --git a/src/noggit/World.cpp b/src/noggit/World.cpp index 2cb2f2c3..99c4cd30 100644 --- a/src/noggit/World.cpp +++ b/src/noggit/World.cpp @@ -2282,3 +2282,65 @@ void World::update_models_by_filename() need_model_updates = false; } + +void World::range_add_to_selection(math::vector_3d const& pos, float radius, bool remove) +{ + for_tile_at(pos, [this, pos, radius, remove](MapTile* tile) + { + std::vector* uids = tile->get_uids(); + + if (remove) + { + for (uint32_t uid : *uids) + { + auto instance = _model_instance_storage.get_instance(uid); + + if (instance.get().which() == eEntry_WMO) + { + auto wmo = boost::get(instance.get()); + + if ((wmo->pos - pos).length() <= radius && is_selected(wmo)) + { + remove_from_selection(wmo); + } + + } else + { + auto model = boost::get(instance.get()); + + if ((model->pos - pos).length() <= radius && is_selected(model)) + { + remove_from_selection(model); + } + } + } + } + else + { + for (uint32_t uid : *uids) + { + auto instance = _model_instance_storage.get_instance(uid); + + if (instance.get().which() == eEntry_WMO) + { + auto wmo = boost::get(instance.get()); + + if ((wmo->pos - pos).length() <= radius && !is_selected(wmo)) + { + add_to_selection(wmo); + } + + } else + { + auto model = boost::get(instance.get()); + + if ((model->pos - pos).length() <= radius && !is_selected(model)) + { + add_to_selection(model); + } + } + } + } + + }); +} diff --git a/src/noggit/World.h b/src/noggit/World.h index 45c169ff..067dd774 100644 --- a/src/noggit/World.h +++ b/src/noggit/World.h @@ -163,6 +163,7 @@ public: void remove_from_selection(std::uint32_t uid); void reset_selection(); void delete_selected_models(); + void range_add_to_selection(math::vector_3d const& pos, float radius, bool remove); enum class m2_scaling_type { diff --git a/src/noggit/ui/ObjectEditor.cpp b/src/noggit/ui/ObjectEditor.cpp index ba9fc473..c112f712 100644 --- a/src/noggit/ui/ObjectEditor.cpp +++ b/src/noggit/ui/ObjectEditor.cpp @@ -53,6 +53,19 @@ namespace noggit { auto layout = new QFormLayout (this); + _radius_spin = new QDoubleSpinBox (this); + _radius_spin->setRange (0.0f, 100.0f); + _radius_spin->setDecimals (2); + _radius_spin->setValue (_radius); + + layout->addRow ("Radius:", _radius_spin); + + _radius_slider = new QSlider (Qt::Orientation::Horizontal, this); + _radius_slider->setRange (0, 100); + _radius_slider->setSliderPosition (_radius); + + layout->addRow (_radius_slider); + QGroupBox *copyBox = new QGroupBox("Copy options", this); auto copy_layout = new QFormLayout (copyBox); @@ -222,6 +235,24 @@ namespace noggit scaleRangeStart->setValue(paste_params->minScale); scaleRangeEnd->setValue(paste_params->maxScale); + connect ( _radius_spin, qOverload (&QDoubleSpinBox::valueChanged) + , [&] (double v) + { + _radius = v; + QSignalBlocker const blocker(_radius_slider); + _radius_slider->setSliderPosition ((int)std::round (v)); + } + ); + + connect ( _radius_slider, &QSlider::valueChanged + , [&] (int v) + { + _radius = v; + QSignalBlocker const blocker(_radius_spin); + _radius_spin->setValue(v); + } + ); + connect ( rotRangeStart, qOverload (&QDoubleSpinBox::valueChanged) , [=] (double v) { @@ -347,6 +378,11 @@ namespace noggit } } + void object_editor::changeRadius(float change) + { + _radius_spin->setValue (_radius + change); + } + void object_editor::showImportModels() { modelImport->show(); diff --git a/src/noggit/ui/ObjectEditor.h b/src/noggit/ui/ObjectEditor.h index bbf3f888..cbbf3c59 100644 --- a/src/noggit/ui/ObjectEditor.h +++ b/src/noggit/ui/ObjectEditor.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include @@ -72,12 +74,21 @@ namespace noggit ); void togglePasteMode(); + void changeRadius(float change); + + float brushRadius() const { return _radius; } + model_import *modelImport; rotation_editor* rotationEditor; helper_models* helper_models_widget; QSize sizeHint() const override; private: + float _radius = 15.0f; + + QSlider* _radius_slider; + QDoubleSpinBox* _radius_spin; + QSettings* _settings; QButtonGroup* pasteModeGroup;