mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
feat(editor): select all, recent zones, minimap selection highlights
- Ctrl+A selects all placed objects, context menu has Select All item - selectAll() added to ObjectPlacer, works with multi-select transforms - Recent Zones submenu in File menu (last 8 loaded zones, deduplicated) - Minimap: selected objects shown as white dots with gold ring outline vs yellow dots for unselected objects - Help panel updated with Ctrl+A and Ctrl+Shift+Click documentation
This commit is contained in:
parent
ddf97e9b8a
commit
533c218983
5 changed files with 49 additions and 3 deletions
|
|
@ -302,6 +302,10 @@ void EditorApp::processEvents() {
|
|||
ui_.openNewTerrainDialog();
|
||||
if (sc == SDL_SCANCODE_O && (event.key.keysym.mod & KMOD_CTRL))
|
||||
ui_.openLoadDialog();
|
||||
if (sc == SDL_SCANCODE_A && (event.key.keysym.mod & KMOD_CTRL)) {
|
||||
objectPlacer_.selectAll();
|
||||
showToast("Selected " + std::to_string(objectPlacer_.selectionCount()) + " objects");
|
||||
}
|
||||
// Ctrl+Y = Redo (alternate binding)
|
||||
if (sc == SDL_SCANCODE_Y && (event.key.keysym.mod & KMOD_CTRL)) {
|
||||
if (terrainEditor_.history().canRedo()) {
|
||||
|
|
@ -699,6 +703,13 @@ void EditorApp::loadADT(const std::string& mapName, int tileX, int tileY) {
|
|||
loadedTileX_ = tileX;
|
||||
loadedTileY_ = tileY;
|
||||
|
||||
// Track recent zones (deduplicate, max 8)
|
||||
recentZones_.erase(std::remove_if(recentZones_.begin(), recentZones_.end(),
|
||||
[&](const RecentZone& rz) { return rz.mapName == mapName && rz.tileX == tileX && rz.tileY == tileY; }),
|
||||
recentZones_.end());
|
||||
recentZones_.insert(recentZones_.begin(), {mapName, tileX, tileY});
|
||||
if (recentZones_.size() > 8) recentZones_.resize(8);
|
||||
|
||||
// Position camera at terrain center using actual chunk positions
|
||||
if (mesh.validChunkCount > 0) {
|
||||
auto& firstChunk = mesh.chunks[0];
|
||||
|
|
|
|||
|
|
@ -138,12 +138,17 @@ private:
|
|||
bool autoSaveEnabled_ = true;
|
||||
bool showQuitConfirm_ = false;
|
||||
|
||||
// Recent zones
|
||||
struct RecentZone { std::string mapName; int tileX; int tileY; };
|
||||
std::vector<RecentZone> recentZones_;
|
||||
|
||||
// Toast notifications
|
||||
struct Toast { std::string msg; float timer; };
|
||||
std::vector<Toast> toasts_;
|
||||
public:
|
||||
void showToast(const std::string& msg, float duration = 3.0f);
|
||||
const std::vector<Toast>& getToasts() const { return toasts_; }
|
||||
const std::vector<RecentZone>& getRecentZones() const { return recentZones_; }
|
||||
void updateToasts(float dt);
|
||||
private:
|
||||
size_t lastObjCount_ = 0;
|
||||
|
|
|
|||
|
|
@ -254,6 +254,16 @@ void EditorUI::renderMenuBar(EditorApp& app) {
|
|||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Recent Zones", !app.getRecentZones().empty())) {
|
||||
for (const auto& rz : app.getRecentZones()) {
|
||||
char label[128];
|
||||
std::snprintf(label, sizeof(label), "%s [%d, %d]",
|
||||
rz.mapName.c_str(), rz.tileX, rz.tileY);
|
||||
if (ImGui::MenuItem(label))
|
||||
app.loadADT(rz.mapName, rz.tileX, rz.tileY);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Content Packs (.wcp)")) {
|
||||
static char wcpImportPath[256] = "content.wcp";
|
||||
ImGui::InputText("Path##wcp", wcpImportPath, sizeof(wcpImportPath));
|
||||
|
|
@ -489,7 +499,9 @@ void EditorUI::renderMenuBar(EditorApp& app) {
|
|||
ImGui::Text("Quick Actions:");
|
||||
ImGui::BulletText("Ctrl+N — new terrain");
|
||||
ImGui::BulletText("Ctrl+O — load map tile");
|
||||
ImGui::BulletText("Ctrl+A — select all objects");
|
||||
ImGui::BulletText("Alt+Click — eyedropper (paint mode)");
|
||||
ImGui::BulletText("Ctrl+Shift+Click — add to selection");
|
||||
ImGui::BulletText("Middle-drag — orbit camera");
|
||||
ImGui::Separator();
|
||||
ImGui::Text("View:");
|
||||
|
|
@ -2044,6 +2056,9 @@ void EditorUI::renderContextMenu(EditorApp& app) {
|
|||
else { app.getNpcSpawner().removeCreature(app.getNpcSpawner().getSelectedIndex()); }
|
||||
app.markObjectsDirty();
|
||||
}
|
||||
if (ImGui::MenuItem("Select All", "Ctrl+A")) {
|
||||
app.getObjectPlacer().selectAll();
|
||||
}
|
||||
if (ImGui::MenuItem("Deselect")) {
|
||||
app.getObjectPlacer().clearSelection();
|
||||
app.getNpcSpawner().clearSelection();
|
||||
|
|
@ -2110,7 +2125,7 @@ void EditorUI::renderMinimap(EditorApp& app) {
|
|||
}
|
||||
}
|
||||
|
||||
// Draw objects as yellow dots
|
||||
// Draw objects (yellow=normal, white+ring=selected)
|
||||
float tileNW_X = (32.0f - static_cast<float>(terrain->coord.y)) * 533.33333f;
|
||||
float tileNW_Y = (32.0f - static_cast<float>(terrain->coord.x)) * 533.33333f;
|
||||
for (const auto& obj : app.getObjectPlacer().getObjects()) {
|
||||
|
|
@ -2118,7 +2133,12 @@ void EditorUI::renderMinimap(EditorApp& app) {
|
|||
float v = (tileNW_Y - obj.position.y) / 533.33333f;
|
||||
if (u >= 0 && u <= 1 && v >= 0 && v <= 1) {
|
||||
ImVec2 pt(origin.x + v * avail.x, origin.y + u * (16 * cellH));
|
||||
dl->AddCircleFilled(pt, 2.0f, IM_COL32(255, 220, 50, 200));
|
||||
if (obj.selected) {
|
||||
dl->AddCircleFilled(pt, 3.5f, IM_COL32(255, 255, 255, 230));
|
||||
dl->AddCircle(pt, 5.0f, IM_COL32(255, 200, 50, 200), 0, 1.5f);
|
||||
} else {
|
||||
dl->AddCircleFilled(pt, 2.0f, IM_COL32(255, 220, 50, 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw NPCs as red dots
|
||||
|
|
|
|||
|
|
@ -111,6 +111,15 @@ PlacedObject* ObjectPlacer::getSelected() {
|
|||
return &objects_[selectedIdx_];
|
||||
}
|
||||
|
||||
void ObjectPlacer::selectAll() {
|
||||
clearSelection();
|
||||
for (int i = 0; i < static_cast<int>(objects_.size()); i++) {
|
||||
objects_[i].selected = true;
|
||||
selectedIndices_.push_back(i);
|
||||
}
|
||||
if (!objects_.empty()) selectedIdx_ = 0;
|
||||
}
|
||||
|
||||
void ObjectPlacer::moveSelected(const glm::vec3& delta) {
|
||||
if (selectedIndices_.size() > 1) {
|
||||
for (int idx : selectedIndices_) objects_[idx].position += delta;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ public:
|
|||
|
||||
const std::vector<PlacedObject>& getObjects() const { return objects_; }
|
||||
std::vector<PlacedObject>& getObjects() { return objects_; }
|
||||
void clearAll() { objects_.clear(); undoStack_.clear(); selectedIdx_ = -1; }
|
||||
void selectAll();
|
||||
void clearAll() { objects_.clear(); undoStack_.clear(); selectedIdx_ = -1; selectedIndices_.clear(); }
|
||||
size_t objectCount() const { return objects_.size(); }
|
||||
|
||||
float getPlacementRotationY() const { return placementRotY_; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue