diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 5c50512df..f33433566 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -3922,133 +3922,20 @@ void CEditor::SortImages() } } -void CEditor::RenderImages(CUIRect ToolBox, CUIRect View) +void CEditor::RenderImagesList(CUIRect ToolBox) { - static float s_ScrollValue = 0; - float ImagesHeight = 30.0f + 14.0f * m_Map.m_vpImages.size() + 27.0f; - float ScrollDifference = ImagesHeight - ToolBox.h; + const float RowHeight = 12.0f; - if(ImagesHeight > ToolBox.h) // Do we even need a scrollbar? - { - CUIRect Scroll; - ToolBox.VSplitRight(20.0f, &ToolBox, &Scroll); - s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue); - - if(UI()->MouseInside(&Scroll) || UI()->MouseInside(&ToolBox)) - { - int ScrollNum = (int)((ImagesHeight - ToolBox.h) / 14.0f) + 1; - if(ScrollNum > 0) - { - if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP)) - s_ScrollValue = clamp(s_ScrollValue - 1.0f / ScrollNum, 0.0f, 1.0f); - if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN)) - s_ScrollValue = clamp(s_ScrollValue + 1.0f / ScrollNum, 0.0f, 1.0f); - } - } - } - - float ImageStartAt = ScrollDifference * s_ScrollValue; - if(ImageStartAt < 0.0f) - ImageStartAt = 0.0f; - - float ImageStopAt = ImagesHeight - ScrollDifference * (1 - s_ScrollValue); - float ImageCur = 0.0f; - - for(int e = 0; e < 2; e++) // two passes, first embedded, then external - { - CUIRect Slot; - - if(ImageCur > ImageStopAt) - break; - else if(ImageCur >= ImageStartAt) - { - ToolBox.HSplitTop(15.0f, &Slot, &ToolBox); - if(e == 0) - UI()->DoLabel(&Slot, "Embedded", 12.0f, TEXTALIGN_CENTER); - else - UI()->DoLabel(&Slot, "External", 12.0f, TEXTALIGN_CENTER); - } - ImageCur += 15.0f; - - for(int i = 0; i < (int)m_Map.m_vpImages.size(); i++) - { - if((e && !m_Map.m_vpImages[i]->m_External) || - (!e && m_Map.m_vpImages[i]->m_External)) - { - continue; - } - - if(ImageCur > ImageStopAt) - break; - else if(ImageCur < ImageStartAt) - { - ImageCur += 14.0f; - continue; - } - ImageCur += 14.0f; - - char aBuf[128]; - str_copy(aBuf, m_Map.m_vpImages[i]->m_aName, sizeof(aBuf)); - ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); - - int Selected = m_SelectedImage == i; - - const bool ImageUsed = std::any_of(m_Map.m_vpGroups.cbegin(), m_Map.m_vpGroups.cend(), [i](const auto &pGroup) { - return std::any_of(pGroup->m_vpLayers.cbegin(), pGroup->m_vpLayers.cend(), [i](const auto &pLayer) { - if(pLayer->m_Type == LAYERTYPE_QUADS) - return static_cast(pLayer)->m_Image == i; - else if(pLayer->m_Type == LAYERTYPE_TILES) - return static_cast(pLayer)->m_Image == i; - return false; - }); - }); - - if(!ImageUsed) - Selected += 2; // Image is unused - - if(Selected < 2 && e == 1) - { - if(!IsVanillaImage(m_Map.m_vpImages[i]->m_aName)) - { - Selected += 4; // Image should be embedded - } - } - - float FontSize = 10.0f; - while(TextRender()->TextWidth(nullptr, FontSize, aBuf, -1, -1.0f) > Slot.w) - FontSize--; - - if(int Result = DoButton_Ex(&m_Map.m_vpImages[i], aBuf, Selected, &Slot, - BUTTON_CONTEXT, "Select image.", 0, FontSize)) - { - m_SelectedImage = i; - - static int s_PopupImageID = 0; - if(Result == 2) - { - CEditorImage *pImg = m_Map.m_vpImages[m_SelectedImage]; - int Height; - if(pImg->m_External || IsVanillaImage(pImg->m_aName)) - Height = 60; - else - Height = 43; - UiInvokePopupMenu(&s_PopupImageID, 0, UI()->MouseX(), UI()->MouseY(), 120, Height, PopupImage); - } - } - - ToolBox.HSplitTop(2.0f, nullptr, &ToolBox); - } - - // separator - ToolBox.HSplitTop(5.0f, &Slot, &ToolBox); - ImageCur += 5.0f; - IGraphics::CLineItem LineItem(Slot.x, Slot.y + Slot.h / 2, Slot.x + Slot.w, Slot.y + Slot.h / 2); - Graphics()->TextureClear(); - Graphics()->LinesBegin(); - Graphics()->LinesDraw(&LineItem, 1); - Graphics()->LinesEnd(); - } + static CScrollRegion s_ScrollRegion; + vec2 ScrollOffset(0.0f, 0.0f); + CScrollRegionParams ScrollParams; + ScrollParams.m_ScrollbarWidth = 10.0f; + ScrollParams.m_ScrollbarMargin = 3.0f; + ScrollParams.m_ScrollUnit = RowHeight * 5; + s_ScrollRegion.Begin(&ToolBox, &ScrollOffset, &ScrollParams); + ToolBox.y += ScrollOffset.y; + bool ScrollToSelection = false; if(Input()->KeyPress(KEY_DOWN) && m_Dialog == DIALOG_NONE) { int OldImage = m_SelectedImage; @@ -4072,6 +3959,7 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect View) } } } + ScrollToSelection = OldImage != m_SelectedImage; } if(Input()->KeyPress(KEY_UP) && m_Dialog == DIALOG_NONE) { @@ -4096,44 +3984,124 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect View) } } } + ScrollToSelection = OldImage != m_SelectedImage; } - // render image - int i = m_SelectedImage; - if(i >= 0 && (size_t)i < m_Map.m_vpImages.size()) + for(int e = 0; e < 2; e++) // two passes, first embedded, then external { - CUIRect r; - View.Margin(10.0f, &r); - if(r.h < r.w) - r.w = r.h; - else - r.h = r.w; - float Max = (float)(maximum(m_Map.m_vpImages[i]->m_Width, m_Map.m_vpImages[i]->m_Height)); - r.w *= m_Map.m_vpImages[i]->m_Width / Max; - r.h *= m_Map.m_vpImages[i]->m_Height / Max; - Graphics()->TextureSet(m_Map.m_vpImages[i]->m_Texture); - Graphics()->BlendNormal(); - Graphics()->WrapClamp(); - Graphics()->QuadsBegin(); - IGraphics::CQuadItem QuadItem(r.x, r.y, r.w, r.h); - Graphics()->QuadsDrawTL(&QuadItem, 1); - Graphics()->QuadsEnd(); - Graphics()->WrapNormal(); - } - //if(ImageCur + 27.0f > ImageStopAt) - // return; + CUIRect Slot; + ToolBox.HSplitTop(RowHeight + 3.0f, &Slot, &ToolBox); + if(s_ScrollRegion.AddRect(Slot)) + UI()->DoLabel(&Slot, e == 0 ? "Embedded" : "External", 12.0f, TEXTALIGN_CENTER); - CUIRect Slot; - ToolBox.HSplitTop(5.0f, &Slot, &ToolBox); + for(int i = 0; i < (int)m_Map.m_vpImages.size(); i++) + { + if((e && !m_Map.m_vpImages[i]->m_External) || + (!e && m_Map.m_vpImages[i]->m_External)) + { + continue; + } + + ToolBox.HSplitTop(RowHeight + 2.0f, &Slot, &ToolBox); + int Selected = m_SelectedImage == i; + if(!s_ScrollRegion.AddRect(Slot, Selected && ScrollToSelection)) + continue; + Slot.HSplitTop(RowHeight, &Slot, nullptr); + + const bool ImageUsed = std::any_of(m_Map.m_vpGroups.cbegin(), m_Map.m_vpGroups.cend(), [i](const auto &pGroup) { + return std::any_of(pGroup->m_vpLayers.cbegin(), pGroup->m_vpLayers.cend(), [i](const auto &pLayer) { + if(pLayer->m_Type == LAYERTYPE_QUADS) + return static_cast(pLayer)->m_Image == i; + else if(pLayer->m_Type == LAYERTYPE_TILES) + return static_cast(pLayer)->m_Image == i; + return false; + }); + }); + + if(!ImageUsed) + Selected += 2; // Image is unused + + if(Selected < 2 && e == 1) + { + if(!IsVanillaImage(m_Map.m_vpImages[i]->m_aName)) + { + Selected += 4; // Image should be embedded + } + } + + float FontSize = 10.0f; + while(TextRender()->TextWidth(nullptr, FontSize, m_Map.m_vpImages[i]->m_aName, -1, -1.0f) > Slot.w) + FontSize--; + + if(int Result = DoButton_Ex(&m_Map.m_vpImages[i], m_Map.m_vpImages[i]->m_aName, Selected, &Slot, + BUTTON_CONTEXT, "Select image.", IGraphics::CORNER_ALL, FontSize)) + { + m_SelectedImage = i; + + static int s_PopupImageID = 0; + if(Result == 2) + { + CEditorImage *pImg = m_Map.m_vpImages[m_SelectedImage]; + int Height; + if(pImg->m_External || IsVanillaImage(pImg->m_aName)) + Height = 60; + else + Height = 43; + UiInvokePopupMenu(&s_PopupImageID, 0, UI()->MouseX(), UI()->MouseY(), 120, Height, PopupImage); + } + } + } + + // separator + ToolBox.HSplitTop(5.0f, &Slot, &ToolBox); + if(s_ScrollRegion.AddRect(Slot)) + { + IGraphics::CLineItem LineItem(Slot.x, Slot.y + Slot.h / 2, Slot.x + Slot.w, Slot.y + Slot.h / 2); + Graphics()->TextureClear(); + Graphics()->LinesBegin(); + Graphics()->LinesDraw(&LineItem, 1); + Graphics()->LinesEnd(); + } + } // new image - static int s_NewImageButton = 0; - ToolBox.HSplitTop(12.0f, &Slot, &ToolBox); - if(DoButton_Editor(&s_NewImageButton, "Add", 0, &Slot, 0, "Load a new image to use in the map")) - InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", "", AddImage, this); + static int s_AddImageButton = 0; + CUIRect AddImageButton; + ToolBox.HSplitTop(5.0f + RowHeight + 1.0f, &AddImageButton, &ToolBox); + if(s_ScrollRegion.AddRect(AddImageButton)) + { + AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton); + AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr); + if(DoButton_Editor(&s_AddImageButton, "Add", 0, &AddImageButton, 0, "Load a new image to use in the map")) + InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", "", AddImage, this); + } + s_ScrollRegion.End(); } -void CEditor::RenderSounds(CUIRect ToolBox, CUIRect View) +void CEditor::RenderSelectedImage(CUIRect View) +{ + if(m_SelectedImage < 0 || (size_t)m_SelectedImage >= m_Map.m_vpImages.size()) + return; + + View.Margin(10.0f, &View); + if(View.h < View.w) + View.w = View.h; + else + View.h = View.w; + float Max = maximum(m_Map.m_vpImages[m_SelectedImage]->m_Width, m_Map.m_vpImages[m_SelectedImage]->m_Height); + View.w *= m_Map.m_vpImages[m_SelectedImage]->m_Width / Max; + View.h *= m_Map.m_vpImages[m_SelectedImage]->m_Height / Max; + Graphics()->TextureSet(m_Map.m_vpImages[m_SelectedImage]->m_Texture); + Graphics()->BlendNormal(); + Graphics()->WrapClamp(); + Graphics()->QuadsBegin(); + IGraphics::CQuadItem QuadItem(View.x, View.y, View.w, View.h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + Graphics()->WrapNormal(); +} + +void CEditor::RenderSounds(CUIRect ToolBox) { static float s_ScrollValue = 0; float SoundsHeight = 30.0f + 14.0f * m_Map.m_vpSounds.size() + 27.0f; @@ -5902,7 +5870,10 @@ void CEditor::Render() if(m_Mode == MODE_LAYERS) RenderLayers(ToolBox); else if(m_Mode == MODE_IMAGES) - RenderImages(ToolBox, View); + { + RenderImagesList(ToolBox); + RenderSelectedImage(View); + } else if(m_Mode == MODE_SOUNDS) RenderSounds(ToolBox, View); } diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 7ebdc0e0d..d5cb0dcfa 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -1127,7 +1127,8 @@ public: bool IsEnvelopeUsed(int EnvelopeIndex) const; void RenderLayers(CUIRect LayersBox); - void RenderImages(CUIRect Toolbox, CUIRect View); + void RenderImagesList(CUIRect Toolbox); + void RenderSelectedImage(CUIRect View); void RenderSounds(CUIRect Toolbox, CUIRect View); void RenderModebar(CUIRect View); void RenderStatusbar(CUIRect View);