mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 14:38:18 +00:00
Merge #5749
5749: Editor: added the possibility to duplicate layers r=def- a=archimede67 <!-- What is the motivation for the changes of this pull request --> Suggested by Pulsar a few years ago, I finally had the motivation to do it. We can now duplicate any non-special layer (tiles, quads and sounds) thanks to a button just above the delete button. ![image](https://user-images.githubusercontent.com/13364635/185260070-cd5b4c8f-5827-457c-b505-176751003dbc.png) For each duplicated layers, all the necessary properties are duplicated, for example name, color, flags, etc. For a tile layer, all the placed tiles are copied. Same goes for a sound layer, all sources are copied. And for the quads layer, all the quads are duplicated. ## Checklist - [x] Tested the change ingame - [x] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test (especially base/) or added coverage to integration test - [x] Considered possible null pointers and out of bounds array indexing - [x] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Corantin H <archi0670@gmail.com>
This commit is contained in:
commit
6a5d99daf1
|
@ -212,6 +212,17 @@ void CLayerGroup::DeleteLayer(int Index)
|
||||||
m_pMap->m_Modified = true;
|
m_pMap->m_Modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CLayerGroup::DuplicateLayer(int Index)
|
||||||
|
{
|
||||||
|
if(Index < 0 || Index >= (int)m_vpLayers.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto *pDup = m_vpLayers[Index]->Duplicate();
|
||||||
|
m_vpLayers.insert(m_vpLayers.begin() + Index + 1, pDup);
|
||||||
|
|
||||||
|
m_pMap->m_Modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
|
void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
|
||||||
{
|
{
|
||||||
*pWidth = 0;
|
*pWidth = 0;
|
||||||
|
@ -745,6 +756,11 @@ int CEditor::FindSelectedQuadIndex(int Index) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CEditor::IsSpecialLayer(const CLayer *pLayer) const
|
||||||
|
{
|
||||||
|
return m_Map.m_pGameLayer == pLayer || m_Map.m_pTeleLayer == pLayer || m_Map.m_pSpeedupLayer == pLayer || m_Map.m_pFrontLayer == pLayer || m_Map.m_pSwitchLayer == pLayer || m_Map.m_pTuneLayer == pLayer;
|
||||||
|
}
|
||||||
|
|
||||||
void CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser)
|
void CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser)
|
||||||
{
|
{
|
||||||
CEditor *pEditor = (CEditor *)pUser;
|
CEditor *pEditor = (CEditor *)pUser;
|
||||||
|
@ -3480,7 +3496,7 @@ void CEditor::RenderLayers(CUIRect ToolBox, CUIRect View)
|
||||||
else
|
else
|
||||||
s_LayerPopupContext.m_vpLayers.clear();
|
s_LayerPopupContext.m_vpLayers.clear();
|
||||||
|
|
||||||
UiInvokePopupMenu(&s_LayerPopupContext, 0, UI()->MouseX(), UI()->MouseY(), 120, 300, PopupLayer, &s_LayerPopupContext);
|
UiInvokePopupMenu(&s_LayerPopupContext, 0, UI()->MouseX(), UI()->MouseY(), 120, 320, PopupLayer, &s_LayerPopupContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,17 @@ public:
|
||||||
m_BrushRefCount = 0;
|
m_BrushRefCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayer(const CLayer &Other)
|
||||||
|
{
|
||||||
|
str_copy(m_aName, Other.m_aName, sizeof(m_aName));
|
||||||
|
m_Flags = Other.m_Flags;
|
||||||
|
m_pEditor = Other.m_pEditor;
|
||||||
|
m_Type = Other.m_Type;
|
||||||
|
m_BrushRefCount = 0;
|
||||||
|
m_Visible = true;
|
||||||
|
m_Readonly = false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~CLayer()
|
virtual ~CLayer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -147,6 +158,8 @@ public:
|
||||||
virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) {}
|
virtual void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) {}
|
||||||
virtual void ModifySoundIndex(INDEX_MODIFY_FUNC pfnFunc) {}
|
virtual void ModifySoundIndex(INDEX_MODIFY_FUNC pfnFunc) {}
|
||||||
|
|
||||||
|
virtual CLayer *Duplicate() const = 0;
|
||||||
|
|
||||||
virtual void GetSize(float *pWidth, float *pHeight)
|
virtual void GetSize(float *pWidth, float *pHeight)
|
||||||
{
|
{
|
||||||
*pWidth = 0;
|
*pWidth = 0;
|
||||||
|
@ -159,7 +172,6 @@ public:
|
||||||
|
|
||||||
bool m_Readonly;
|
bool m_Readonly;
|
||||||
bool m_Visible;
|
bool m_Visible;
|
||||||
|
|
||||||
int m_BrushRefCount;
|
int m_BrushRefCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,6 +210,7 @@ public:
|
||||||
void GetSize(float *pWidth, float *pHeight) const;
|
void GetSize(float *pWidth, float *pHeight) const;
|
||||||
|
|
||||||
void DeleteLayer(int Index);
|
void DeleteLayer(int Index);
|
||||||
|
void DuplicateLayer(int Index);
|
||||||
int SwapLayers(int Index0, int Index1);
|
int SwapLayers(int Index0, int Index1);
|
||||||
|
|
||||||
bool IsEmpty() const
|
bool IsEmpty() const
|
||||||
|
@ -554,6 +567,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CLayerTiles(int w, int h);
|
CLayerTiles(int w, int h);
|
||||||
|
CLayerTiles(const CLayerTiles &Other);
|
||||||
~CLayerTiles();
|
~CLayerTiles();
|
||||||
|
|
||||||
virtual CTile GetTile(int x, int y);
|
virtual CTile GetTile(int x, int y);
|
||||||
|
@ -580,6 +594,8 @@ public:
|
||||||
void BrushFlipY() override;
|
void BrushFlipY() override;
|
||||||
void BrushRotate(float Amount) override;
|
void BrushRotate(float Amount) override;
|
||||||
|
|
||||||
|
CLayer *Duplicate() const override;
|
||||||
|
|
||||||
virtual void ShowInfo();
|
virtual void ShowInfo();
|
||||||
int RenderProperties(CUIRect *pToolbox) override;
|
int RenderProperties(CUIRect *pToolbox) override;
|
||||||
|
|
||||||
|
@ -637,6 +653,7 @@ class CLayerQuads : public CLayer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CLayerQuads();
|
CLayerQuads();
|
||||||
|
CLayerQuads(const CLayerQuads &Other);
|
||||||
~CLayerQuads();
|
~CLayerQuads();
|
||||||
|
|
||||||
void Render(bool QuadPicker = false) override;
|
void Render(bool QuadPicker = false) override;
|
||||||
|
@ -655,6 +672,7 @@ public:
|
||||||
void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
||||||
|
|
||||||
void GetSize(float *pWidth, float *pHeight) override;
|
void GetSize(float *pWidth, float *pHeight) override;
|
||||||
|
CLayer *Duplicate() const override;
|
||||||
|
|
||||||
int m_Image;
|
int m_Image;
|
||||||
std::vector<CQuad> m_vQuads;
|
std::vector<CQuad> m_vQuads;
|
||||||
|
@ -842,6 +860,7 @@ public:
|
||||||
void DeleteSelectedQuads();
|
void DeleteSelectedQuads();
|
||||||
bool IsQuadSelected(int Index) const;
|
bool IsQuadSelected(int Index) const;
|
||||||
int FindSelectedQuadIndex(int Index) const;
|
int FindSelectedQuadIndex(int Index) const;
|
||||||
|
bool IsSpecialLayer(const CLayer *pLayer) const;
|
||||||
|
|
||||||
float ScaleFontSize(char *pText, int TextSize, float FontSize, int Width);
|
float ScaleFontSize(char *pText, int TextSize, float FontSize, int Width);
|
||||||
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
|
||||||
|
@ -1318,6 +1337,7 @@ class CLayerSounds : public CLayer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CLayerSounds();
|
CLayerSounds();
|
||||||
|
CLayerSounds(const CLayerSounds &Other);
|
||||||
~CLayerSounds();
|
~CLayerSounds();
|
||||||
|
|
||||||
void Render(bool Tileset = false) override;
|
void Render(bool Tileset = false) override;
|
||||||
|
@ -1332,6 +1352,8 @@ public:
|
||||||
void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
void ModifyEnvelopeIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
||||||
void ModifySoundIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
void ModifySoundIndex(INDEX_MODIFY_FUNC pfnFunc) override;
|
||||||
|
|
||||||
|
CLayer *Duplicate() const override;
|
||||||
|
|
||||||
int m_Sound;
|
int m_Sound;
|
||||||
std::vector<CSoundSource> m_vSources;
|
std::vector<CSoundSource> m_vSources;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,13 @@ CLayerQuads::CLayerQuads()
|
||||||
m_Image = -1;
|
m_Image = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayerQuads::CLayerQuads(const CLayerQuads &Other) :
|
||||||
|
CLayer(Other)
|
||||||
|
{
|
||||||
|
m_Image = Other.m_Image;
|
||||||
|
m_vQuads = Other.m_vQuads;
|
||||||
|
}
|
||||||
|
|
||||||
CLayerQuads::~CLayerQuads() = default;
|
CLayerQuads::~CLayerQuads() = default;
|
||||||
|
|
||||||
void CLayerQuads::Render(bool QuadPicker)
|
void CLayerQuads::Render(bool QuadPicker)
|
||||||
|
@ -255,3 +262,8 @@ void CLayerQuads::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func)
|
||||||
Func(&Quad.m_ColorEnv);
|
Func(&Quad.m_ColorEnv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayer *CLayerQuads::Duplicate() const
|
||||||
|
{
|
||||||
|
return new CLayerQuads(*this);
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,13 @@ CLayerSounds::CLayerSounds()
|
||||||
m_Sound = -1;
|
m_Sound = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayerSounds::CLayerSounds(const CLayerSounds &Other) :
|
||||||
|
CLayer(Other)
|
||||||
|
{
|
||||||
|
m_Sound = Other.m_Sound;
|
||||||
|
m_vSources = Other.m_vSources;
|
||||||
|
}
|
||||||
|
|
||||||
CLayerSounds::~CLayerSounds() = default;
|
CLayerSounds::~CLayerSounds() = default;
|
||||||
|
|
||||||
void CLayerSounds::Render(bool Tileset)
|
void CLayerSounds::Render(bool Tileset)
|
||||||
|
@ -219,3 +226,8 @@ void CLayerSounds::ModifyEnvelopeIndex(INDEX_MODIFY_FUNC Func)
|
||||||
Func(&Source.m_PosEnv);
|
Func(&Source.m_PosEnv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayer *CLayerSounds::Duplicate() const
|
||||||
|
{
|
||||||
|
return new CLayerSounds(*this);
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,33 @@ CLayerTiles::CLayerTiles(int w, int h)
|
||||||
mem_zero(m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
|
mem_zero(m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayerTiles::CLayerTiles(const CLayerTiles &Other) :
|
||||||
|
CLayer(Other)
|
||||||
|
{
|
||||||
|
m_Width = Other.m_Width;
|
||||||
|
m_Height = Other.m_Height;
|
||||||
|
m_pTiles = new CTile[m_Width * m_Height];
|
||||||
|
mem_copy(m_pTiles, Other.m_pTiles, (size_t)m_Width * m_Height * sizeof(CTile));
|
||||||
|
|
||||||
|
m_Image = Other.m_Image;
|
||||||
|
m_Texture = Other.m_Texture;
|
||||||
|
m_Game = Other.m_Game;
|
||||||
|
m_Color = Other.m_Color;
|
||||||
|
m_ColorEnv = Other.m_ColorEnv;
|
||||||
|
m_ColorEnvOffset = Other.m_ColorEnvOffset;
|
||||||
|
|
||||||
|
m_AutoMapperConfig = Other.m_AutoMapperConfig;
|
||||||
|
m_Seed = Other.m_Seed;
|
||||||
|
m_AutoAutoMap = Other.m_AutoAutoMap;
|
||||||
|
m_Tele = Other.m_Tele;
|
||||||
|
m_Speedup = Other.m_Speedup;
|
||||||
|
m_Front = Other.m_Front;
|
||||||
|
m_Switch = Other.m_Switch;
|
||||||
|
m_Tune = Other.m_Tune;
|
||||||
|
|
||||||
|
mem_copy(m_aFileName, Other.m_aFileName, IO_MAX_PATH_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
CLayerTiles::~CLayerTiles()
|
CLayerTiles::~CLayerTiles()
|
||||||
{
|
{
|
||||||
delete[] m_pTiles;
|
delete[] m_pTiles;
|
||||||
|
@ -571,6 +598,11 @@ void CLayerTiles::BrushRotate(float Amount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLayer *CLayerTiles::Duplicate() const
|
||||||
|
{
|
||||||
|
return new CLayerTiles(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void CLayerTiles::Resize(int NewW, int NewH)
|
void CLayerTiles::Resize(int NewW, int NewH)
|
||||||
{
|
{
|
||||||
CTile *pNewData = new CTile[NewW * NewH];
|
CTile *pNewData = new CTile[NewW * NewH];
|
||||||
|
|
|
@ -397,6 +397,21 @@ int CEditor::PopupLayer(CEditor *pEditor, CUIRect View, void *pContext)
|
||||||
return CLayerTiles::RenderCommonProperties(pPopup->m_CommonPropState, pEditor, &View, pPopup->m_vpLayers);
|
return CLayerTiles::RenderCommonProperties(pPopup->m_CommonPropState, pEditor, &View, pPopup->m_vpLayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// duplicate layer button
|
||||||
|
CUIRect DupButton;
|
||||||
|
static int s_DuplicationButton = 0;
|
||||||
|
View.HSplitBottom(4.0f, &View, nullptr);
|
||||||
|
View.HSplitBottom(12.0f, &View, &DupButton);
|
||||||
|
|
||||||
|
if(!pEditor->IsSpecialLayer(pEditor->GetSelectedLayer(0)))
|
||||||
|
{
|
||||||
|
if(pEditor->DoButton_Editor(&s_DuplicationButton, "Duplicate layer", 0, &DupButton, 0, "Duplicates the layer"))
|
||||||
|
{
|
||||||
|
pEditor->m_Map.m_vpGroups[pEditor->m_SelectedGroup]->DuplicateLayer(pEditor->m_vSelectedLayers[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// don't allow deletion of game layer
|
// don't allow deletion of game layer
|
||||||
if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0) &&
|
if(pEditor->m_Map.m_pGameLayer != pEditor->GetSelectedLayer(0) &&
|
||||||
pEditor->DoButton_Editor(&s_DeleteButton, "Delete layer", 0, &Button, 0, "Deletes the layer"))
|
pEditor->DoButton_Editor(&s_DeleteButton, "Delete layer", 0, &Button, 0, "Deletes the layer"))
|
||||||
|
|
Loading…
Reference in a new issue