Refactor ResourcesInUseHelper and TextObject for exposing fonts

This commit is contained in:
Florian Rival
2018-11-13 22:03:46 +00:00
parent 45d2844d8b
commit 871b01124f
17 changed files with 177 additions and 164 deletions

View File

@@ -370,8 +370,8 @@
<Unit filename="GDCore/IDE/Events/ExpressionsCorrectnessTesting.h" />
<Unit filename="GDCore/IDE/ExtensionsLoader.cpp" />
<Unit filename="GDCore/IDE/ExtensionsLoader.h" />
<Unit filename="GDCore/IDE/Project/ImagesUsedInventorizer.cpp" />
<Unit filename="GDCore/IDE/Project/ImagesUsedInventorizer.h" />
<Unit filename="GDCore/IDE/Project/ResourcesInUseHelper.cpp" />
<Unit filename="GDCore/IDE/Project/ResourcesInUseHelper.h" />
<Unit filename="GDCore/Extensions/Metadata/MetadataProvider.cpp" />
<Unit filename="GDCore/Extensions/Metadata/MetadataProvider.h" />
<Unit filename="GDCore/IDE/PlatformLoader.cpp" />

View File

@@ -41,7 +41,7 @@
#include "GDCore/IDE/Dialogs/DndResourcesEditor.h"
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#include "GDCore/IDE/Dialogs/ResourceLibraryDialog.h"
#include "GDCore/IDE/Project/ImagesUsedInventorizer.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/IDE/Project/ProjectResourcesAdder.h"
#include "GDCore/IDE/wxTools/FileProperty.h"
#include "GDCore/IDE/wxTools/SkinHelper.h"
@@ -1332,7 +1332,7 @@ void ResourcesEditor::Refresh() {
void ResourcesEditor::OnDeleteUnusedFiles(wxCommandEvent& event) {
std::vector<gd::String> unusedImages =
gd::ProjectResourcesAdder::GetAllUselessImages(project);
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
// Construct corresponding wxArrayString with unused images
wxArrayString imagesNotUsed;

View File

@@ -34,7 +34,7 @@ namespace gd {
* sometimes update them.
*
* \see ResourcesMergingHelper
* \see gd::ImagesUsedInventorizer
* \see gd::ResourcesInUseHelper
*
* \see gd::LaunchResourceWorkerOnEvents
*

View File

@@ -1,52 +0,0 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Class used to track all images used in a game.
*
* Usage example:
\code
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
//Get a set with the name of all images in the project:
std::set<gd::String> & usedImages = inventorizer.GetAllUsedImages();
\endcode
*
* \ingroup IDE
*/
class ImagesUsedInventorizer : public gd::ArbitraryResourceWorker {
public:
ImagesUsedInventorizer() : gd::ArbitraryResourceWorker(){};
virtual ~ImagesUsedInventorizer(){};
std::set<gd::String>& GetAllUsedImages() { return allUsedImages; };
virtual void ExposeFile(gd::String& resource){
/*Don't care, we just list images*/};
virtual void ExposeImage(gd::String& imageName) {
allUsedImages.insert(imageName);
};
protected:
std::set<gd::String> allUsedImages;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -5,7 +5,7 @@
*/
#include "ProjectResourcesAdder.h"
#include "GDCore/CommonTools.h"
#include "GDCore/IDE/Project/ImagesUsedInventorizer.h"
#include "GDCore/IDE/Project/ResourcesInUseHelper.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Tools/Log.h"
@@ -14,51 +14,52 @@ using namespace std;
namespace gd {
bool ProjectResourcesAdder::AddAllMissingImages(gd::Project& project) {
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
std::set<gd::String>& allImages = inventorizer.GetAllUsedImages();
bool ProjectResourcesAdder::AddAllMissing(gd::Project& project,
const gd::String& resourceType) {
// Search for resources used in the project
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
ResourcesManager& resourcesManager = project.GetResourcesManager();
for (std::set<gd::String>::const_iterator it = allImages.begin();
it != allImages.end();
++it) {
if (!resourcesManager.HasResource(*it)) {
std::cout << "Adding missing resource \"" << *it << "\"to the project.";
resourcesManager.AddResource(*it, /*filename=*/*it, "image");
for (auto& resourceName : resourcesInUse.GetAll(resourceType)) {
if (!resourcesManager.HasResource(resourceName)) {
std::cout << "Adding missing resource \"" << resourceName
<< "\"to the project." << std::endl;
resourcesManager.AddResource(
resourceName, /*filename=*/resourceName, resourceType);
}
}
return true;
}
std::vector<gd::String> ProjectResourcesAdder::GetAllUselessImages(
gd::Project& project) {
std::vector<gd::String> ProjectResourcesAdder::GetAllUseless(
gd::Project& project, const gd::String& resourceType) {
std::vector<gd::String> unusedResources;
// Search for resources used in the project
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
std::set<gd::String>& usedResources = resourcesInUse.GetAll(resourceType);
// Search for used images
gd::ImagesUsedInventorizer inventorizer;
project.ExposeResources(inventorizer);
std::set<gd::String>& usedImages = inventorizer.GetAllUsedImages();
// Search all images resources not used
// Search all resources not used
std::vector<gd::String> resources =
project.GetResourcesManager().GetAllResourceNames();
for (std::size_t i = 0; i < resources.size(); i++) {
if (project.GetResourcesManager().GetResource(resources[i]).GetKind() !=
"image")
resourceType)
continue;
if (usedImages.find(resources[i]) == usedImages.end())
if (usedResources.find(resources[i]) == usedResources.end())
unusedResources.push_back(resources[i]);
}
return unusedResources;
}
void ProjectResourcesAdder::RemoveAllUselessImages(gd::Project& project) {
std::vector<gd::String> unusedResources = GetAllUselessImages(project);
void ProjectResourcesAdder::RemoveAllUseless(gd::Project& project,
const gd::String& resourceType) {
std::vector<gd::String> unusedResources =
GetAllUseless(project, resourceType);
for (std::size_t i = 0; i < unusedResources.size(); ++i) {
project.GetResourcesManager().RemoveResource(unusedResources[i]);

View File

@@ -21,38 +21,35 @@ namespace gd {
class GD_CORE_API ProjectResourcesAdder {
public:
/**
* \brief Update the project so that all missing images are added, with an
* \brief Update the project so that all missing resources are added, with an
* filename that is equal to the missing resource name.
*
* \param project The project to be updated.
* \param resourceType The type of the resource the be searched
*
* \return true if no error happened
*/
static bool AddAllMissingImages(gd::Project& project);
static bool AddAllMissing(gd::Project& project, const gd::String & resourceType);
/**
* \brief Find all resources that are
* not used in the project.
*
* \note For now, only images resources can be tracked and marked
* as not used.
* \brief Find all resources of the specified kind that are
* not used by the project.
*
* \param project The project to be crawled.
* \param resourceType The type of the resource the be searched
*
* \return A vector containing the name of all unused resources
*/
static std::vector<gd::String> GetAllUselessImages(gd::Project& project);
static std::vector<gd::String> GetAllUseless(gd::Project& project, const gd::String & resourceType);
/**
* \brief Remove all resources that are not used
* in the project.
*
* \note For now, only images resources can be tracked and marked
* as not used.
* \brief Remove all resources of the specified kind that are not used
* by the project.
*
* \param project The project to be crawled.
* \param resourceType The type of the resource the be searched
*/
static void RemoveAllUselessImages(gd::Project& project);
static void RemoveAllUseless(gd::Project& project, const gd::String & resourceType);
};
} // namespace gd

View File

@@ -0,0 +1,72 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#ifndef IMAGESUSEDINVENTORIZER_H
#define IMAGESUSEDINVENTORIZER_H
#include <set>
#include <vector>
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
/**
* \brief Class used to track all resources used by a game,
* or a part of it (like a gd::Object).
*
* Usage example:
\code
gd::ResourcesInUseHelper resourcesInUse;
project.ExposeResources(resourcesInUse);
//Get a set with the name of all images in the project:
std::set<gd::String> & usedImages = resourcesInUse.GetAllImages();
\endcode
*
* \ingroup IDE
*/
class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
public:
ResourcesInUseHelper() : gd::ArbitraryResourceWorker(){};
virtual ~ResourcesInUseHelper(){};
std::set<gd::String>& GetAllImages() { return GetAll("image"); };
std::set<gd::String>& GetAllFonts() { return GetAll("font"); };
std::set<gd::String>& GetAllAudios() { return GetAll("audio"); };
std::set<gd::String>& GetAll(const gd::String& resourceType) {
return resourceType == "image"
? allImages
: (resourceType == "audio"
? allAudios
: (resourceType == "font") ? allFonts : emptyResources);
};
virtual void ExposeFile(gd::String& resource) override{
/*Don't care, we just list resource names*/
};
virtual void ExposeImage(gd::String& imageResourceName) override {
allImages.insert(imageResourceName);
};
virtual void ExposeAudio(gd::String& audioResourceName) override {
allAudios.insert(audioResourceName);
};
virtual void ExposeFont(gd::String& fontResourceName) override {
allFonts.insert(fontResourceName);
};
protected:
std::set<gd::String> allImages;
std::set<gd::String> allAudios;
std::set<gd::String> allFonts;
std::set<gd::String> emptyResources;
};
} // namespace gd
#endif // IMAGESUSEDINVENTORIZER_H
#endif

View File

@@ -136,20 +136,11 @@ bool ImageResource::UpdateProperty(const gd::String& name,
bool ResourcesManager::AddResource(const gd::Resource& resource) {
if (HasResource(resource.GetName())) return false;
try {
const Resource& castedResource = dynamic_cast<const Resource&>(resource);
std::shared_ptr<Resource> newResource =
std::shared_ptr<Resource>(castedResource.Clone());
if (newResource == std::shared_ptr<Resource>()) return false;
resources.push_back(newResource);
} catch (...) {
//TODO: Remove this
std::cout << "WARNING: Tried to add a resource which is not a GD C++ "
"Platform Resource to a GD C++ Platform project";
std::cout << char(7);
}
std::shared_ptr<Resource> newResource =
std::shared_ptr<Resource>(resource.Clone());
if (newResource == std::shared_ptr<Resource>()) return false;
resources.push_back(newResource);
return true;
}
@@ -411,17 +402,8 @@ bool ResourceFolder::HasResource(const gd::String& name) const {
void ResourceFolder::AddResource(const gd::String& name,
gd::ResourcesManager& parentManager) {
try {
ResourcesManager& manager = dynamic_cast<ResourcesManager&>(parentManager);
std::shared_ptr<Resource> resource =
std::dynamic_pointer_cast<Resource>(manager.GetResourceSPtr(name));
if (resource != std::shared_ptr<Resource>()) resources.push_back(resource);
} catch (...) {
//TODO: Remove this
std::cout << "Warning: A resources manager which is not part of GD C++ "
"Platform was used during call to AddResource"
<< std::endl;
}
std::shared_ptr<Resource> resource = parentManager.GetResourceSPtr(name);
if (resource != std::shared_ptr<Resource>()) resources.push_back(resource);
}
void ResourcesManager::RenameResource(const gd::String& oldName,

View File

@@ -87,11 +87,11 @@ TEST_CASE("Resources", "[common][resources]") {
SECTION("ProjectResourcesAdder") {
std::vector<gd::String> uselessResources =
gd::ProjectResourcesAdder::GetAllUselessImages(project);
gd::ProjectResourcesAdder::GetAllUseless(project, "image");
REQUIRE(uselessResources.size() == 2);
gd::ProjectResourcesAdder::RemoveAllUselessImages(project);
gd::ProjectResourcesAdder::RemoveAllUseless(project, "image");
std::vector<gd::String> remainingResources =
project.GetResourcesManager().GetAllResourceNames();
REQUIRE(remainingResources.size() == 2);

View File

@@ -35,7 +35,7 @@ TextObjectEditor::TextObjectEditor(wxWindow* parent,
// Update from the text object
m_textCtrl->SetValue(object.GetString());
m_fontTextCtrl->SetValue(object.GetFontFilename());
m_fontTextCtrl->SetValue(object.GetFontName());
m_sizeCombobox->SetValue(gd::String::From<float>(object.GetCharacterSize()));
textColor =
wxColour(object.GetColorR(), object.GetColorG(), object.GetColorB());
@@ -56,7 +56,7 @@ TextObjectEditor::~TextObjectEditor() {}
void TextObjectEditor::OnOkBtClicked(wxCommandEvent& event) {
// Update the text object
object.SetString(m_textCtrl->GetValue());
object.SetFontFilename(m_fontTextCtrl->GetValue());
object.SetFontName(m_fontTextCtrl->GetValue());
object.SetCharacterSize(gd::String(m_sizeCombobox->GetValue()).To<float>());
object.SetColor(textColor.Red(), textColor.Green(), textColor.Blue());
object.SetBold(m_toolbar->GetToolToggled(BOLD_TOOL_ID));

View File

@@ -54,7 +54,7 @@ TextObject::~TextObject(){};
void TextObject::DoUnserializeFrom(gd::Project& project,
const gd::SerializerElement& element) {
SetString(element.GetChild("string", 0, "String").GetValue().GetString());
SetFontFilename(element.GetChild("font", 0, "Font").GetValue().GetString());
SetFontName(element.GetChild("font", 0, "Font").GetValue().GetString());
SetCharacterSize(element.GetChild("characterSize", 0, "CharacterSize")
.GetValue()
.GetInt());
@@ -119,7 +119,7 @@ void TextObject::LoadResources(gd::Project& project, gd::Layout& layout) {
void TextObject::DoSerializeTo(gd::SerializerElement& element) const {
element.AddChild("string").SetValue(GetString());
element.AddChild("font").SetValue(GetFontFilename());
element.AddChild("font").SetValue(GetFontName());
element.AddChild("characterSize").SetValue(GetCharacterSize());
element.AddChild("color")
.SetAttribute("r", (int)GetColorR())
@@ -157,19 +157,12 @@ void TextObject::EditObject(wxWindow* parent,
}
#endif
void TextObject::SetFontFilename(const gd::String& fontFilename) {
fontName = fontFilename;
#if defined(GD_IDE_ONLY)
fontName = gd::AbstractFileSystem::NormalizeSeparator(fontName);
#endif
};
/* RuntimeTextObject : */
RuntimeTextObject::RuntimeTextObject(RuntimeScene& scene,
const TextObject& textObject)
: RuntimeObject(scene, textObject), opacity(255), angle(0) {
ChangeFont(textObject.GetFontFilename());
ChangeFont(textObject.GetFontName());
SetSmooth(textObject.IsSmoothed());
SetColor(
textObject.GetColorR(), textObject.GetColorG(), textObject.GetColorB());
@@ -332,7 +325,7 @@ void RuntimeTextObject::GetPropertyForDebugger(std::size_t propertyNb,
value = GetString();
} else if (propertyNb == 1) {
name = _("Font");
value = GetFontFilename();
value = GetFontName();
} else if (propertyNb == 2) {
name = _("Font Size");
value = gd::String::From(GetCharacterSize());

View File

@@ -15,26 +15,17 @@ This project is released under the MIT License.
class ImageManager;
class RuntimeScene;
namespace gd {
class Project;
class Object;
}
namespace gd {
class ImageManager;
}
namespace gd {
class InitialInstance;
}
#if defined(GD_IDE_ONLY)
class wxBitmap;
namespace gd {
class Project;
}
class wxWindow;
namespace gd {
class MainFrameWrapper;
}
namespace gd {
class ResourcesMergingHelper;
}
#endif
/**
@@ -82,13 +73,13 @@ class GD_EXTENSION_API TextObject : public gd::Object {
*/
inline float GetCharacterSize() const { return characterSize; };
/** \brief Return the font filename.
/** \brief Return the name of the font resource used for the text.
*/
inline const gd::String& GetFontFilename() const { return fontName; };
inline const gd::String& GetFontName() const { return fontName; };
/** \brief Change the font filename.
/** \brief Change the font resource used for the text.
*/
void SetFontFilename(const gd::String& fontFilename);
void SetFontName(const gd::String& resourceName) { fontName = resourceName; };
bool IsBold() const { return bold; };
void SetBold(bool enable) { bold = enable; };
@@ -170,9 +161,9 @@ class GD_EXTENSION_API RuntimeTextObject : public RuntimeObject {
*/
void ChangeFont(const gd::String& fontFilename);
/** \brief Return the font file name.
/** \brief Return the font resource name.
*/
inline gd::String GetFontFilename() const { return fontName; };
inline gd::String GetFontName() const { return fontName; };
void SetFontStyle(int style);
int GetFontStyle();

View File

@@ -91,9 +91,9 @@ export default class TextEditor extends React.Component<EditorProps, void> {
resourcesLoader={ResourcesLoader}
resourceKind="font"
fullWidth
initialResourceName={textObject.getFontFilename()}
initialResourceName={textObject.getFontName()}
onChange={resourceName => {
textObject.setFontFilename(resourceName);
textObject.setFontName(resourceName);
this.forceUpdate();
}}
hintText="Choose a font"

View File

@@ -36,7 +36,7 @@ function RenderedTextInstance(
this._styleFontDirty = true;
this._fontFamily = this._pixiResourcesLoader.getFontFamily(
this._project,
textObject.getFontFilename()
textObject.getFontName()
);
this.update();
}
@@ -69,11 +69,11 @@ RenderedTextInstance.prototype.update = function() {
this._styleFontDirty = true;
}
if (this._fontFilename !== textObject.getFontFilename()) {
if (this._fontName !== textObject.getFontName()) {
//Avoid calling loadFontFamily if the font didn't changed.
this._fontFilename = textObject.getFontFilename();
this._fontName = textObject.getFontName();
this._pixiResourcesLoader
.loadFontFamily(this._project, textObject.getFontFilename())
.loadFontFamily(this._project, textObject.getFontName())
.then(fontFamily => {
// Once the font is loaded, we can use the given fontFamily.
this._fontFamily = fontFamily;

View File

@@ -86,6 +86,14 @@ const publicAudioUrls = [
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/sfx_lose.ogg',
];
const publicFontUrls = [
// Platformer fonts (see platformer.json in fixtures)
'https://df5lqcdudryde.cloudfront.net/examples/platformer/Bimbo_JVE.ttf',
// Space shooter fonts (see space-shooter.json in fixtures)
'https://df5lqcdudryde.cloudfront.net/examples/space-shooter/kenvector_future.ttf',
];
const nameFromUrl = (url: string): string => {
const urlParts = url.split('/');
return urlParts[urlParts.length - 1]
@@ -225,7 +233,7 @@ export default [
name: 'publicImageUrlChooser',
displayName: 'Choose an image from library',
kind: 'image',
component: class AudioResourceChooser extends React.Component {
component: class ImageResourceChooser extends React.Component {
chooseResources = () => {
if (this._chooser) return this._chooser.chooseResources();
};
@@ -243,5 +251,26 @@ export default [
}
},
},
//TODO: add publicFontUrlChooser
{
name: 'publicFontUrlChooser',
displayName: 'Choose a font from library',
kind: 'font',
component: class FontResourceChooser extends React.Component {
chooseResources = () => {
if (this._chooser) return this._chooser.chooseResources();
};
render() {
return (
<GenericResourcesChooser
{...this.props}
urls={publicFontUrls}
urlsAreImages={false}
createNewResource={() => new gd.FontResource()}
title="Choose a font from the library"
ref={chooser => (this._chooser = chooser)}
/>
);
}
},
},
];

View File

@@ -109,12 +109,12 @@ export default class ResourcesList extends React.Component<Props, State> {
_removeAllUnusedImages = () => {
const { project } = this.props;
gd.ProjectResourcesAdder
.getAllUselessImages(project)
.getAllUseless(project, 'image')
.toJSArray()
.forEach(imageName => {
console.info(`Removing unused image resource: ${imageName}`);
});
gd.ProjectResourcesAdder.removeAllUselessImages(project);
gd.ProjectResourcesAdder.removeAllUseless(project, 'image');
this.forceUpdate();
};

View File

@@ -804,10 +804,10 @@ export default class SceneEditor extends React.Component<Props, State> {
reloadResourcesFor = (object: gdObject) => {
const { project } = this.props;
const imagesUsedInventorizer = new gd.ImagesUsedInventorizer();
object.exposeResources(imagesUsedInventorizer);
const objectResourceNames = imagesUsedInventorizer
.getAllUsedImages()
const resourcesInUse = new gd.ResourcesInUseHelper();
object.exposeResources(resourcesInUse);
const objectResourceNames = resourcesInUse
.getAllImages()
.toNewVectorString()
.toJSArray();