From 6aa4487c5ddf4b50ada7a037a50a81659e891b30 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Wed, 12 Jun 2024 22:28:06 +0800 Subject: [PATCH 1/8] Add an ability to edit Rumors for maps close #8714 --- VisualStudio/fheroes2/sources.props | 2 + src/fheroes2/agg/agg_image.cpp | 17 +- src/fheroes2/agg/icn.h | 3 + .../editor/editor_map_specs_window.cpp | 20 +- src/fheroes2/editor/editor_rumor_window.cpp | 279 ++++++++++++++++++ src/fheroes2/editor/editor_rumor_window.h | 29 ++ src/fheroes2/world/world.cpp | 12 +- src/fheroes2/world/world.h | 2 +- src/fheroes2/world/world_loadmap.cpp | 6 +- 9 files changed, 357 insertions(+), 13 deletions(-) create mode 100644 src/fheroes2/editor/editor_rumor_window.cpp create mode 100644 src/fheroes2/editor/editor_rumor_window.h diff --git a/VisualStudio/fheroes2/sources.props b/VisualStudio/fheroes2/sources.props index 9afb1ece581..0e5be57fb5d 100644 --- a/VisualStudio/fheroes2/sources.props +++ b/VisualStudio/fheroes2/sources.props @@ -114,6 +114,7 @@ + @@ -330,6 +331,7 @@ + diff --git a/src/fheroes2/agg/agg_image.cpp b/src/fheroes2/agg/agg_image.cpp index 32963461564..6fc4737a4c5 100644 --- a/src/fheroes2/agg/agg_image.cpp +++ b/src/fheroes2/agg/agg_image.cpp @@ -182,7 +182,9 @@ namespace ICN::BUTTON_HSCORES_VERTICAL_EXIT, ICN::BUTTON_HSCORES_VERTICAL_STANDARD, ICN::DISMISS_HERO_DISABLED_BUTTON, - ICN::NEW_CAMPAIGN_DISABLED_BUTTON }; + ICN::NEW_CAMPAIGN_DISABLED_BUTTON, + ICN::BUTTON_RUMORS_GOOD, + ICN::BUTTON_RUMORS_EVIL }; #ifndef NDEBUG bool isLanguageDependentIcnId( const int id ) @@ -2105,6 +2107,17 @@ namespace fheroes2 break; } + case ICN::BUTTON_RUMORS_GOOD: + case ICN::BUTTON_RUMORS_EVIL: { + _icnVsSprite[id].resize( 2 ); + + const bool isEvilInterface = ( id == ICN::BUTTON_RUMORS_EVIL ); + + getTextAdaptedButton( _icnVsSprite[id][0], _icnVsSprite[id][1], gettext_noop( "RUMORS" ), + isEvilInterface ? ICN::EMPTY_EVIL_BUTTON : ICN::EMPTY_GOOD_BUTTON, isEvilInterface ? ICN::STONEBAK_EVIL : ICN::STONEBAK ); + + break; + } default: // You're calling this function for non-specified ICN id. Check your logic! // Did you add a new image for one language without generating a default @@ -2765,6 +2778,8 @@ namespace fheroes2 case ICN::BUTTON_HSCORES_VERTICAL_CAMPAIGN: case ICN::BUTTON_HSCORES_VERTICAL_EXIT: case ICN::BUTTON_HSCORES_VERTICAL_STANDARD: + case ICN::BUTTON_RUMORS_GOOD: + case ICN::BUTTON_RUMORS_EVIL: generateLanguageSpecificImages( id ); return true; case ICN::PHOENIX: diff --git a/src/fheroes2/agg/icn.h b/src/fheroes2/agg/icn.h index 202f7f2fbc4..cdada782012 100644 --- a/src/fheroes2/agg/icn.h +++ b/src/fheroes2/agg/icn.h @@ -1116,6 +1116,9 @@ namespace ICN BUTTON_LOAD_MAP_EVIL, BUTTON_LOAD_MAP_GOOD, + BUTTON_RUMORS_GOOD, + BUTTON_RUMORS_EVIL, + // IMPORTANT! Put any new entry just above this one. LASTICN }; diff --git a/src/fheroes2/editor/editor_map_specs_window.cpp b/src/fheroes2/editor/editor_map_specs_window.cpp index 236a34637cb..c2800b49f06 100644 --- a/src/fheroes2/editor/editor_map_specs_window.cpp +++ b/src/fheroes2/editor/editor_map_specs_window.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2024 * * * * 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 * @@ -34,6 +34,7 @@ #include "cursor.h" #include "dialog.h" #include "difficulty.h" +#include "editor_rumor_window.h" #include "game_hotkeys.h" #include "icn.h" #include "image.h" @@ -588,6 +589,11 @@ namespace Editor background.renderButton( buttonOk, buttonOkIcn, 0, 1, { 20 + buttonCancelRoi.width + 10, 6 }, fheroes2::StandardWindow::Padding::BOTTOM_RIGHT ); const fheroes2::Rect buttonOkRoi( buttonOk.area() ); + fheroes2::Button buttonRumors; + const int buttonRumorsIcn = isEvilInterface ? ICN::BUTTON_RUMORS_EVIL : ICN::BUTTON_RUMORS_GOOD; + background.renderButton( buttonRumors, buttonRumorsIcn, 0, 1, { 20, 6 }, fheroes2::StandardWindow::Padding::BOTTOM_LEFT ); + const fheroes2::Rect buttonRumorsRoi( buttonRumors.area() ); + LocalEvent & le = LocalEvent::Get(); display.render( background.totalArea() ); @@ -595,6 +601,7 @@ namespace Editor while ( le.HandleEvents() ) { buttonOk.drawOnState( le.isMouseLeftButtonPressedInArea( buttonOkRoi ) ); buttonCancel.drawOnState( le.isMouseLeftButtonPressedInArea( buttonCancelRoi ) ); + buttonRumors.drawOnState( le.isMouseLeftButtonPressedInArea( buttonRumorsRoi ) ); #ifndef HIDE_VICTORY_LOSS_CONDITIONS victoryDroplistButton.drawOnState( le.isMouseLeftButtonPressedInArea( victoryDroplistButtonRoi ) ); lossDroplistButton.drawOnState( le.isMouseLeftButtonPressedInArea( lossDroplistButtonRoi ) ); @@ -608,7 +615,13 @@ namespace Editor break; } - if ( le.MouseClickLeft( mapNameRoi ) ) { + if ( le.MouseClickLeft( buttonRumorsRoi ) ) { + auto temp = mapFormat.rumors; + if ( openRumorWindow( temp ) ) { + mapFormat.rumors = std::move( temp ); + } + } + else if ( le.MouseClickLeft( mapNameRoi ) ) { // TODO: Edit texts directly in this dialog. std::string editableMapName = mapFormat.name; @@ -679,6 +692,9 @@ namespace Editor else if ( le.isMouseRightButtonPressedInArea( buttonOkRoi ) ) { fheroes2::showStandardTextMessage( _( "Okay" ), _( "Click to accept the changes made." ), Dialog::ZERO ); } + else if ( le.isMouseRightButtonPressedInArea( buttonRumorsRoi ) ) { + fheroes2::showStandardTextMessage( _( "Rumors" ), _( "Click to edit custom rumors." ), Dialog::ZERO ); + } else if ( le.isMouseRightButtonPressedInArea( mapNameRoi ) ) { fheroes2::showStandardTextMessage( _( "Map Name" ), _( "Click to change your map name." ), Dialog::ZERO ); } diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp new file mode 100644 index 00000000000..ceace35aac7 --- /dev/null +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -0,0 +1,279 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2024 * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "editor_rumor_window.h" + +#include + +#include "agg_image.h" +#include "cursor.h" +#include "dialog.h" +#include "game_hotkeys.h" +#include "icn.h" +#include "interface_list.h" +#include "settings.h" +#include "translations.h" +#include "ui_window.h" +#include "ui_dialog.h" + +namespace +{ + const int32_t elementOffset{ 9 }; + + const fheroes2::Size rumorArea{ 400, 200 }; + + const int32_t listAreaHeightDeduction{ 8 }; + + const size_t longestRumor{ 300 }; + + class RumorListBox final : public Interface::ListBox + { + public: + using Interface::ListBox::ActionListDoubleClick; + using Interface::ListBox::ActionListSingleClick; + using Interface::ListBox::ActionListPressRight; + + using ListBox::ListBox; + + void RedrawItem( const std::string & rumor, int32_t posX, int32_t posY, bool current ) override + { + fheroes2::Text text{ rumor, ( current ? fheroes2::FontType::normalYellow() : fheroes2::FontType::normalWhite() ) }; + text.fitToOneRow( rumorArea.width - 10 ); + text.draw( posX + 5, posY + 5, fheroes2::Display::instance() ); + } + + void RedrawBackground( const fheroes2::Point & /*unused*/ ) override + { + _listBackground->restore(); + } + + void ActionCurrentUp() override + { + // Do nothing. + } + + void ActionCurrentDn() override + { + // Do nothing. + } + + void ActionListDoubleClick( std::string & /*unused*/ ) override + { + // Do nothing. + } + + void ActionListSingleClick( std::string & /*unused*/ ) override + { + // Do nothing. + } + + void ActionListPressRight( std::string & /*unused*/ ) override + { + // Do nothing. + } + + int getCurrentId() const + { + return _currentId; + } + + void initListBackgroundRestorer( fheroes2::Rect roi ) + { + _listBackground = std::make_unique( fheroes2::Display::instance(), roi.x, roi.y, roi.width, roi.height ); + } + + void updateScrollBarImage() + { + const int32_t scrollBarWidth = _scrollbar.width(); + + setScrollBarImage( fheroes2::generateScrollbarSlider( _scrollbar, false, _scrollbar.getArea().height, VisibleItemCount(), _size(), + { 0, 0, scrollBarWidth, 8 }, { 0, 7, scrollBarWidth, 8 } ) ); + _scrollbar.moveToIndex( _topId ); + } + + private: + std::unique_ptr _listBackground; + }; +} + +namespace Editor +{ + bool openRumorWindow( std::vector & rumors ) + { + // Remove all empty rumors. + rumors.erase( std::remove_if( rumors.begin(), rumors.end(), []( const auto & rumor ) { return rumor.empty(); } ), rumors.end() ); + + const CursorRestorer cursorRestorer( true, Cursor::POINTER ); + + fheroes2::Display & display = fheroes2::Display::instance(); + fheroes2::StandardWindow background{ rumorArea.width + 50, rumorArea.height + 100, true, display }; + + const fheroes2::Rect windowArea{ background.activeArea() }; + + int32_t offsetY = windowArea.y + elementOffset; + + const fheroes2::Text title( _( "Rumors" ), fheroes2::FontType::normalYellow() ); + title.draw( windowArea.x + ( windowArea.width - title.width() ) / 2, offsetY, display ); + + offsetY += title.height() + elementOffset; + + const fheroes2::Rect rumorsRoi{ windowArea.x + elementOffset, offsetY, rumorArea.width, rumorArea.height }; + background.applyTextBackgroundShading( rumorsRoi ); + + const bool isEvilInterface = Settings::Get().isEvilInterfaceEnabled(); + + RumorListBox rumorList( rumorsRoi.getPosition() ); + rumorList.initListBackgroundRestorer( rumorsRoi ); + + rumorList.SetAreaItems( { rumorsRoi.x, rumorsRoi.y, rumorsRoi.width, rumorsRoi.height - listAreaHeightDeduction } ); + + int32_t scrollbarOffsetX = rumorsRoi.x + rumorsRoi.width + 5; + background.renderScrollbarBackground( { scrollbarOffsetX, rumorsRoi.y, rumorsRoi.width, rumorsRoi.height }, isEvilInterface ); + + const int listIcnId = isEvilInterface ? ICN::SCROLLE : ICN::SCROLL; + const int32_t topPartHeight = 19; + ++scrollbarOffsetX; + + rumorList.SetScrollButtonUp( listIcnId, 0, 1, { scrollbarOffsetX, rumorsRoi.y + 1 } ); + rumorList.SetScrollButtonDn( listIcnId, 2, 3, { scrollbarOffsetX, rumorsRoi.y + rumorsRoi.height - 15 } ); + rumorList.setScrollBarArea( { scrollbarOffsetX + 2, rumorsRoi.y + topPartHeight, 10, rumorsRoi.height - 2 * topPartHeight } ); + rumorList.setScrollBarImage( fheroes2::AGG::GetICN( listIcnId, 4 ) ); + rumorList.SetAreaMaxItems( 10 ); + rumorList.SetListContent( rumors ); + rumorList.updateScrollBarImage(); + + rumorList.Redraw(); + + const fheroes2::Sprite & buttonImage = fheroes2::AGG::GetICN( ICN::CELLWIN, 13 ); + const int32_t buttonWidth = buttonImage.width(); + const int32_t buttonOffset = ( rumorArea.width - 3 * buttonWidth ) / 2 + buttonWidth; + + fheroes2::Button buttonAdd( rumorsRoi.x, rumorsRoi.y + rumorsRoi.height + 5, ICN::CELLWIN, 13, 14 ); + buttonAdd.draw(); + + fheroes2::Button buttonEdit( rumorsRoi.x + buttonOffset, rumorsRoi.y + rumorsRoi.height + 5, ICN::CELLWIN, 15, 16 ); + buttonEdit.draw(); + + fheroes2::Button buttonDelete( rumorsRoi.x + rumorArea.width - buttonWidth, rumorsRoi.y + rumorsRoi.height + 5, ICN::CELLWIN, 17, 18 ); + buttonDelete.draw(); + + // Prepare OKAY and CANCEL buttons and render their shadows. + fheroes2::Button buttonOk; + fheroes2::Button buttonCancel; + + background.renderOkayCancelButtons( buttonOk, buttonCancel, isEvilInterface ); + + display.render( background.totalArea() ); + + bool isRedrawNeeded = false; + + LocalEvent & le = LocalEvent::Get(); + while ( le.HandleEvents() ) { + buttonOk.drawOnState( le.isMouseLeftButtonPressedInArea( buttonOk.area() ) ); + buttonCancel.drawOnState( le.isMouseLeftButtonPressedInArea( buttonCancel.area() ) ); + buttonAdd.drawOnState( le.isMouseLeftButtonPressedInArea( buttonAdd.area() ) ); + buttonEdit.drawOnState( le.isMouseLeftButtonPressedInArea( buttonEdit.area() ) ); + buttonDelete.drawOnState( le.isMouseLeftButtonPressedInArea( buttonDelete.area() ) ); + + if ( le.MouseClickLeft( buttonCancel.area() ) || Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_CANCEL ) ) { + break; + } + + if ( buttonOk.isEnabled() && ( le.MouseClickLeft( buttonOk.area() ) || Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_OKAY ) ) ) { + return true; + } + + rumorList.QueueEventProcessing(); + + if ( rumorList.IsNeedRedraw() ) { + rumorList.Redraw(); + isRedrawNeeded = true; + } + + if ( le.MouseClickLeft( buttonAdd.area() ) ) { + std::string newRumor; + if ( Dialog::inputString( _( "Rumor:" ), newRumor, {}, longestRumor, false, true ) ) { + if ( std::any_of( rumors.begin(), rumors.end(), [&newRumor]( const auto & rumor ) { return rumor == newRumor; } ) ) { + fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor exists in the list." ), Dialog::OK ); + continue; + } + + rumors.emplace_back( std::move( newRumor ) ); + + rumorList.updateScrollBarImage(); + rumorList.Redraw(); + isRedrawNeeded = true; + } + } + else if ( le.MouseClickLeft( buttonEdit.area() ) ) { + if ( rumorList.getCurrentId() < 0 ) { + continue; + } + + std::string temp = rumorList.GetCurrent(); + if ( Dialog::inputString( _( "Rumor:" ), temp, {}, longestRumor, false, true ) ) { + const auto count = std::count_if( rumors.begin(), rumors.end(), [&temp]( const auto & rumor ) { return rumor == temp; } ); + if ( rumorList.GetCurrent() != temp && count > 0 ) { + fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor exists in the list." ), Dialog::OK ); + continue; + } + + rumorList.GetCurrent() = std::move( temp ); + + rumorList.Redraw(); + isRedrawNeeded = true; + } + } + else if ( le.MouseClickLeft( buttonDelete.area() ) ) { + if ( rumorList.getCurrentId() < 0 ) { + continue; + } + + rumorList.RemoveSelected(); + rumorList.updateScrollBarImage(); + rumorList.Redraw(); + isRedrawNeeded = true; + } + else if ( le.isMouseRightButtonPressedInArea( buttonCancel.area() ) ) { + fheroes2::showStandardTextMessage( _( "Cancel" ), _( "Exit this menu without doing anything." ), Dialog::ZERO ); + } + else if ( le.isMouseRightButtonPressedInArea( buttonOk.area() ) ) { + fheroes2::showStandardTextMessage( _( "Okay" ), _( "Click to save rumors." ), Dialog::ZERO ); + } + else if ( le.isMouseRightButtonPressedInArea( buttonAdd.area() ) ) { + fheroes2::showStandardTextMessage( _( "Add Rumor" ), _( "Add an additional rumor for the question." ), Dialog::ZERO ); + } + else if ( le.isMouseRightButtonPressedInArea( buttonEdit.area() ) ) { + fheroes2::showStandardTextMessage( _( "Edit Rumor" ), _( "Edit an existing rumor for the question." ), Dialog::ZERO ); + } + else if ( le.isMouseRightButtonPressedInArea( buttonDelete.area() ) ) { + fheroes2::showStandardTextMessage( _( "Delete Rumor" ), _( "Delete an existing rumor for the question." ), Dialog::ZERO ); + } + + if ( isRedrawNeeded ) { + isRedrawNeeded = false; + + display.render( windowArea ); + } + } + + return false; + } +} diff --git a/src/fheroes2/editor/editor_rumor_window.h b/src/fheroes2/editor/editor_rumor_window.h new file mode 100644 index 00000000000..7794673d61b --- /dev/null +++ b/src/fheroes2/editor/editor_rumor_window.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * fheroes2: https://github.com/ihhub/fheroes2 * + * Copyright (C) 2024 * + * * + * 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 * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#pragma once + +#include +#include + +namespace Editor +{ + bool openRumorWindow( std::vector & rumors ); +} diff --git a/src/fheroes2/world/world.cpp b/src/fheroes2/world/world.cpp index 94bd70cea3c..631375cc768 100644 --- a/src/fheroes2/world/world.cpp +++ b/src/fheroes2/world/world.cpp @@ -329,7 +329,7 @@ void World::Reset() vec_eventsday.clear(); // rumors - _rumors.clear(); + _customRumors.clear(); // castles vec_castles.Clear(); @@ -711,7 +711,7 @@ void World::MonthOfMonstersAction( const Monster & mons ) std::string World::getCurrentRumor() const { const uint32_t standardRumorCount = 10; - const uint32_t totalRumorCount = static_cast( _rumors.size() ) + standardRumorCount; + const uint32_t totalRumorCount = static_cast( _customRumors.size() ) + standardRumorCount; const uint32_t chosenRumorId = Rand::GetWithSeed( 0, totalRumorCount - 1, GetWeekSeed() ); switch ( chosenRumorId ) { @@ -779,7 +779,7 @@ std::string World::getCurrentRumor() const } assert( chosenRumorId >= standardRumorCount && chosenRumorId < totalRumorCount ); - return _rumors[chosenRumorId - standardRumorCount]; + return _customRumors[chosenRumorId - standardRumorCount]; } MapsIndexes World::GetTeleportEndPoints( const int32_t index ) const @@ -1441,7 +1441,7 @@ StreamBase & operator>>( StreamBase & msg, MapObjects & objs ) StreamBase & operator<<( StreamBase & msg, const World & w ) { - return msg << w.width << w.height << w.vec_tiles << w.vec_heroes << w.vec_castles << w.vec_kingdoms << w._rumors << w.vec_eventsday << w.map_captureobj + return msg << w.width << w.height << w.vec_tiles << w.vec_heroes << w.vec_castles << w.vec_kingdoms << w._customRumors << w.vec_eventsday << w.map_captureobj << w.ultimate_artifact << w.day << w.week << w.month << w.heroIdAsWinCondition << w.heroIdAsLossCondition << w.map_objects << w._seed; } @@ -1460,8 +1460,8 @@ StreamBase & operator>>( StreamBase & msg, World & w ) msg >> w.width >> w.height; } - msg >> w.vec_tiles >> w.vec_heroes >> w.vec_castles >> w.vec_kingdoms >> w._rumors >> w.vec_eventsday >> w.map_captureobj >> w.ultimate_artifact >> w.day >> w.week - >> w.month >> w.heroIdAsWinCondition >> w.heroIdAsLossCondition; + msg >> w.vec_tiles >> w.vec_heroes >> w.vec_castles >> w.vec_kingdoms >> w._customRumors >> w.vec_eventsday >> w.map_captureobj >> w.ultimate_artifact >> w.day + >> w.week >> w.month >> w.heroIdAsWinCondition >> w.heroIdAsLossCondition; static_assert( LAST_SUPPORTED_FORMAT_VERSION < FORMAT_VERSION_1010_RELEASE, "Remove the logic below." ); if ( Game::GetVersionOfCurrentSaveFile() < FORMAT_VERSION_1010_RELEASE ) { diff --git a/src/fheroes2/world/world.h b/src/fheroes2/world/world.h index 91bbe24f38b..984fc920296 100644 --- a/src/fheroes2/world/world.h +++ b/src/fheroes2/world/world.h @@ -389,7 +389,7 @@ class World : protected fheroes2::Size AllHeroes vec_heroes; AllCastles vec_castles; Kingdoms vec_kingdoms; - std::vector _rumors; + std::vector _customRumors; EventsDate vec_eventsday; // index, object, color diff --git a/src/fheroes2/world/world_loadmap.cpp b/src/fheroes2/world/world_loadmap.cpp index 965cf253da1..e40023ddbbf 100644 --- a/src/fheroes2/world/world_loadmap.cpp +++ b/src/fheroes2/world/world_loadmap.cpp @@ -647,8 +647,8 @@ bool World::LoadMapMP2( const std::string & filename, const bool isOriginalMp2Fi std::string rumor( reinterpret_cast( pblock.data() ) + 8 ); if ( !rumor.empty() ) { - _rumors.emplace_back( std::move( rumor ) ); - DEBUG_LOG( DBG_GAME, DBG_INFO, "MP2 format: add rumor " << _rumors.back() ) + _customRumors.emplace_back( std::move( rumor ) ); + DEBUG_LOG( DBG_GAME, DBG_INFO, "MP2 format: add rumor " << _customRumors.back() ) } } else { @@ -1057,7 +1057,7 @@ bool World::loadResurrectionMap( const std::string & filename ) // Load rumors. for ( auto & rumor : map.rumors ) { if ( !rumor.empty() ) { - _rumors.emplace_back( std::move( rumor ) ); + _customRumors.emplace_back( std::move( rumor ) ); } } From ce2ec382712995962145b46ccad9b1c430b012ca Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Wed, 12 Jun 2024 22:29:20 +0800 Subject: [PATCH 2/8] Sort headers --- src/fheroes2/editor/editor_rumor_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index ceace35aac7..7752c9b6eeb 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -30,8 +30,8 @@ #include "interface_list.h" #include "settings.h" #include "translations.h" -#include "ui_window.h" #include "ui_dialog.h" +#include "ui_window.h" namespace { From a2ef62c91080b34f81a48b834ec4f4c605f577b5 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Wed, 12 Jun 2024 22:31:26 +0800 Subject: [PATCH 3/8] Update texts --- src/fheroes2/editor/editor_rumor_window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index 7752c9b6eeb..55bd0eb37c1 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -258,13 +258,13 @@ namespace Editor fheroes2::showStandardTextMessage( _( "Okay" ), _( "Click to save rumors." ), Dialog::ZERO ); } else if ( le.isMouseRightButtonPressedInArea( buttonAdd.area() ) ) { - fheroes2::showStandardTextMessage( _( "Add Rumor" ), _( "Add an additional rumor for the question." ), Dialog::ZERO ); + fheroes2::showStandardTextMessage( _( "Add Rumor" ), _( "Add an additional rumor." ), Dialog::ZERO ); } else if ( le.isMouseRightButtonPressedInArea( buttonEdit.area() ) ) { - fheroes2::showStandardTextMessage( _( "Edit Rumor" ), _( "Edit an existing rumor for the question." ), Dialog::ZERO ); + fheroes2::showStandardTextMessage( _( "Edit Rumor" ), _( "Edit an existing rumor." ), Dialog::ZERO ); } else if ( le.isMouseRightButtonPressedInArea( buttonDelete.area() ) ) { - fheroes2::showStandardTextMessage( _( "Delete Rumor" ), _( "Delete an existing rumor for the question." ), Dialog::ZERO ); + fheroes2::showStandardTextMessage( _( "Delete Rumor" ), _( "Delete an existing rumor." ), Dialog::ZERO ); } if ( isRedrawNeeded ) { From 2d90382cd80dbe455dec611bf9d533ec40a191d0 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Wed, 12 Jun 2024 22:42:14 +0800 Subject: [PATCH 4/8] Make IWYU happy --- src/fheroes2/editor/editor_rumor_window.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index 55bd0eb37c1..015860c2591 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -21,16 +21,27 @@ #include "editor_rumor_window.h" #include +#include +#include +#include +#include #include "agg_image.h" #include "cursor.h" #include "dialog.h" #include "game_hotkeys.h" #include "icn.h" +#include "image.h" #include "interface_list.h" +#include "localevent.h" +#include "math_base.h" +#include "screen.h" #include "settings.h" #include "translations.h" +#include "ui_button.h" #include "ui_dialog.h" +#include "ui_scrollbar.h" +#include "ui_text.h" #include "ui_window.h" namespace From bf329d9fb6a8cd07db6827de55b5cce998840644 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sat, 15 Jun 2024 19:04:44 +0800 Subject: [PATCH 5/8] Address comments --- src/fheroes2/editor/editor_rumor_window.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index 015860c2591..2bc9299e303 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -48,11 +48,11 @@ namespace { const int32_t elementOffset{ 9 }; - const fheroes2::Size rumorArea{ 400, 200 }; + const fheroes2::Size rumorArea{ 550, 300 }; const int32_t listAreaHeightDeduction{ 8 }; - const size_t longestRumor{ 300 }; + const size_t longestRumor{ 200 }; class RumorListBox final : public Interface::ListBox { @@ -129,6 +129,8 @@ namespace Editor bool openRumorWindow( std::vector & rumors ) { // Remove all empty rumors. + assert( std::all_of( rumors.begin(), rumors.end(), []( const auto & rumor ) { return !rumor.empty(); } ) ); + rumors.erase( std::remove_if( rumors.begin(), rumors.end(), []( const auto & rumor ) { return rumor.empty(); } ), rumors.end() ); const CursorRestorer cursorRestorer( true, Cursor::POINTER ); @@ -222,7 +224,7 @@ namespace Editor std::string newRumor; if ( Dialog::inputString( _( "Rumor:" ), newRumor, {}, longestRumor, false, true ) ) { if ( std::any_of( rumors.begin(), rumors.end(), [&newRumor]( const auto & rumor ) { return rumor == newRumor; } ) ) { - fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor exists in the list." ), Dialog::OK ); + fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor already exists in the list." ), Dialog::OK ); continue; } @@ -242,7 +244,7 @@ namespace Editor if ( Dialog::inputString( _( "Rumor:" ), temp, {}, longestRumor, false, true ) ) { const auto count = std::count_if( rumors.begin(), rumors.end(), [&temp]( const auto & rumor ) { return rumor == temp; } ); if ( rumorList.GetCurrent() != temp && count > 0 ) { - fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor exists in the list." ), Dialog::OK ); + fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor already exists in the list." ), Dialog::OK ); continue; } @@ -266,7 +268,7 @@ namespace Editor fheroes2::showStandardTextMessage( _( "Cancel" ), _( "Exit this menu without doing anything." ), Dialog::ZERO ); } else if ( le.isMouseRightButtonPressedInArea( buttonOk.area() ) ) { - fheroes2::showStandardTextMessage( _( "Okay" ), _( "Click to save rumors." ), Dialog::ZERO ); + fheroes2::showStandardTextMessage( _( "Okay" ), _( "Click to save the rumors." ), Dialog::ZERO ); } else if ( le.isMouseRightButtonPressedInArea( buttonAdd.area() ) ) { fheroes2::showStandardTextMessage( _( "Add Rumor" ), _( "Add an additional rumor." ), Dialog::ZERO ); From 0d8d57ab83afcfe25f6925ea4fd9b5734d3a6d70 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sat, 15 Jun 2024 19:13:19 +0800 Subject: [PATCH 6/8] Make IWYU happy --- src/fheroes2/editor/editor_rumor_window.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index 2bc9299e303..b9b5a089003 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -21,6 +21,7 @@ #include "editor_rumor_window.h" #include +#include #include #include #include From f7027cac48265b7755ee04e26f8c0249a727c4c9 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 16 Jun 2024 12:28:31 +0800 Subject: [PATCH 7/8] Fix window update --- src/fheroes2/editor/editor_map_specs_window.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fheroes2/editor/editor_map_specs_window.cpp b/src/fheroes2/editor/editor_map_specs_window.cpp index c2800b49f06..bf271918d9c 100644 --- a/src/fheroes2/editor/editor_map_specs_window.cpp +++ b/src/fheroes2/editor/editor_map_specs_window.cpp @@ -620,6 +620,8 @@ namespace Editor if ( openRumorWindow( temp ) ) { mapFormat.rumors = std::move( temp ); } + + display.render( background.totalArea() ); } else if ( le.MouseClickLeft( mapNameRoi ) ) { // TODO: Edit texts directly in this dialog. From 3bc421509df6bbfe60d41f664964e72e7c27568a Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Sun, 16 Jun 2024 12:34:39 +0800 Subject: [PATCH 8/8] Address comments --- src/fheroes2/editor/editor_rumor_window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fheroes2/editor/editor_rumor_window.cpp b/src/fheroes2/editor/editor_rumor_window.cpp index b9b5a089003..a78e256cd43 100644 --- a/src/fheroes2/editor/editor_rumor_window.cpp +++ b/src/fheroes2/editor/editor_rumor_window.cpp @@ -223,7 +223,7 @@ namespace Editor if ( le.MouseClickLeft( buttonAdd.area() ) ) { std::string newRumor; - if ( Dialog::inputString( _( "Rumor:" ), newRumor, {}, longestRumor, false, true ) ) { + if ( Dialog::inputString( _( "Rumor:" ), newRumor, {}, longestRumor, true, true ) ) { if ( std::any_of( rumors.begin(), rumors.end(), [&newRumor]( const auto & rumor ) { return rumor == newRumor; } ) ) { fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor already exists in the list." ), Dialog::OK ); continue; @@ -242,7 +242,7 @@ namespace Editor } std::string temp = rumorList.GetCurrent(); - if ( Dialog::inputString( _( "Rumor:" ), temp, {}, longestRumor, false, true ) ) { + if ( Dialog::inputString( _( "Rumor:" ), temp, {}, longestRumor, true, true ) ) { const auto count = std::count_if( rumors.begin(), rumors.end(), [&temp]( const auto & rumor ) { return rumor == temp; } ); if ( rumorList.GetCurrent() != temp && count > 0 ) { fheroes2::showStandardTextMessage( _( "Rumor" ), _( "This rumor already exists in the list." ), Dialog::OK );