From d0e549d985d89d918aa06ae875fc8d239d85aaa2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 27 Feb 2010 20:12:42 +0000 Subject: [PATCH] Make scenery picker generic --- include/ISceneryPicker.hpp | 3 +- include/gui/ILayout.hpp | 1 + src/Editor.cpp | 9 +- src/Resource.cpp | 224 ++++++++++++++++++------------------- src/SceneryPicker.cpp | 143 +++++++++++++++-------- src/gui/Layout.cpp | 7 ++ 6 files changed, 221 insertions(+), 166 deletions(-) diff --git a/include/ISceneryPicker.hpp b/include/ISceneryPicker.hpp index bf4a1c8..7a36f4a 100644 --- a/include/ISceneryPicker.hpp +++ b/include/ISceneryPicker.hpp @@ -31,6 +31,7 @@ struct ISceneryPicker { typedef shared_ptr ISceneryPickerPtr; -ISceneryPickerPtr makeSceneryPicker(gui::ILayoutPtr layout); +ISceneryPickerPtr makeBuildingPicker(gui::ILayoutPtr layout); +ISceneryPickerPtr makeTreePicker(gui::ILayoutPtr layout); #endif diff --git a/include/gui/ILayout.hpp b/include/gui/ILayout.hpp index d467d02..40d451c 100644 --- a/include/gui/ILayout.hpp +++ b/include/gui/ILayout.hpp @@ -38,6 +38,7 @@ namespace gui { } virtual Widget& get(const string& path) const = 0; + virtual bool exists(const string& path) const = 0; virtual void render() const = 0; virtual bool click(int x, int y) = 0; diff --git a/src/Editor.cpp b/src/Editor.cpp index ab466b8..786b8ab 100644 --- a/src/Editor.cpp +++ b/src/Editor.cpp @@ -1,5 +1,5 @@ // -// Copyright (C) 2009 Nick Gasson +// Copyright (C) 2009-2010 Nick Gasson // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -85,7 +85,7 @@ private: // GUI elements gui::ILayoutPtr layout; - ISceneryPickerPtr buildingPicker; + ISceneryPickerPtr buildingPicker, treePicker; }; Editor::Editor(IMapPtr aMap) @@ -134,7 +134,8 @@ void Editor::buildGUI() layout->get("/lower/action_wnd/save").connect(gui::Widget::SIG_CLICK, bind(&Editor::save, this)); - buildingPicker = makeSceneryPicker(layout); + buildingPicker = makeBuildingPicker(layout); + treePicker = makeTreePicker(layout); } void Editor::setMap(IMapPtr aMap) @@ -455,7 +456,7 @@ void Editor::plantTrees() for (int x = xmin; x <= xmax; x++) { for (int y = ymin; y <= ymax; y++) - map->addScenery(makePoint(x, y), loadTree("pine")); + map->addScenery(makePoint(x, y), treePicker->get()); } } diff --git a/src/Resource.cpp b/src/Resource.cpp index 184b522..7955b70 100644 --- a/src/Resource.cpp +++ b/src/Resource.cpp @@ -28,159 +28,159 @@ using namespace boost::filesystem; // A resource that reads data from a filesystem directory class FilesystemResource : public IResource { public: - FilesystemResource(const path& aPath) - : myPath(aPath) - { - - } - - // IResource interface - string name() const { return myPath.filename(); } - string xmlFileName() const - { - return (myPath / (name() + ".xml")).file_string(); - } - - Handle openFile(const string& aFileName) - { - return Handle((myPath / aFileName).file_string(), Handle::READ); - } - - Handle writeFile(const string& aFileName) - { - return Handle((myPath / aFileName).file_string(), Handle::WRITE); - } + FilesystemResource(const path& aPath) + : myPath(aPath) + { + + } + + // IResource interface + string name() const { return myPath.filename(); } + string xmlFileName() const + { + return (myPath / (name() + ".xml")).file_string(); + } + + Handle openFile(const string& aFileName) + { + return Handle((myPath / aFileName).file_string(), Handle::READ); + } + + Handle writeFile(const string& aFileName) + { + return Handle((myPath / aFileName).file_string(), Handle::WRITE); + } private: - const path myPath; + const path myPath; }; IResource::Handle::Handle(const string& aFileName, Mode aMode) - : myFileName(aFileName) + : myFileName(aFileName) { - if (aMode == READ) { - myReadStream = shared_ptr(new ifstream(aFileName.c_str())); + if (aMode == READ) { + myReadStream = shared_ptr(new ifstream(aFileName.c_str())); - if (!myReadStream->good()) - throw runtime_error("Failed to open resource file " + aFileName); - } - else if (aMode == WRITE) { - myWriteStream = shared_ptr(new ofstream(aFileName.c_str())); + if (!myReadStream->good()) + throw runtime_error("Failed to open resource file " + aFileName); + } + else if (aMode == WRITE) { + myWriteStream = shared_ptr(new ofstream(aFileName.c_str())); - if (!myWriteStream->good()) - throw runtime_error("Failed to open resource file " + aFileName); - } - else - throw runtime_error("Bad mode for Handle"); + if (!myWriteStream->good()) + throw runtime_error("Failed to open resource file " + aFileName); + } + else + throw runtime_error("Bad mode for Handle"); } namespace { - const char* classes[] = { - "maps", "buildings", "engines", "waggons", "trees", - NULL - }; - - typedef map ResourceMap; - ResourceMap theResources; - - ResourceList& resClassList(const string& aClass) - { - if (theResources.find(aClass) == theResources.end()) - theResources[aClass] = ResourceList(); - return theResources[aClass]; - } - - void addResource(const string& aClass, IResourcePtr aRes) - { - resClassList(aClass).push_back(aRes); - } - - void addResourceDir(const char* aClass, const path& aPath) - { - debug() << "Adding " << aPath << " to " << aClass << " class"; - - const path xmlFile = aPath / (aPath.filename() + ".xml"); - - if (!exists(xmlFile)) - warn() << "Missing resource XML file: " << xmlFile; - else - addResource(aClass, IResourcePtr(new FilesystemResource(aPath))); - } + const char* classes[] = { + "maps", "buildings", "engines", "waggons", "trees", + NULL + }; + + typedef map ResourceMap; + ResourceMap theResources; + + ResourceList& resClassList(const string& aClass) + { + if (theResources.find(aClass) == theResources.end()) + theResources[aClass] = ResourceList(); + return theResources[aClass]; + } + + void addResource(const string& aClass, IResourcePtr aRes) + { + resClassList(aClass).push_back(aRes); + } + + void addResourceDir(const char* aClass, const path& aPath) + { + debug() << "Adding " << aPath << " to " << aClass << " class"; + + const path xmlFile = aPath / (aPath.filename() + ".xml"); + + if (!exists(xmlFile)) + warn() << "Missing resource XML file: " << xmlFile; + else + addResource(aClass, IResourcePtr(new FilesystemResource(aPath))); + } - void lookInDir(const path& aPath) - { - log() << "Looking for resources in " << aPath; - - for (const char** p = classes; *p != NULL; ++p) { - if (exists(aPath / *p)) { - for (directory_iterator it(aPath / *p); - it != directory_iterator(); ++it) - if (is_directory(it->status())) - addResourceDir(*p, *it); - } - } - } + void lookInDir(const path& aPath) + { + log() << "Looking for resources in " << aPath; + + for (const char** p = classes; *p != NULL; ++p) { + if (exists(aPath / *p)) { + for (directory_iterator it(aPath / *p); + it != directory_iterator(); ++it) + if (is_directory(it->status())) + addResourceDir(*p, *it); + } + } + } } // Set up the resource database and cache available objects void initResources() { - lookInDir(current_path()); + lookInDir(current_path()); } // Find all the resources of the given type void enumResources(const string& aClass, ResourceList& aList) { - ResourceList& lst = resClassList(aClass); - copy(lst.begin(), lst.end(), back_inserter(aList)); + ResourceList& lst = resClassList(aClass); + copy(lst.begin(), lst.end(), back_inserter(aList)); } namespace { - // Find a resource of a particular type - // Returns null pointer on failure - IResourcePtr maybeFindResource(const string& aResId, const string& aClass) - { - ResourceList& rlist = resClassList(aClass); - for (ResourceListIt it = rlist.begin(); it != rlist.end(); ++it) { - if ((*it)->name() == aResId) - return *it; - } - - return IResourcePtr(); - } + // Find a resource of a particular type + // Returns null pointer on failure + IResourcePtr maybeFindResource(const string& aResId, const string& aClass) + { + ResourceList& rlist = resClassList(aClass); + for (ResourceListIt it = rlist.begin(); it != rlist.end(); ++it) { + if ((*it)->name() == aResId) + return *it; + } + + return IResourcePtr(); + } } // Find a resource or throw an exception on failure IResourcePtr findResource(const string& aResId, const string& aClass) { - IResourcePtr r = maybeFindResource(aResId, aClass); - if (r) - return r; - else - throw runtime_error("Failed to find resource " + aResId - + " in class " + aClass); + IResourcePtr r = maybeFindResource(aResId, aClass); + if (r) + return r; + else + throw runtime_error("Failed to find resource " + aResId + + " in class " + aClass); } // True if the given resource exists bool resourceExists(const string& aResId, const string& aClass) { - return maybeFindResource(aResId, aClass); + return maybeFindResource(aResId, aClass); } // Create an empty resource directory IResourcePtr makeNewResource(const string& aResId, const string& aClass) { - const path p = path(aClass) / aResId; + const path p = path(aClass) / aResId; - if (exists(p)) - throw runtime_error("Cannot create resource " + aResId - + " in class " + aClass + ": already exists!"); + if (exists(p)) + throw runtime_error("Cannot create resource " + aResId + + " in class " + aClass + ": already exists!"); - if (!create_directories(p)) - throw runtime_error("Failed to create resource directory " - + p.file_string()); + if (!create_directories(p)) + throw runtime_error("Failed to create resource directory " + + p.file_string()); - IResourcePtr r = IResourcePtr(new FilesystemResource(p)); - addResource(aClass, r); + IResourcePtr r = IResourcePtr(new FilesystemResource(p)); + addResource(aClass, r); - return r; + return r; } diff --git a/src/SceneryPicker.cpp b/src/SceneryPicker.cpp index a3a5298..a7b6465 100644 --- a/src/SceneryPicker.cpp +++ b/src/SceneryPicker.cpp @@ -21,94 +21,104 @@ #include "OpenGLHelper.hpp" #include "gui/Label.hpp" +#include + class SceneryPicker : public ISceneryPicker { public: - SceneryPicker(gui::ILayoutPtr l); - -private: + SceneryPicker(gui::ILayoutPtr l, + const string& resourceClass, const string& guiPath, + const string& btnGuiPath); + +protected: void next(); void prev(); void rotate(); - ISceneryPtr get() const; - void renderBuildingPreview(gui::Widget& canvas); + void renderPreview(gui::Widget& canvas); void show(); void hide(); void changeActive(const string& newResName); + void selectFirstItem(); - ResourceList buildingList; - ResourceList::const_iterator buildingIt; - ISceneryPtr activeBuilding; + ResourceList resourceList; + ResourceList::const_iterator resourceIt; + ISceneryPtr activeItem; gui::ILayoutPtr layout; float rotation; - string resName; + string resName, guiPath, resClass; }; -SceneryPicker::SceneryPicker(gui::ILayoutPtr l) +SceneryPicker::SceneryPicker(gui::ILayoutPtr l, + const string& resourceClass, const string& guiPath, + const string& btnGuiPath) : layout(l), - rotation(0.0f) + rotation(0.0f), + guiPath(guiPath), + resClass(resourceClass) { using namespace placeholders; - enumResources("buildings", buildingList); - - if (buildingList.empty()) - warn() << "No buildings found"; - else { - buildingIt = buildingList.begin(); - changeActive((*buildingIt)->name()); - } + enumResources(resourceClass, resourceList); - layout->get("/building_wnd/preview").connect(gui::Widget::SIG_RENDER, - bind(&SceneryPicker::renderBuildingPreview, this, _1)); - layout->get("/building_wnd/next").connect(gui::Widget::SIG_CLICK, + layout->get(guiPath + "/preview").connect(gui::Widget::SIG_RENDER, + bind(&SceneryPicker::renderPreview, this, _1)); + layout->get(guiPath + "/next").connect(gui::Widget::SIG_CLICK, bind(&SceneryPicker::next, this)); - layout->get("/building_wnd/prev").connect(gui::Widget::SIG_CLICK, + layout->get(guiPath + "/prev").connect(gui::Widget::SIG_CLICK, bind(&SceneryPicker::prev, this)); - layout->get("/building_wnd/rotate").connect(gui::Widget::SIG_CLICK, - bind(&SceneryPicker::rotate, this)); - layout->get("/tool_wnd/tools/building").connect(gui::Widget::SIG_ENTER, + if (layout->exists(guiPath + "/rotate")) + layout->get(guiPath + "/rotate").connect(gui::Widget::SIG_CLICK, + bind(&SceneryPicker::rotate, this)); + + layout->get(btnGuiPath).connect(gui::Widget::SIG_ENTER, bind(&SceneryPicker::show, this)); - layout->get("/tool_wnd/tools/building").connect(gui::Widget::SIG_LEAVE, + layout->get(btnGuiPath).connect(gui::Widget::SIG_LEAVE, bind(&SceneryPicker::hide, this)); hide(); } + +void SceneryPicker::selectFirstItem() +{ + // A kludge to avoid calling the pure virtual get() in constructor + + if (resourceList.empty()) + warn() << "No scenery found in class " << resClass; + else { + resourceIt = resourceList.begin(); + changeActive((*resourceIt)->name()); + } +} void SceneryPicker::next() { - if (++buildingIt == buildingList.end()) - buildingIt = buildingList.begin(); + if (++resourceIt == resourceList.end()) + resourceIt = resourceList.begin(); - changeActive((*buildingIt)->name()); + changeActive((*resourceIt)->name()); } void SceneryPicker::prev() { - if (buildingIt == buildingList.begin()) - buildingIt = buildingList.end(); - buildingIt--; + if (resourceIt == resourceList.begin()) + resourceIt = resourceList.end(); + resourceIt--; - changeActive((*buildingIt)->name()); + changeActive((*resourceIt)->name()); } void SceneryPicker::show() { - layout->get("/building_wnd").visible(true); + layout->get(guiPath).visible(true); } void SceneryPicker::hide() { - layout->get("/building_wnd").visible(false); -} - -ISceneryPtr SceneryPicker::get() const -{ - return loadBuilding(resName, rotation); + layout->get(guiPath).visible(false); } -void SceneryPicker::renderBuildingPreview(gui::Widget& canvas) +void SceneryPicker::renderPreview(gui::Widget& canvas) { static ILightPtr sun = makeSunLight(); @@ -118,17 +128,17 @@ void SceneryPicker::renderBuildingPreview(gui::Widget& canvas) glColor3f(1.0f, 1.0f, 1.0f); sun->apply(); - activeBuilding->render(); + activeItem->render(); } void SceneryPicker::changeActive(const string& newResName) { if (newResName != resName) { - activeBuilding = loadBuilding(newResName, rotation); resName = newResName; + activeItem = this->get(); - layout->cast("/building_wnd/name") - .text(activeBuilding->name()); + layout->cast(guiPath + "/name") + .text(activeItem->name()); } } @@ -138,10 +148,45 @@ void SceneryPicker::rotate() if (rotation >= 350.0f) rotation = 0.0f; - activeBuilding->setAngle(rotation); + activeItem->setAngle(rotation); +} + +class BuildingPicker : public SceneryPicker { +public: + BuildingPicker(gui::ILayoutPtr layout) + : SceneryPicker(layout, "buildings", + "/building_wnd", "/tool_wnd/tools/building") + { + selectFirstItem(); + } + + virtual ISceneryPtr get() const + { + return loadBuilding(resName, rotation); + } +}; + +class TreePicker : public SceneryPicker { +public: + TreePicker(gui::ILayoutPtr layout) + : SceneryPicker(layout, "trees", + "/tree_wnd", "/tool_wnd/tools/tree") + { + selectFirstItem(); + } + + virtual ISceneryPtr get() const + { + return loadTree(resName); + } +}; + +ISceneryPickerPtr makeTreePicker(gui::ILayoutPtr layout) +{ + return ISceneryPickerPtr(new TreePicker(layout)); } -ISceneryPickerPtr makeSceneryPicker(gui::ILayoutPtr layout) +ISceneryPickerPtr makeBuildingPicker(gui::ILayoutPtr layout) { - return ISceneryPickerPtr(new SceneryPicker(layout)); + return ISceneryPickerPtr(new BuildingPicker(layout)); } diff --git a/src/gui/Layout.cpp b/src/gui/Layout.cpp index 8e12237..904a7c7 100644 --- a/src/gui/Layout.cpp +++ b/src/gui/Layout.cpp @@ -44,6 +44,7 @@ public: // ILayout interface Widget& get(const string& path) const; + bool exists(const string& path) const; void render() const; bool click(int x, int y); @@ -179,6 +180,12 @@ Widget& Layout::get(const string& path) const throw runtime_error("Widget " + path + " does not exist"); } +bool Layout::exists(const string& path) const +{ + WidgetMap::const_iterator it = widgets.find(path); + return it != widgets.end(); +} + bool Layout::click(int x, int y) { return root->handleClick(x, y); -- 2.39.2