Fix image/sound readding broken by error messages

When an image/sound is readded, this reuses the `ReplaceImage/Sound` callback functions. The added error handling to prevent duplicate images/sounds was causing this to not work, as the image/sound being readded was already present. The implementation is separated from the callback functions and an additional parameter is added to toggle the duplicate name check.

Previously this was hard to notice, as the error message popup was not shown due to the top-most popup being closed immediately. This will be fixed separately by a larger refactoring, so a popup can close itself immediately after opening another popup without closing the child popup instead.

Closes #6500.
This commit is contained in:
Robert Müller 2023-04-03 15:51:08 +02:00
parent b4c114450c
commit eaa4e19188
3 changed files with 55 additions and 41 deletions

View file

@ -4045,31 +4045,32 @@ bool CEditor::SelectLayerByTile()
return false;
}
bool CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser)
bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDuplicate)
{
CEditor *pEditor = (CEditor *)pUser;
// check if we have that image already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
for(const auto &pImage : pEditor->m_Map.m_vpImages)
if(CheckDuplicate)
{
if(!str_comp(pImage->m_aName, aBuf))
for(const auto &pImage : m_Map.m_vpImages)
{
pEditor->ShowFileDialogError("Image named '%s' was already added.", pImage->m_aName);
return false;
if(!str_comp(pImage->m_aName, aBuf))
{
ShowFileDialogError("Image named '%s' was already added.", pImage->m_aName);
return false;
}
}
}
CEditorImage ImgInfo(pEditor);
if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType))
CEditorImage ImgInfo(this);
if(!Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType))
{
pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
return false;
}
CEditorImage *pImg = pEditor->m_Map.m_vpImages[pEditor->m_SelectedImage];
pEditor->Graphics()->UnloadTexture(&(pImg->m_Texture));
CEditorImage *pImg = m_Map.m_vpImages[m_SelectedImage];
Graphics()->UnloadTexture(&(pImg->m_Texture));
free(pImg->m_pData);
pImg->m_pData = nullptr;
*pImg = ImgInfo;
@ -4086,21 +4087,26 @@ bool CEditor::ReplaceImage(const char *pFileName, int StorageType, void *pUser)
}
pImg->m_AutoMapper.Load(pImg->m_aName);
int TextureLoadFlag = pEditor->Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0)
TextureLoadFlag = 0;
pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, TextureLoadFlag, pFileName);
pImg->m_Texture = Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, TextureLoadFlag, pFileName);
ImgInfo.m_pData = nullptr;
pEditor->SortImages();
for(size_t i = 0; i < pEditor->m_Map.m_vpImages.size(); ++i)
SortImages();
for(size_t i = 0; i < m_Map.m_vpImages.size(); ++i)
{
if(!str_comp(pEditor->m_Map.m_vpImages[i]->m_aName, pImg->m_aName))
pEditor->m_SelectedImage = i;
if(!str_comp(m_Map.m_vpImages[i]->m_aName, pImg->m_aName))
m_SelectedImage = i;
}
pEditor->m_Dialog = DIALOG_NONE;
m_Dialog = DIALOG_NONE;
return true;
}
bool CEditor::ReplaceImageCallback(const char *pFileName, int StorageType, void *pUser)
{
return static_cast<CEditor *>(pUser)->ReplaceImage(pFileName, StorageType, true);
}
bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
{
CEditor *pEditor = (CEditor *)pUser;
@ -4222,44 +4228,45 @@ bool CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
return true;
}
bool CEditor::ReplaceSound(const char *pFileName, int StorageType, void *pUser)
bool CEditor::ReplaceSound(const char *pFileName, int StorageType, bool CheckDuplicate)
{
CEditor *pEditor = (CEditor *)pUser;
// check if we have that sound already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
for(const auto &pSound : pEditor->m_Map.m_vpSounds)
if(CheckDuplicate)
{
if(!str_comp(pSound->m_aName, aBuf))
for(const auto &pSound : m_Map.m_vpSounds)
{
pEditor->ShowFileDialogError("Sound named '%s' was already added.", pSound->m_aName);
return false;
if(!str_comp(pSound->m_aName, aBuf))
{
ShowFileDialogError("Sound named '%s' was already added.", pSound->m_aName);
return false;
}
}
}
// load external
void *pData;
unsigned DataSize;
if(!pEditor->Storage()->ReadFile(pFileName, StorageType, &pData, &DataSize))
if(!Storage()->ReadFile(pFileName, StorageType, &pData, &DataSize))
{
pEditor->ShowFileDialogError("Failed to open sound file '%s'.", pFileName);
ShowFileDialogError("Failed to open sound file '%s'.", pFileName);
return false;
}
// load sound
const int SoundId = pEditor->Sound()->LoadOpusFromMem(pData, DataSize, true);
const int SoundId = Sound()->LoadOpusFromMem(pData, DataSize, true);
if(SoundId == -1)
{
free(pData);
pEditor->ShowFileDialogError("Failed to load sound from file '%s'.", pFileName);
ShowFileDialogError("Failed to load sound from file '%s'.", pFileName);
return false;
}
CEditorSound *pSound = pEditor->m_Map.m_vpSounds[pEditor->m_SelectedSound];
CEditorSound *pSound = m_Map.m_vpSounds[m_SelectedSound];
// unload sample
pEditor->Sound()->UnloadSample(pSound->m_SoundID);
Sound()->UnloadSample(pSound->m_SoundID);
free(pSound->m_pData);
// replace sound
@ -4268,10 +4275,15 @@ bool CEditor::ReplaceSound(const char *pFileName, int StorageType, void *pUser)
pSound->m_pData = pData;
pSound->m_DataSize = DataSize;
pEditor->m_Dialog = DIALOG_NONE;
m_Dialog = DIALOG_NONE;
return true;
}
bool CEditor::ReplaceSoundCallback(const char *pFileName, int StorageType, void *pUser)
{
return static_cast<CEditor *>(pUser)->ReplaceSound(pFileName, StorageType, true);
}
void CEditor::SelectGameLayer()
{
for(size_t g = 0; g < m_Map.m_vpGroups.size(); g++)

View file

@ -1302,8 +1302,10 @@ public:
void DoQuad(CQuad *pQuad, int Index);
ColorRGBA GetButtonColor(const void *pID, int Checked);
static bool ReplaceImage(const char *pFilename, int StorageType, void *pUser);
static bool ReplaceSound(const char *pFileName, int StorageType, void *pUser);
bool ReplaceImage(const char *pFilename, int StorageType, bool CheckDuplicate);
static bool ReplaceImageCallback(const char *pFilename, int StorageType, void *pUser);
bool ReplaceSound(const char *pFileName, int StorageType, bool CheckDuplicate);
static bool ReplaceSoundCallback(const char *pFileName, int StorageType, void *pUser);
static bool AddImage(const char *pFilename, int StorageType, void *pUser);
static bool AddSound(const char *pFileName, int StorageType, void *pUser);

View file

@ -1283,17 +1283,17 @@ int CEditor::PopupImage(CEditor *pEditor, CUIRect View, void *pContext)
if(s_SelectionPopupContext.m_pSelection != nullptr)
{
const bool WasExternal = pImg->m_External;
ReplaceImage(s_SelectionPopupContext.m_pSelection->c_str(), IStorage::TYPE_ALL, pEditor);
const bool Result = pEditor->ReplaceImage(s_SelectionPopupContext.m_pSelection->c_str(), IStorage::TYPE_ALL, false);
pImg->m_External = WasExternal;
s_SelectionPopupContext.Reset();
return 1;
return Result ? 1 : 0;
}
View.HSplitTop(5.0f, nullptr, &View);
View.HSplitTop(12.0f, &Slot, &View);
if(pEditor->DoButton_MenuItem(&s_ReplaceButton, "Replace", 0, &Slot, 0, "Replaces the image with a new one"))
{
pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Replace Image", "Replace", "mapres", "", ReplaceImage, pEditor);
pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Replace Image", "Replace", "mapres", "", ReplaceImageCallback, pEditor);
return 1;
}
@ -1344,16 +1344,16 @@ int CEditor::PopupSound(CEditor *pEditor, CUIRect View, void *pContext)
}
if(s_SelectionPopupContext.m_pSelection != nullptr)
{
ReplaceSound(s_SelectionPopupContext.m_pSelection->c_str(), IStorage::TYPE_ALL, pEditor);
const bool Result = pEditor->ReplaceSound(s_SelectionPopupContext.m_pSelection->c_str(), IStorage::TYPE_ALL, false);
s_SelectionPopupContext.Reset();
return 1;
return Result ? 1 : 0;
}
View.HSplitTop(5.0f, nullptr, &View);
View.HSplitTop(12.0f, &Slot, &View);
if(pEditor->DoButton_MenuItem(&s_ReplaceButton, "Replace", 0, &Slot, 0, "Replaces the sound with a new one"))
{
pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_SOUND, "Replace sound", "Replace", "mapres", "", ReplaceSound, pEditor);
pEditor->InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_SOUND, "Replace sound", "Replace", "mapres", "", ReplaceSoundCallback, pEditor);
return 1;
}