From 2462bd524707b004230072a0826fbe339b7917da Mon Sep 17 00:00:00 2001 From: Mr-Bajs <93934125+Mr-Bajs@users.noreply.github.com> Date: Sun, 13 Oct 2024 23:53:10 +0000 Subject: [PATCH 01/18] Swedish Translation Update (#9186) --- files/lang/sv.po | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/files/lang/sv.po b/files/lang/sv.po index d0921e8c1d..c7a2bf83fc 100644 --- a/files/lang/sv.po +++ b/files/lang/sv.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-12 11:25+0000\n" -"PO-Revision-Date: 2024-08-19 15:55+0200\n" +"PO-Revision-Date: 2024-10-12 14:24+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Swedish \n" "Language: sv\n" @@ -319,7 +319,7 @@ msgid "EVENTS" msgstr "HÄNDELSER" msgid "LANGUAGE" -msgstr "" +msgstr "SPRÅK" msgid "Warrior" msgstr "Krigare" @@ -491,7 +491,7 @@ msgstr "" "stridsbesvärjelser." msgid "You cannot cast spells without a commanding hero." -msgstr "" +msgstr "Du kan inte kasta besvärjelser utan en hjälte." msgid "You have already cast a spell this round." msgstr "Du har redan kastat en besvärjelse denna runda." @@ -3220,9 +3220,8 @@ msgstr "Välj skrollhastigheten." msgid "Select Game Language:" msgstr "Välj spelspråk:" -#, fuzzy msgid "Select Language:" -msgstr "Välj spelspråk:" +msgstr "Välj språk:" msgid "Click to choose the selected language." msgstr "Klicka för att anta valt språk." @@ -3399,9 +3398,8 @@ msgstr "Välj maximalt antal varelser att rekrytera." msgid "Select only 1 monster to be recruited." msgstr "Välj endast 1 varelse att rekrytera." -#, fuzzy msgid "Select this game resolution." -msgstr "Välj spelupplösning" +msgstr "Välj denna spelupplösningen." msgid "" "Selecting this resolution will set a resolution that is scaled from the " @@ -3412,6 +3410,12 @@ msgid "" "better because the pixels are upscaled evenly in both horizontal and " "vertical directions." msgstr "" +"Denna upplösningen kommer att skala upplösningen från den ursprungliga" +"upplösningen (%{resolution}) genom att multiplicera den med numret inom " +"parentesen (%{scale}).\n" +"\n" +"En upplösning med heltal (2.0x, 3.0x etc.) kommer vanligtvis se bättre ut " +"för att pixlarna skalas upp lika i både horisontal och vertikal riktning." msgid "Select Game Resolution:" msgstr "Ange Spelupplösning:" @@ -3625,12 +3629,14 @@ msgstr "Lojalitetens Pris" msgid "Resurrection" msgstr "Resurrection" -#, fuzzy msgid "" "\n" "\n" "Language:\n" -msgstr "Språk" +msgstr "" +"\n" +"\n" +"Språk:\n" msgid "Lose all your heroes and towns." msgstr "Förlora alla dina hjältar och städer." @@ -4533,6 +4539,9 @@ msgid "" "%{newLanguage}. Some texts might not be displayed properly after this. Do " "you want to proceed?" msgstr "" +"Du tänker ändra kartans språk från %{oldLanguage} till %{newLanguage}. En " +"del texter kan eventuellt inte visas korrekt efter detta. Vill du " +"fortfarande ändra språk?" msgid "Change Map Name" msgstr "Ändra Kartnamn" @@ -4555,9 +4564,8 @@ msgstr "Klicka för att redigera dagliga händelser." msgid "Events" msgstr "Händelser" -#, fuzzy msgid "Click to change the language of the map." -msgstr "Ändra spelets språk" +msgstr "Klicka för att ändra kartans språk." msgid "Click to change your map name." msgstr "Klicka för att ändra kartans namn." @@ -7730,23 +7738,23 @@ msgstr "" "att bli belönad. Svarar du fel, kommer du att bli uppäten. Accepterar du " "utmaningen?\"" -#, fuzzy msgid "" "The Sphinx asks you the following riddle:\n" "\n" "'" msgstr "" -"Sfinxen frågar dig följande gåta:\n" +"Sfinxen ställer dig följande gåta:\n" "\n" -"'%{riddle}'\n" -"\n" -"Vad är ditt svar?" +"'" msgid "" "sphinx|'\n" "\n" "Your answer?" msgstr "" +"'\n" +"\n" +"Ditt svar?" msgid "" "\"You guessed incorrectly,\" the Sphinx says, smiling. The Sphinx swipes at " From af49cefa53d9e9aad866c8d4b7a61831ab4b76bd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:47:27 +0300 Subject: [PATCH 02/18] Update translation files (#9197) --- docs/json/lang_sv.json | 2 +- files/lang/sv.po | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/json/lang_sv.json b/docs/json/lang_sv.json index e561c909c9..6e8c341ada 100644 --- a/docs/json/lang_sv.json +++ b/docs/json/lang_sv.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"Swedish","message":"99%","color":"green"} +{"schemaVersion":1,"label":"Swedish","message":"100%","color":"green"} diff --git a/files/lang/sv.po b/files/lang/sv.po index c7a2bf83fc..7425c6a0eb 100644 --- a/files/lang/sv.po +++ b/files/lang/sv.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-14 00:04+0000\n" "PO-Revision-Date: 2024-10-12 14:24+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Swedish \n" @@ -3410,9 +3410,9 @@ msgid "" "better because the pixels are upscaled evenly in both horizontal and " "vertical directions." msgstr "" -"Denna upplösningen kommer att skala upplösningen från den ursprungliga" -"upplösningen (%{resolution}) genom att multiplicera den med numret inom " -"parentesen (%{scale}).\n" +"Denna upplösningen kommer att skala upplösningen från den " +"ursprungligaupplösningen (%{resolution}) genom att multiplicera den med " +"numret inom parentesen (%{scale}).\n" "\n" "En upplösning med heltal (2.0x, 3.0x etc.) kommer vanligtvis se bättre ut " "för att pixlarna skalas upp lika i både horisontal och vertikal riktning." From c53e07346b829ef1b60f9f93d2b6ebbd2fc0c5d4 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Tue, 15 Oct 2024 10:35:09 +0800 Subject: [PATCH 03/18] Cache translation file loading operations (#9191) --- src/engine/translations.cpp | 306 +++++++++++++++++-------------- src/engine/translations.h | 17 +- src/fheroes2/system/settings.cpp | 13 +- 3 files changed, 190 insertions(+), 146 deletions(-) diff --git a/src/engine/translations.cpp b/src/engine/translations.cpp index e362cc723f..27595c4e4c 100644 --- a/src/engine/translations.cpp +++ b/src/engine/translations.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "logging.h" @@ -218,14 +217,14 @@ namespace // TODO: plural forms are not in use: Plural-Forms. LocaleType locale{ LocaleType::LOCALE_EN }; RWStreamBuf buf; - std::map hashOffsets; - std::string domain; + std::unordered_map hashOffsets; std::string encoding; + bool isValid{ false }; const char * ngettext( const char * str, size_t plural ) { const auto iter = std::as_const( hashOffsets ).find( crc32b( str ) ); - if ( iter == hashOffsets.end() ) { + if ( iter == hashOffsets.cend() ) { return stripContext( str ); } @@ -244,12 +243,12 @@ namespace return reinterpret_cast( ptr ); } - bool open( const std::string & file ) + bool load( const std::string & fileName ) { - assert( buf.data() == nullptr && hashOffsets.empty() && encoding.empty() ); + assert( buf.data() == nullptr && hashOffsets.empty() && encoding.empty() && !isValid ); StreamFile sf; - if ( !sf.open( file, "rb" ) ) { + if ( !sf.open( fileName, "rb" ) ) { return false; } @@ -258,7 +257,7 @@ namespace sf >> magicNumber; if ( magicNumber != 0x950412de ) { - ERROR_LOG( "Incorrect magic number " << GetHexString( magicNumber ) << " for " << file ) + ERROR_LOG( "Incorrect magic number " << GetHexString( magicNumber ) << " for " << fileName ) return false; } @@ -267,7 +266,7 @@ namespace sf >> majorVersion >> minorVersion; if ( 0 != majorVersion ) { - ERROR_LOG( "Incorrect major version " << GetHexString( majorVersion, 4 ) << " for " << file ) + ERROR_LOG( "Incorrect major version " << GetHexString( majorVersion, 4 ) << " for " << fileName ) return false; } @@ -330,155 +329,178 @@ namespace const uint32_t offset2 = buf.get32(); - if ( const auto [dummy, inserted] = hashOffsets.try_emplace( crc, Chunk{ offset2, length2 } ); !inserted ) { + if ( const auto [dummy, inserted] = hashOffsets.try_emplace( crc, offset2, length2 ); !inserted ) { ERROR_LOG( "Clashing hash value for: " << msg1 ) } } - return ( totalTranslationStrings > 0 ); + if ( totalTranslationStrings == 0 ) { + return false; + } + + isValid = true; + + return true; } }; MOFile * current = nullptr; - std::map> domains; + std::map> cache; } -bool Translation::bindDomain( const char * domain, const char * file ) +std::pair Translation::setLanguage( const std::string_view name ) { - assert( domain != nullptr && *domain != 0 && file != nullptr ); + assert( !name.empty() ); - // Search for already loaded domain or load from file - { - const auto iter = domains.find( domain ); - if ( iter != domains.end() ) { - current = &iter->second; - return true; + if ( const auto iter = cache.find( name ); iter != cache.end() ) { + MOFile & item = iter->second; + + if ( item.isValid ) { + current = &item; } + + return { true, item.isValid }; } - if ( !domains[domain].open( file ) ) { + return { false, false }; +} + +bool Translation::setLanguage( const std::string & name, const std::string_view fileName ) +{ + assert( !name.empty() ); + + const auto [cacheIter, inserted] = cache.try_emplace( name ); + MOFile & item = cacheIter->second; + + if ( !inserted ) { + if ( item.isValid ) { + current = &item; + } + + return item.isValid; + } + + if ( fileName.empty() || !item.load( std::string{ fileName } ) ) { + assert( !item.isValid ); + return false; } - current = &domains[domain]; - - // Update locale - current->domain = domain; - current->locale = [domain]() { - static const std::unordered_map domainToLocale{ // Afrikaans - { "af", LocaleType::LOCALE_AF }, - { "afrikaans", LocaleType::LOCALE_AF }, - // Arabic - { "ar", LocaleType::LOCALE_AR }, - { "arabic", LocaleType::LOCALE_AR }, - // Belarusian - { "be", LocaleType::LOCALE_BE }, - { "belarusian", LocaleType::LOCALE_BE }, - // Bulgarian - { "bg", LocaleType::LOCALE_BG }, - { "bulgarian", LocaleType::LOCALE_BG }, - // Catalan - { "ca", LocaleType::LOCALE_CA }, - { "catalan", LocaleType::LOCALE_CA }, - // Czech - { "cs", LocaleType::LOCALE_CS }, - { "czech", LocaleType::LOCALE_CS }, - // Danish - { "dk", LocaleType::LOCALE_DK }, - { "danish", LocaleType::LOCALE_DK }, - // German - { "de", LocaleType::LOCALE_DE }, - { "german", LocaleType::LOCALE_DE }, - // Greek - { "el", LocaleType::LOCALE_EL }, - { "greek", LocaleType::LOCALE_EL }, - // Spanish - { "es", LocaleType::LOCALE_ES }, - { "spanish", LocaleType::LOCALE_ES }, - // Estonian - { "et", LocaleType::LOCALE_ET }, - { "estonian", LocaleType::LOCALE_ET }, - // Basque - { "eu", LocaleType::LOCALE_EU }, - { "basque", LocaleType::LOCALE_EU }, - // Finnish - { "fi", LocaleType::LOCALE_FI }, - { "finnish", LocaleType::LOCALE_FI }, - // French - { "fr", LocaleType::LOCALE_FR }, - { "french", LocaleType::LOCALE_FR }, - // Galician - { "gl", LocaleType::LOCALE_GL }, - { "galician", LocaleType::LOCALE_GL }, - // Hebrew - { "he", LocaleType::LOCALE_HE }, - { "hebrew", LocaleType::LOCALE_HE }, - // Croatian - { "hr", LocaleType::LOCALE_HR }, - { "croatian", LocaleType::LOCALE_HR }, - // Hungarian - { "hu", LocaleType::LOCALE_HU }, - { "hungarian", LocaleType::LOCALE_HU }, - // Indonesian - { "id", LocaleType::LOCALE_ID }, - { "indonesian", LocaleType::LOCALE_ID }, - // Italian - { "it", LocaleType::LOCALE_IT }, - { "italian", LocaleType::LOCALE_IT }, - // Latin - { "la", LocaleType::LOCALE_LA }, - { "latin", LocaleType::LOCALE_LA }, - // Lithuanian - { "lt", LocaleType::LOCALE_LT }, - { "lithuanian", LocaleType::LOCALE_LT }, - // Latvian - { "lv", LocaleType::LOCALE_LV }, - { "latvian", LocaleType::LOCALE_LV }, - // Macedonian - { "mk", LocaleType::LOCALE_MK }, - { "macedonian", LocaleType::LOCALE_MK }, - // Norwegian - { "nb", LocaleType::LOCALE_NB }, - { "norwegian", LocaleType::LOCALE_NB }, - // Dutch - { "nl", LocaleType::LOCALE_NL }, - { "dutch", LocaleType::LOCALE_NL }, - // Polish - { "pl", LocaleType::LOCALE_PL }, - { "polish", LocaleType::LOCALE_PL }, - // Portuguese - { "pt", LocaleType::LOCALE_PT }, - { "portuguese", LocaleType::LOCALE_PT }, - // Romanian - { "ro", LocaleType::LOCALE_RO }, - { "romanian", LocaleType::LOCALE_RO }, - // Russian - { "ru", LocaleType::LOCALE_RU }, - { "russian", LocaleType::LOCALE_RU }, - // Slovak - { "sk", LocaleType::LOCALE_SK }, - { "slovak", LocaleType::LOCALE_SK }, - // Slovenian - { "sl", LocaleType::LOCALE_SL }, - { "slovenian", LocaleType::LOCALE_SL }, - // Serbian - { "sr", LocaleType::LOCALE_SR }, - { "serbian", LocaleType::LOCALE_SR }, - // Swedish - { "sv", LocaleType::LOCALE_SV }, - { "swedish", LocaleType::LOCALE_SV }, - // Turkish - { "tr", LocaleType::LOCALE_TR }, - { "turkish", LocaleType::LOCALE_TR }, - // Ukrainian - { "uk", LocaleType::LOCALE_UK }, - { "ukrainian", LocaleType::LOCALE_UK }, - // Vietnamese - { "vi", LocaleType::LOCALE_VI }, - { "vietnamese", LocaleType::LOCALE_VI } }; - - const auto iter = domainToLocale.find( domain ); - if ( iter == domainToLocale.end() ) { + item.locale = [&name]() { + static const std::unordered_map langToLocale{ // Afrikaans + { "af", LocaleType::LOCALE_AF }, + { "afrikaans", LocaleType::LOCALE_AF }, + // Arabic + { "ar", LocaleType::LOCALE_AR }, + { "arabic", LocaleType::LOCALE_AR }, + // Belarusian + { "be", LocaleType::LOCALE_BE }, + { "belarusian", LocaleType::LOCALE_BE }, + // Bulgarian + { "bg", LocaleType::LOCALE_BG }, + { "bulgarian", LocaleType::LOCALE_BG }, + // Catalan + { "ca", LocaleType::LOCALE_CA }, + { "catalan", LocaleType::LOCALE_CA }, + // Czech + { "cs", LocaleType::LOCALE_CS }, + { "czech", LocaleType::LOCALE_CS }, + // Danish + { "dk", LocaleType::LOCALE_DK }, + { "danish", LocaleType::LOCALE_DK }, + // German + { "de", LocaleType::LOCALE_DE }, + { "german", LocaleType::LOCALE_DE }, + // Greek + { "el", LocaleType::LOCALE_EL }, + { "greek", LocaleType::LOCALE_EL }, + // Spanish + { "es", LocaleType::LOCALE_ES }, + { "spanish", LocaleType::LOCALE_ES }, + // Estonian + { "et", LocaleType::LOCALE_ET }, + { "estonian", LocaleType::LOCALE_ET }, + // Basque + { "eu", LocaleType::LOCALE_EU }, + { "basque", LocaleType::LOCALE_EU }, + // Finnish + { "fi", LocaleType::LOCALE_FI }, + { "finnish", LocaleType::LOCALE_FI }, + // French + { "fr", LocaleType::LOCALE_FR }, + { "french", LocaleType::LOCALE_FR }, + // Galician + { "gl", LocaleType::LOCALE_GL }, + { "galician", LocaleType::LOCALE_GL }, + // Hebrew + { "he", LocaleType::LOCALE_HE }, + { "hebrew", LocaleType::LOCALE_HE }, + // Croatian + { "hr", LocaleType::LOCALE_HR }, + { "croatian", LocaleType::LOCALE_HR }, + // Hungarian + { "hu", LocaleType::LOCALE_HU }, + { "hungarian", LocaleType::LOCALE_HU }, + // Indonesian + { "id", LocaleType::LOCALE_ID }, + { "indonesian", LocaleType::LOCALE_ID }, + // Italian + { "it", LocaleType::LOCALE_IT }, + { "italian", LocaleType::LOCALE_IT }, + // Latin + { "la", LocaleType::LOCALE_LA }, + { "latin", LocaleType::LOCALE_LA }, + // Lithuanian + { "lt", LocaleType::LOCALE_LT }, + { "lithuanian", LocaleType::LOCALE_LT }, + // Latvian + { "lv", LocaleType::LOCALE_LV }, + { "latvian", LocaleType::LOCALE_LV }, + // Macedonian + { "mk", LocaleType::LOCALE_MK }, + { "macedonian", LocaleType::LOCALE_MK }, + // Norwegian + { "nb", LocaleType::LOCALE_NB }, + { "norwegian", LocaleType::LOCALE_NB }, + // Dutch + { "nl", LocaleType::LOCALE_NL }, + { "dutch", LocaleType::LOCALE_NL }, + // Polish + { "pl", LocaleType::LOCALE_PL }, + { "polish", LocaleType::LOCALE_PL }, + // Portuguese + { "pt", LocaleType::LOCALE_PT }, + { "portuguese", LocaleType::LOCALE_PT }, + // Romanian + { "ro", LocaleType::LOCALE_RO }, + { "romanian", LocaleType::LOCALE_RO }, + // Russian + { "ru", LocaleType::LOCALE_RU }, + { "russian", LocaleType::LOCALE_RU }, + // Slovak + { "sk", LocaleType::LOCALE_SK }, + { "slovak", LocaleType::LOCALE_SK }, + // Slovenian + { "sl", LocaleType::LOCALE_SL }, + { "slovenian", LocaleType::LOCALE_SL }, + // Serbian + { "sr", LocaleType::LOCALE_SR }, + { "serbian", LocaleType::LOCALE_SR }, + // Swedish + { "sv", LocaleType::LOCALE_SV }, + { "swedish", LocaleType::LOCALE_SV }, + // Turkish + { "tr", LocaleType::LOCALE_TR }, + { "turkish", LocaleType::LOCALE_TR }, + // Ukrainian + { "uk", LocaleType::LOCALE_UK }, + { "ukrainian", LocaleType::LOCALE_UK }, + // Vietnamese + { "vi", LocaleType::LOCALE_VI }, + { "vietnamese", LocaleType::LOCALE_VI } }; + + const auto iter = langToLocale.find( name ); + if ( iter == langToLocale.end() ) { assert( 0 ); return LocaleType::LOCALE_EN; } @@ -486,6 +508,10 @@ bool Translation::bindDomain( const char * domain, const char * file ) return iter->second; }(); + assert( item.isValid ); + + current = &item; + return true; } diff --git a/src/engine/translations.h b/src/engine/translations.h index 03efed1b50..dc0313040a 100644 --- a/src/engine/translations.h +++ b/src/engine/translations.h @@ -25,12 +25,25 @@ #include #include +#include +#include namespace Translation { - bool bindDomain( const char * domain, const char * file ); + // Sets the language with the given name as the current language if the translation for this language is + // already cached and valid, otherwise does nothing. Returns a pair of two flags, the first of which is + // set to true if the translation for the given language is already present in the cache (even if this + // translation is invalid), and the second is set to true if this translation is both present in the cache + // and valid. + std::pair setLanguage( const std::string_view name ); - // Reset any translation to the default language - English. + // Sets the language with the given name as the current language if the translation for this language is + // already cached and valid. If this translation is not yet cached, then tries to load it from the given + // file. If the load fails, then adds this language to the cache as invalid and does nothing else. Returns + // true if the current language has been successfully set, otherwise returns false. + bool setLanguage( const std::string & name, const std::string_view fileName ); + + // Resets the current language to the default language (English). void reset(); const char * gettext( const char * str ); diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index 9d90cc1cf3..d5bb828646 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -513,6 +513,11 @@ bool Settings::setGameLanguage( const std::string & language ) return true; } + // First, let's see if the translation for the requested language is already cached + if ( const auto [isCached, isValid] = Translation::setLanguage( language ); isCached ) { + return isValid; + } + const std::string fileName = std::string( _gameLanguage ).append( ".mo" ); #if defined( MACOS_APP_BUNDLE ) const ListFiles translations = Settings::FindFiles( "translations", fileName, false ); @@ -520,12 +525,12 @@ bool Settings::setGameLanguage( const std::string & language ) const ListFiles translations = Settings::FindFiles( System::concatPath( "files", "lang" ), fileName, false ); #endif - if ( !translations.empty() ) { - return Translation::bindDomain( language.c_str(), translations.back().c_str() ); + if ( translations.empty() ) { + ERROR_LOG( "Translation file " << fileName << " was not found." ) } - ERROR_LOG( "Translation file " << fileName << " was not found." ) - return false; + // If the translation for this language could not be loaded, it will still remain in the cache as invalid + return Translation::setLanguage( language, translations.empty() ? std::string_view{} : translations.back() ); } void Settings::setEditorAnimation( const bool enable ) From ed50ad9e685a4d351680ea3e5c83b490dcdfca15 Mon Sep 17 00:00:00 2001 From: big4billy <143273129+big4billy@users.noreply.github.com> Date: Tue, 15 Oct 2024 04:35:53 +0200 Subject: [PATCH 04/18] Hungarian language translation update (#9195) --- files/lang/hu.po | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/files/lang/hu.po b/files/lang/hu.po index e6bcedc11b..0b45e71e10 100644 --- a/files/lang/hu.po +++ b/files/lang/hu.po @@ -141,7 +141,7 @@ msgid "ALL" msgstr "MIND" msgid "SELECT" -msgstr "KIVÁLASZT" +msgstr "VÁLASZT" msgid "" "STANDARD\n" @@ -320,7 +320,7 @@ msgid "EVENTS" msgstr "ESEMÉNYEK" msgid "LANGUAGE" -msgstr "" +msgstr "NYELV" msgid "Warrior" msgstr "Harcos" @@ -490,7 +490,7 @@ msgid "" msgstr "A Tagadás Gömbje varázstárgy hatására a csatában nem lehet varázsolni." msgid "You cannot cast spells without a commanding hero." -msgstr "" +msgstr "Nem varázsolhatsz hős nélkül." msgid "You have already cast a spell this round." msgstr "Már varázsoltál ebben a körben." @@ -3221,9 +3221,8 @@ msgstr "Beállítja az ablakok görgetésének sebességét." msgid "Select Game Language:" msgstr "Játék nyelvének kiválasztása:" -#, fuzzy msgid "Select Language:" -msgstr "Játék nyelvének kiválasztása:" +msgstr "Nyelv kiválasztása:" msgid "Click to choose the selected language." msgstr "Kattints a kijelölt nyelv kiválasztásához." @@ -3400,9 +3399,8 @@ msgstr "A lények maximális számának kiválasztása toborzáshoz." msgid "Select only 1 monster to be recruited." msgstr "Csak egyetlen lény kiválasztása toborzáshoz." -#, fuzzy msgid "Select this game resolution." -msgstr "Játék felbontás kiválasztása" +msgstr "Pálya felbontás kiválasztása." msgid "" "Selecting this resolution will set a resolution that is scaled from the " @@ -3413,6 +3411,11 @@ msgid "" "better because the pixels are upscaled evenly in both horizontal and " "vertical directions." msgstr "" +"A pálya felbontásának kiválasztásával az eredeti felbontáshoz (%{resolution}) " +"képest adhatjuk meg a skálázás mértékét egy szorzószámmal (%{scale}).\n" +"\n" +"Az egész számú szorzó (2.0x, 3.0x stb.) általában jobb képet ad, mivel " +"a pixelek egyformán lesznek felskálázva vízszintesen és függőlegesen." msgid "Select Game Resolution:" msgstr "Játék felbontás kiválasztása:" @@ -3628,12 +3631,14 @@ msgstr "A hűség ára" msgid "Resurrection" msgstr "Feltámasztás" -#, fuzzy msgid "" "\n" "\n" "Language:\n" -msgstr "Nyelv" +msgstr "" +"\n" +"\n" +"Nyelv:\n" msgid "Lose all your heroes and towns." msgstr "Összes hős és város elvesztése." @@ -4541,6 +4546,9 @@ msgid "" "%{newLanguage}. Some texts might not be displayed properly after this. Do " "you want to proceed?" msgstr "" +"A térkép nyelvét készülsz megváltoztatni. Régi nyelv: %{oldLanguage}, " +"új nyelv: %{newLanguage}. Néhány szöveg nem biztos, hogy megfelelően " +"jelenik meg ezután. Így is végre akarod hajtani a műveletet?" msgid "Change Map Name" msgstr "Térkép nevének megváltoztatása" @@ -4563,9 +4571,8 @@ msgstr "Kattints a napi események szerkesztéséhez." msgid "Events" msgstr "Események" -#, fuzzy msgid "Click to change the language of the map." -msgstr "A játék nyelvének megváltoztatása." +msgstr "Kattints a térkép nyelvének megváltoztatásához." msgid "Click to change your map name." msgstr "Kattints a térképed nevének megváltoztatásához." @@ -7716,23 +7723,23 @@ msgstr "" "\"Van számodra egy rejtvényem.\" - mondja. \"Ha jó a válaszod, " "megjutalmazlak. Ha rossz a válaszod, felfallak. Elfogadod a kihívást?\"" -#, fuzzy msgid "" "The Sphinx asks you the following riddle:\n" "\n" "'" msgstr "" -"A Szfinx a következő találós kérdést adja fel:\n" +"A Szfinx a következő találós kérdést teszi fel:\n" "\n" -"'%{riddle}'\n" -"\n" -"Mi a válaszod?" +"'" msgid "" "sphinx|'\n" "\n" "Your answer?" msgstr "" +"'\n" +"\n" +"Mit válaszolsz?" msgid "" "\"You guessed incorrectly,\" the Sphinx says, smiling. The Sphinx swipes at " From 5e86ba1900f1ea0eaa002a68cfa2b71300300a11 Mon Sep 17 00:00:00 2001 From: Oleg Derevenetz Date: Tue, 15 Oct 2024 05:38:09 +0300 Subject: [PATCH 05/18] Do not mark captured castle objects by Color::UNUSED (#9156) --- src/fheroes2/heroes/heroes_spell.cpp | 1 - src/fheroes2/kingdom/color.cpp | 87 ++++++++++++++++------------ src/fheroes2/kingdom/color.h | 24 ++++---- src/fheroes2/maps/maps_tiles.cpp | 15 ++--- src/fheroes2/maps/maps_tiles.h | 4 +- src/fheroes2/world/world.cpp | 26 +++++---- src/fheroes2/world/world.h | 15 +++-- 7 files changed, 96 insertions(+), 76 deletions(-) diff --git a/src/fheroes2/heroes/heroes_spell.cpp b/src/fheroes2/heroes/heroes_spell.cpp index bffdb798a5..fcf25ace2d 100644 --- a/src/fheroes2/heroes/heroes_spell.cpp +++ b/src/fheroes2/heroes/heroes_spell.cpp @@ -336,7 +336,6 @@ namespace if ( spell == Spell::HAUNT ) { world.CaptureObject( tile.GetIndex(), Color::NONE ); - tile.removeOwnershipFlag( MP2::OBJ_MINE ); // Update the color of haunted mine on radar. Interface::AdventureMap & I = Interface::AdventureMap::Get(); diff --git a/src/fheroes2/kingdom/color.cpp b/src/fheroes2/kingdom/color.cpp index f52a578b6a..55a7b1d230 100644 --- a/src/fheroes2/kingdom/color.cpp +++ b/src/fheroes2/kingdom/color.cpp @@ -23,6 +23,8 @@ #include "color.h" +#include + #include "players.h" #include "serialize.h" #include "tools.h" @@ -45,7 +47,7 @@ namespace }; } -std::string Color::String( int color ) +std::string Color::String( const int color ) { switch ( color ) { case Color::BLUE: @@ -69,7 +71,7 @@ std::string Color::String( int color ) return "None"; } -int Color::GetIndex( int color ) +int Color::GetIndex( const int color ) { switch ( color ) { case BLUE: @@ -92,42 +94,31 @@ int Color::GetIndex( int color ) return 6; } -int Color::Count( int colors ) +int Color::Count( const int colors ) { return CountBits( colors & ALL ); } -int Color::FromInt( int col ) -{ - switch ( col ) { - case BLUE: - case GREEN: - case RED: - case YELLOW: - case ORANGE: - case PURPLE: - return col; - default: - break; - } - - return NONE; -} - -int Color::GetFirst( int colors ) +int Color::GetFirst( const int colors ) { - if ( colors & BLUE ) + if ( colors & BLUE ) { return BLUE; - else if ( colors & GREEN ) + } + if ( colors & GREEN ) { return GREEN; - else if ( colors & RED ) + } + if ( colors & RED ) { return RED; - else if ( colors & YELLOW ) + } + if ( colors & YELLOW ) { return YELLOW; - else if ( colors & ORANGE ) + } + if ( colors & ORANGE ) { return ORANGE; - else if ( colors & PURPLE ) + } + if ( colors & PURPLE ) { return PURPLE; + } return NONE; } @@ -206,32 +197,54 @@ const char * fheroes2::getTentColorName( const int color ) return "None"; } -Colors::Colors( int colors ) +Colors::Colors( const int colors /* = Color::ALL */ ) { reserve( 6 ); - if ( colors & Color::BLUE ) + if ( colors & Color::BLUE ) { push_back( Color::BLUE ); - if ( colors & Color::GREEN ) + } + if ( colors & Color::GREEN ) { push_back( Color::GREEN ); - if ( colors & Color::RED ) + } + if ( colors & Color::RED ) { push_back( Color::RED ); - if ( colors & Color::YELLOW ) + } + if ( colors & Color::YELLOW ) { push_back( Color::YELLOW ); - if ( colors & Color::ORANGE ) + } + if ( colors & Color::ORANGE ) { push_back( Color::ORANGE ); - if ( colors & Color::PURPLE ) + } + if ( colors & Color::PURPLE ) { push_back( Color::PURPLE ); + } } -bool ColorBase::isFriends( int col ) const +bool ColorBase::isFriends( const int col ) const { return ( col & Color::ALL ) && ( color == col || Players::isFriends( color, col ) ); } -void ColorBase::SetColor( int col ) +void ColorBase::SetColor( const int col ) { - color = Color::FromInt( col ); + switch ( col ) { + case Color::NONE: + case Color::BLUE: + case Color::GREEN: + case Color::RED: + case Color::YELLOW: + case Color::ORANGE: + case Color::PURPLE: + color = col; + break; + default: +#ifdef WITH_DEBUG + assert( 0 ); +#endif + color = Color::NONE; + break; + } } Kingdom & ColorBase::GetKingdom() const diff --git a/src/fheroes2/kingdom/color.h b/src/fheroes2/kingdom/color.h index 3ed36255b3..c37167bb5b 100644 --- a/src/fheroes2/kingdom/color.h +++ b/src/fheroes2/kingdom/color.h @@ -30,6 +30,8 @@ class IStreamBase; class OStreamBase; +class Kingdom; + namespace fheroes2 { const char * getBarrierColorName( const int color ); @@ -53,11 +55,12 @@ namespace Color ALL = BLUE | GREEN | RED | YELLOW | ORANGE | PURPLE }; - std::string String( int color ); - int Count( int colors ); - int GetIndex( int color ); - int GetFirst( int colors ); - int FromInt( int col ); + std::string String( const int color ); + + int GetIndex( const int color ); + + int Count( const int colors ); + int GetFirst( const int colors ); uint8_t IndexToColor( const int index ); } @@ -65,11 +68,9 @@ namespace Color class Colors : public std::vector { public: - explicit Colors( int colors = Color::ALL ); + explicit Colors( const int colors = Color::ALL ); }; -class Kingdom; - class ColorBase { int color; @@ -78,15 +79,16 @@ class ColorBase friend IStreamBase & operator>>( IStreamBase & stream, ColorBase & col ); public: - explicit ColorBase( int col = Color::NONE ) + explicit ColorBase( const int col = Color::NONE ) : color( col ) {} - bool isFriends( int ) const; - void SetColor( int ); + bool isFriends( const int col ) const; Kingdom & GetKingdom() const; + void SetColor( const int col ); + int GetColor() const { return color; diff --git a/src/fheroes2/maps/maps_tiles.cpp b/src/fheroes2/maps/maps_tiles.cpp index f9facc091a..a514a2d5f9 100644 --- a/src/fheroes2/maps/maps_tiles.cpp +++ b/src/fheroes2/maps/maps_tiles.cpp @@ -1124,7 +1124,7 @@ Maps::TilesAddon * Maps::Tiles::getAddonWithFlag( const uint32_t uid ) return nullptr; } -void Maps::Tiles::setOwnershipFlag( const MP2::MapObjectType objectType, const int color ) +void Maps::Tiles::setOwnershipFlag( const MP2::MapObjectType objectType, int color ) { // All flags in FLAG32.ICN are actually the same except the fact of having different offset. // Set the default value for the UNUSED color. @@ -1153,7 +1153,8 @@ void Maps::Tiles::setOwnershipFlag( const MP2::MapObjectType objectType, const i objectSpriteIndex = 5; break; case Color::UNUSED: - // Neutral (gray) flag. Index '6' is already set. + // Should never be called using this color as an argument. + assert( 0 ); break; default: // Did you add a new color type? Add logic above! @@ -1216,6 +1217,11 @@ void Maps::Tiles::setOwnershipFlag( const MP2::MapObjectType objectType, const i break; case MP2::OBJ_CASTLE: + // Neutral castles always have flags on both sides of the gate, they should not be completely removed. + if ( color == Color::NONE ) { + color = Color::UNUSED; + } + objectSpriteIndex *= 2; if ( isValidDirection( _index, Direction::LEFT ) ) { Tiles & tile = world.GetTiles( GetDirectionIndex( _index, Direction::LEFT ) ); @@ -1234,11 +1240,6 @@ void Maps::Tiles::setOwnershipFlag( const MP2::MapObjectType objectType, const i } } -void Maps::Tiles::removeOwnershipFlag( const MP2::MapObjectType objectType ) -{ - setOwnershipFlag( objectType, Color::NONE ); -} - void Maps::Tiles::updateFlag( const int color, const uint8_t objectSpriteIndex, const uint32_t uid, const bool setOnUpperLayer ) { // Flag deletion or installation must be done in relation to object UID as flag is attached to the object. diff --git a/src/fheroes2/maps/maps_tiles.h b/src/fheroes2/maps/maps_tiles.h index 403bff1ba7..11e99c99fe 100644 --- a/src/fheroes2/maps/maps_tiles.h +++ b/src/fheroes2/maps/maps_tiles.h @@ -218,9 +218,7 @@ namespace Maps // Update passability based on neighbours around. void updatePassability(); - void setOwnershipFlag( const MP2::MapObjectType objectType, const int color ); - - void removeOwnershipFlag( const MP2::MapObjectType objectType ); + void setOwnershipFlag( const MP2::MapObjectType objectType, int color ); // Return fog direction of tile. A tile without fog returns "Direction::UNKNOWN". uint16_t getFogDirection() const diff --git a/src/fheroes2/world/world.cpp b/src/fheroes2/world/world.cpp index 9403332f43..45e6434932 100644 --- a/src/fheroes2/world/world.cpp +++ b/src/fheroes2/world/world.cpp @@ -284,7 +284,7 @@ void CapturedObjects::ResetColor( const int color ) auto & [objectType, col] = objCol; - col = ( objectType == MP2::OBJ_CASTLE ) ? Color::UNUSED : Color::NONE; + col = Color::NONE; world.GetTiles( idx ).setOwnershipFlag( objectType, col ); } } @@ -855,12 +855,12 @@ int32_t World::NextWhirlpool( const int32_t index ) const return Rand::Get( whilrpools ); } -uint32_t World::CountCapturedObject( const MP2::MapObjectType obj, const int col ) const +uint32_t World::CountCapturedObject( const MP2::MapObjectType obj, const int color ) const { - return map_captureobj.GetCount( obj, col ); + return map_captureobj.GetCount( obj, color ); } -uint32_t World::CountCapturedMines( int type, int color ) const +uint32_t World::CountCapturedMines( const int type, const int color ) const { switch ( type ) { case Resource::WOOD: @@ -874,32 +874,36 @@ uint32_t World::CountCapturedMines( int type, int color ) const return map_captureobj.GetCountMines( type, color ); } -void World::CaptureObject( int32_t index, int color ) +void World::CaptureObject( const int32_t index, const int color ) { + assert( CountBits( color ) <= 1 ); + const MP2::MapObjectType objectType = GetTiles( index ).GetObject( false ); map_captureobj.Set( index, objectType, color ); + if ( color != Color::NONE && !( color & Color::ALL ) ) { + return; + } + Castle * castle = getCastleEntrance( Maps::GetPoint( index ) ); if ( castle && castle->GetColor() != color ) { castle->ChangeColor( color ); } - if ( color & ( Color::ALL | Color::UNUSED ) ) { - GetTiles( index ).setOwnershipFlag( objectType, color ); - } + GetTiles( index ).setOwnershipFlag( objectType, color ); } -int World::ColorCapturedObject( int32_t index ) const +int World::ColorCapturedObject( const int32_t index ) const { return map_captureobj.GetColor( index ); } -CapturedObject & World::GetCapturedObject( int32_t index ) +CapturedObject & World::GetCapturedObject( const int32_t index ) { return map_captureobj.Get( index ); } -void World::ResetCapturedObjects( int color ) +void World::ResetCapturedObjects( const int color ) { map_captureobj.ResetColor( color ); } diff --git a/src/fheroes2/world/world.h b/src/fheroes2/world/world.h index 6c407cd4ad..7cbf6e70e9 100644 --- a/src/fheroes2/world/world.h +++ b/src/fheroes2/world/world.h @@ -366,13 +366,16 @@ class World : protected fheroes2::Size int32_t NextWhirlpool( const int32_t index ) const; MapsIndexes GetWhirlpoolEndPoints( const int32_t index ) const; - void CaptureObject( int32_t, int col ); - uint32_t CountCapturedObject( const MP2::MapObjectType obj, const int col ) const; - uint32_t CountCapturedMines( int type, int col ) const; + void CaptureObject( const int32_t index, const int color ); + + uint32_t CountCapturedObject( const MP2::MapObjectType obj, const int color ) const; + uint32_t CountCapturedMines( const int type, const int color ) const; uint32_t CountObeliskOnMaps(); - int ColorCapturedObject( int32_t ) const; - void ResetCapturedObjects( int ); - CapturedObject & GetCapturedObject( int32_t ); + + int ColorCapturedObject( const int32_t index ) const; + void ResetCapturedObjects( const int color ); + + CapturedObject & GetCapturedObject( const int32_t index ); void ActionForMagellanMaps( int color ); void ClearFog( int color ) const; From 9aaa029f3d1ba2d9c56e8a1d72246d910d86abca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Oct 2024 23:37:46 +0300 Subject: [PATCH 06/18] Update translation files (#9202) --- docs/json/lang_hu.json | 2 +- files/lang/hu.po | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/json/lang_hu.json b/docs/json/lang_hu.json index ab7ba1517a..2f1e48e51d 100644 --- a/docs/json/lang_hu.json +++ b/docs/json/lang_hu.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"Hungarian","message":"99%","color":"green"} +{"schemaVersion":1,"label":"Hungarian","message":"100%","color":"green"} diff --git a/files/lang/hu.po b/files/lang/hu.po index 0b45e71e10..d60ac6fdb8 100644 --- a/files/lang/hu.po +++ b/files/lang/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-15 02:51+0000\n" "PO-Revision-Date: 2023-09-04 21:55+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Hungarian \n" @@ -3411,11 +3411,12 @@ msgid "" "better because the pixels are upscaled evenly in both horizontal and " "vertical directions." msgstr "" -"A pálya felbontásának kiválasztásával az eredeti felbontáshoz (%{resolution}) " -"képest adhatjuk meg a skálázás mértékét egy szorzószámmal (%{scale}).\n" +"A pálya felbontásának kiválasztásával az eredeti felbontáshoz " +"(%{resolution}) képest adhatjuk meg a skálázás mértékét egy szorzószámmal " +"(%{scale}).\n" "\n" -"Az egész számú szorzó (2.0x, 3.0x stb.) általában jobb képet ad, mivel " -"a pixelek egyformán lesznek felskálázva vízszintesen és függőlegesen." +"Az egész számú szorzó (2.0x, 3.0x stb.) általában jobb képet ad, mivel a " +"pixelek egyformán lesznek felskálázva vízszintesen és függőlegesen." msgid "Select Game Resolution:" msgstr "Játék felbontás kiválasztása:" @@ -4546,9 +4547,9 @@ msgid "" "%{newLanguage}. Some texts might not be displayed properly after this. Do " "you want to proceed?" msgstr "" -"A térkép nyelvét készülsz megváltoztatni. Régi nyelv: %{oldLanguage}, " -"új nyelv: %{newLanguage}. Néhány szöveg nem biztos, hogy megfelelően " -"jelenik meg ezután. Így is végre akarod hajtani a műveletet?" +"A térkép nyelvét készülsz megváltoztatni. Régi nyelv: %{oldLanguage}, új " +"nyelv: %{newLanguage}. Néhány szöveg nem biztos, hogy megfelelően jelenik " +"meg ezután. Így is végre akarod hajtani a műveletet?" msgid "Change Map Name" msgstr "Térkép nevének megváltoztatása" From f24feeefbf0027f03f178cb73564ad712e4713c5 Mon Sep 17 00:00:00 2001 From: Oleg Derevenetz Date: Fri, 18 Oct 2024 02:52:50 +0300 Subject: [PATCH 07/18] Remove the temporary workaround to fix the Windows CMake build (#9209) --- .github/workflows/cmake.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index a9e5e88bc0..c2124732fb 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -66,12 +66,6 @@ jobs: cmake-vcpkg-cache- - name: Install dependencies run: | - # Temporary workaround for the vcpkg internal issue - # See https://github.com/microsoft/vcpkg/issues/41199#issuecomment-2378255699 for details - export SystemDrive=$SYSTEMDRIVE - export SystemRoot=$SYSTEMROOT - export windir=$WINDIR - vcpkg.exe --triplet x64-windows install sdl2 sdl2-mixer sdl2-image zlib - name: Build run: | From 2084e98f9dd5f9194e709820a9678851cc053e23 Mon Sep 17 00:00:00 2001 From: Zenseii Date: Fri, 18 Oct 2024 01:53:44 +0200 Subject: [PATCH 08/18] Fix debug build crash with French and Italian assets (#9200) --- src/fheroes2/agg/agg_image.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/fheroes2/agg/agg_image.cpp b/src/fheroes2/agg/agg_image.cpp index 18511c715d..04b8524168 100644 --- a/src/fheroes2/agg/agg_image.cpp +++ b/src/fheroes2/agg/agg_image.cpp @@ -2539,34 +2539,38 @@ namespace std::swap( imageArray[220], imageArray[222] ); imageArray.erase( imageArray.begin() + 221, imageArray.end() ); } - // French version has its own special encoding but should conform to CP1252 too + // The French version replaces several ASCII special characters with language-specific characters. + // In the engine we use CP1252 for the French translation but we have to preserve the homegrown encoding + // of the original so that original French maps' texts are displayed correctly. if ( crc32 == 0xD9556567 || crc32 == 0x406967B9 ) { + // The engine expects that letter indexes correspond to charcode - 0x20, but the original French + // Price of Loyalty maps use 0x09 for lowercase i with circonflex. This is currently not supported + // by the engine. const fheroes2::Sprite firstSprite{ imageArray[0] }; - imageArray.insert( imageArray.begin() + 96, 160 - 32, firstSprite ); + imageArray.insert( imageArray.begin() + 96, 128, firstSprite ); + // Capital letters with accents aren't present in the original assets so we use unaccented letters. imageArray[192 - 32] = imageArray[33]; imageArray[199 - 32] = imageArray[35]; imageArray[201 - 32] = imageArray[37]; imageArray[202 - 32] = imageArray[37]; - imageArray[244 - 32] = imageArray[3]; - imageArray[251 - 32] = imageArray[4]; - imageArray[249 - 32] = imageArray[6]; - imageArray[226 - 32] = imageArray[10]; - imageArray[239 - 32] = imageArray[28]; - imageArray[238 - 32] = imageArray[30]; + imageArray[224 - 32] = imageArray[32]; + imageArray[226 - 32] = imageArray[10]; imageArray[231 - 32] = imageArray[62]; imageArray[232 - 32] = imageArray[64]; - imageArray[239 - 32] = imageArray[91]; + imageArray[233 - 32] = imageArray[94]; imageArray[234 - 32] = imageArray[92]; imageArray[238 - 32] = imageArray[93]; - imageArray[233 - 32] = imageArray[94]; - imageArray[238 - 32] = imageArray[95]; - imageArray.erase( imageArray.begin() + 252 - 32, imageArray.end() ); + imageArray[239 - 32] = imageArray[91]; + imageArray[244 - 32] = imageArray[3]; + imageArray[249 - 32] = imageArray[6]; + imageArray[251 - 32] = imageArray[4]; + imageArray.erase( imageArray.begin() + 220, imageArray.end() ); } // Italian version uses CP1252 if ( crc32 == 0x219B3124 || crc32 == 0x1F3C3C74 ) { const fheroes2::Sprite firstSprite{ imageArray[0] }; - imageArray.insert( imageArray.begin() + 101, 155 - 32, firstSprite ); + imageArray.insert( imageArray.begin() + 101, 123, firstSprite ); imageArray[192 - 32] = imageArray[33]; imageArray[200 - 32] = imageArray[37]; imageArray[201 - 32] = imageArray[37]; @@ -2579,7 +2583,7 @@ namespace imageArray[236 - 32] = imageArray[98]; imageArray[242 - 32] = imageArray[99]; imageArray[249 - 32] = imageArray[100]; - imageArray.erase( imageArray.begin() + 250 - 32, imageArray.end() ); + imageArray.erase( imageArray.begin() + 218, imageArray.end() ); } return true; } From 6c7e664c7ec6c1ca8770269c09f65961f2ca66b7 Mon Sep 17 00:00:00 2001 From: altiereslima Date: Thu, 17 Oct 2024 20:56:38 -0300 Subject: [PATCH 09/18] Update Portuguese Translation (#9199) --- files/lang/pt.po | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/files/lang/pt.po b/files/lang/pt.po index ebb39def61..2e83a33128 100644 --- a/files/lang/pt.po +++ b/files/lang/pt.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-12 11:25+0000\n" -"PO-Revision-Date: 2024-10-11 19:28-0300\n" +"PO-Revision-Date: 2024-10-14 16:46-0300\n" "Last-Translator: fheroes2 team \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" @@ -320,7 +320,7 @@ msgid "EVENTS" msgstr "EVENTOS" msgid "LANGUAGE" -msgstr "" +msgstr "IDIOMA" msgid "Warrior" msgstr "Guerreiro" @@ -492,7 +492,7 @@ msgstr "" "os feitiços de combate." msgid "You cannot cast spells without a commanding hero." -msgstr "" +msgstr "Você não pode lançar feitiços sem um herói no comando." msgid "You have already cast a spell this round." msgstr "Você já lançou um feitiço nesse turno." @@ -3237,9 +3237,8 @@ msgstr "Defina a velocidade com a qual você rola a janela." msgid "Select Game Language:" msgstr "Escolha o idioma do jogo:" -#, fuzzy msgid "Select Language:" -msgstr "Escolha o idioma do jogo:" +msgstr "Selecionar Idioma:" msgid "Click to choose the selected language." msgstr "Clique para escolher o idioma selecionado." @@ -3656,12 +3655,14 @@ msgstr "O Preço da Lealdade" msgid "Resurrection" msgstr "Ressurreição" -#, fuzzy msgid "" "\n" "\n" "Language:\n" -msgstr "Idioma" +msgstr "" +"\n" +"\n" +"Idioma:\n" msgid "Lose all your heroes and towns." msgstr "Perder todos os seus heróis e cidades." @@ -4571,6 +4572,9 @@ msgid "" "%{newLanguage}. Some texts might not be displayed properly after this. Do " "you want to proceed?" msgstr "" +"Você está prestes a alterar o idioma do mapa de %{oldLanguage} para " +"%{newLanguage}. Alguns textos podem não ser exibidos corretamente depois " +"disso. Deseja prosseguir?" msgid "Change Map Name" msgstr "Alterar o Nome do Mapa" @@ -4593,9 +4597,8 @@ msgstr "Clique para editar eventos diários." msgid "Events" msgstr "Eventos" -#, fuzzy msgid "Click to change the language of the map." -msgstr "Mude o idioma do jogo." +msgstr "Clique para alterar o idioma do mapa." msgid "Click to change your map name." msgstr "Clique para alterar o nome do mapa." @@ -7806,7 +7809,6 @@ msgstr "" "você será recompensado. Responda incorretamente, e você será devorado. Você " "aceita o desafio?\"" -#, fuzzy msgid "" "The Sphinx asks you the following riddle:\n" "\n" @@ -7814,15 +7816,16 @@ msgid "" msgstr "" "A Esfinge lhe pergunta o seguinte enigma:\n" "\n" -"'%{riddle}'\n" -"\n" -"Sua resposta?" +"'" msgid "" "sphinx|'\n" "\n" "Your answer?" msgstr "" +"'\n" +"\n" +"Sua resposta?" msgid "" "\"You guessed incorrectly,\" the Sphinx says, smiling. The Sphinx swipes at " From 5a2bc7bda197d0f94c5cc8d66867c0ba0ff540e6 Mon Sep 17 00:00:00 2001 From: Oleg Derevenetz Date: Fri, 18 Oct 2024 02:58:00 +0300 Subject: [PATCH 10/18] Fix a few code smells (#9198) --- script/tools/changelog_update_metainfo.py | 58 +++++++++++------ script/tools/check_copyright_headers.py | 79 ++++++++++++++--------- src/engine/translations.h | 4 +- src/fheroes2/gui/interface_itemsbar.h | 20 ++---- src/fheroes2/system/settings.cpp | 4 +- 5 files changed, 98 insertions(+), 67 deletions(-) diff --git a/script/tools/changelog_update_metainfo.py b/script/tools/changelog_update_metainfo.py index 247503dbe2..0f6664845e 100644 --- a/script/tools/changelog_update_metainfo.py +++ b/script/tools/changelog_update_metainfo.py @@ -2,7 +2,7 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2023 # +# Copyright (C) 2023 - 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 # @@ -20,35 +20,51 @@ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ########################################################################### +# pylint: disable=missing-module-docstring + import argparse import datetime import re import sys + from xml.sax.saxutils import escape # -# Appstream file could be validated with 'appstream-util validate io.github.ihhub.Fheroes2.metainfo.xml' +# Appstream file can be validated using the following command: +# appstream-util validate io.github.ihhub.Fheroes2.metainfo.xml # -class CustomArgumentParser(argparse.ArgumentParser): + +class CustomArgumentParser( + argparse.ArgumentParser +): # pylint: disable=missing-class-docstring def error(self, message): self.print_usage(sys.stderr) - self.exit(1, "%(prog)s: error: %(message)s\n" % - {"prog": self.prog, "message": message}) + self.exit( + 1, + "%(prog)s: error: %(message)s\n" % {"prog": self.prog, "message": message}, + ) + -def parse_arguments(): +def parse_arguments(): # pylint: disable=missing-function-docstring parser = CustomArgumentParser() + parser.add_argument("changelog_file", help="changelog.txt file") parser.add_argument("metainfo_file", help="*.metainfo.xml file") + return parser.parse_args() -def main(): + +def main(): # pylint: disable=missing-function-docstring args = parse_arguments() - changelog = open(args.changelog_file, encoding='utf-8').read() - metainfo = open(args.metainfo_file, encoding='utf-8').read() + with open(args.changelog_file, encoding="utf-8") as changelog_file: + changelog = changelog_file.read() + + with open(args.metainfo_file, encoding="utf-8") as metainfo_file: + metainfo = metainfo_file.read() - tpl = ''' + tpl = """ https://github.com/ihhub/fheroes2/releases/tag/{} @@ -57,26 +73,32 @@ def main(): {} - \n'''.lstrip("\r\n") - tmp = '' + \n""".lstrip( + "\r\n" + ) + tmp = "" - regex = r"version ([\d.]+) \(([\w ]+)\)\n(.*?)[\n]{2}" + regex = r"version ([\d.]+) \(([\w ]+)\)\n(.*?)\n{2}" for match in re.findall(regex, changelog, re.MULTILINE | re.DOTALL): tmp += tpl.format( - datetime.datetime.strptime(match[1], '%d %B %Y').strftime('%Y-%m-%d'), + datetime.datetime.strptime(match[1], "%d %B %Y").strftime("%Y-%m-%d"), match[0], match[0], match[0], match[1], - re.sub(r'- (.*)', r'
  • \1
  • ', escape(match[2])) + re.sub(r"- (.*)", r"
  • \1
  • ", escape(match[2])), ) - new_metainfo = re.sub(r'(.*?)', r'\n' + tmp + ' ', + new_metainfo = re.sub( + r"(.*?)", + r"\n" + tmp + " ", metainfo, - flags=re.MULTILINE | re.DOTALL + flags=re.MULTILINE | re.DOTALL, ) - open(args.metainfo_file, 'w', encoding='utf-8').write(new_metainfo) + with open(args.metainfo_file, "w", encoding="utf-8") as metainfo_file: + metainfo_file.write(new_metainfo) + if __name__ == "__main__": main() diff --git a/script/tools/check_copyright_headers.py b/script/tools/check_copyright_headers.py index 2232f5dc4d..9246c706f3 100644 --- a/script/tools/check_copyright_headers.py +++ b/script/tools/check_copyright_headers.py @@ -2,7 +2,7 @@ ########################################################################### # fheroes2: https://github.com/ihhub/fheroes2 # -# Copyright (C) 2022 - 2023 # +# Copyright (C) 2022 - 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 # @@ -20,6 +20,8 @@ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ########################################################################### +# pylint: disable=missing-module-docstring + import argparse import datetime import os @@ -30,59 +32,68 @@ CURRENT_YEAR = datetime.datetime.now().date().year -class CustomArgumentParser(argparse.ArgumentParser): +class CustomArgumentParser( + argparse.ArgumentParser +): # pylint: disable=missing-class-docstring def error(self, message): self.print_usage(sys.stderr) - self.exit(1, "%(prog)s: error: %(message)s\n" % - {"prog": self.prog, "message": message}) + self.exit( + 1, + "%(prog)s: error: %(message)s\n" % {"prog": self.prog, "message": message}, + ) -def parse_arguments(): +def parse_arguments(): # pylint: disable=missing-function-docstring parser = CustomArgumentParser() + parser.add_argument( "--handle-shebang", action="store_true", - help="handle the shebang at the beginning of the source file(s)" - ) - parser.add_argument( - "full_header_file", - help="full header file" - ) - parser.add_argument( - "header_template_file", - help="header template file" + help="handle the shebang at the beginning of the source file(s)", ) + parser.add_argument("full_header_file", help="full header file") + parser.add_argument("header_template_file", help="header template file") parser.add_argument( - "source_file", - help="source files (at least one, can be multiple)", - nargs="+" + "source_file", help="source files (at least one, can be multiple)", nargs="+" ) + return parser.parse_args() -def main(): - # if something is wrong with the commandline arguments, - # the script exits here with return code 1: +def main(): # pylint: disable=missing-function-docstring,too-many-locals,too-many-branches args = parse_arguments() with open(args.full_header_file, "r", encoding="latin_1") as full_header_file: - copyright_hdr_full = full_header_file.read().strip().replace("{YR}", f"{CURRENT_YEAR}") - with open(args.header_template_file, "r", encoding="latin_1") as header_template_file: + copyright_hdr_full = ( + full_header_file.read().strip().replace("{YR}", f"{CURRENT_YEAR}") + ) + + with open( + args.header_template_file, "r", encoding="latin_1" + ) as header_template_file: copyright_hdr_tmpl = header_template_file.read().strip() copyright_hdr_re_tmpl = copyright_hdr_tmpl for ch_to_replace in "*()": - copyright_hdr_re_tmpl = copyright_hdr_re_tmpl.replace(ch_to_replace, "\\" + ch_to_replace) + copyright_hdr_re_tmpl = copyright_hdr_re_tmpl.replace( + ch_to_replace, "\\" + ch_to_replace + ) - copyright_hdr_year_re = re.compile("^" + copyright_hdr_re_tmpl.replace("{Y1} - {Y2}", - "([0-9]{4}) ")) - copyright_hdr_yrng_re = re.compile("^" + copyright_hdr_re_tmpl.replace("{Y1}", "([0-9]{4})") - .replace("{Y2}", "([0-9]{4})")) + copyright_hdr_year_re = re.compile( + "^" + copyright_hdr_re_tmpl.replace("{Y1} - {Y2}", "([0-9]{4}) ") + ) + copyright_hdr_yrng_re = re.compile( + "^" + + copyright_hdr_re_tmpl.replace("{Y1}", "([0-9]{4})").replace( + "{Y2}", "([0-9]{4})" + ) + ) for file_name in args.source_file: if not os.path.exists(file_name): continue + with open(file_name, "r", encoding="latin_1") as src_file: src = src_file.read() @@ -108,12 +119,14 @@ def main(): if not src_is_ok: if year_re_match: - hdr = copyright_hdr_tmpl.replace("{Y1}", f"{year_re_match.group(1)}") \ - .replace("{Y2}", f"{CURRENT_YEAR}") + hdr = copyright_hdr_tmpl.replace( + "{Y1}", f"{year_re_match.group(1)}" + ).replace("{Y2}", f"{CURRENT_YEAR}") src = copyright_hdr_year_re.sub(hdr, src) elif yrng_re_match: - hdr = copyright_hdr_tmpl.replace("{Y1}", f"{yrng_re_match.group(1)}") \ - .replace("{Y2}", f"{CURRENT_YEAR}") + hdr = copyright_hdr_tmpl.replace( + "{Y1}", f"{yrng_re_match.group(1)}" + ).replace("{Y2}", f"{CURRENT_YEAR}") src = copyright_hdr_yrng_re.sub(hdr, src) else: src = copyright_hdr_full + "\n\n" + src.lstrip("\n") @@ -124,7 +137,9 @@ def main(): with open(file_name + ".tmp", "x", encoding="latin_1") as tmp_file: tmp_file.write(src) - with subprocess.Popen(["diff", "-u", file_name, file_name + ".tmp"]) as diff_proc: + with subprocess.Popen( + ["diff", "-u", file_name, file_name + ".tmp"] + ) as diff_proc: diff_proc.wait() os.remove(file_name + ".tmp") diff --git a/src/engine/translations.h b/src/engine/translations.h index dc0313040a..ab99bb03b9 100644 --- a/src/engine/translations.h +++ b/src/engine/translations.h @@ -33,8 +33,8 @@ namespace Translation // Sets the language with the given name as the current language if the translation for this language is // already cached and valid, otherwise does nothing. Returns a pair of two flags, the first of which is // set to true if the translation for the given language is already present in the cache (even if this - // translation is invalid), and the second is set to true if this translation is both present in the cache - // and valid. + // translation is invalid), and the second is set to true if the current language has been successfully + // set. std::pair setLanguage( const std::string_view name ); // Sets the language with the given name as the current language if the translation for this language is diff --git a/src/fheroes2/gui/interface_itemsbar.h b/src/fheroes2/gui/interface_itemsbar.h index b8c281b4fe..4f0f2ed508 100644 --- a/src/fheroes2/gui/interface_itemsbar.h +++ b/src/fheroes2/gui/interface_itemsbar.h @@ -179,10 +179,6 @@ namespace Interface using ItemsIterator = typename std::vector::iterator; using ItemIterPos = std::pair; - std::vector items; - - std::vector _customItemsCountInRow; - virtual void SetContentItems() { // Do nothing. @@ -198,11 +194,6 @@ namespace Interface return items.end(); } - virtual ItemsIterator GetCurItemIter() - { - return items.end(); - } - virtual void RedrawItemIter( ItemsIterator it, const fheroes2::Rect & pos, fheroes2::Image & output ) { RedrawItem( **it, pos, output ); @@ -270,6 +261,9 @@ namespace Interface return { items.end(), {} }; } + std::vector items; + std::vector _customItemsCountInRow; + private: void calculateItemsPos() { @@ -454,10 +448,7 @@ namespace Interface using ItemsIterator = typename ItemsBar::ItemsIterator; using ItemIterPos = typename ItemsBar::ItemIterPos; - ItemsIterator topItem; - ItemIterPos curItemPos; - - ItemsIterator GetCurItemIter() override + ItemsIterator GetCurItemIter() { return curItemPos.first; } @@ -586,6 +577,9 @@ namespace Interface return false; } + + ItemsIterator topItem; + ItemIterPos curItemPos; }; } diff --git a/src/fheroes2/system/settings.cpp b/src/fheroes2/system/settings.cpp index d5bb828646..c2315b0981 100644 --- a/src/fheroes2/system/settings.cpp +++ b/src/fheroes2/system/settings.cpp @@ -514,8 +514,8 @@ bool Settings::setGameLanguage( const std::string & language ) } // First, let's see if the translation for the requested language is already cached - if ( const auto [isCached, isValid] = Translation::setLanguage( language ); isCached ) { - return isValid; + if ( const auto [isCached, isSet] = Translation::setLanguage( language ); isCached ) { + return isSet; } const std::string fileName = std::string( _gameLanguage ).append( ".mo" ); From 8a79173b69315a5a83e558f0ca200649f29f67f7 Mon Sep 17 00:00:00 2001 From: Ihar Hubchyk Date: Fri, 18 Oct 2024 07:58:28 +0800 Subject: [PATCH 11/18] Add missing popup dialogs to buttons within View World mode (#9194) --- src/fheroes2/kingdom/view_world.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fheroes2/kingdom/view_world.cpp b/src/fheroes2/kingdom/view_world.cpp index 1fd919ebfd..e3e3dee9c9 100644 --- a/src/fheroes2/kingdom/view_world.cpp +++ b/src/fheroes2/kingdom/view_world.cpp @@ -32,6 +32,7 @@ #include "castle.h" #include "color.h" #include "cursor.h" +#include "dialog.h" #include "game_hotkeys.h" #include "heroes.h" #include "icn.h" @@ -48,8 +49,10 @@ #include "resource.h" #include "screen.h" #include "settings.h" +#include "translations.h" #include "ui_button.h" #include "ui_constants.h" +#include "ui_dialog.h" #include "ui_tool.h" #include "world.h" @@ -710,6 +713,12 @@ void ViewWorld::ViewWorldWindow( const int32_t color, const ViewWorldMode mode, else if ( le.isMouseWheelDown() ) { changed = currentROI.zoomOut( false ); } + else if ( le.isMouseRightButtonPressedInArea( buttonExit.area() ) ) { + fheroes2::showStandardTextMessage( _( "Exit" ), _( "Exit this menu." ), Dialog::ZERO ); + } + else if ( le.isMouseRightButtonPressedInArea( buttonZoom.area() ) ) { + fheroes2::showStandardTextMessage( _( "Zoom" ), _( "Click this button to adjust the level of zoom." ), Dialog::ZERO ); + } if ( !le.isMouseLeftButtonPressedInArea( visibleScreenInPixels ) || !le.isMouseCursorPosInArea( visibleScreenInPixels ) ) { isDrag = false; From dddf7222b4bd4e3e482d9cf3229fec038a2b29c0 Mon Sep 17 00:00:00 2001 From: Zenseii Date: Fri, 18 Oct 2024 02:00:01 +0200 Subject: [PATCH 12/18] Shorten map title when too long in several places (#9207) --- src/fheroes2/dialog/dialog_selectscenario.cpp | 10 ++++++---- src/fheroes2/game/game_scenarioinfo.cpp | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/fheroes2/dialog/dialog_selectscenario.cpp b/src/fheroes2/dialog/dialog_selectscenario.cpp index 506d255877..36e95a3b2f 100644 --- a/src/fheroes2/dialog/dialog_selectscenario.cpp +++ b/src/fheroes2/dialog/dialog_selectscenario.cpp @@ -286,7 +286,8 @@ void ScenarioListBox::_renderSelectedScenarioInfo( fheroes2::Display & display, _renderMapIcon( info.width, display, dst.x + SELECTED_SCENARIO_MAP_SIZE_OFFSET_X, dst.y + SELECTED_SCENARIO_GENERAL_OFFSET_Y ); fheroes2::Blit( _getMapTypeIcon( info.version ), display, dst.x + SELECTED_SCENARIO_MAP_TYPE_OFFSET_X, dst.y + SELECTED_SCENARIO_GENERAL_OFFSET_Y ); - const fheroes2::Text mapNameText{ info.name, fheroes2::FontType::normalWhite(), info.getSupportedLanguage() }; + fheroes2::Text mapNameText{ info.name, fheroes2::FontType::normalWhite(), info.getSupportedLanguage() }; + mapNameText.fitToOneRow( SCENARIO_LIST_MAP_NAME_WIDTH ); mapNameText.draw( GetCenteredTextXCoordinate( dst.x + SELECTED_SCENARIO_MAP_NAME_OFFSET_X, SELECTED_SCENARIO_MAP_NAME_WIDTH, mapNameText.width() ), dst.y + SELECTED_SCENARIO_GENERAL_OFFSET_Y + 2, display ); @@ -310,9 +311,10 @@ void ScenarioListBox::_renderSelectedScenarioInfo( fheroes2::Display & display, void ScenarioListBox::_renderMapName( const Maps::FileInfo & info, bool selected, const int32_t & baseYOffset, fheroes2::Display & display ) const { - const fheroes2::Text mapName{ info.name, - { fheroes2::FontSize::NORMAL, ( selected ? fheroes2::FontColor::YELLOW : fheroes2::FontColor::WHITE ) }, - info.getSupportedLanguage() }; + fheroes2::Text mapName{ info.name, + { fheroes2::FontSize::NORMAL, ( selected ? fheroes2::FontColor::YELLOW : fheroes2::FontColor::WHITE ) }, + info.getSupportedLanguage() }; + mapName.fitToOneRow( SCENARIO_LIST_MAP_NAME_WIDTH ); const int32_t xCoordinate = GetCenteredTextXCoordinate( _offsetX + SCENARIO_LIST_MAP_NAME_OFFSET_X, SCENARIO_LIST_MAP_NAME_WIDTH, mapName.width() ); const int32_t yCoordinate = baseYOffset + MAP_LIST_ROW_SPACING_Y - 1; mapName.draw( xCoordinate, yCoordinate, display ); diff --git a/src/fheroes2/game/game_scenarioinfo.cpp b/src/fheroes2/game/game_scenarioinfo.cpp index cf8750ca5b..32a41cda2e 100644 --- a/src/fheroes2/game/game_scenarioinfo.cpp +++ b/src/fheroes2/game/game_scenarioinfo.cpp @@ -110,8 +110,9 @@ namespace void RedrawMapTitle( const fheroes2::Rect & roi ) { const auto & info = Settings::Get().getCurrentMapInfo(); - const fheroes2::Text text{ info.name, fheroes2::FontType::normalWhite(), info.getSupportedLanguage() }; - text.draw( roi.x, roi.y + 8, roi.width, fheroes2::Display::instance() ); + fheroes2::Text text{ info.name, fheroes2::FontType::normalWhite(), info.getSupportedLanguage() }; + text.fitToOneRow( roi.width ); + text.draw( roi.x, roi.y + 3, roi.width, fheroes2::Display::instance() ); } void RedrawDifficultyInfo( const fheroes2::Point & dst ) @@ -245,8 +246,15 @@ namespace fheroes2::addGradientShadow( icon, display, { coordDifficulty[i].x, coordDifficulty[i].y }, { -5, 5 } ); } + // We calculate the allowed text width according to the select button's width while ensuring symmetric placement of the map title. + const int32_t boxBorder = 6; + const int32_t halfBoxTextAreaWidth = ( scenarioBoxRoi.width - ( 2 * boxBorder ) ) / 2; + const int32_t rightSideAvailableTextWidth + = halfBoxTextAreaWidth > buttonSelectWidth ? halfBoxTextAreaWidth - buttonSelectWidth : buttonSelectWidth - halfBoxTextAreaWidth; + // Set up restorers. - fheroes2::ImageRestorer mapTitleArea( display, scenarioBoxRoi.x + 6, scenarioBoxRoi.y + 5, 279, scenarioBoxRoi.height ); + fheroes2::ImageRestorer mapTitleArea( display, scenarioBoxRoi.x + boxBorder + buttonSelectWidth, scenarioBoxRoi.y + 5, 2 * rightSideAvailableTextWidth, + scenarioBoxRoi.height ); fheroes2::ImageRestorer opponentsArea( display, roi.x, pointOpponentInfo.y, roi.width, 65 ); fheroes2::ImageRestorer classArea( display, roi.x, pointClassInfo.y, roi.width, 69 ); fheroes2::ImageRestorer handicapArea( display, roi.x, pointClassInfo.y + 69, roi.width, 31 ); @@ -254,7 +262,7 @@ namespace roi.width - buttonOk.area().width - buttonCancel.area().width - 20 * 2, buttonOk.area().height ); // Map name - RedrawMapTitle( scenarioBoxRoi ); + RedrawMapTitle( mapTitleArea.rect() ); playersInfo.RedrawInfo( false ); @@ -318,7 +326,7 @@ namespace conf.setCurrentMapInfo( *fi ); mapTitleArea.restore(); - RedrawMapTitle( scenarioBoxRoi ); + RedrawMapTitle( mapTitleArea.rect() ); Game::LoadPlayers( fi->filename, players ); opponentsArea.restore(); From 66c6a35d4611e6ca9ef84dcb0842945b66816221 Mon Sep 17 00:00:00 2001 From: "Sergei Ivanov (Districh)" <113276641+Districh-ru@users.noreply.github.com> Date: Fri, 18 Oct 2024 03:08:08 +0300 Subject: [PATCH 13/18] Fix render of overlapped UI elements (#9201) --- src/fheroes2/castle/captain.cpp | 4 +- src/fheroes2/game/game_interface.h | 6 + src/fheroes2/game/game_startgame.cpp | 31 ++- src/fheroes2/gui/interface_buttons.cpp | 212 +++++++++++--------- src/fheroes2/gui/interface_buttons.h | 54 +++--- src/fheroes2/gui/interface_events.cpp | 10 +- src/fheroes2/gui/interface_focus.cpp | 42 ++-- src/fheroes2/gui/interface_icons.cpp | 225 ++++++++++------------ src/fheroes2/gui/interface_icons.h | 117 ++++++----- src/fheroes2/gui/interface_list.h | 3 +- src/fheroes2/gui/ui_button.cpp | 6 +- src/fheroes2/gui/ui_button.h | 18 +- src/fheroes2/gui/ui_scrollbar.cpp | 69 +++---- src/fheroes2/gui/ui_scrollbar.h | 13 +- src/fheroes2/heroes/heroes_action.cpp | 2 +- src/fheroes2/kingdom/kingdom.cpp | 5 +- src/fheroes2/kingdom/kingdom_overview.cpp | 18 +- 17 files changed, 428 insertions(+), 407 deletions(-) diff --git a/src/fheroes2/castle/captain.cpp b/src/fheroes2/castle/captain.cpp index 6a5476d774..bdfe977f19 100644 --- a/src/fheroes2/castle/captain.cpp +++ b/src/fheroes2/castle/captain.cpp @@ -253,8 +253,8 @@ void Captain::PortraitRedraw( const int32_t px, const int32_t py, const Portrait const fheroes2::Sprite & mana = fheroes2::AGG::GetICN( ICN::MANA, GetManaIndexSprite() ); - const int iconWidth = Interface::IconsBar::GetItemWidth(); - const int iconHeight = Interface::IconsBar::GetItemHeight(); + const int iconWidth = Interface::IconsBar::getItemWidth(); + const int iconHeight = Interface::IconsBar::getItemHeight(); const int barWidth = 7; // background diff --git a/src/fheroes2/game/game_interface.h b/src/fheroes2/game/game_interface.h index 349dc3aa50..305c40663a 100644 --- a/src/fheroes2/game/game_interface.h +++ b/src/fheroes2/game/game_interface.h @@ -32,6 +32,7 @@ #include "interface_cpanel.h" #include "interface_icons.h" #include "interface_status.h" +#include "math_base.h" #include "players.h" class Castle; @@ -109,6 +110,11 @@ namespace Interface return _statusPanel; } + const fheroes2::Rect & getButtonsPanelRect() const + { + return _buttonsPanel.GetRect(); + } + void SetFocus( Heroes *, const bool retainScrollBarPosition ); void SetFocus( Castle * ); void ResetFocus( const int priority, const bool retainScrollBarPosition ); diff --git a/src/fheroes2/game/game_startgame.cpp b/src/fheroes2/game/game_startgame.cpp index 957e539bfd..c73f7dd46e 100644 --- a/src/fheroes2/game/game_startgame.cpp +++ b/src/fheroes2/game/game_startgame.cpp @@ -703,7 +703,7 @@ fheroes2::GameMode Interface::AdventureMap::StartGame() _radar.Build(); _radar.SetHide( true ); - _iconsPanel.HideIcons( ICON_ANY ); + _iconsPanel.hideIcons( ICON_ANY ); _statusPanel.Reset(); // Prepare for render the whole game interface with adventure map filled with fog as it was not uncovered by 'updateMapFogDirections()'. @@ -785,7 +785,7 @@ fheroes2::GameMode Interface::AdventureMap::StartGame() AudioManager::ResetAudio(); if ( isHotSeatGame ) { - _iconsPanel.HideIcons( ICON_ANY ); + _iconsPanel.hideIcons( ICON_ANY ); _statusPanel.Reset(); // Fully update fog directions in Hot Seat mode to cover the map with fog on player change. @@ -808,8 +808,8 @@ fheroes2::GameMode Interface::AdventureMap::StartGame() kingdom.ActionBeforeTurn(); - _iconsPanel.ShowIcons( ICON_ANY ); - _iconsPanel.SetRedraw(); + _iconsPanel.showIcons( ICON_ANY ); + _iconsPanel.setRedraw(); res = HumanTurn( isLoadedFromSave ); @@ -1200,40 +1200,31 @@ fheroes2::GameMode Interface::AdventureMap::HumanTurn( const bool isLoadedFromSa // followed by the buttons panel, followed by the icons panel, followed by the radar, followed by the control panel, and under all // of them there is a game area. It is necessary to process events in exactly the same order in which all these UI elements overlap. // - // When the mouse is captured by any UI element, events should not be handled by other UI elements, even if the UI element that - // captured the mouse cannot handle them itself (for example, because it was hidden after the mouse was captured by it). + // When the mouse is captured by any UI element, events should not be handled by other UI elements. // // Mouse is captured by the status panel if ( _statusPanel.isMouseCaptured() ) { resetCursor(); - if ( !isHiddenInterface || conf.ShowStatus() ) { - _statusPanel.QueueEventProcessing(); - } + _statusPanel.QueueEventProcessing(); } // Mouse is captured by the buttons panel else if ( _buttonsPanel.isMouseCaptured() ) { resetCursor(); - if ( !isHiddenInterface || conf.ShowButtons() ) { - res = _buttonsPanel.QueueEventProcessing(); - } + res = _buttonsPanel.queueEventProcessing(); } // Mouse is captured by the icons panel else if ( _iconsPanel.isMouseCaptured() ) { resetCursor(); - if ( !isHiddenInterface || conf.ShowIcons() ) { - _iconsPanel.QueueEventProcessing(); - } + _iconsPanel.queueEventProcessing(); } // Mouse is captured by radar else if ( _radar.isMouseCaptured() ) { resetCursor(); - if ( !isHiddenInterface || conf.ShowRadar() ) { - _radar.QueueEventProcessing(); - } + _radar.QueueEventProcessing(); } // Mouse is captured by the game area for scrolling by dragging else if ( _gameArea.isDragScroll() ) { @@ -1288,13 +1279,13 @@ fheroes2::GameMode Interface::AdventureMap::HumanTurn( const bool isLoadedFromSa else if ( ( !isHiddenInterface || conf.ShowButtons() ) && le.isMouseCursorPosInArea( _buttonsPanel.GetRect() ) ) { resetCursorIfNoNeedToScroll(); - res = _buttonsPanel.QueueEventProcessing(); + res = _buttonsPanel.queueEventProcessing(); } // Cursor is over the icons panel else if ( ( !isHiddenInterface || conf.ShowIcons() ) && le.isMouseCursorPosInArea( _iconsPanel.GetRect() ) ) { resetCursorIfNoNeedToScroll(); - _iconsPanel.QueueEventProcessing(); + _iconsPanel.queueEventProcessing(); } // Cursor is over the radar else if ( ( !isHiddenInterface || conf.ShowRadar() ) && le.isMouseCursorPosInArea( _radar.GetRect() ) ) { diff --git a/src/fheroes2/gui/interface_buttons.cpp b/src/fheroes2/gui/interface_buttons.cpp index 37374684cd..cf2f158f32 100644 --- a/src/fheroes2/gui/interface_buttons.cpp +++ b/src/fheroes2/gui/interface_buttons.cpp @@ -35,16 +35,12 @@ #include "localevent.h" #include "mp2.h" #include "route.h" +#include "screen.h" #include "settings.h" #include "translations.h" #include "ui_dialog.h" #include "world.h" -Interface::ButtonsPanel::ButtonsPanel( AdventureMap & basic ) - : BorderWindow( { 0, 0, 144, 72 } ) - , interface( basic ) -{} - void Interface::ButtonsPanel::SavePosition() { Settings & conf = Settings::Get(); @@ -53,9 +49,9 @@ void Interface::ButtonsPanel::SavePosition() conf.Save( Settings::configFileName ); } -void Interface::ButtonsPanel::SetRedraw() const +void Interface::ButtonsPanel::setRedraw() const { - interface.setRedraw( REDRAW_BUTTONS ); + _interface.setRedraw( REDRAW_BUTTONS ); } void Interface::ButtonsPanel::SetPos( int32_t x, int32_t y ) @@ -64,173 +60,199 @@ void Interface::ButtonsPanel::SetPos( int32_t x, int32_t y ) const int icnbtn = Settings::Get().isEvilInterfaceEnabled() ? ICN::ADVEBTNS : ICN::ADVBTNS; - buttonNextHero.setICNInfo( icnbtn, 0, 1 ); - buttonHeroMovement.setICNInfo( icnbtn, 2, 3 ); - buttonKingdom.setICNInfo( icnbtn, 4, 5 ); - buttonSpell.setICNInfo( icnbtn, 6, 7 ); - buttonEndTurn.setICNInfo( icnbtn, 8, 9 ); - buttonAdventure.setICNInfo( icnbtn, 10, 11 ); - buttonFile.setICNInfo( icnbtn, 12, 13 ); - buttonSystem.setICNInfo( icnbtn, 14, 15 ); + _buttonNextHero.setICNInfo( icnbtn, 0, 1 ); + _buttonHeroMovement.setICNInfo( icnbtn, 2, 3 ); + _buttonKingdom.setICNInfo( icnbtn, 4, 5 ); + _buttonSpell.setICNInfo( icnbtn, 6, 7 ); + _buttonEndTurn.setICNInfo( icnbtn, 8, 9 ); + _buttonAdventure.setICNInfo( icnbtn, 10, 11 ); + _buttonFile.setICNInfo( icnbtn, 12, 13 ); + _buttonSystem.setICNInfo( icnbtn, 14, 15 ); - SetButtonStatus(); + _setButtonStatus(); x = GetArea().x; y = GetArea().y; // Top row - buttonNextHero.setPosition( x, y ); - nextHeroRect = buttonNextHero.area(); + _buttonNextHero.setPosition( x, y ); + _nextHeroRect = _buttonNextHero.area(); - buttonHeroMovement.setPosition( nextHeroRect.x + nextHeroRect.width, y ); - heroMovementRect = buttonHeroMovement.area(); + _buttonHeroMovement.setPosition( _nextHeroRect.x + _nextHeroRect.width, y ); + _heroMovementRect = _buttonHeroMovement.area(); - buttonKingdom.setPosition( heroMovementRect.x + heroMovementRect.width, y ); - kingdomRect = buttonKingdom.area(); + _buttonKingdom.setPosition( _heroMovementRect.x + _heroMovementRect.width, y ); + _kingdomRect = _buttonKingdom.area(); - buttonSpell.setPosition( kingdomRect.x + kingdomRect.width, y ); - spellRect = buttonSpell.area(); + _buttonSpell.setPosition( _kingdomRect.x + _kingdomRect.width, y ); + _spellRect = _buttonSpell.area(); // Bottom row - y = nextHeroRect.y + nextHeroRect.height; + y = _nextHeroRect.y + _nextHeroRect.height; - buttonEndTurn.setPosition( x, y ); - endTurnRect = buttonEndTurn.area(); + _buttonEndTurn.setPosition( x, y ); + _endTurnRect = _buttonEndTurn.area(); - buttonAdventure.setPosition( endTurnRect.x + endTurnRect.width, y ); - adventureRect = buttonAdventure.area(); + _buttonAdventure.setPosition( _endTurnRect.x + _endTurnRect.width, y ); + _adventureRect = _buttonAdventure.area(); - buttonFile.setPosition( adventureRect.x + adventureRect.width, y ); - fileRect = buttonFile.area(); + _buttonFile.setPosition( _adventureRect.x + _adventureRect.width, y ); + _fileRect = _buttonFile.area(); - buttonSystem.setPosition( fileRect.x + fileRect.width, y ); - systemRect = buttonSystem.area(); + _buttonSystem.setPosition( _fileRect.x + _fileRect.width, y ); + _systemRect = _buttonSystem.area(); } void Interface::ButtonsPanel::_redraw() { const Settings & conf = Settings::Get(); - if ( !conf.isHideInterfaceEnabled() || conf.ShowButtons() ) { - if ( conf.isHideInterfaceEnabled() ) - BorderWindow::Redraw(); - - SetButtonStatus(); + if ( conf.isHideInterfaceEnabled() ) { + if ( !conf.ShowButtons() ) { + return; + } - buttonNextHero.draw(); - buttonHeroMovement.draw(); - buttonKingdom.draw(); - buttonSpell.draw(); - buttonEndTurn.draw(); - buttonAdventure.draw(); - buttonFile.draw(); - buttonSystem.draw(); + BorderWindow::Redraw(); } + + _setButtonStatus(); + + _buttonNextHero.draw(); + _buttonHeroMovement.draw(); + _buttonKingdom.draw(); + _buttonSpell.draw(); + _buttonEndTurn.draw(); + _buttonAdventure.draw(); + _buttonFile.draw(); + _buttonSystem.draw(); } -fheroes2::GameMode Interface::ButtonsPanel::QueueEventProcessing() +fheroes2::GameMode Interface::ButtonsPanel::queueEventProcessing() { captureMouse(); LocalEvent & le = LocalEvent::Get(); - le.isMouseLeftButtonPressedInArea( nextHeroRect ) ? buttonNextHero.drawOnPress() : buttonNextHero.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( heroMovementRect ) ? buttonHeroMovement.drawOnPress() : buttonHeroMovement.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( kingdomRect ) ? buttonKingdom.drawOnPress() : buttonKingdom.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( spellRect ) ? buttonSpell.drawOnPress() : buttonSpell.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( endTurnRect ) ? buttonEndTurn.drawOnPress() : buttonEndTurn.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( adventureRect ) ? buttonAdventure.drawOnPress() : buttonAdventure.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( fileRect ) ? buttonFile.drawOnPress() : buttonFile.drawOnRelease(); - le.isMouseLeftButtonPressedInArea( systemRect ) ? buttonSystem.drawOnPress() : buttonSystem.drawOnRelease(); + // In the "no interface" mode, the buttons panel may be overlapped by other UI elements, so we can't render the + // pressed or released buttons exclusively in a usual way. The overlapping UI elements should also be rendered. + const auto drawOnPressOrRelease = [this, &le]( fheroes2::Button & button, const fheroes2::Rect & buttonRect ) { + bool shouldRedraw = false; + + if ( le.isMouseLeftButtonPressedInArea( buttonRect ) ) { + if ( !button.isPressed() && button.press() ) { + shouldRedraw = true; + } + } + else { + if ( !button.isReleased() && button.release() ) { + shouldRedraw = true; + } + } + + if ( shouldRedraw ) { + _interface.redraw( REDRAW_BUTTONS ); + + // Render now only the changed part of the screen. + fheroes2::Display::instance().render( buttonRect ); + } + }; + + drawOnPressOrRelease( _buttonNextHero, _nextHeroRect ); + drawOnPressOrRelease( _buttonHeroMovement, _heroMovementRect ); + drawOnPressOrRelease( _buttonKingdom, _kingdomRect ); + drawOnPressOrRelease( _buttonSpell, _spellRect ); + drawOnPressOrRelease( _buttonEndTurn, _endTurnRect ); + drawOnPressOrRelease( _buttonAdventure, _adventureRect ); + drawOnPressOrRelease( _buttonFile, _fileRect ); + drawOnPressOrRelease( _buttonSystem, _systemRect ); fheroes2::GameMode res = fheroes2::GameMode::CANCEL; - // Move the window border + // Move the window border. if ( Settings::Get().ShowButtons() && BorderWindow::QueueEventProcessing() ) { - SetRedraw(); + setRedraw(); } - else if ( buttonNextHero.isEnabled() && le.MouseClickLeft( nextHeroRect ) ) { - interface.EventNextHero(); + else if ( _buttonNextHero.isEnabled() && le.MouseClickLeft( _nextHeroRect ) ) { + _interface.EventNextHero(); } - else if ( buttonHeroMovement.isEnabled() && le.MouseClickLeft( heroMovementRect ) ) { - res = interface.EventHeroMovement(); + else if ( _buttonHeroMovement.isEnabled() && le.MouseClickLeft( _heroMovementRect ) ) { + res = _interface.EventHeroMovement(); } - else if ( buttonHeroMovement.isEnabled() && le.MouseLongPressLeft( heroMovementRect ) ) { - interface.EventResetHeroPath(); + else if ( _buttonHeroMovement.isEnabled() && le.MouseLongPressLeft( _heroMovementRect ) ) { + _interface.EventResetHeroPath(); } - else if ( le.MouseClickLeft( kingdomRect ) ) { - interface.EventKingdomInfo(); + else if ( le.MouseClickLeft( _kingdomRect ) ) { + _interface.EventKingdomInfo(); } - else if ( buttonSpell.isEnabled() && le.MouseClickLeft( spellRect ) ) { - interface.EventCastSpell(); + else if ( _buttonSpell.isEnabled() && le.MouseClickLeft( _spellRect ) ) { + _interface.EventCastSpell(); } - else if ( le.MouseClickLeft( endTurnRect ) ) { - res = interface.EventEndTurn(); + else if ( le.MouseClickLeft( _endTurnRect ) ) { + res = _interface.EventEndTurn(); } - else if ( le.MouseClickLeft( adventureRect ) ) { - res = interface.EventAdventureDialog(); + else if ( le.MouseClickLeft( _adventureRect ) ) { + res = _interface.EventAdventureDialog(); } - else if ( le.MouseClickLeft( fileRect ) ) { - res = interface.EventFileDialog(); + else if ( le.MouseClickLeft( _fileRect ) ) { + res = _interface.EventFileDialog(); } - else if ( le.MouseClickLeft( systemRect ) ) { - interface.EventSystemDialog(); + else if ( le.MouseClickLeft( _systemRect ) ) { + _interface.EventSystemDialog(); } - - if ( le.isMouseRightButtonPressedInArea( nextHeroRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _nextHeroRect ) ) { fheroes2::showStandardTextMessage( _( "Next Hero" ), _( "Select the next Hero." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( heroMovementRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _heroMovementRect ) ) { fheroes2::showStandardTextMessage( _( "Hero Movement" ), _( "Start the Hero's movement along the current path or re-visit the object occupied by the Hero. Press and hold this button to reset the Hero's path." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( kingdomRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _kingdomRect ) ) { fheroes2::showStandardTextMessage( _( "Kingdom Summary" ), _( "View a summary of your Kingdom." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( spellRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _spellRect ) ) { fheroes2::showStandardTextMessage( _( "Cast Spell" ), _( "Cast an adventure spell." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( endTurnRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _endTurnRect ) ) { fheroes2::showStandardTextMessage( _( "End Turn" ), _( "End your turn and let the computer take its turn." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( adventureRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _adventureRect ) ) { fheroes2::showStandardTextMessage( _( "Adventure Options" ), _( "Bring up the adventure options menu." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( fileRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _fileRect ) ) { fheroes2::showStandardTextMessage( _( "File Options" ), _( "Bring up the file options menu, allowing you to load, save, start a new game or quit." ), Dialog::ZERO ); } - else if ( le.isMouseRightButtonPressedInArea( systemRect ) ) { + else if ( le.isMouseRightButtonPressedInArea( _systemRect ) ) { fheroes2::showStandardTextMessage( _( "System Options" ), _( "Bring up the system options menu, allowing you to customize your game." ), Dialog::ZERO ); } return res; } -void Interface::ButtonsPanel::SetButtonStatus() +void Interface::ButtonsPanel::_setButtonStatus() { Heroes * currentHero = GetFocusHeroes(); if ( currentHero && currentHero->GetPath().isValidForMovement() && currentHero->MayStillMove( false, true ) ) { - buttonHeroMovement.setICNIndexes( 2, 3 ); - buttonHeroMovement.enable(); + _buttonHeroMovement.setICNIndexes( 2, 3 ); + _buttonHeroMovement.enable(); } else if ( currentHero && MP2::isInGameActionObject( currentHero->getObjectTypeUnderHero(), currentHero->isShipMaster() ) ) { - buttonHeroMovement.setICNIndexes( 16, 17 ); - buttonHeroMovement.enable(); + _buttonHeroMovement.setICNIndexes( 16, 17 ); + _buttonHeroMovement.enable(); } else { - buttonHeroMovement.setICNIndexes( 2, 3 ); - buttonHeroMovement.disable(); + _buttonHeroMovement.setICNIndexes( 2, 3 ); + _buttonHeroMovement.disable(); } if ( currentHero && currentHero->HaveSpellBook() && currentHero->MayCastAdventureSpells() ) { - buttonSpell.enable(); + _buttonSpell.enable(); } else { - buttonSpell.disable(); + _buttonSpell.disable(); } const Kingdom & kingdom = world.GetKingdom( Settings::Get().CurrentColor() ); @@ -243,9 +265,9 @@ void Interface::ButtonsPanel::SetButtonStatus() } ); if ( isMovableHeroPresent ) { - buttonNextHero.enable(); + _buttonNextHero.enable(); } else { - buttonNextHero.disable(); + _buttonNextHero.disable(); } } diff --git a/src/fheroes2/gui/interface_buttons.h b/src/fheroes2/gui/interface_buttons.h index 885e13f66f..88d662fc17 100644 --- a/src/fheroes2/gui/interface_buttons.h +++ b/src/fheroes2/gui/interface_buttons.h @@ -38,7 +38,13 @@ namespace Interface class ButtonsPanel final : public BorderWindow { public: - explicit ButtonsPanel( AdventureMap & ); + explicit ButtonsPanel( AdventureMap & baseInterface ) + : BorderWindow( { 0, 0, 144, 72 } ) + , _interface( baseInterface ) + { + // Do nothing. + } + ButtonsPanel( const ButtonsPanel & ) = delete; ~ButtonsPanel() override = default; @@ -47,36 +53,36 @@ namespace Interface void SetPos( int32_t x, int32_t y ) override; void SavePosition() override; - void SetRedraw() const; + void setRedraw() const; - fheroes2::GameMode QueueEventProcessing(); + fheroes2::GameMode queueEventProcessing(); // Do not call this method directly, use Interface::AdventureMap::redraw() instead to avoid issues in the "no interface" mode. // The name of this method starts from _ on purpose to do not mix with other public methods. void _redraw(); private: - void SetButtonStatus(); - - AdventureMap & interface; - - fheroes2::Button buttonNextHero; - fheroes2::Button buttonHeroMovement; - fheroes2::Button buttonKingdom; - fheroes2::Button buttonSpell; - fheroes2::Button buttonEndTurn; - fheroes2::Button buttonAdventure; - fheroes2::Button buttonFile; - fheroes2::Button buttonSystem; - - fheroes2::Rect nextHeroRect; - fheroes2::Rect heroMovementRect; - fheroes2::Rect kingdomRect; - fheroes2::Rect spellRect; - fheroes2::Rect endTurnRect; - fheroes2::Rect adventureRect; - fheroes2::Rect fileRect; - fheroes2::Rect systemRect; + void _setButtonStatus(); + + AdventureMap & _interface; + + fheroes2::Button _buttonNextHero; + fheroes2::Button _buttonHeroMovement; + fheroes2::Button _buttonKingdom; + fheroes2::Button _buttonSpell; + fheroes2::Button _buttonEndTurn; + fheroes2::Button _buttonAdventure; + fheroes2::Button _buttonFile; + fheroes2::Button _buttonSystem; + + fheroes2::Rect _nextHeroRect; + fheroes2::Rect _heroMovementRect; + fheroes2::Rect _kingdomRect; + fheroes2::Rect _spellRect; + fheroes2::Rect _endTurnRect; + fheroes2::Rect _adventureRect; + fheroes2::Rect _fileRect; + fheroes2::Rect _systemRect; }; } diff --git a/src/fheroes2/gui/interface_events.cpp b/src/fheroes2/gui/interface_events.cpp index 9df74bbed6..6ebe4cc691 100644 --- a/src/fheroes2/gui/interface_events.cpp +++ b/src/fheroes2/gui/interface_events.cpp @@ -91,7 +91,7 @@ void Interface::AdventureMap::ShowPathOrStartMoveHero( Heroes * hero, const int3 DEBUG_LOG( DBG_GAME, DBG_TRACE, hero->GetName() << ", distance: " << world.getDistance( *hero, destinationIdx ) << ", route: " << path.String() ) _gameArea.SetRedraw(); - _buttonsPanel.SetRedraw(); + _buttonsPanel.setRedraw(); } // Start the hero's movement else if ( path.isValidForMovement() && hero->MayStillMove( false, true ) ) { @@ -211,7 +211,7 @@ void Interface::AdventureMap::EventKingdomInfo() const Kingdom & myKingdom = world.GetKingdom( Settings::Get().CurrentColor() ); myKingdom.openOverviewDialog(); - _iconsPanel.SetRedraw(); + _iconsPanel.setRedraw(); } void Interface::AdventureMap::EventCastSpell() @@ -408,7 +408,7 @@ void Interface::AdventureMap::EventSwitchHeroSleeping() hero->Modes( Heroes::SLEEPER ) ? hero->ResetModes( Heroes::SLEEPER ) : hero->SetModes( Heroes::SLEEPER ); setRedraw( REDRAW_HEROES ); - _buttonsPanel.SetRedraw(); + _buttonsPanel.setRedraw(); } } @@ -547,7 +547,7 @@ void Interface::AdventureMap::EventSwitchShowButtons() const } else { conf.SetShowButtons( true ); - _buttonsPanel.SetRedraw(); + _buttonsPanel.setRedraw(); } } } @@ -579,7 +579,7 @@ void Interface::AdventureMap::EventSwitchShowIcons() const } else { conf.SetShowIcons( true ); - _iconsPanel.SetRedraw(); + _iconsPanel.setRedraw(); } } } diff --git a/src/fheroes2/gui/interface_focus.cpp b/src/fheroes2/gui/interface_focus.cpp index 8a780f3954..38b6e4ee9d 100644 --- a/src/fheroes2/gui/interface_focus.cpp +++ b/src/fheroes2/gui/interface_focus.cpp @@ -80,7 +80,7 @@ void Interface::AdventureMap::SetFocus( Heroes * hero, const bool retainScrollBa setRedraw( REDRAW_BUTTONS ); if ( !retainScrollBarPosition ) { - _iconsPanel.Select( hero ); + _iconsPanel.select( hero ); } _gameArea.SetCenter( hero->GetCenter() ); @@ -123,7 +123,7 @@ void Interface::AdventureMap::SetFocus( Castle * castle ) setRedraw( REDRAW_BUTTONS ); - _iconsPanel.Select( castle ); + _iconsPanel.select( castle ); _gameArea.SetCenter( castle->GetCenter() ); _statusPanel.SetState( StatusType::STATUS_FUNDS ); @@ -170,7 +170,7 @@ void Interface::AdventureMap::ResetFocus( const int priority, const bool retainS Kingdom & myKingdom = world.GetKingdom( player->GetColor() ); if ( !retainScrollBarPosition ) { - _iconsPanel.ResetIcons( ICON_ANY ); + _iconsPanel.resetIcons( ICON_ANY ); } switch ( priority ) { @@ -197,12 +197,12 @@ void Interface::AdventureMap::ResetFocus( const int priority, const bool retainS else if ( !myKingdom.GetHeroes().empty() ) { // Reset scrollbar here because the current focused hero might have // lost a battle and is not in the heroes list anymore. - _iconsPanel.ResetIcons( ICON_HEROES ); + _iconsPanel.resetIcons( ICON_HEROES ); SetFocus( myKingdom.GetHeroes().front(), false ); } else if ( !myKingdom.GetCastles().empty() ) { // There are no heroes left in the kingdom. Reset the heroes scrollbar and focus on the first castle. - _iconsPanel.SetRedraw( ICON_HEROES ); + _iconsPanel.setRedraw( ICON_HEROES ); SetFocus( myKingdom.GetCastles().front() ); } else { @@ -217,12 +217,12 @@ void Interface::AdventureMap::ResetFocus( const int priority, const bool retainS } else if ( !myKingdom.GetCastles().empty() ) { // The previously focused castle is lost, so we update the castles scrollbar. - _iconsPanel.ResetIcons( ICON_CASTLES ); + _iconsPanel.resetIcons( ICON_CASTLES ); SetFocus( myKingdom.GetCastles().front() ); } else if ( !myKingdom.GetHeroes().empty() ) { // There are no castles left in the kingdom. Reset the castles scrollbar and focus on the first hero. - _iconsPanel.SetRedraw( ICON_CASTLES ); + _iconsPanel.setRedraw( ICON_CASTLES ); SetFocus( myKingdom.GetHeroes().front(), false ); } else { @@ -272,31 +272,31 @@ void Interface::AdventureMap::RedrawFocus() { const int type = GetFocusType(); - if ( type != FOCUS_HEROES && _iconsPanel.IsSelected( ICON_HEROES ) ) { - _iconsPanel.ResetIcons( ICON_HEROES ); - _iconsPanel.SetRedraw(); + if ( type != FOCUS_HEROES && _iconsPanel.isSelected( ICON_HEROES ) ) { + _iconsPanel.resetIcons( ICON_HEROES ); + _iconsPanel.setRedraw(); } - else if ( type == FOCUS_HEROES && !_iconsPanel.IsSelected( ICON_HEROES ) ) { - _iconsPanel.Select( GetFocusHeroes() ); - _iconsPanel.SetRedraw(); + else if ( type == FOCUS_HEROES && !_iconsPanel.isSelected( ICON_HEROES ) ) { + _iconsPanel.select( GetFocusHeroes() ); + _iconsPanel.setRedraw(); } - if ( type != FOCUS_CASTLE && _iconsPanel.IsSelected( ICON_CASTLES ) ) { - _iconsPanel.ResetIcons( ICON_CASTLES ); - _iconsPanel.SetRedraw(); + if ( type != FOCUS_CASTLE && _iconsPanel.isSelected( ICON_CASTLES ) ) { + _iconsPanel.resetIcons( ICON_CASTLES ); + _iconsPanel.setRedraw(); } - else if ( type == FOCUS_CASTLE && !_iconsPanel.IsSelected( ICON_CASTLES ) ) { - _iconsPanel.Select( GetFocusCastle() ); - _iconsPanel.SetRedraw(); + else if ( type == FOCUS_CASTLE && !_iconsPanel.isSelected( ICON_CASTLES ) ) { + _iconsPanel.select( GetFocusCastle() ); + _iconsPanel.setRedraw(); } setRedraw( REDRAW_GAMEAREA | REDRAW_RADAR_CURSOR ); if ( type == FOCUS_HEROES ) { - _iconsPanel.SetRedraw( ICON_HEROES ); + _iconsPanel.setRedraw( ICON_HEROES ); } else if ( type == FOCUS_CASTLE ) { - _iconsPanel.SetRedraw( ICON_CASTLES ); + _iconsPanel.setRedraw( ICON_CASTLES ); } _statusPanel.setRedraw(); diff --git a/src/fheroes2/gui/interface_icons.cpp b/src/fheroes2/gui/interface_icons.cpp index 1c2c4b3945..31bf145258 100644 --- a/src/fheroes2/gui/interface_icons.cpp +++ b/src/fheroes2/gui/interface_icons.cpp @@ -42,36 +42,24 @@ namespace { - const int32_t iconsWidth = 46; - const int32_t iconsHeight = 22; const int32_t iconsCursorWidth = 56; const int32_t iconsCursorHeight = 32; } -bool Interface::IconsBar::IsVisible() +bool Interface::IconsBar::isVisible() { const Settings & conf = Settings::Get(); return !conf.isHideInterfaceEnabled() || conf.ShowIcons(); } -int32_t Interface::IconsBar::GetItemWidth() +void Interface::redrawCastleIcon( const Castle & castle, const int32_t posX, const int32_t posY ) { - return iconsWidth; + fheroes2::drawCastleIcon( castle, fheroes2::Display::instance(), { posX, posY } ); } -int32_t Interface::IconsBar::GetItemHeight() +void Interface::redrawHeroesIcon( const Heroes & hero, const int32_t posX, const int32_t posY ) { - return iconsHeight; -} - -void Interface::RedrawCastleIcon( const Castle & castle, int32_t sx, int32_t sy ) -{ - fheroes2::drawCastleIcon( castle, fheroes2::Display::instance(), { sx, sy } ); -} - -void Interface::RedrawHeroesIcon( const Heroes & hero, int32_t sx, int32_t sy ) -{ - hero.PortraitRedraw( sx, sy, PORT_SMALL, fheroes2::Display::instance() ); + hero.PortraitRedraw( posX, posY, PORT_SMALL, fheroes2::Display::instance() ); } void Interface::IconsBar::redrawBackground( fheroes2::Image & output, const fheroes2::Point & offset, const int32_t validItemCount ) const @@ -89,8 +77,8 @@ void Interface::IconsBar::redrawBackground( fheroes2::Image & output, const fher int32_t internalOffsetY = offset.y + srcrt.height; srcrt.height = 32; - if ( iconsCount > 2 ) { - for ( int32_t i = 0; i < iconsCount - 2; ++i ) { + if ( _iconsCount > 2 ) { + for ( int32_t i = 0; i < _iconsCount - 2; ++i ) { fheroes2::Blit( icnadv, srcrt.x, srcrt.y, output, offset.x, internalOffsetY, srcrt.width, srcrt.height ); internalOffsetY += srcrt.height; } @@ -100,25 +88,26 @@ void Interface::IconsBar::redrawBackground( fheroes2::Image & output, const fher srcrt.height = 32; fheroes2::Blit( icnadv, srcrt.x, srcrt.y, output, offset.x, internalOffsetY, srcrt.width, srcrt.height ); - for ( int32_t i = validItemCount; i < iconsCount; ++i ) { + for ( int32_t i = validItemCount; i < _iconsCount; ++i ) { const fheroes2::Sprite & background = fheroes2::AGG::GetICN( isEvilInterface ? ICN::LOCATORE : ICN::LOCATORS, 1 + i % 8 ); - fheroes2::Blit( background, output, offset.x + 5, offset.y + 5 + i * ( IconsBar::GetItemHeight() + 10 ) ); + fheroes2::Copy( background, 0, 0, output, offset.x + 5, offset.y + 5 + i * ( IconsBar::getItemHeight() + 10 ), background.width(), background.height() ); } } void Interface::CastleIcons::RedrawItem( const CASTLE & item, int32_t ox, int32_t oy, bool current ) { - if ( item && show ) { - RedrawCastleIcon( *item, ox + 5, oy + 5 ); + if ( item && _show ) { + redrawCastleIcon( *item, ox + 5, oy + 5 ); - if ( current ) - fheroes2::Blit( marker, fheroes2::Display::instance(), ox, oy ); + if ( current ) { + fheroes2::Blit( _marker, fheroes2::Display::instance(), ox, oy ); + } } } void Interface::CastleIcons::RedrawBackground( const fheroes2::Point & pos ) { - redrawBackground( fheroes2::Display::instance(), pos, show ? _size() : 0 ); + redrawBackground( fheroes2::Display::instance(), pos, _show ? _size() : 0 ); } void Interface::CastleIcons::ActionCurrentUp() @@ -155,19 +144,21 @@ void Interface::CastleIcons::ActionListPressRight( CASTLE & item ) } } -void Interface::CastleIcons::SetShow( bool f ) +void Interface::CastleIcons::showIcons( const bool show ) { - IconsBar::SetShow( f ); + IconsBar::setShow( show ); - if ( IconsBar::IsVisible() ) { - if ( f ) + if ( IconsBar::isVisible() ) { + if ( show ) { GetScrollbar().show(); - else + } + else { GetScrollbar().hide(); + } } } -void Interface::CastleIcons::SetPos( int32_t px, int32_t py ) +void Interface::CastleIcons::setPos( const int32_t px, const int32_t py ) { Castle * selectedCastle = isSelected() ? GetCurrent() : nullptr; @@ -175,20 +166,20 @@ void Interface::CastleIcons::SetPos( int32_t px, int32_t py ) _topLeftCorner = fheroes2::Point( px, py ); SetTopLeft( _topLeftCorner ); - setScrollBarArea( { px + iconsCursorWidth + 3, py + 19, 10, iconsCursorHeight * iconsCount - 38 } ); + setScrollBarArea( { px + iconsCursorWidth + 3, py + 19, 10, iconsCursorHeight * _iconsCount - 38 } ); VecCastles & castles = world.GetKingdom( Settings::Get().CurrentColor() ).GetCastles(); const fheroes2::Sprite & originalSlider = fheroes2::AGG::GetICN( icnscroll, 4 ); const fheroes2::Image scrollbarSlider - = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * iconsCount - 38, iconsCount, static_cast( castles.size() ), + = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * _iconsCount - 38, _iconsCount, static_cast( castles.size() ), { 0, 0, originalSlider.width(), 8 }, { 0, 7, originalSlider.width(), 8 } ); setScrollBarImage( scrollbarSlider ); SetScrollButtonUp( icnscroll, 0, 1, { px + iconsCursorWidth + 1, py + 1 } ); - SetScrollButtonDn( icnscroll, 2, 3, { px + iconsCursorWidth + 1, py + iconsCount * iconsCursorHeight - 15 } ); - SetAreaMaxItems( iconsCount ); - SetAreaItems( { px, py, iconsCursorWidth, iconsCount * iconsCursorHeight } ); + SetScrollButtonDn( icnscroll, 2, 3, { px + iconsCursorWidth + 1, py + _iconsCount * iconsCursorHeight - 15 } ); + SetAreaMaxItems( _iconsCount ); + SetAreaItems( { px, py, iconsCursorWidth, _iconsCount * iconsCursorHeight } ); DisableHotkeys( true ); SetListContent( castles ); @@ -201,17 +192,18 @@ void Interface::CastleIcons::SetPos( int32_t px, int32_t py ) void Interface::HeroesIcons::RedrawItem( const HEROES & item, int32_t ox, int32_t oy, bool current ) { - if ( item && show ) { - RedrawHeroesIcon( *item, ox + 5, oy + 5 ); + if ( item && _show ) { + redrawHeroesIcon( *item, ox + 5, oy + 5 ); - if ( current ) - fheroes2::Blit( marker, fheroes2::Display::instance(), ox, oy ); + if ( current ) { + fheroes2::Blit( _marker, fheroes2::Display::instance(), ox, oy ); + } } } void Interface::HeroesIcons::RedrawBackground( const fheroes2::Point & pos ) { - redrawBackground( fheroes2::Display::instance(), pos, show ? _size() : 0 ); + redrawBackground( fheroes2::Display::instance(), pos, _show ? _size() : 0 ); } void Interface::HeroesIcons::ActionCurrentUp() @@ -248,19 +240,21 @@ void Interface::HeroesIcons::ActionListPressRight( HEROES & item ) } } -void Interface::HeroesIcons::SetShow( bool f ) +void Interface::HeroesIcons::showIcons( const bool show ) { - IconsBar::SetShow( f ); + IconsBar::setShow( show ); - if ( IconsBar::IsVisible() ) { - if ( f ) + if ( IconsBar::isVisible() ) { + if ( show ) { GetScrollbar().show(); - else + } + else { GetScrollbar().hide(); + } } } -void Interface::HeroesIcons::SetPos( int32_t px, int32_t py ) +void Interface::HeroesIcons::setPos( const int32_t px, const int32_t py ) { Heroes * selectedHero = isSelected() ? GetCurrent() : nullptr; @@ -268,20 +262,20 @@ void Interface::HeroesIcons::SetPos( int32_t px, int32_t py ) _topLeftCorner = fheroes2::Point( px, py ); SetTopLeft( _topLeftCorner ); - setScrollBarArea( { px + iconsCursorWidth + 3, py + 19, 10, iconsCursorHeight * iconsCount - 38 } ); + setScrollBarArea( { px + iconsCursorWidth + 3, py + 19, 10, iconsCursorHeight * _iconsCount - 38 } ); VecHeroes & heroes = world.GetKingdom( Settings::Get().CurrentColor() ).GetHeroes(); const fheroes2::Sprite & originalSlider = fheroes2::AGG::GetICN( icnscroll, 4 ); const fheroes2::Image scrollbarSlider - = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * iconsCount - 38, iconsCount, static_cast( heroes.size() ), + = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * _iconsCount - 38, _iconsCount, static_cast( heroes.size() ), { 0, 0, originalSlider.width(), 8 }, { 0, 7, originalSlider.width(), 8 } ); setScrollBarImage( scrollbarSlider ); SetScrollButtonUp( icnscroll, 0, 1, { px + iconsCursorWidth + 1, py + 1 } ); - SetScrollButtonDn( icnscroll, 2, 3, { px + iconsCursorWidth + 1, py + iconsCount * iconsCursorHeight - 15 } ); - SetAreaMaxItems( iconsCount ); - SetAreaItems( { px, py, iconsCursorWidth, iconsCount * iconsCursorHeight } ); + SetScrollButtonDn( icnscroll, 2, 3, { px + iconsCursorWidth + 1, py + _iconsCount * iconsCursorHeight - 15 } ); + SetAreaMaxItems( _iconsCount ); + SetAreaItems( { px, py, iconsCursorWidth, _iconsCount * iconsCursorHeight } ); DisableHotkeys( true ); SetListContent( heroes ); @@ -292,16 +286,14 @@ void Interface::HeroesIcons::SetPos( int32_t px, int32_t py ) } } -Interface::IconsPanel::IconsPanel( AdventureMap & basic ) +Interface::IconsPanel::IconsPanel( AdventureMap & interface ) : BorderWindow( { 0, 0, 144, 128 } ) - , interface( basic ) - , castleIcons( 4, sfMarker ) - , heroesIcons( 4, sfMarker ) + , _interface( interface ) { - sfMarker.resize( iconsCursorWidth, iconsCursorHeight ); - sfMarker.reset(); + _sfMarker.resize( iconsCursorWidth, iconsCursorHeight ); + _sfMarker.reset(); - fheroes2::DrawBorder( sfMarker, fheroes2::GetColorId( 0xA0, 0xE0, 0xE0 ) ); + fheroes2::DrawBorder( _sfMarker, fheroes2::GetColorId( 0xA0, 0xE0, 0xE0 ) ); } void Interface::IconsPanel::SavePosition() @@ -312,32 +304,27 @@ void Interface::IconsPanel::SavePosition() conf.Save( Settings::configFileName ); } -void Interface::IconsPanel::SetRedraw( const icons_t type ) const +void Interface::IconsPanel::setRedraw( const HeroesCastlesIcons type ) const { - if ( !IconsBar::IsVisible() ) { + if ( !IconsBar::isVisible() ) { return; } switch ( type ) { case ICON_HEROES: - interface.setRedraw( REDRAW_HEROES ); + _interface.setRedraw( REDRAW_HEROES ); break; case ICON_CASTLES: - interface.setRedraw( REDRAW_CASTLES ); + _interface.setRedraw( REDRAW_CASTLES ); break; case ICON_ANY: - interface.setRedraw( REDRAW_ICONS ); + _interface.setRedraw( REDRAW_ICONS ); break; default: break; } } -void Interface::IconsPanel::SetRedraw() const -{ - SetRedraw( ICON_ANY ); -} - void Interface::IconsPanel::SetPos( int32_t x, int32_t y ) { int32_t iconsCount = 0; @@ -352,18 +339,18 @@ void Interface::IconsPanel::SetPos( int32_t x, int32_t y ) BorderWindow::SetPosition( x, y, 144, iconsCount * iconsCursorHeight ); - heroesIcons.SetIconsCount( iconsCount ); - castleIcons.SetIconsCount( iconsCount ); + _heroesIcons.setIconsCount( iconsCount ); + _castleIcons.setIconsCount( iconsCount ); const fheroes2::Rect & rect = GetArea(); - heroesIcons.SetPos( rect.x, rect.y ); - castleIcons.SetPos( rect.x + 72, rect.y ); + _heroesIcons.setPos( rect.x, rect.y ); + _castleIcons.setPos( rect.x + 72, rect.y ); } void Interface::IconsPanel::_redraw() { - if ( !IconsBar::IsVisible() ) { + if ( !IconsBar::isVisible() ) { return; } @@ -371,47 +358,49 @@ void Interface::IconsPanel::_redraw() BorderWindow::Redraw(); } - heroesIcons.Redraw(); - castleIcons.Redraw(); + _heroesIcons.Redraw(); + _castleIcons.Redraw(); } -void Interface::IconsPanel::QueueEventProcessing() +void Interface::IconsPanel::queueEventProcessing() { captureMouse(); // Move the window border if ( Settings::Get().ShowIcons() && BorderWindow::QueueEventProcessing() ) { - SetRedraw(); + setRedraw(); } - else if ( heroesIcons.QueueEventProcessing() ) { - if ( heroesIcons.isSelected() ) { - castleIcons.Unselect(); - } + else { + if ( _heroesIcons.QueueEventProcessing() ) { + if ( _heroesIcons.isSelected() ) { + _castleIcons.Unselect(); + } - SetRedraw(); - } - else if ( castleIcons.QueueEventProcessing() ) { - if ( castleIcons.isSelected() ) { - heroesIcons.Unselect(); + setRedraw(); } + else if ( _castleIcons.QueueEventProcessing() ) { + if ( _castleIcons.isSelected() ) { + _heroesIcons.Unselect(); + } - SetRedraw(); + setRedraw(); + } } } -void Interface::IconsPanel::Select( Heroes * const hr ) +void Interface::IconsPanel::select( Heroes * const hero ) { - castleIcons.Unselect(); - heroesIcons.SetCurrent( hr ); + _castleIcons.Unselect(); + _heroesIcons.SetCurrent( hero ); } -void Interface::IconsPanel::Select( Castle * const cs ) +void Interface::IconsPanel::select( Castle * const castle ) { - heroesIcons.Unselect(); - castleIcons.SetCurrent( cs ); + _heroesIcons.Unselect(); + _castleIcons.SetCurrent( castle ); } -void Interface::IconsPanel::ResetIcons( const icons_t type ) +void Interface::IconsPanel::resetIcons( const HeroesCastlesIcons type ) { Kingdom & kingdom = world.GetKingdom( Settings::Get().CurrentColor() ); @@ -421,66 +410,66 @@ void Interface::IconsPanel::ResetIcons( const icons_t type ) const fheroes2::Sprite & originalSlider = fheroes2::AGG::GetICN( icnscroll, 4 ); if ( type & ICON_HEROES ) { - const fheroes2::Image scrollbarSlider = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * heroesIcons.getIconsCount() - 38, - heroesIcons.getIconsCount(), static_cast( kingdom.GetHeroes().size() ), + const fheroes2::Image scrollbarSlider = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * _heroesIcons.getIconsCount() - 38, + _heroesIcons.getIconsCount(), static_cast( kingdom.GetHeroes().size() ), { 0, 0, originalSlider.width(), 8 }, { 0, 7, originalSlider.width(), 8 } ); - heroesIcons.setScrollBarImage( scrollbarSlider ); - heroesIcons.SetListContent( kingdom.GetHeroes() ); + _heroesIcons.setScrollBarImage( scrollbarSlider ); + _heroesIcons.SetListContent( kingdom.GetHeroes() ); // SetListContent() selects the first item (hero) in the list. We reset it by unselecting. - heroesIcons.Unselect(); + _heroesIcons.Unselect(); } if ( type & ICON_CASTLES ) { - const fheroes2::Image scrollbarSlider = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * castleIcons.getIconsCount() - 38, - castleIcons.getIconsCount(), static_cast( kingdom.GetCastles().size() ), + const fheroes2::Image scrollbarSlider = fheroes2::generateScrollbarSlider( originalSlider, false, iconsCursorHeight * _castleIcons.getIconsCount() - 38, + _castleIcons.getIconsCount(), static_cast( kingdom.GetCastles().size() ), { 0, 0, originalSlider.width(), 8 }, { 0, 7, originalSlider.width(), 8 } ); - castleIcons.setScrollBarImage( scrollbarSlider ); - castleIcons.SetListContent( kingdom.GetCastles() ); + _castleIcons.setScrollBarImage( scrollbarSlider ); + _castleIcons.SetListContent( kingdom.GetCastles() ); // SetListContent() selects the first item (castle/town) in the list. We reset it by unselecting. - castleIcons.Unselect(); + _castleIcons.Unselect(); } } } -void Interface::IconsPanel::HideIcons( const icons_t type ) +void Interface::IconsPanel::hideIcons( const HeroesCastlesIcons type ) { if ( type & ICON_HEROES ) { - heroesIcons.SetShow( false ); + _heroesIcons.showIcons( false ); } if ( type & ICON_CASTLES ) { - castleIcons.SetShow( false ); + _castleIcons.showIcons( false ); } } -void Interface::IconsPanel::ShowIcons( const icons_t type ) +void Interface::IconsPanel::showIcons( const HeroesCastlesIcons type ) { if ( type & ICON_HEROES ) { - heroesIcons.SetShow( true ); + _heroesIcons.showIcons( true ); } if ( type & ICON_CASTLES ) { - castleIcons.SetShow( true ); + _castleIcons.showIcons( true ); } } -void Interface::IconsPanel::_redrawIcons( const icons_t type ) +void Interface::IconsPanel::_redrawIcons( const HeroesCastlesIcons type ) { if ( type & ICON_HEROES ) { - heroesIcons.Redraw(); + _heroesIcons.Redraw(); } if ( type & ICON_CASTLES ) { - castleIcons.Redraw(); + _castleIcons.Redraw(); } } -bool Interface::IconsPanel::IsSelected( const icons_t type ) const +bool Interface::IconsPanel::isSelected( const HeroesCastlesIcons type ) const { if ( type & ICON_HEROES ) { - return heroesIcons.isSelected(); + return _heroesIcons.isSelected(); } if ( type & ICON_CASTLES ) { - return castleIcons.isSelected(); + return _castleIcons.isSelected(); } return false; diff --git a/src/fheroes2/gui/interface_icons.h b/src/fheroes2/gui/interface_icons.h index 1192632280..1156632052 100644 --- a/src/fheroes2/gui/interface_icons.h +++ b/src/fheroes2/gui/interface_icons.h @@ -35,7 +35,7 @@ class Castle; class Heroes; -enum icons_t : uint8_t +enum HeroesCastlesIcons : uint8_t { ICON_HEROES = 0x01, ICON_CASTLES = 0x02, @@ -52,10 +52,9 @@ namespace Interface class IconsBar { public: - IconsBar( const int32_t count, const fheroes2::Image & sf ) - : marker( sf ) - , iconsCount( count ) - , show( true ) + IconsBar( const int32_t count, const fheroes2::Image & markerImage ) + : _marker( markerImage ) + , _iconsCount( count ) { assert( count >= 0 ); } @@ -66,42 +65,51 @@ namespace Interface IconsBar & operator=( const IconsBar & ) = delete; - void SetShow( bool f ) + void setShow( bool show ) { - show = f; + _show = show; } void redrawBackground( fheroes2::Image & output, const fheroes2::Point & offset, const int32_t validItemCount ) const; - void SetIconsCount( const int32_t c ) + void setIconsCount( const int32_t count ) { - iconsCount = c; + _iconsCount = count; } int32_t getIconsCount() const { - return iconsCount; + return _iconsCount; } - static int32_t GetItemWidth(); - static int32_t GetItemHeight(); - static bool IsVisible(); + static int32_t getItemWidth() + { + return 46; + } + static int32_t getItemHeight() + { + return 22; + } + + static bool isVisible(); protected: - const fheroes2::Image & marker; - int32_t iconsCount; - bool show; + const fheroes2::Image & _marker; + int32_t _iconsCount; + bool _show{ true }; }; - void RedrawHeroesIcon( const Heroes &, int32_t, int32_t ); - void RedrawCastleIcon( const Castle &, int32_t, int32_t ); + void redrawHeroesIcon( const Heroes & hero, const int32_t posX, const int32_t posY ); + void redrawCastleIcon( const Castle & castle, const int32_t posX, const int32_t posY ); class HeroesIcons final : public Interface::ListBox, public IconsBar { public: - HeroesIcons( const int32_t count, const fheroes2::Image & sf ) - : IconsBar( count, sf ) - {} + HeroesIcons( const int32_t count, const fheroes2::Image & markerImage ) + : IconsBar( count, markerImage ) + { + // Do nothing. + } HeroesIcons( const HeroesIcons & ) = delete; @@ -109,8 +117,8 @@ namespace Interface HeroesIcons & operator=( const HeroesIcons & ) = delete; - void SetPos( int32_t px, int32_t py ); - void SetShow( bool ); + void setPos( const int32_t px, const int32_t py ); + void showIcons( const bool show ); private: using Interface::ListBox::ActionListDoubleClick; @@ -119,11 +127,11 @@ namespace Interface void ActionCurrentUp() override; void ActionCurrentDn() override; - void ActionListDoubleClick( HEROES & ) override; - void ActionListSingleClick( HEROES & ) override; - void ActionListPressRight( HEROES & ) override; + void ActionListDoubleClick( HEROES & item ) override; + void ActionListSingleClick( HEROES & item ) override; + void ActionListPressRight( HEROES & item ) override; void RedrawItem( const HEROES & item, int32_t ox, int32_t oy, bool current ) override; - void RedrawBackground( const fheroes2::Point & ) override; + void RedrawBackground( const fheroes2::Point & pos ) override; fheroes2::Point _topLeftCorner; }; @@ -131,9 +139,11 @@ namespace Interface class CastleIcons final : public Interface::ListBox, public IconsBar { public: - CastleIcons( const int32_t count, const fheroes2::Image & sf ) - : IconsBar( count, sf ) - {} + CastleIcons( const int32_t count, const fheroes2::Image & markerImage ) + : IconsBar( count, markerImage ) + { + // Do nothing. + } CastleIcons( const CastleIcons & ) = delete; @@ -141,8 +151,8 @@ namespace Interface CastleIcons & operator=( const CastleIcons & ) = delete; - void SetPos( int32_t px, int32_t py ); - void SetShow( bool ); + void setPos( const int32_t px, const int32_t py ); + void showIcons( const bool show ); private: using Interface::ListBox::ActionListDoubleClick; @@ -151,11 +161,11 @@ namespace Interface void ActionCurrentUp() override; void ActionCurrentDn() override; - void ActionListDoubleClick( CASTLE & ) override; - void ActionListSingleClick( CASTLE & ) override; - void ActionListPressRight( CASTLE & ) override; + void ActionListDoubleClick( CASTLE & item ) override; + void ActionListSingleClick( CASTLE & item ) override; + void ActionListPressRight( CASTLE & item ) override; void RedrawItem( const CASTLE & item, int32_t ox, int32_t oy, bool current ) override; - void RedrawBackground( const fheroes2::Point & ) override; + void RedrawBackground( const fheroes2::Point & pos ) override; fheroes2::Point _topLeftCorner; }; @@ -163,7 +173,7 @@ namespace Interface class IconsPanel final : public BorderWindow { public: - explicit IconsPanel( AdventureMap & basic ); + explicit IconsPanel( AdventureMap & interface ); IconsPanel( const IconsPanel & ) = delete; ~IconsPanel() override = default; @@ -172,32 +182,37 @@ namespace Interface void SetPos( int32_t x, int32_t y ) override; void SavePosition() override; - void SetRedraw() const; - void SetRedraw( const icons_t type ) const; - void QueueEventProcessing(); + void setRedraw() const + { + setRedraw( ICON_ANY ); + } + + void setRedraw( const HeroesCastlesIcons type ) const; + + void queueEventProcessing(); - void Select( Heroes * const ); - void Select( Castle * const ); + void select( Heroes * const hero ); + void select( Castle * const castle ); - bool IsSelected( const icons_t type ) const; - void ResetIcons( const icons_t type ); - void HideIcons( const icons_t type ); - void ShowIcons( const icons_t type ); + bool isSelected( const HeroesCastlesIcons type ) const; + void resetIcons( const HeroesCastlesIcons type ); + void hideIcons( const HeroesCastlesIcons type ); + void showIcons( const HeroesCastlesIcons type ); // Do not call this method directly, use Interface::AdventureMap::redraw() instead to avoid issues in the "no interface" mode. // The name of this method starts from _ on purpose to do not mix with other public methods. void _redraw(); // The name of this method starts from _ on purpose to do not mix with other public methods. - void _redrawIcons( const icons_t type ); + void _redrawIcons( const HeroesCastlesIcons type ); private: - AdventureMap & interface; + AdventureMap & _interface; - fheroes2::Image sfMarker; + fheroes2::Image _sfMarker; - CastleIcons castleIcons; - HeroesIcons heroesIcons; + CastleIcons _castleIcons{ 4, _sfMarker }; + HeroesIcons _heroesIcons{ 4, _sfMarker }; }; } diff --git a/src/fheroes2/gui/interface_list.h b/src/fheroes2/gui/interface_list.h index e8e388dac9..990854989b 100644 --- a/src/fheroes2/gui/interface_list.h +++ b/src/fheroes2/gui/interface_list.h @@ -494,8 +494,9 @@ namespace Interface Item & item = ( *content )[static_cast( id )]; // id is always >= 0 const int32_t offsetY = ( id - _topId ) * rtAreaItems.height / maxItems; - if ( ActionListCursor( item, mousePos ) ) + if ( ActionListCursor( item, mousePos ) ) { return true; + } if ( !_lockClick && le.MouseClickLeft( rtAreaItems ) ) { // This is a legitimate click and not a mouse-up on a finished drag. diff --git a/src/fheroes2/gui/ui_button.cpp b/src/fheroes2/gui/ui_button.cpp index 5249842704..5074701bbe 100644 --- a/src/fheroes2/gui/ui_button.cpp +++ b/src/fheroes2/gui/ui_button.cpp @@ -343,7 +343,7 @@ namespace fheroes2 return true; } - bool ButtonBase::drawOnPress( Display & output ) + bool ButtonBase::drawOnPress( Display & output /* = Display::instance() */ ) { if ( isPressed() ) { return false; @@ -355,12 +355,13 @@ namespace fheroes2 if ( isVisible() ) { draw( output ); + output.render( area() ); } return true; } - bool ButtonBase::drawOnRelease( Display & output ) + bool ButtonBase::drawOnRelease( Display & output /* = Display::instance() */ ) { if ( !isPressed() ) { return false; @@ -372,6 +373,7 @@ namespace fheroes2 if ( isVisible() ) { draw( output ); + output.render( area() ); } return true; diff --git a/src/fheroes2/gui/ui_button.h b/src/fheroes2/gui/ui_button.h index bfb5065329..a51e1ffbf3 100644 --- a/src/fheroes2/gui/ui_button.h +++ b/src/fheroes2/gui/ui_button.h @@ -80,9 +80,12 @@ namespace fheroes2 bool press(); bool release(); void enable(); - void disable(); // button becomes disabled and released - void show(); // this method doesn't call draw - void hide(); // this method doesn't call draw + // Button becomes disabled and released + void disable(); + // This method doesn't call draw() + void show(); + // This method doesn't call draw() + void hide(); void setPosition( const int32_t offsetX_, const int32_t offsetY_ ) { @@ -90,7 +93,8 @@ namespace fheroes2 _offsetY = offsetY_; } - bool draw( Image & output = Display::instance() ) const; // will draw on screen by default + // Will draw on screen by default + bool draw( Image & output = Display::instance() ) const; // Will draw on screen by default. Returns true in case of state change. This method calls render() internally. bool drawOnPress( Display & output = Display::instance() ); @@ -189,7 +193,8 @@ namespace fheroes2 void createButton( int32_t offsetX, int32_t offsetY, const Sprite & released, const Sprite & pressed, int returnValue ); void addButton( ButtonSprite && button, int returnValue ); - void draw( Image & area = Display::instance() ) const; // will draw on screen by default + // Will draw on screen by default + void draw( Image & area = Display::instance() ) const; // Make sure that id is less than size! ButtonBase & button( size_t id ); @@ -224,7 +229,8 @@ namespace fheroes2 public: void addButton( ButtonBase * button ); - void draw( Image & area = Display::instance() ) const; // will draw on screen by default + // Will draw on screen by default + void draw( Image & area = Display::instance() ) const; protected: void senderUpdate( const ActionObject * sender ) override; diff --git a/src/fheroes2/gui/ui_scrollbar.cpp b/src/fheroes2/gui/ui_scrollbar.cpp index 1ebd3d0bda..025238deab 100644 --- a/src/fheroes2/gui/ui_scrollbar.cpp +++ b/src/fheroes2/gui/ui_scrollbar.cpp @@ -31,16 +31,6 @@ namespace namespace fheroes2 { - void Scrollbar::setImage( const Image & image ) - { - Copy( image, *this ); - } - - void Scrollbar::setArea( const Rect & area ) - { - _area = area; - } - void Scrollbar::setRange( const int minIndex, const int maxIndex ) { assert( maxIndex >= minIndex ); @@ -78,6 +68,11 @@ namespace fheroes2 bool Scrollbar::moveToIndex( const int indexId ) { + if ( _currentIndex == indexId ) { + // Nothing to change. + return false; + } + const int32_t roiWidth = _area.width - width(); const int32_t roiHeight = _area.height - height(); @@ -88,15 +83,7 @@ namespace fheroes2 return false; } - if ( indexId < _minIndex ) { - _currentIndex = _minIndex; - } - else if ( indexId > _maxIndex ) { - _currentIndex = _maxIndex; - } - else { - _currentIndex = indexId; - } + _currentIndex = std::clamp( indexId, _minIndex, _maxIndex ); Point newPosition; @@ -120,43 +107,31 @@ namespace fheroes2 void Scrollbar::moveToPos( const Point & position ) { - if ( _maxIndex == _minIndex ) + if ( _maxIndex == _minIndex ) { return; + } - const int roiWidth = _area.width - width(); - const int roiHeight = _area.height - height(); - - if ( isVertical() ) { - const int32_t scrollbarImageMiddle = height() / 2; - const int32_t minYPos = _area.y + scrollbarImageMiddle; - const int32_t maxYPos = _area.y + roiHeight + scrollbarImageMiddle; - - int32_t posY = position.y; - if ( posY < minYPos ) - posY = minYPos; - else if ( posY > maxYPos ) - posY = maxYPos; + const int32_t roiWidth = _area.width - width(); + const int32_t roiHeight = _area.height - height(); - const double tempPos = static_cast( posY - minYPos ) * ( _maxIndex - _minIndex ) / roiHeight; - _currentIndex = static_cast( std::lround( tempPos ) ) + _minIndex; + Point newPosition; - setPosition( _area.x + roiWidth / 2, posY - scrollbarImageMiddle ); + if ( isVertical() ) { + newPosition.y = std ::clamp( position.y - height() / 2, _area.y, _area.y + roiHeight ); + newPosition.x = _area.x + roiWidth / 2; } else { - const int32_t scrollbarImageMiddle = width() / 2; - const int32_t minXPos = _area.x + scrollbarImageMiddle; - const int32_t maxXPos = _area.x + roiWidth + scrollbarImageMiddle; + newPosition.x = std ::clamp( position.x - width() / 2, _area.x, _area.x + roiWidth ); + newPosition.y = _area.y + roiHeight / 2; + } - int32_t posX = position.x; - if ( posX < minXPos ) - posX = minXPos; - else if ( posX > maxXPos ) - posX = maxXPos; + if ( newPosition.x != x() || newPosition.y != y() ) { + // Update only on the change. - const double tempPos = static_cast( posX - minXPos ) * ( _maxIndex - _minIndex ) / roiWidth; - _currentIndex = static_cast( std::lround( tempPos ) ) + _minIndex; + const double indexPos = isVertical() ? static_cast( newPosition.y - _area.y ) / roiHeight : static_cast( newPosition.x - _area.x ) / roiWidth; + _currentIndex = static_cast( std::lround( indexPos * ( _maxIndex - _minIndex ) ) ) + _minIndex; - setPosition( posX - scrollbarImageMiddle, _area.y + roiHeight / 2 ); + setPosition( newPosition.x, newPosition.y ); } } diff --git a/src/fheroes2/gui/ui_scrollbar.h b/src/fheroes2/gui/ui_scrollbar.h index ea5976d0ab..fef6cdb582 100644 --- a/src/fheroes2/gui/ui_scrollbar.h +++ b/src/fheroes2/gui/ui_scrollbar.h @@ -28,7 +28,7 @@ namespace fheroes2 { - class Scrollbar : public fheroes2::MovableSprite + class Scrollbar final : public fheroes2::MovableSprite { public: Scrollbar() = default; @@ -42,9 +42,16 @@ namespace fheroes2 } // The original resources do not support proper scrollbar slider scaling. Use generateScrollbarSlider() function to generate needed image. - void setImage( const Image & image ); + void setImage( const Image & image ) + { + Copy( image, *this ); + } + + void setArea( const Rect & area ) + { + _area = area; + } - void setArea( const Rect & area ); void setRange( const int minIndex, const int maxIndex ); void forward(); diff --git a/src/fheroes2/heroes/heroes_action.cpp b/src/fheroes2/heroes/heroes_action.cpp index 52f91dd091..4a0fd2701c 100644 --- a/src/fheroes2/heroes/heroes_action.cpp +++ b/src/fheroes2/heroes/heroes_action.cpp @@ -3308,7 +3308,7 @@ namespace prisoner->Recruit( hero.GetColor(), Maps::GetPoint( dst_index ) ); // Update the kingdom heroes list including the scrollbar. - Interface::AdventureMap::Get().GetIconsPanel().ResetIcons( ICON_HEROES ); + Interface::AdventureMap::Get().GetIconsPanel().resetIcons( ICON_HEROES ); } } else { diff --git a/src/fheroes2/kingdom/kingdom.cpp b/src/fheroes2/kingdom/kingdom.cpp index d8e5f38643..e7c8a1cc8e 100644 --- a/src/fheroes2/kingdom/kingdom.cpp +++ b/src/fheroes2/kingdom/kingdom.cpp @@ -342,8 +342,9 @@ void Kingdom::AddCastle( Castle * castle ) } const Player * player = Settings::Get().GetPlayers().GetCurrent(); - if ( player && player->isColor( GetColor() ) ) - Interface::AdventureMap::Get().GetIconsPanel().ResetIcons( ICON_CASTLES ); + if ( player && player->isColor( GetColor() ) ) { + Interface::AdventureMap::Get().GetIconsPanel().resetIcons( ICON_CASTLES ); + } } lost_town_days = Game::GetLostTownDays() + 1; diff --git a/src/fheroes2/kingdom/kingdom_overview.cpp b/src/fheroes2/kingdom/kingdom_overview.cpp index 2d849adb93..469377a98b 100644 --- a/src/fheroes2/kingdom/kingdom_overview.cpp +++ b/src/fheroes2/kingdom/kingdom_overview.cpp @@ -278,7 +278,7 @@ namespace void StatsHeroesList::ActionListSingleClick( HeroRow & row, const fheroes2::Point & cursor, int32_t ox, int32_t oy ) { - if ( row.hero && ( fheroes2::Rect( ox + 5, oy + 4, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) ) { + if ( row.hero && ( fheroes2::Rect( ox + 5, oy + 4, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) ) { Game::OpenHeroesDialog( *row.hero, false, false ); needFadeIn = true; @@ -287,7 +287,7 @@ namespace void StatsHeroesList::ActionListPressRight( HeroRow & row, const fheroes2::Point & cursor, int32_t ox, int32_t oy ) { - if ( row.hero && ( fheroes2::Rect( ox + 5, oy + 4, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) ) { + if ( row.hero && ( fheroes2::Rect( ox + 5, oy + 4, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) ) { Dialog::QuickInfoWithIndicationOnRadar( *row.hero, _windowArea ); } } @@ -334,7 +334,7 @@ namespace fheroes2::Blit( fheroes2::AGG::GetICN( ICN::OVERVIEW, 10 ), display, dstx, dsty ); // base info - Interface::RedrawHeroesIcon( *row.hero, dstx + 5, dsty + 4 ); + Interface::redrawHeroesIcon( *row.hero, dstx + 5, dsty + 4 ); int32_t offsetX = dstx + 90; const int32_t offsetY = dsty + 22; @@ -533,12 +533,12 @@ namespace { if ( row.castle ) { // click castle icon - if ( fheroes2::Rect( ox + 17, oy + 19, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) { + if ( fheroes2::Rect( ox + 17, oy + 19, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) { Game::OpenCastleDialog( *row.castle, false, false ); } // click hero icon - else if ( fheroes2::Rect( ox + 82, oy + 19, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) { + else if ( fheroes2::Rect( ox + 82, oy + 19, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) { Heroes * hero = row.castle->GetHero(); if ( !hero ) { @@ -558,10 +558,10 @@ namespace void StatsCastlesList::ActionListPressRight( CstlRow & row, const fheroes2::Point & cursor, int32_t ox, int32_t oy ) { if ( row.castle ) { - if ( fheroes2::Rect( ox + 17, oy + 19, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) { + if ( fheroes2::Rect( ox + 17, oy + 19, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) { Dialog::QuickInfoWithIndicationOnRadar( *row.castle, _windowArea ); } - else if ( fheroes2::Rect( ox + 82, oy + 19, Interface::IconsBar::GetItemWidth(), Interface::IconsBar::GetItemHeight() ) & cursor ) { + else if ( fheroes2::Rect( ox + 82, oy + 19, Interface::IconsBar::getItemWidth(), Interface::IconsBar::getItemHeight() ) & cursor ) { const Heroes * hero = row.castle->GetHero(); if ( hero ) { Dialog::QuickInfoWithIndicationOnRadar( *hero, _windowArea ); @@ -620,12 +620,12 @@ namespace fheroes2::Blit( fheroes2::AGG::GetICN( ICN::OVERVIEW, 11 ), display, dstx, dsty ); // base info - Interface::RedrawCastleIcon( *row.castle, dstx + 17, dsty + 19 ); + Interface::redrawCastleIcon( *row.castle, dstx + 17, dsty + 19 ); const Heroes * hero = row.castle->GetHero(); if ( hero ) { - Interface::RedrawHeroesIcon( *hero, dstx + 82, dsty + 19 ); + Interface::redrawHeroesIcon( *hero, dstx + 82, dsty + 19 ); const std::string sep = "-"; const fheroes2::Text text( std::to_string( hero->GetAttack() ) + sep + std::to_string( hero->GetDefense() ) + sep + std::to_string( hero->GetPower() ) + sep From e7590ca1f5c43d5baad1375c06fefe0a9a094e78 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 18 Oct 2024 12:07:34 +0800 Subject: [PATCH 14/18] Update translation files (#9210) --- docs/json/lang_hu.json | 2 +- docs/json/lang_sv.json | 2 +- docs/json/lang_uk.json | 2 +- files/lang/be.po | 8 +++++++- files/lang/bg.po | 8 +++++++- files/lang/cs.po | 8 +++++++- files/lang/de.po | 8 +++++++- files/lang/dk.po | 8 +++++++- files/lang/es.po | 8 +++++++- files/lang/fr.po | 8 +++++++- files/lang/hu.po | 8 +++++++- files/lang/it.po | 8 +++++++- files/lang/lt.po | 8 +++++++- files/lang/nb.po | 8 +++++++- files/lang/nl.po | 8 +++++++- files/lang/pl.po | 8 +++++++- files/lang/pt.po | 8 +++++++- files/lang/ro.po | 8 +++++++- files/lang/ru.po | 8 +++++++- files/lang/sk.po | 8 +++++++- files/lang/sv.po | 8 +++++++- files/lang/tr.po | 8 +++++++- files/lang/uk.po | 8 +++++++- files/lang/vi.po | 8 +++++++- 24 files changed, 150 insertions(+), 24 deletions(-) diff --git a/docs/json/lang_hu.json b/docs/json/lang_hu.json index 2f1e48e51d..ab7ba1517a 100644 --- a/docs/json/lang_hu.json +++ b/docs/json/lang_hu.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"Hungarian","message":"100%","color":"green"} +{"schemaVersion":1,"label":"Hungarian","message":"99%","color":"green"} diff --git a/docs/json/lang_sv.json b/docs/json/lang_sv.json index 6e8c341ada..e561c909c9 100644 --- a/docs/json/lang_sv.json +++ b/docs/json/lang_sv.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"Swedish","message":"100%","color":"green"} +{"schemaVersion":1,"label":"Swedish","message":"99%","color":"green"} diff --git a/docs/json/lang_uk.json b/docs/json/lang_uk.json index b5a9343e50..ea27e872d7 100644 --- a/docs/json/lang_uk.json +++ b/docs/json/lang_uk.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"Ukrainian","message":"99%","color":"green"} +{"schemaVersion":1,"label":"Ukrainian","message":"98%","color":"green"} diff --git a/files/lang/be.po b/files/lang/be.po index 673fc1d0b4..881af57470 100644 --- a/files/lang/be.po +++ b/files/lang/be.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-09-23 16:01+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8016,6 +8016,12 @@ msgstr "Нястрымная" msgid "speed|Instant" msgstr "Імгненная" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/bg.po b/files/lang/bg.po index bbd14c293d..1c576351dc 100644 --- a/files/lang/bg.po +++ b/files/lang/bg.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-11-08 16:44+0000\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8955,6 +8955,12 @@ msgstr "Пламтяща" msgid "speed|Instant" msgstr "Мигновена" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Катерицата" diff --git a/files/lang/cs.po b/files/lang/cs.po index dfe9fd41d3..c28d5526fc 100644 --- a/files/lang/cs.po +++ b/files/lang/cs.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2023-09-24 16:05+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Czech \n" @@ -8474,6 +8474,12 @@ msgstr "" msgid "speed|Instant" msgstr "" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/de.po b/files/lang/de.po index eb2a656cc0..804f8ff0ca 100644 --- a/files/lang/de.po +++ b/files/lang/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-09-02 18:39+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -9068,6 +9068,12 @@ msgstr "Blitzschnell" msgid "speed|Instant" msgstr "Sofort" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Eichhörnchen" diff --git a/files/lang/dk.po b/files/lang/dk.po index 5e8e1a6758..3293680a46 100644 --- a/files/lang/dk.po +++ b/files/lang/dk.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-05-21 12:45+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Danish (Denmark)\n" @@ -8825,6 +8825,12 @@ msgstr "Stormende" msgid "speed|Instant" msgstr "Fantom" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "egern" diff --git a/files/lang/es.po b/files/lang/es.po index cab4d2c2e9..0bb6347631 100644 --- a/files/lang/es.po +++ b/files/lang/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-10-07 15:36+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Spanish \n" @@ -8781,6 +8781,12 @@ msgstr "Fugaz" msgid "speed|Instant" msgstr "Instantáneo" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Ardilla" diff --git a/files/lang/fr.po b/files/lang/fr.po index 6864b2ea3e..56e37496e0 100644 --- a/files/lang/fr.po +++ b/files/lang/fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-10-07 15:36+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: French \n" @@ -8962,6 +8962,12 @@ msgstr "Foudroyante" msgid "speed|Instant" msgstr "Téléportée" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "de l'écureuil" diff --git a/files/lang/hu.po b/files/lang/hu.po index d60ac6fdb8..412e16359e 100644 --- a/files/lang/hu.po +++ b/files/lang/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-15 02:51+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2023-09-04 21:55+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Hungarian \n" @@ -8685,6 +8685,12 @@ msgstr "Villámgyors" msgid "speed|Instant" msgstr "Itt terem" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Mókus" diff --git a/files/lang/it.po b/files/lang/it.po index 3afd753b55..a37d0665f3 100644 --- a/files/lang/it.po +++ b/files/lang/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-12-03 04:36+0100\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8235,6 +8235,12 @@ msgstr "Folgore" msgid "speed|Instant" msgstr "Istantanea" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Scoiattolo" diff --git a/files/lang/lt.po b/files/lang/lt.po index 195016d10e..5caeaf967b 100644 --- a/files/lang/lt.po +++ b/files/lang/lt.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-09-23 16:14+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Lithuanian \n" @@ -8043,6 +8043,12 @@ msgstr "" msgid "speed|Instant" msgstr "" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/nb.po b/files/lang/nb.po index 235e2ba7cf..d6ab4dcda1 100644 --- a/files/lang/nb.po +++ b/files/lang/nb.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2023-09-03 18:42+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -9079,6 +9079,12 @@ msgstr "Fykende" msgid "speed|Instant" msgstr "Lynrask" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "ekorn" diff --git a/files/lang/nl.po b/files/lang/nl.po index df1649f07c..6de1b244e4 100644 --- a/files/lang/nl.po +++ b/files/lang/nl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-10-25 08:52+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Dutch \n" @@ -8038,6 +8038,12 @@ msgstr "" msgid "speed|Instant" msgstr "" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/pl.po b/files/lang/pl.po index e821badfe6..73ce891dfd 100644 --- a/files/lang/pl.po +++ b/files/lang/pl.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-07-20 23:19+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: https://discord.com/" @@ -8935,6 +8935,12 @@ msgstr "Ogromna" msgid "speed|Instant" msgstr "Błyskawica" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Wiewiórka" diff --git a/files/lang/pt.po b/files/lang/pt.po index 2e83a33128..a114ae5749 100644 --- a/files/lang/pt.po +++ b/files/lang/pt.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-10-14 16:46-0300\n" "Last-Translator: fheroes2 team \n" "Language-Team: Brazilian Portuguese \n" @@ -8782,6 +8782,12 @@ msgstr "Ultra Rápida" msgid "speed|Instant" msgstr "Instantânea" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Esquilo" diff --git a/files/lang/ro.po b/files/lang/ro.po index 261a208c10..1bac028446 100644 --- a/files/lang/ro.po +++ b/files/lang/ro.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-10-25 08:56+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -7980,6 +7980,12 @@ msgstr "" msgid "speed|Instant" msgstr "" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/ru.po b/files/lang/ru.po index c3fe9fea87..8fbd9f1e77 100644 --- a/files/lang/ru.po +++ b/files/lang/ru.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-10-04 15:32+0300\n" "Last-Translator: fheroes2 team \n" "Language-Team: <>\n" @@ -8722,6 +8722,12 @@ msgstr "Молниеносная" msgid "speed|Instant" msgstr "Мгновенная" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Белки" diff --git a/files/lang/sk.po b/files/lang/sk.po index d8b4291955..427af7a50f 100644 --- a/files/lang/sk.po +++ b/files/lang/sk.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2023-09-11 20:22+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8879,6 +8879,12 @@ msgstr "Spaľujúca" msgid "speed|Instant" msgstr "Okamžitá" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Veverice" diff --git a/files/lang/sv.po b/files/lang/sv.po index 7425c6a0eb..688306cffc 100644 --- a/files/lang/sv.po +++ b/files/lang/sv.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-14 00:04+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-10-12 14:24+0200\n" "Last-Translator: fheroes2 team \n" "Language-Team: Swedish \n" @@ -8694,6 +8694,12 @@ msgstr "Blixtsnabb" msgid "speed|Instant" msgstr "Ögonblicklig" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Ekorrens" diff --git a/files/lang/tr.po b/files/lang/tr.po index 3f1d8d254d..c8431628f8 100644 --- a/files/lang/tr.po +++ b/files/lang/tr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2022-10-01 20:20+0300\n" "Last-Translator: fheroes2 team \n" "Language-Team: Turkish \n" @@ -7823,6 +7823,12 @@ msgstr "" msgid "speed|Instant" msgstr "" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "" diff --git a/files/lang/uk.po b/files/lang/uk.po index 9e9a639308..43d0a3ab7b 100644 --- a/files/lang/uk.po +++ b/files/lang/uk.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-08-23 09:35+0300\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8728,6 +8728,12 @@ msgstr "Блискавична" msgid "speed|Instant" msgstr "Миттєва" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Білки" diff --git a/files/lang/vi.po b/files/lang/vi.po index ef0f69543d..a33611da73 100644 --- a/files/lang/vi.po +++ b/files/lang/vi.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: fheroes2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-12 11:25+0000\n" +"POT-Creation-Date: 2024-10-18 00:20+0000\n" "PO-Revision-Date: 2024-02-20 08:49+0700\n" "Last-Translator: fheroes2 team \n" "Language-Team: \n" @@ -8931,6 +8931,12 @@ msgstr "Tốc độ" msgid "speed|Instant" msgstr "Tức thì" +msgid "Click this button to adjust the level of zoom." +msgstr "" + +msgid "Zoom" +msgstr "" + msgid "week|Squirrel" msgstr "Sóc" From 522add315370182baa12f463a8b9e34f34bc29cf Mon Sep 17 00:00:00 2001 From: Oleg Derevenetz Date: Fri, 18 Oct 2024 18:26:21 +0300 Subject: [PATCH 15/18] Remove the unused function (#9211) --- src/fheroes2/game/game_interface.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/fheroes2/game/game_interface.h b/src/fheroes2/game/game_interface.h index 305c40663a..349dc3aa50 100644 --- a/src/fheroes2/game/game_interface.h +++ b/src/fheroes2/game/game_interface.h @@ -32,7 +32,6 @@ #include "interface_cpanel.h" #include "interface_icons.h" #include "interface_status.h" -#include "math_base.h" #include "players.h" class Castle; @@ -110,11 +109,6 @@ namespace Interface return _statusPanel; } - const fheroes2::Rect & getButtonsPanelRect() const - { - return _buttonsPanel.GetRect(); - } - void SetFocus( Heroes *, const bool retainScrollBarPosition ); void SetFocus( Castle * ); void ResetFocus( const int priority, const bool retainScrollBarPosition ); From fcd24e9ce6bce35e3bd07e359182b27cf6ec0c2f Mon Sep 17 00:00:00 2001 From: George King <98261225+GeorgeK1ng@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:27:06 +0200 Subject: [PATCH 16/18] Add Czech Virtual Keyboard (#9203) --- src/fheroes2/gui/ui_keyboard.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/fheroes2/gui/ui_keyboard.cpp b/src/fheroes2/gui/ui_keyboard.cpp index 7cac23b18a..601edf86aa 100644 --- a/src/fheroes2/gui/ui_keyboard.cpp +++ b/src/fheroes2/gui/ui_keyboard.cpp @@ -68,6 +68,7 @@ namespace bool isSupportedForLanguageSwitching( const fheroes2::SupportedLanguage language ) { switch ( language ) { + case fheroes2::SupportedLanguage::Czech: case fheroes2::SupportedLanguage::English: // English is a default language so it is not considered as an extra language. return false; @@ -284,6 +285,7 @@ namespace { // Numeric layout can be used for special letters as well. switch ( language ) { + case fheroes2::SupportedLanguage::Czech: case fheroes2::SupportedLanguage::English: case fheroes2::SupportedLanguage::Polish: case fheroes2::SupportedLanguage::Russian: @@ -302,6 +304,8 @@ namespace std::vector getCapitalCharacterLayout( const fheroes2::SupportedLanguage language ) { switch ( language ) { + case fheroes2::SupportedLanguage::Czech: + return { "\xCC\x8A\xC8\xD8\x8E\xDD\xC1\xCD\xC9", "QWERTZUIOP\xDA", "ASDFGHJKL\xD9", "YXCVBNM" }; case fheroes2::SupportedLanguage::English: return { "QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM" }; case fheroes2::SupportedLanguage::Polish: @@ -324,6 +328,8 @@ namespace std::vector getNonCapitalCharacterLayout( const fheroes2::SupportedLanguage language ) { switch ( language ) { + case fheroes2::SupportedLanguage::Czech: + return { "\xEC\x9A\xE8\xF8\xBE\xFD\xE1\xED\xE9", "qwertzuiop\xFA", "asdfghjkl\xF9", "yxcvbnm" }; case fheroes2::SupportedLanguage::English: return { "qwertyuiop", "asdfghjkl", "zxcvbnm" }; case fheroes2::SupportedLanguage::Polish: @@ -371,6 +377,7 @@ namespace // Different languages have different number of letters per row. // We cannot expand the virtual keyboard window beyond 640 pixels but we can change the size of buttons. switch ( language ) { + case fheroes2::SupportedLanguage::Czech: case fheroes2::SupportedLanguage::English: case fheroes2::SupportedLanguage::Polish: return 30; @@ -495,6 +502,7 @@ namespace const bool isEvilInterface, const bool isExtraLanguageSupported ) { switch ( language ) { + case fheroes2::SupportedLanguage::Czech: case fheroes2::SupportedLanguage::English: case fheroes2::SupportedLanguage::Polish: case fheroes2::SupportedLanguage::Russian: From 328a254fe9af91d781121d7654f1cae8b1d6cdd1 Mon Sep 17 00:00:00 2001 From: "Sergei Ivanov (Districh)" <113276641+Districh-ru@users.noreply.github.com> Date: Sat, 19 Oct 2024 04:28:03 +0300 Subject: [PATCH 17/18] Fix incorrect Scrollbar position after it is upscaled (#9213) --- src/fheroes2/gui/ui_scrollbar.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/fheroes2/gui/ui_scrollbar.cpp b/src/fheroes2/gui/ui_scrollbar.cpp index 025238deab..d17bd90daa 100644 --- a/src/fheroes2/gui/ui_scrollbar.cpp +++ b/src/fheroes2/gui/ui_scrollbar.cpp @@ -68,10 +68,8 @@ namespace fheroes2 bool Scrollbar::moveToIndex( const int indexId ) { - if ( _currentIndex == indexId ) { - // Nothing to change. - return false; - } + // TODO: Make a function to update the Scrollbar position after its image is changed + // and call it in the code instead of this one with 'indexId' that is equal to '_currentId'. const int32_t roiWidth = _area.width - width(); const int32_t roiHeight = _area.height - height(); From 55e7ec0a08ed33e83d7d618a3161d2f3cfa19e11 Mon Sep 17 00:00:00 2001 From: Zenseii Date: Sat, 19 Oct 2024 07:56:12 +0200 Subject: [PATCH 18/18] Fix French smallfont i with circumflex (#9205) --- src/fheroes2/agg/agg_image.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/fheroes2/agg/agg_image.cpp b/src/fheroes2/agg/agg_image.cpp index 04b8524168..1b81670c0e 100644 --- a/src/fheroes2/agg/agg_image.cpp +++ b/src/fheroes2/agg/agg_image.cpp @@ -2560,11 +2560,27 @@ namespace imageArray[232 - 32] = imageArray[64]; imageArray[233 - 32] = imageArray[94]; imageArray[234 - 32] = imageArray[92]; - imageArray[238 - 32] = imageArray[93]; imageArray[239 - 32] = imageArray[91]; imageArray[244 - 32] = imageArray[3]; imageArray[249 - 32] = imageArray[6]; imageArray[251 - 32] = imageArray[4]; + // The original small font has 1 letter at three indexes (30, 93, 95) that has an empty wide transparent + // area that we need to remove. Plus we need to add a missing pixel. + if ( id == ICN::SMALFONT && imageArray[93].width() > 19 ) { + imageArray[238 - 32].resize( 4, 9 ); + imageArray[238 - 32].reset(); + Copy( imageArray[93], 0, 0, imageArray[238 - 32], 0, 1, 4, 8 ); + Copy( imageArray[93], 1, 0, imageArray[238 - 32], 2, 0, 1, 1 ); + imageArray[238 - 32].setPosition( 0, -1 ); + fheroes2::updateShadow( imageArray[238 - 32], { -1, 1 }, 2, true ); + // Copy the fixed sprite back. + for ( const int & charCode : { 30, 93, 95 } ) { + imageArray[charCode] = imageArray[238 - 32]; + } + } + else { + imageArray[238 - 32] = imageArray[93]; + } imageArray.erase( imageArray.begin() + 220, imageArray.end() ); } // Italian version uses CP1252