mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
Merge remote-tracking branch 'origin/develop' into ban_stuff_on_water_maps
This commit is contained in:
commit
a200e87640
4
.github/workflows/github.yml
vendored
4
.github/workflows/github.yml
vendored
@ -76,6 +76,10 @@ jobs:
|
||||
os: ubuntu-20.04
|
||||
test: 0
|
||||
preset: linux-gcc-test
|
||||
- platform: linux
|
||||
os: ubuntu-20.04
|
||||
test: 0
|
||||
preset: linux-gcc-debug
|
||||
- platform: mac-intel
|
||||
os: macos-12
|
||||
test: 0
|
||||
|
@ -448,6 +448,12 @@ void AIGateway::battleResultsApplied()
|
||||
status.setBattle(NO_BATTLE);
|
||||
}
|
||||
|
||||
void AIGateway::beforeObjectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void AIGateway::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
LOG_TRACE(logAi);
|
||||
@ -699,7 +705,7 @@ void AIGateway::showGarrisonDialog(const CArmedInstance * up, const CGHeroInstan
|
||||
//you can't request action from action-response thread
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
if(removableUnits)
|
||||
if(removableUnits && up->tempOwner == down->tempOwner)
|
||||
pickBestCreatures(down, up);
|
||||
|
||||
answerQuery(queryID, 0);
|
||||
@ -1000,7 +1006,7 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
|
||||
//FIXME: why are the above possible to be null?
|
||||
|
||||
bool emptySlotFound = false;
|
||||
for(auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
|
||||
for(auto slot : artifact->artType->getPossibleSlots().at(target->bearerType()))
|
||||
{
|
||||
ArtifactLocation destLocation(target, slot);
|
||||
if(target->isPositionFree(slot) && artifact->canBePutAt(destLocation, true)) //combined artifacts are not always allowed to move
|
||||
@ -1013,7 +1019,7 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
|
||||
}
|
||||
if(!emptySlotFound) //try to put that atifact in already occupied slot
|
||||
{
|
||||
for(auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
|
||||
for(auto slot : artifact->artType->getPossibleSlots().at(target->bearerType()))
|
||||
{
|
||||
auto otherSlot = target->getSlot(slot);
|
||||
if(otherSlot && otherSlot->artifact) //we need to exchange artifact for better one
|
||||
|
@ -161,6 +161,7 @@ public:
|
||||
void heroManaPointsChanged(const CGHeroInstance * hero) override;
|
||||
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
|
||||
void battleResultsApplied() override;
|
||||
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void objectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
|
||||
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
|
||||
|
@ -306,10 +306,10 @@ bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2
|
||||
auto art1 = a1->artType;
|
||||
auto art2 = a2->artType;
|
||||
|
||||
if(art1->price == art2->price)
|
||||
if(art1->getPrice() == art2->getPrice())
|
||||
return art1->valOfBonuses(BonusType::PRIMARY_SKILL) > art2->valOfBonuses(BonusType::PRIMARY_SKILL);
|
||||
else
|
||||
return art1->price > art2->price;
|
||||
return art1->getPrice() > art2->getPrice();
|
||||
}
|
||||
|
||||
bool isWeeklyRevisitable(const CGObjectInstance * obj)
|
||||
|
@ -256,8 +256,8 @@ bool compareArtifacts(const CArtifactInstance * a1, const CArtifactInstance * a2
|
||||
auto art1 = a1->artType;
|
||||
auto art2 = a2->artType;
|
||||
|
||||
if(art1->price == art2->price)
|
||||
if(art1->getPrice() == art2->getPrice())
|
||||
return art1->valOfBonuses(BonusType::PRIMARY_SKILL) > art2->valOfBonuses(BonusType::PRIMARY_SKILL);
|
||||
else
|
||||
return art1->price > art2->price;
|
||||
return art1->getPrice() > art2->getPrice();
|
||||
}
|
||||
|
@ -538,6 +538,11 @@ void VCAI::battleResultsApplied()
|
||||
status.setBattle(NO_BATTLE);
|
||||
}
|
||||
|
||||
void VCAI::beforeObjectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
LOG_TRACE(logAi);
|
||||
@ -1187,7 +1192,7 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
|
||||
//FIXME: why are the above possible to be null?
|
||||
|
||||
bool emptySlotFound = false;
|
||||
for(auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
|
||||
for(auto slot : artifact->artType->getPossibleSlots().at(target->bearerType()))
|
||||
{
|
||||
ArtifactLocation destLocation(target, slot);
|
||||
if(target->isPositionFree(slot) && artifact->canBePutAt(destLocation, true)) //combined artifacts are not always allowed to move
|
||||
@ -1200,7 +1205,7 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
|
||||
}
|
||||
if(!emptySlotFound) //try to put that atifact in already occupied slot
|
||||
{
|
||||
for(auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
|
||||
for(auto slot : artifact->artType->getPossibleSlots().at(target->bearerType()))
|
||||
{
|
||||
auto otherSlot = target->getSlot(slot);
|
||||
if(otherSlot && otherSlot->artifact) //we need to exchange artifact for better one
|
||||
|
@ -194,6 +194,7 @@ public:
|
||||
void heroManaPointsChanged(const CGHeroInstance * hero) override;
|
||||
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
|
||||
void battleResultsApplied() override;
|
||||
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void objectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
|
||||
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
|
||||
|
@ -70,6 +70,18 @@
|
||||
"description": "VCMI Linux GCC",
|
||||
"inherits": "linux-release",
|
||||
"cacheVariables": {
|
||||
"ENABLE_LUA" : "ON",
|
||||
"CMAKE_C_COMPILER": "/usr/bin/gcc",
|
||||
"CMAKE_CXX_COMPILER": "/usr/bin/g++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug",
|
||||
"displayName": "GCC x86_64-pc-linux-gnu (debug)",
|
||||
"description": "VCMI Linux GCC (Debug)",
|
||||
"inherits": "linux-release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"ENABLE_LUA" : "ON",
|
||||
"ENABLE_PCH" : "OFF",
|
||||
"CMAKE_C_COMPILER": "/usr/bin/gcc",
|
||||
@ -93,7 +105,6 @@
|
||||
"inherits": "linux-test",
|
||||
"cacheVariables": {
|
||||
"ENABLE_LUA" : "OFF",
|
||||
"ENABLE_PCH" : "OFF",
|
||||
"CMAKE_C_COMPILER": "/usr/bin/gcc",
|
||||
"CMAKE_CXX_COMPILER": "/usr/bin/g++"
|
||||
}
|
||||
@ -239,6 +250,11 @@
|
||||
"hidden": true,
|
||||
"configuration": "RelWithDebInfo"
|
||||
},
|
||||
{
|
||||
"name": "default-debug",
|
||||
"hidden": true,
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-clang-release",
|
||||
"configurePreset": "linux-clang-release",
|
||||
@ -259,6 +275,11 @@
|
||||
"configurePreset": "linux-gcc-release",
|
||||
"inherits": "default-release"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-debug",
|
||||
"configurePreset": "linux-gcc-debug",
|
||||
"inherits": "default-debug"
|
||||
},
|
||||
{
|
||||
"name": "macos-xcode-release",
|
||||
"configurePreset": "macos-xcode-release",
|
||||
|
@ -74,9 +74,11 @@
|
||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d milliseconds",
|
||||
"vcmi.systemOptions.framerateButton.hover" : "Show FPS",
|
||||
"vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\nToggle the visibility of the Frames Per Second counter in the corner of the game window",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.hover" : "Haptic feedback",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.help" : "{Haptic feedback}\n\nToggle the haptic feedback on touch inputs",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "Show Messages in Info Panel",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in the info pannel, instead of popping up in a separate window.",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in the info panel, instead of popping up in a separate window.",
|
||||
"vcmi.adventureOptions.numericQuantities.hover" : "Numeric Creature Quantities",
|
||||
"vcmi.adventureOptions.numericQuantities.help" : "{Numeric Creature Quantities}\n\nShow the approximate quantities of enemy creatures in the numeric A-B format.",
|
||||
"vcmi.adventureOptions.forceMovementInfo.hover" : "Always Show Movement Cost",
|
||||
|
342
Mods/vcmi/config/vcmi/french.json
Normal file
342
Mods/vcmi/config/vcmi/french.json
Normal file
@ -0,0 +1,342 @@
|
||||
{
|
||||
"vcmi.adventureMap.monsterThreat.title" : "\n\nDiscussion : ",
|
||||
"vcmi.adventureMap.monsterThreat.levels.0" : "Sans effort",
|
||||
"vcmi.adventureMap.monsterThreat.levels.1" : "Très faible",
|
||||
"vcmi.adventureMap.monsterThreat.levels.2" : "Faible",
|
||||
"vcmi.adventureMap.monsterThreat.levels.3" : "Un peu plus faible",
|
||||
"vcmi.adventureMap.monsterThreat.levels.4" : "Égal",
|
||||
"vcmi.adventureMap.monsterThreat.levels.5" : "Un peu plus fort",
|
||||
"vcmi.adventureMap.monsterThreat.levels.6" : "Fort",
|
||||
"vcmi.adventureMap.monsterThreat.levels.7" : "Très fort",
|
||||
"vcmi.adventureMap.monsterThreat.levels.8" : "Difficile",
|
||||
"vcmi.adventureMap.monsterThreat.levels.9" : "Surpuissant",
|
||||
"vcmi.adventureMap.monsterThreat.levels.10" : "Mortel",
|
||||
"vcmi.adventureMap.monsterThreat.levels.11" : "Impossible",
|
||||
|
||||
"vcmi.adventureMap.confirmRestartGame" : "Êtes-vous sûr de vouloir redémarrer le jeu ?",
|
||||
"vcmi.adventureMap.noTownWithMarket" : "Il n'y a pas de marchés disponibles !",
|
||||
"vcmi.adventureMap.noTownWithTavern" : "Il n'y a pas de villes disponibles avec des tavernes !",
|
||||
"vcmi.adventureMap.spellUnknownProblem" : "Il y a un problème inconnu avec ce sort ! Pas plus d'informations sont disponibles.",
|
||||
"vcmi.adventureMap.playerAttacked" : "Le joueur a été attaqué : %s",
|
||||
"vcmi.adventureMap.moveCostDetails" : "Points de mouvement - Coût : %TURNS tours + %POINTS points, Points restants : %REMAINING",
|
||||
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Points de mouvement - Coût : %POINTS points, Points restants : %REMAINING",
|
||||
|
||||
"vcmi.capitalColors.0" : "Rouge",
|
||||
"vcmi.capitalColors.1" : "Bleu",
|
||||
"vcmi.capitalColors.2" : "Ocre",
|
||||
"vcmi.capitalColors.3" : "Vert",
|
||||
"vcmi.capitalColors.4" : "Orange",
|
||||
"vcmi.capitalColors.5" : "Violet",
|
||||
"vcmi.capitalColors.6" : "Turquoise",
|
||||
"vcmi.capitalColors.7" : "Rose",
|
||||
|
||||
"vcmi.mainMenu.tutorialNotImplemented" : "Désolé, le didacticiel n'est pas encore implémenté\n",
|
||||
"vcmi.mainMenu.highscoresNotImplemented" : "Désolé, le menu des meilleurs scores n'est pas encore implémenté\n",
|
||||
"vcmi.mainMenu.serverConnecting" : "Connexion...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "Entrez l'adresse :",
|
||||
"vcmi.mainMenu.serverClosing" : "Fermeture...",
|
||||
"vcmi.mainMenu.hostTCP" : "Hôte TCP/IP jeu",
|
||||
"vcmi.mainMenu.joinTCP" : "Rejoindre TCP/IP jeu",
|
||||
"vcmi.mainMenu.playerName" : "Joueur",
|
||||
|
||||
"vcmi.server.errors.existingProcess" : "Un autre processus de serveur VCMI est en cours d'exécution. Veuillez l'arrêter' avant de démarrer un nouveau jeu.",
|
||||
"vcmi.server.errors.modsIncompatibility" : "Les mods suivants sont nécessaires pour charger le jeu :",
|
||||
"vcmi.server.confirmReconnect" : "Voulez-vous vous reconnecter à la dernière session ?",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "Général",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "Passe à l'onglet Options générales, qui contient des paramètres liés au comportement général du client de jeu",
|
||||
"vcmi.settingsMainWindow.battleTab.hover" : "Bataille",
|
||||
"vcmi.settingsMainWindow.battleTab.help" : "Passe à l'onglet Options de combat, ce qui permet de configurer le comportement du jeu pendant les batailles",
|
||||
"vcmi.settingsMainWindow.adventureTab.hover" : "Carte d'aventure",
|
||||
"vcmi.settingsMainWindow.adventureTab.help" : "Passe à l'onglet Options de carte d'aventure (la carte d'aventure est la section du jeu où les joueurs peuvent contrôler les mouvements de leurs héros)",
|
||||
|
||||
"vcmi.systemOptions.videoGroup" : "Paramètres Vidéo",
|
||||
"vcmi.systemOptions.audioGroup" : "Paramètres Audio",
|
||||
"vcmi.systemOptions.otherGroup" : "Autres Paramètres", // Unused right now
|
||||
"vcmi.systemOptions.townsGroup" : "Écran de la Ville",
|
||||
|
||||
"vcmi.systemOptions.fullscreenBorderless.hover" : "Plein écran (sans bord)",
|
||||
"vcmi.systemOptions.fullscreenBorderless.help" : "{Borderless Fullscreen}\n\nSi sélectionné, VCMI fonctionnera en mode plein écran sans bordure. Dans ce mode, le jeu utilisera toujours la même résolution de le bureau, ignorant la résolution sélectionnée.",
|
||||
"vcmi.systemOptions.fullscreenExclusive.hover" : "Plein écran (exclusif)",
|
||||
"vcmi.systemOptions.fullscreenExclusive.help" : "{Fullscreen}\n\nSi sélectionné, VCMI s'exécutera en mode plein écran exclusif. Dans ce mode, le jeu modifiera la résolution du moniteur en résolution sélectionnée.",
|
||||
"vcmi.systemOptions.resolutionButton.hover" : "Résolution : %wx%h",
|
||||
"vcmi.systemOptions.resolutionButton.help" : "{Select Resolution}\n\nChanger la résolution d'écran dans le jeu.",
|
||||
"vcmi.systemOptions.resolutionMenu.hover" : "Sélectionner la résolution",
|
||||
"vcmi.systemOptions.resolutionMenu.help" : "Changer la résolution d'écran dans le jeu.",
|
||||
"vcmi.systemOptions.scalingButton.hover" : "Échelle d'interface : %p%",
|
||||
"vcmi.systemOptions.scalingButton.help" : "{Interface Scaling}\n\nChanger l'échelle de l'interface dans le jeu",
|
||||
"vcmi.systemOptions.scalingMenu.hover" : "Sélectionner la mise à l'échelle de l'interface",
|
||||
"vcmi.systemOptions.scalingMenu.help" : "Changer la mise à l'échelle de l'interface dans le jeu.",
|
||||
"vcmi.systemOptions.longTouchButton.hover" : "Intervalle de touche long : %d ms", // Translation note: "ms" = "milliseconds"
|
||||
"vcmi.systemOptions.longTouchButton.help" : "{Long Touch Interval}\n\nAu moment d'utiliser l'écran tactile, les fenêtres contextuelles apparaîtront après avoir touché l'écran pour une durée spécifiée, en millisecondes",
|
||||
"vcmi.systemOptions.longTouchMenu.hover" : "Sélectionner l'intervalle de touche long",
|
||||
"vcmi.systemOptions.longTouchMenu.help" : "Changer la durée de l'intervalle de touche long.",
|
||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d millisecondes",
|
||||
"vcmi.systemOptions.framerateButton.hover" : "Afficher les FPS",
|
||||
"vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\nAfficher/masquer le compteur de Frames Par Seconde dans le coin de la fenêtre du jeu",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "Afficher les messages dans le panneau d'information",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nAutant que possible, les messages de jeu de la visite des objets de la carte seront affichés dans le panneau d'informations, au lieu de faire apparaître dans une fenêtre séparée.",
|
||||
"vcmi.adventureOptions.numericQuantities.hover" : "Dénombrement de créatures",
|
||||
"vcmi.adventureOptions.numericQuantities.help" : "{Numeric Creature Quantities}\n\nAfficher les estimation de nombre de créatures ennemies au format numérique A-B.",
|
||||
"vcmi.adventureOptions.forceMovementInfo.hover" : "Toujours afficher le coût de mouvement",
|
||||
"vcmi.adventureOptions.forceMovementInfo.help" : "{Always Show Movement Cost}\n\nToujours afficher les données des points de mouvement dans les informations sur la barre d'état (au lieu de les voir que pen maintenant la touche alt).",
|
||||
"vcmi.adventureOptions.showGrid.hover" : "Afficher la grille",
|
||||
"vcmi.adventureOptions.showGrid.help" : "{Show Grid}\n\nMontrer la superposition de la grille, mettant en évidence les frontières entre les carreaux de carte d'aventure.",
|
||||
"vcmi.adventureOptions.borderScroll.hover" : "Défilement de bord",
|
||||
"vcmi.adventureOptions.borderScroll.help" : "{Border Scrolling}\n\nFait défiler la carte aventure lorsque le curseur est sur le bord de la fenêtre. Peut être désactivé en maintenant la touche Ctrl.",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.help": "Régler la vitesse de défilement de la carte sur très lent",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.help": "Régler la vitesse de défilement de la carte très rapide",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.help": "Régler la vitesse de défilement de la carte sur instantanément.",
|
||||
|
||||
"vcmi.battleOptions.queueSizeLabel.hover": "Afficher l'ordre de fil de tour",
|
||||
"vcmi.battleOptions.queueSizeNoneButton.hover": "Désactivé",
|
||||
"vcmi.battleOptions.queueSizeAutoButton.hover": "AUTO",
|
||||
"vcmi.battleOptions.queueSizeSmallButton.hover": "PETITE",
|
||||
"vcmi.battleOptions.queueSizeBigButton.hover": "GRANDE",
|
||||
"vcmi.battleOptions.queueSizeNoneButton.help": "Ne pas afficher l'ordre de fil de tour",
|
||||
"vcmi.battleOptions.queueSizeAutoButton.help": "Ajuster automatiquement la taille de l'ordre de fil de tour en fonction de la résolution du jeu (la PETITE taille est utilisée lorsque vous jouez au jeu sur une hauteur de résolution inférieure à 700 pixels, la GRANDE taille est utilisée au sinon)",
|
||||
"vcmi.battleOptions.queueSizeSmallButton.help": "Régler la taille de l'ordre de fil de tour sur PETITE",
|
||||
"vcmi.battleOptions.queueSizeBigButton.help": "Régler la taille de l'ordre de fil de tour à GRANDE (non prise en charge si la hauteur de la résolution du jeu est inférieure à 700 pixels)",
|
||||
"vcmi.battleOptions.animationsSpeed1.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed5.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed6.hover": "",
|
||||
"vcmi.battleOptions.animationsSpeed1.help": "Régler la vitesse d'animation très lente",
|
||||
"vcmi.battleOptions.animationsSpeed5.help": "Régler la vitesse d'animation très rapide",
|
||||
"vcmi.battleOptions.animationsSpeed6.help": "Régler la vitesse d'animation sur instantané",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.hover": "Mise en surbrillance du mouvement au survol",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.help": "{Movement Highlight on Hover}\n\nMettre en surbrillance la plage de mouvement de l'unité lorsque vous la survolez.",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Afficher les limites de portée pour les tireurs",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.help": "{Show range limits for shooters on Hover}\n\nAfficher les limites de portée du tireur lorsque vous le survolez.",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Ignorer la musique d'introduction",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.help": "{Skip Intro Music}\n\nAutoriser les actions pendant la musique d'intro qui joue au début de chaque bataille",
|
||||
"vcmi.battleWindow.pressKeyToSkipIntro" : "Appuyez sur n'importe quelle touche pour commencer la bataille immédiatement",
|
||||
|
||||
"vcmi.battleWindow.damageEstimation.melee" : "Attaque %CREATURE (%DAMAGE).",
|
||||
"vcmi.battleWindow.damageEstimation.meleeKills" : "Attaque %CREATURE (%DAMAGE, %KILLS).",
|
||||
"vcmi.battleWindow.damageEstimation.ranged" : "Tir sur %CREATURE (%SHOTS, %DAMAGE).",
|
||||
"vcmi.battleWindow.damageEstimation.rangedKills" : "Tir sur %CREATURE (%SHOTS, %DAMAGE, %KILLS).",
|
||||
"vcmi.battleWindow.damageEstimation.shots" : "%d tirs restants",
|
||||
"vcmi.battleWindow.damageEstimation.shots.1" : "%d tir restant",
|
||||
"vcmi.battleWindow.damageEstimation.damage" : "%d dégâts",
|
||||
"vcmi.battleWindow.damageEstimation.damage.1" : "%d dégâts",
|
||||
"vcmi.battleWindow.damageEstimation.kills" : "%d va mourir",
|
||||
"vcmi.battleWindow.damageEstimation.kills.1" : "%d va mourir",
|
||||
|
||||
"vcmi.battleResultsWindow.applyResultsLabel" : "Appliquer le résultat de la bataille",
|
||||
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Afficher les créatures disponibles",
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Show Available Creatures}\n\nAfficher le nombre de créatures disponibles au recrutement au lieu de leur croissance dans le résumé de la ville (coin inférieur gauche de l'écran de la ville).",
|
||||
"vcmi.otherOptions.creatureGrowthAsDwellingLabel.hover" : "Afficher la croissance hebdomadaire des créatures",
|
||||
"vcmi.otherOptions.creatureGrowthAsDwellingLabel.help" : "{Show Weekly Growth of Creatures}\n\nAfficher la croissance hebdomadaire des créatures au lieu de la quantité disponible dans le résumé de la ville (coin inférieur gauche de l'écran de la ville).",
|
||||
"vcmi.otherOptions.compactTownCreatureInfo.hover": "Infos compactes sur la créature",
|
||||
"vcmi.otherOptions.compactTownCreatureInfo.help": "{Compact Creature Info}\n\nAfficher des informations plus petites pour les créatures de la ville dans le résumé de la ville (coin inférieur gauche de l'écran de la ville).",
|
||||
|
||||
"vcmi.townHall.missingBase" : "Le bâtiment de base %s doit être construit avant",
|
||||
"vcmi.townHall.noCreaturesToRecruit" : "Il n'y a aucune créature à recruter !",
|
||||
"vcmi.townHall.greetingManaVortex" : "Alors que vous approchez du %s, votre corps est rempli d'une nouvelle énergie. Vous avez doublé vos points de sort normaux.",
|
||||
"vcmi.townHall.greetingKnowledge" : "Vous étudiez les glyphes sur le %s et découvrez le fonctionnement de diverses magies (+1 Connaissance).",
|
||||
"vcmi.townHall.greetingSpellPower" : "Le %s vous apprend de nouvelles façons de concentrer vos pouvoirs magiques (+1 Pouvoir).",
|
||||
"vcmi.townHall.greetingExperience" : "Une visite au %s vous apprend de nombreuses nouvelles compétences (+1000 Expérience).",
|
||||
"vcmi.townHall.greetingAttack" : "Un peu de temps passé au %s vous permet d'apprendre des compétences de combat plus efficaces (+1 compétence d'attaque).",
|
||||
"vcmi.townHall.greetingDefence" : "En passant du temps dans le %s, les guerriers expérimentés qui s'y trouvent vous enseignent des compétences défensives supplémentaires (+1 Défense).",
|
||||
"vcmi.townHall.hasNotProduced" : "Le %s n'a encore rien produit.",
|
||||
"vcmi.townHall.hasProduced" : "Le %s a produit %d %s cette semaine.",
|
||||
"vcmi.townHall.greetingCustomBonus" : "%s vous offre +%d %s%s",
|
||||
"vcmi.townHall.greetingCustomUntil" : " jusqu'à la prochaine bataille.",
|
||||
"vcmi.townHall.greetingInTownMagicWell" : "%s a restauré vos points de sort au maximum.",
|
||||
|
||||
"vcmi.logicalExpressions.anyOf" : "L'un des éléments suivants :",
|
||||
"vcmi.logicalExpressions.allOf" : "Tous les éléments suivants :",
|
||||
"vcmi.logicalExpressions.noneOf" : "Aucun des éléments suivants :",
|
||||
|
||||
"vcmi.heroWindow.openCommander.hover" : "Ouvrir la fenêtre d'informations du commandant",
|
||||
"vcmi.heroWindow.openCommander.help" : "Affiche des détails sur le commandant de ce héros",
|
||||
|
||||
"vcmi.commanderWindow.artifactMessage" : "Voulez-vous rendre cet artefact au héros ?",
|
||||
|
||||
"vcmi.creatureWindow.showBonuses.hover" : "Passer en vue bonus",
|
||||
"vcmi.creatureWindow.showBonuses.help" : "Afficher tous les bonus actifs du commandant",
|
||||
"vcmi.creatureWindow.showSkills.hover" : "Passer à la vue des compétences",
|
||||
"vcmi.creatureWindow.showSkills.help" : "Afficher toutes les compétences apprises du commandant",
|
||||
"vcmi.creatureWindow.returnArtifact.hover" : "Remettre l'artefact",
|
||||
"vcmi.creatureWindow.returnArtifact.help" : "Cliquez sur ce bouton pour remettre l'artefact dans le sac à dos du héros",
|
||||
|
||||
"vcmi.questLog.hideComplete.hover" : "Masquer les quêtes terminées",
|
||||
"vcmi.questLog.hideComplete.help" : "Masquer toutes les quêtes terminées",
|
||||
|
||||
"vcmi.randomMapTab.widgets.defaultTemplate" : "(par défaut)",
|
||||
"vcmi.randomMapTab.widgets.templateLabel" : "Modèle",
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsButton" : "Configuration...",
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Alignements d'équipe",
|
||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Types de routes",
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "L'ennemi a réussi à survivre jusqu'à ce jour. La victoire est à eux !",
|
||||
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Félicitations ! Vous avez réussi à survivre. La victoire est à vous !",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "L'ennemi a vaincu tous les monstres qui sévissent sur cette terre et revendique la victoire !",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toSelf" : "Félicitations ! Vous avez vaincu tous les monstres qui affligent ce pays et vous pouvez revendiquer la victoire !",
|
||||
"vcmi.map.victoryCondition.collectArtifacts.message" : "Acquérir trois artefacts",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Félicitations ! Tous vos ennemis ont été vaincus et vous avez l'alliance angélique ! La victoire est à vous !",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Vaincre tous les ennemis et créer une alliance angélique",
|
||||
|
||||
// few strings from WoG used by vcmi
|
||||
"vcmi.stackExperience.description" : "» D é t a i l s d e P i l e d ' E x p é r i e n c e «\n\nType de créature ................ : %s\nRang d'expérience ............... : %s (%i)\nPoints d'expérience ............. : %i\nPoints d'XP au rang suivant ..... : %i\nExpérience maximum par bataille . : %i%% (%i)\nNb de créatures dans la pile .... : %i\nMaximum de nouvelles recrues\n sans perdre le rang actuel ..... : %i\nMultiplicateur d'expérience ..... : %.2f\nMultiplicateur d'amélioration ... : %.2f\nExpérience après le rang 10 ..... : %i\nMaximum de Nouvelles Recrues pour\n rester au Rang 10 si\n l'Expérience Maximum ........... : %i",
|
||||
"vcmi.stackExperience.rank.0" : "Basique",
|
||||
"vcmi.stackExperience.rank.1" : "Novice",
|
||||
"vcmi.stackExperience.rank.2" : "Formé",
|
||||
"vcmi.stackExperience.rank.3" : "Qualifié",
|
||||
"vcmi.stackExperience.rank.4" : "Éprouvé",
|
||||
"vcmi.stackExperience.rank.5" : "Vétéran",
|
||||
"vcmi.stackExperience.rank.6" : "Adepte",
|
||||
"vcmi.stackExperience.rank.7" : "Expert",
|
||||
"vcmi.stackExperience.rank.8" : "Élite",
|
||||
"vcmi.stackExperience.rank.9" : "Maître",
|
||||
"vcmi.stackExperience.rank.10" : "As",
|
||||
|
||||
"core.bonus.ADDITIONAL_ATTACK.name": "Double frappe",
|
||||
"core.bonus.ADDITIONAL_ATTACK.description": "Attaque deux fois",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.name": "Représailles supplémentaires",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.description": "Peut riposter ${val} fois de plus",
|
||||
"core.bonus.AIR_IMMUNITY.name": "Immunité aérienne",
|
||||
"core.bonus.AIR_IMMUNITY.description": "Immunisé contre tous les sorts de l'école de magie de l'Air",
|
||||
"core.bonus.ATTACKS_ALL_ADJACENT.name": "Attaque tout autour",
|
||||
"core.bonus.ATTACKS_ALL_ADJACENT.description": "Attaque tous les ennemis adjacents",
|
||||
"core.bonus.BLOCKS_RETALIATION.name": "Pas de représailles",
|
||||
"core.bonus.BLOCKS_RETALIATION.description": "L'ennemi ne peut pas riposter",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "Pas de représailles à distance",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.description": "L'ennemi ne peut pas riposter en utilisant une attaque à distance",
|
||||
"core.bonus.CATAPULT.name": "Catapulte",
|
||||
"core.bonus.CATAPULT.description": "Attaque les murs de siège",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name": "Réduire le coût de lancement (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Réduit le coût d'incantation du héros de ${val}",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Amortisseur magique (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Augmente le coût d'incantation des sorts ennemis de ${val}",
|
||||
"core.bonus.CHARGE_IMMUNITY.name": "Immunisé contre la charge",
|
||||
"core.bonus.CHARGE_IMMUNITY.description": "Immunisé contre la charge du cavalier et du champion",
|
||||
"core.bonus.DARKNESS.name": "Couverture de ténèbres",
|
||||
"core.bonus.DARKNESS.description": "Crée un linceul de ténèbres avec un rayon de ${val}",
|
||||
"core.bonus.DEATH_STARE.name": "Regard mortel (${val}%)",
|
||||
"core.bonus.DEATH_STARE.description": "A ${val}% de chances de tuer une seule créature",
|
||||
"core.bonus.DEFENSIVE_STANCE.name": "Bonus de défense",
|
||||
"core.bonus.DEFENSIVE_STANCE.description": "+${val} Défense en défense",
|
||||
"core.bonus.DESTRUCTION.name": "Destruction",
|
||||
"core.bonus.DESTRUCTION.description": "A ${val} % de chances de tuer des unités supplémentaires après l'attaque",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Coup mortel",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.description": "A ${val}% de chances d'infliger des dégâts de base doublés en attaquant",
|
||||
"core.bonus.DRAGON_NATURE.name": "Dragon",
|
||||
"core.bonus.DRAGON_NATURE.description": "La créature a une nature de dragon",
|
||||
"core.bonus.EARTH_IMMUNITY.name": "Immunité terrestre",
|
||||
"core.bonus.EARTH_IMMUNITY.description": "Immunisé contre tous les sorts de l'école de magie de la Terre",
|
||||
"core.bonus.ENCHANTER.name": "Enchanteur",
|
||||
"core.bonus.ENCHANTER.description": "Peut lancer en masse ${subtype.spell} à chaque tour",
|
||||
"core.bonus.ENCHANTED.name": "Enchanté",
|
||||
"core.bonus.ENCHANTED.description": "Affecté par ${subtype.spell} permanent",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignorer la défense (${val}%)",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Lors de l'attaque, ${val}% de la défense du défenseur est ignorée",
|
||||
"core.bonus.FIRE_IMMUNITY.name": "Immunité au feu",
|
||||
"core.bonus.FIRE_IMMUNITY.description": "Immunisé contre tous les sorts de l'école de magie du Feu",
|
||||
"core.bonus.FIRE_SHIELD.name": "Bouclier de feu (${val}%)",
|
||||
"core.bonus.FIRE_SHIELD.description": "Reflète une partie des dégâts de mêlée",
|
||||
"core.bonus.FIRST_STRIKE.name": "Premier coup",
|
||||
"core.bonus.FIRST_STRIKE.description": "Cette créature riposte avant d'être attaquée",
|
||||
"core.bonus.FEAR.name": "Peur",
|
||||
"core.bonus.FEAR.description": "Provoque la peur sur une pile ennemie",
|
||||
"core.bonus.FEARLESS.name": "Intrépide",
|
||||
"core.bonus.FEARLESS.description": "Immunité à la peur",
|
||||
"core.bonus.FLYING.name": "Vol",
|
||||
"core.bonus.FLYING.description": "Vole en se déplaçant (ignore les obstacles)",
|
||||
"core.bonus.FREE_SHOOTING.name": "Tirer de près",
|
||||
"core.bonus.FREE_SHOOTING.description": "Peut utiliser des attaques à distance au corps à corps",
|
||||
"core.bonus.GARGOYLE.name": "Gargouille",
|
||||
"core.bonus.GARGOYLE.description": "Ne peut pas être réanimé ou soigné",
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Réduit les dégâts (${val}%)",
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Réduit les dégâts physiques des attaques à distance ou de mêlée",
|
||||
"core.bonus.HATE.name": "Déteste ${subtype.creature}",
|
||||
"core.bonus.HATE.description": "Inflige ${val} % de dégâts supplémentaires à ${subtype.creature}",
|
||||
"core.bonus.HEALER.name": "Guérisseur",
|
||||
"core.bonus.HEALER.description": "Soigne les unités alliées",
|
||||
"core.bonus.HP_REGENERATION.name": "Régénération",
|
||||
"core.bonus.HP_REGENERATION.description": "Soigne ${val} points de vie à chaque tour",
|
||||
"core.bonus.JOUSTING.name": "Charge de champion",
|
||||
"core.bonus.JOUSTING.description": "+${val}% de dégâts pour chaque hexagone parcouru",
|
||||
"core.bonus.KING.name": "Roi",
|
||||
"core.bonus.KING.description": "Vulnérable au niveau POURFENDEUR ${val} ou supérieur",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Immunité aux sorts 1-${val}",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Immunisé aux sorts de niveaux 1-${val}",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Portée de tir limitée",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Impossible de cibler des unités plus loin que ${val} hexagones",
|
||||
"core.bonus.LIFE_DRAIN.name": "Durée de vie du drain (${val}%)",
|
||||
"core.bonus.LIFE_DRAIN.description": "Draine ${val}% des dégâts infligés",
|
||||
"core.bonus.MANA_CHANNELING.name": "Chaîne magique ${val}%",
|
||||
"core.bonus.MANA_CHANNELING.description": "Donne à votre héros ${val}% du mana dépensé par l'ennemi",
|
||||
"core.bonus.MANA_DRAIN.name": "Drain de mana",
|
||||
"core.bonus.MANA_DRAIN.description": "Draine ${val} mana à chaque tour",
|
||||
"core.bonus.MAGIC_MIRROR.name": "Miroir magique (${val}%)",
|
||||
"core.bonus.MAGIC_MIRROR.description": "A ${val} % de chances de rediriger un sort offensif vers une unité ennemie",
|
||||
"core.bonus.MAGIC_RESISTANCE.name": "Résistance magique (${val}%)",
|
||||
"core.bonus.MAGIC_RESISTANCE.description": "A ${val}% de chances de résister à un sort ennemi",
|
||||
"core.bonus.MIND_IMMUNITY.name": "Immunité contre les sorts de l'esprit",
|
||||
"core.bonus.MIND_IMMUNITY.description": "Immunisé contre les sorts de type Mental",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.name": "Aucune pénalité de distance",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.description": "Inflige des dégâts complets à n'importe quelle distance",
|
||||
"core.bonus.NO_MELEE_PENALTY.name": "Aucune pénalité de mêlée",
|
||||
"core.bonus.NO_MELEE_PENALTY.description": "La créature n'a pas de pénalité de mêlée",
|
||||
"core.bonus.NO_MORALE.name": "Moral neutre",
|
||||
"core.bonus.NO_MORALE.description": "La créature est immunisée contre les effets de moral",
|
||||
"core.bonus.NO_WALL_PENALTY.name": "Aucune pénalité de mur",
|
||||
"core.bonus.NO_WALL_PENALTY.description": "Dégâts complets pendant le siège",
|
||||
"core.bonus.NON_LIVING.name": "Non vivant",
|
||||
"core.bonus.NON_LIVING.description": "Immunité à de nombreux effets",
|
||||
"core.bonus.RANDOM_SPELLCASTER.name": "Lanceur de sorts aléatoire",
|
||||
"core.bonus.RANDOM_SPELLCASTER.description": "Peut lancer un sort aléatoire",
|
||||
"core.bonus.RANGED_RETALIATION.name": "Représailles à distance",
|
||||
"core.bonus.RANGED_RETALIATION.description": "Peut effectuer une contre-attaque à distance",
|
||||
"core.bonus.RECEPTIVE.name": "Réceptif",
|
||||
"core.bonus.RECEPTIVE.description": "Pas d'immunité aux sorts amicaux",
|
||||
"core.bonus.REBIRTH.name": "Renaissance (${val}%)",
|
||||
"core.bonus.REBIRTH.description": "${val}% de la pile augmentera après la mort",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.name": "Attaque et retour",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.description": "Revient après une attaque au corps à corps",
|
||||
"core.bonus.SHOOTER.name": "Distance",
|
||||
"core.bonus.SHOOTER.description": "La créature peut tirer",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Tirer tout autour",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.description": "Les attaques à distance de cette créature touchent toutes les cibles dans une petite zone",
|
||||
"core.bonus.SOUL_STEAL.name": "Vol d'âme",
|
||||
"core.bonus.SOUL_STEAL.description": "Gagne ${val} nouvelles créatures pour chaque ennemi tué",
|
||||
"core.bonus.SPELLCASTER.name": "Lanceur de sorts",
|
||||
"core.bonus.SPELLCASTER.description": "Peut lancer ${subtype.spell}",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.name": "Lancer après l'attaque",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.description": "A ${val}% de chances de lancer ${subtype.spell} après avoir attaqué",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.name": "Lancer avant l'attaque",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.description": "A ${val}% de chances de lancer ${subtype.spell} avant qu'il n'attaque",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Résistance aux sorts",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Dégâts des sorts réduits de ${val}%.",
|
||||
"core.bonus.SPELL_IMMUNITY.name": "Immunité aux sorts",
|
||||
"core.bonus.SPELL_IMMUNITY.description": "Immunisé contre ${subtype.spell}",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.name": "Attaque semblable à un sort",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.description": "Attaque avec ${subtype.spell}",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura de résistance",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.description": "Les piles à proximité obtiennent ${val}% de résistance magique",
|
||||
"core.bonus.SUMMON_GUARDIANS.name": "Invoquer des gardiens",
|
||||
"core.bonus.SUMMON_GUARDIANS.description": "Au début de la bataille, invoque ${subtype.creature} (${val}%)",
|
||||
"core.bonus.SYNERGY_TARGET.name": "Synergique",
|
||||
"core.bonus.SYNERGY_TARGET.description": "Cette créature est vulnérable à l'effet de synergie",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.name": "Souffle",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.description": "Attaque de souffle (portée de 2 hexagones)",
|
||||
"core.bonus.THREE_HEADED_ATTACK.name": "Attaque à trois têtes",
|
||||
"core.bonus.THREE_HEADED_ATTACK.description": "Attaque trois unités adjacentes",
|
||||
"core.bonus.TRANSMUTATION.name": "Transmutation",
|
||||
"core.bonus.TRANSMUTATION.description": "${val}% de chances de transformer l'unité attaquée en un type différent",
|
||||
"core.bonus.UNDEAD.name": "Morts-vivants",
|
||||
"core.bonus.UNDEAD.description": "La créature est un mort-vivant",
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.name": "Représailles illimitées",
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.description": "Peut riposter contre un nombre illimité d'attaques",
|
||||
"core.bonus.WATER_IMMUNITY.name": "Immunité à l'eau",
|
||||
"core.bonus.WATER_IMMUNITY.description": "Immunisé contre tous les sorts de l'école de magie de l'Eau",
|
||||
"core.bonus.WIDE_BREATH.name": "Large souffle",
|
||||
"core.bonus.WIDE_BREATH.description": "Attaque à souffle large (plusieurs hexagones)"
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
"vcmi.adventureMap.monsterThreat.levels.7" : "Sehr Stark",
|
||||
"vcmi.adventureMap.monsterThreat.levels.8" : "Herausfordernd",
|
||||
"vcmi.adventureMap.monsterThreat.levels.9" : "Überwältigend",
|
||||
"vcmi.adventureMap.monsterThreat.levels.10" : "Tötlich",
|
||||
"vcmi.adventureMap.monsterThreat.levels.10" : "Tödlich",
|
||||
"vcmi.adventureMap.monsterThreat.levels.11" : "Unmöglich",
|
||||
|
||||
"vcmi.adventureMap.confirmRestartGame" : "Seid Ihr sicher, dass Ihr das Spiel neu starten wollt?",
|
||||
@ -67,8 +67,15 @@
|
||||
"vcmi.systemOptions.scalingButton.help" : "{Interface-Skalierung}\n\nÄndern der Skalierung des Interfaces im Spiel",
|
||||
"vcmi.systemOptions.scalingMenu.hover" : "Skalierung des Interfaces auswählen",
|
||||
"vcmi.systemOptions.scalingMenu.help" : "Ändern der Skalierung des Interfaces im Spiel.",
|
||||
"vcmi.systemOptions.longTouchButton.hover" : "Berührungsdauer für langer Touch: %d ms", // Translation note: "ms" = "milliseconds"
|
||||
"vcmi.systemOptions.longTouchButton.help" : "{Berührungsdauer für langer Touch}\n\nBei Verwendung des Touchscreens erscheinen Popup-Fenster nach Berührung des Bildschirms für die angegebene Dauer (in Millisekunden)",
|
||||
"vcmi.systemOptions.longTouchMenu.hover" : "Wähle Berührungsdauer für langer Touch",
|
||||
"vcmi.systemOptions.longTouchMenu.help" : "Ändere die Berührungsdauer für den langen Touch",
|
||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d Millisekunden",
|
||||
"vcmi.systemOptions.framerateButton.hover" : "FPS anzeigen",
|
||||
"vcmi.systemOptions.framerateButton.help" : "{FPS anzeigen}\n\n Schaltet die Sichtbarkeit des Zählers für die Bilder pro Sekunde in der Ecke des Spielfensters um.",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.hover" : "Haptisches Feedback",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.help" : "{Haptisches Feedback}\n\nHaptisches Feedback bei Touch-Eingaben.",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "Meldungen im Infobereich anzeigen",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Meldungen im Infobereich anzeigen}\n\nWann immer möglich, werden Spielnachrichten von besuchten Kartenobjekten in der Infoleiste angezeigt, anstatt als Popup-Fenster zu erscheinen",
|
||||
@ -78,6 +85,8 @@
|
||||
"vcmi.adventureOptions.forceMovementInfo.help" : "{Bewegungskosten immer anzeigen}\n\n Ersetzt die Standardinformationen in der Statusleiste durch die Daten der Bewegungspunkte, ohne dass die ALT-Taste gedrückt werden muss.",
|
||||
"vcmi.adventureOptions.showGrid.hover" : "Raster anzeigen",
|
||||
"vcmi.adventureOptions.showGrid.help" : "{Raster anzeigen}\n\n Zeigt eine Rasterüberlagerung, die die Grenzen zwischen den Kacheln der Abenteuerkarte anzeigt.",
|
||||
"vcmi.adventureOptions.borderScroll.hover" : "Scrollen am Rand",
|
||||
"vcmi.adventureOptions.borderScroll.help" : "{Scrollen am Rand}\n\nScrollt die Abenteuerkarte, wenn sich der Cursor neben dem Fensterrand befindet. Kann mit gedrückter STRG-Taste deaktiviert werden.",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
@ -100,10 +109,10 @@
|
||||
"vcmi.battleOptions.animationsSpeed1.help": "Setzt die Animationsgeschwindigkeit auf sehr langsam",
|
||||
"vcmi.battleOptions.animationsSpeed5.help": "Setzt die Animationsgeschwindigkeit auf sehr schnell",
|
||||
"vcmi.battleOptions.animationsSpeed6.help": "Setzt die Animationsgeschwindigkeit auf sofort",
|
||||
"vcmi.battleOptions.touchscreenMode.hover": "Touchscreen-Modus",
|
||||
"vcmi.battleOptions.touchscreenMode.help": "{Touchscreen-Modus}\n\nFalls aktiviert, ist ein zweiter Klick erforderlich, um die Aktion zu bestätigen und auszuführen. Dies ist besser für Touchscreen-Geräte geeignet.",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.hover": "Hervorhebung der Bewegung bei Hover",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.help": "{Hervorhebung der Bewegung bei Hover}\n\nHebt die Bewegungsreichweite der Einheit hervor, wenn man mit dem Mauszeiger über sie fährt.",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Bereichsgrenzen für Schützen anzeigen",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.help": "{Bereichsgrenzen für Schützen anzeigen}\n\nZeigt die Entfernungsgrenzen des Schützen an, wenn man mit dem Mauszeiger über ihn fährt.",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Intro-Musik überspringen",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.help": "{Intro-Musik überspringen}\n\n Überspringe die kurze Musik, die zu Beginn eines jeden Kampfes gespielt wird, bevor die Action beginnt. Kann auch durch Drücken der ESC-Taste übersprungen werden.",
|
||||
"vcmi.battleWindow.pressKeyToSkipIntro" : "Beliebige Taste drücken, um das Kampf-Intro zu überspringen",
|
||||
@ -118,6 +127,7 @@
|
||||
"vcmi.battleWindow.damageEstimation.damage.1" : "%d Schaden",
|
||||
"vcmi.battleWindow.damageEstimation.kills" : "%d werden verenden",
|
||||
"vcmi.battleWindow.damageEstimation.kills.1" : "%d werden verenden",
|
||||
|
||||
"vcmi.battleResultsWindow.applyResultsLabel" : "Kampfergebnis übernehmen",
|
||||
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Verfügbare Kreaturen anzeigen",
|
||||
@ -165,7 +175,16 @@
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsButton" : "Einrichtung...",
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team-Zuordnungen",
|
||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Straßentypen",
|
||||
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "Der Feind hat es geschafft, bis zum heutigen Tag zu überleben. Der Sieg gehört ihm!",
|
||||
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Herzlichen Glückwunsch! Ihr habt es geschafft, zu überleben. Der Sieg ist euer!",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "Der Feind hat alle Monster besiegt, die das Land heimsuchen, und fordert den Sieg!",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toSelf" : "Herzlichen Glückwunsch! Ihr habt alle Monster besiegt, die dieses Land plagen, und könnt den Sieg für euch beanspruchen!",
|
||||
"vcmi.map.victoryCondition.collectArtifacts.message" : "Sammelt drei Artefakte",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Herzlichen Glückwunsch! Alle eure Feinde wurden besiegt und ihr habt die Engelsallianz! Der Sieg ist euer!",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Besiege alle Feinde und gründe eine Engelsallianz",
|
||||
|
||||
// few strings from WoG used by vcmi
|
||||
"vcmi.stackExperience.description" : "» D e t a i l s z u r S t a p e l e r f a h r u n g «\n\nKreatur-Typ ................... : %s\nErfahrungsrang ................. : %s (%i)\nErfahrungspunkte ............... : %i\nErfahrungspunkte für den nächsten Rang .. : %i\nMaximale Erfahrung pro Kampf ... : %i%% (%i)\nAnzahl der Kreaturen im Stapel .... : %i\nMaximale Anzahl neuer Rekruten\n ohne Verlust von aktuellem Rang .... : %i\nErfahrungs-Multiplikator ........... : %.2f\nUpgrade-Multiplikator .............. : %.2f\nErfahrung nach Rang 10 ........ : %i\nMaximale Anzahl der neuen Rekruten, die bei\n Rang 10 bei maximaler Erfahrung übrig sind : %i",
|
||||
"vcmi.stackExperience.rank.0" : "Grundlagen",
|
||||
@ -199,8 +218,8 @@
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Zauberdämpfer (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Erhöht die Kosten von gegnerischen Zaubern",
|
||||
"core.bonus.CHARGE_IMMUNITY.name": "Immun gegen Aufladung",
|
||||
"core.bonus.CHARGE_IMMUNITY.description": "Immune to Champion charge",
|
||||
"core.bonus.DARKNESS.name": "Darkness cover",
|
||||
"core.bonus.CHARGE_IMMUNITY.description": "Immun gegen Aufladung",
|
||||
"core.bonus.DARKNESS.name": "Abdeckung der Dunkelheit",
|
||||
"core.bonus.DARKNESS.description": "Fügt ${val} Dunkelheitsradius hinzu",
|
||||
"core.bonus.DEATH_STARE.name": "Todesstarren (${val}%)",
|
||||
"core.bonus.DEATH_STARE.description": "${val}% Chance, eine einzelne Kreatur zu töten",
|
||||
|
@ -21,9 +21,27 @@
|
||||
"vcmi.adventureMap.moveCostDetails" : "Punkty ruchu - Koszt: %TURNS tury + %POINTS punkty, Pozostałe punkty: %REMAINING",
|
||||
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Punkty ruchu - Koszt: %POINTS punkty, Pozostałe punkty: %REMAINING",
|
||||
|
||||
"vcmi.server.errors.existingProcess" : "Inny proces vcmiserver został już uruchomiony, zakończ go nim przejdziesz dalej",
|
||||
"vcmi.server.errors.modsIncompatibility" : "Mody wymagane do wczytania gry:",
|
||||
"vcmi.server.confirmReconnect" : "Połączyć z ostatnią sesją?",
|
||||
"vcmi.capitalColors.0" : "Czerwony",
|
||||
"vcmi.capitalColors.1" : "Niebieski",
|
||||
"vcmi.capitalColors.2" : "Brązowy",
|
||||
"vcmi.capitalColors.3" : "Zielony",
|
||||
"vcmi.capitalColors.4" : "Pomarańczowy",
|
||||
"vcmi.capitalColors.5" : "Fioletowy",
|
||||
"vcmi.capitalColors.6" : "Jasnoniebieski",
|
||||
"vcmi.capitalColors.7" : "Różowy",
|
||||
|
||||
"vcmi.mainMenu.tutorialNotImplemented" : "Przepraszamy, trening nie został jeszcze zaimplementowany\n",
|
||||
"vcmi.mainMenu.highscoresNotImplemented" : "Przepraszamy, najlepsze wyniki nie zostały jeszcze zaimplementowane\n",
|
||||
"vcmi.mainMenu.serverConnecting" : "Łączenie...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "Wprowadź adres:",
|
||||
"vcmi.mainMenu.serverClosing" : "Zamykanie...",
|
||||
"vcmi.mainMenu.hostTCP" : "Hostuj grę TCP/IP",
|
||||
"vcmi.mainMenu.joinTCP" : "Dołącz do gry TCP/IP",
|
||||
"vcmi.mainMenu.playerName" : "Gracz",
|
||||
|
||||
"vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej",
|
||||
"vcmi.server.errors.modsIncompatibility" : "Następujące mody są wymagane do wczytania gry:",
|
||||
"vcmi.server.confirmReconnect" : "Połączyć ponownie z ostatnią sesją?",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "Ogólne",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "Przełącza do zakładki opcji ogólnych, która zawiera ustawienia związane z ogólnym działaniem gry",
|
||||
@ -37,10 +55,23 @@
|
||||
"vcmi.systemOptions.otherGroup" : "Inne ustawienia", // unused right now
|
||||
"vcmi.systemOptions.townsGroup" : "Ekran miasta",
|
||||
|
||||
"vcmi.systemOptions.fullscreenBorderless.hover" : "Pełny ekran (borderless/okno pełnoekranowe)",
|
||||
"vcmi.systemOptions.fullscreenBorderless.help" : "{Pełny ekran w trybie okna}\n\nPo wybraniu VCMI będzie działać w trybie okna pełnoekranowego. W tym trybie gra będzie zawsze używać rozdzielczości pulpitu, ignorując wybraną rozdzielczość.",
|
||||
"vcmi.systemOptions.fullscreenExclusive.hover" : "Pełny ekran (tradycyjny)",
|
||||
"vcmi.systemOptions.fullscreenExclusive.help" : "{Pełny ekran}\n\nPo wybraniu VCMI będzie działać w trybie ekskluzywnego pełnego ekranu. W tym trybie gra zmieni rozdzielczość monitora do wybranej rozdzielczości.",
|
||||
"vcmi.systemOptions.resolutionButton.hover" : "Rozdzielczość: %wx%h",
|
||||
"vcmi.systemOptions.resolutionButton.help" : "{Wybierz rozdzielczość}\n\n Zmień rozdzielczość ekranu w grze. Restart gry jest wymagany, by zmiany zostały uwzględnione.",
|
||||
"vcmi.systemOptions.resolutionButton.help" : "{Wybierz rozdzielczość}\n\n Zmień rozdzielczość ekranu w grze.",
|
||||
"vcmi.systemOptions.resolutionMenu.hover" : "Wybierz rozdzielczość",
|
||||
"vcmi.systemOptions.resolutionMenu.help" : "Zmień rozdzielczość ekranu w grze.",
|
||||
"vcmi.systemOptions.scalingButton.hover" : "Skalowanie interfejsu: %p%",
|
||||
"vcmi.systemOptions.scalingButton.help" : "{Skalowanie interfejsu}\n\nZmienia skalę interfejsu gry",
|
||||
"vcmi.systemOptions.scalingMenu.hover" : "Wybierz skalowanie interfejsu",
|
||||
"vcmi.systemOptions.scalingMenu.help" : "Zmień skalę interfejsu w grze.",
|
||||
"vcmi.systemOptions.longTouchButton.hover" : "Czas długiego dotyku: %d ms", // Translation note: "ms" = "milliseconds"
|
||||
"vcmi.systemOptions.longTouchButton.help" : "{Czas długiego dotyku}\n\nPodczas używania ekranu dotykowego, wyskakujące okienka pojawią się po dotknięciu ekranu przez określony czas, w milisekundach",
|
||||
"vcmi.systemOptions.longTouchMenu.hover" : "Wybierz czas długiego dotyku",
|
||||
"vcmi.systemOptions.longTouchMenu.help" : "Zmienia czas wymagany do aktywacji długiego dotyku.",
|
||||
"vcmi.systemOptions.longTouchMenu.entry" : "%d milisekund",
|
||||
"vcmi.systemOptions.framerateButton.hover" : "Pokaż FPS",
|
||||
"vcmi.systemOptions.framerateButton.help" : "{Pokaż FPS}\n\n Przełącza widoczność licznika klatek na sekundę (FPS) w rogu okna gry.",
|
||||
|
||||
@ -52,6 +83,8 @@
|
||||
"vcmi.adventureOptions.forceMovementInfo.help" : "{Zawsze pokazuj koszt ruchu}\n\n Zastępuje domyślne informacje paska statusu danymi o ruchu bez potrzeby przytrzymywania klawisza ALT.",
|
||||
"vcmi.adventureOptions.showGrid.hover" : "Pokaż siatkę",
|
||||
"vcmi.adventureOptions.showGrid.help" : "{Pokaż siatkę}\n\n Włącza siatkę pokazującą brzegi pól mapy przygody.",
|
||||
"vcmi.adventureOptions.borderScroll.hover" : "Przewijanie na brzegu mapy",
|
||||
"vcmi.adventureOptions.borderScroll.help" : "{Przewijanie na brzegu mapy}\n\nPrzewijanie mapy przygody gdy kursor najeżdża na brzeg okna gry. Może być wyłączone poprzez przytrzymanie klawisza CTRL.",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
@ -74,9 +107,12 @@
|
||||
"vcmi.battleOptions.animationsSpeed1.help": "Ustawia szybkość animacji na bardzo wolną",
|
||||
"vcmi.battleOptions.animationsSpeed5.help": "Ustawia szybkość animacji na bardzo szybką",
|
||||
"vcmi.battleOptions.animationsSpeed6.help": "Ustawia szybkość animacji na błyskawiczną",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.hover": "Pokaż możliwości ruchu po najechaniu",
|
||||
"vcmi.battleOptions.movementHighlightOnHover.help": "{Pokaż możliwości ruchu po najechaniu}\n\nPodświetla zasięg ruchu jednostki gdy najedziesz na nią myszą.",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Pokaż limit zasięgu dla strzelców",
|
||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.help": "{Pokaż limit zasięgu dla strzelców po najechaniu}\n\nPokazuje limity zasięgu jednostki strzeleckiej gdy najedziesz na nią myszą.",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Pomiń czekanie startowe",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.help": "{Pomiń czekanie startowe}\n\n Pomija konieczność czekania podczas muzyki startowej, która jest odtwarzana na początku każdej bitwy przed rozpoczęciem akcji.",
|
||||
|
||||
"vcmi.battleWindow.pressKeyToSkipIntro" : "Naciśnij dowolny klawisz by rozpocząć bitwę natychmiastowo",
|
||||
|
||||
"vcmi.battleWindow.damageEstimation.melee" : "Atakuj %CREATURE (%DAMAGE).",
|
||||
@ -90,6 +126,8 @@
|
||||
"vcmi.battleWindow.damageEstimation.kills" : "zginie: %d",
|
||||
"vcmi.battleWindow.damageEstimation.kills.1" : "zginie: %d",
|
||||
|
||||
"vcmi.battleResultsWindow.applyResultsLabel" : "Zatwierdź wynik bitwy",
|
||||
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Pokaż dostępne stworzenia",
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Pokaż dostępne stworzenia}\n\n Pokazuje dostępne stworzenia zamiast tygodniowego przyrostu w podsumowaniu miasta (lewy dolny róg).",
|
||||
"vcmi.otherOptions.creatureGrowthAsDwellingLabel.hover" : "Pokaż tygodniowy przyrost stworzeń",
|
||||
@ -136,6 +174,15 @@
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Sojusze",
|
||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Typy dróg",
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "Wróg dał radę przetrwać do dzisiejszego dnia. Zwycięstwo należy do niego!",
|
||||
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Gratulacje! Dałeś radę przetrwać. Zwycięstwo jest twoje!",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "Wróg zdołał pokonać wszystkie potwory pustoszące te ziemie i odnosi zwycięstwo!",
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toSelf" : "Gratulacje! Pokonałeś wszystkie potwory pustoszące te ziemie i odnosisz zwycięstwo!",
|
||||
"vcmi.map.victoryCondition.collectArtifacts.message" : "Zdobądź trzy artefakty",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Gratulacje! Wszyscy wrogowie zostali pokonani, a ty masz Miecz Anielskiego Sojuszu! Zwycięstwo jest twoje!",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Pokonaj wszystkich wrogów i stwórz Miecz Anielskiego Sojuszu",
|
||||
|
||||
//WoG strings translations missing here - should be taken from polish WoG translation
|
||||
|
||||
"core.bonus.ADDITIONAL_ATTACK.name": "Podwójne Uderzenie",
|
||||
|
@ -11,6 +11,17 @@
|
||||
"config/vcmi/chinese.json"
|
||||
]
|
||||
},
|
||||
|
||||
"french" : {
|
||||
"name" : "VCMI - fichiers nécessaires",
|
||||
"description" : "Fichiers nécessaires pour exécuter correctement VCMI",
|
||||
"author" : "L'équipe VCMI",
|
||||
|
||||
"skipValidation" : true,
|
||||
"translations" : [
|
||||
"config/vcmi/french.json"
|
||||
]
|
||||
},
|
||||
|
||||
"german" : {
|
||||
"name" : "VCMI - grundlegende Dateien",
|
||||
@ -60,7 +71,7 @@
|
||||
"name" : "VCMI - ficheros necesarios",
|
||||
"description" : "Ficheros necesarios para ejecutar VCMI correctamente",
|
||||
"author" : "Abel Rivas",
|
||||
|
||||
|
||||
"skipValidation" : true,
|
||||
"translations" : [
|
||||
"config/vcmi/spanish.json"
|
||||
|
@ -3,6 +3,7 @@
|
||||
package="eu.vcmi.vcmi">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<application
|
||||
android:extractNativeLibs="true"
|
||||
@ -50,4 +51,4 @@
|
||||
android:exported="false"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
@ -3,11 +3,14 @@ package eu.vcmi.vcmi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
|
||||
import org.libsdl.app.SDL;
|
||||
import org.libsdl.app.SDLActivity;
|
||||
@ -138,6 +141,17 @@ public class NativeMethods
|
||||
{
|
||||
internalProgressDisplay(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings(Const.JNI_METHOD_SUPPRESS)
|
||||
public static void hapticFeedback()
|
||||
{
|
||||
final Context ctx = SDL.getContext();
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK));
|
||||
} else {
|
||||
((Vibrator) ctx.getSystemService(ctx.VIBRATOR_SERVICE)).vibrate(30);
|
||||
}
|
||||
}
|
||||
|
||||
private static void internalProgressDisplay(final boolean show)
|
||||
{
|
||||
|
@ -449,19 +449,6 @@ void playIntro()
|
||||
|
||||
static void mainLoop()
|
||||
{
|
||||
SettingsListener resChanged = settings.listen["video"]["resolution"];
|
||||
SettingsListener fsChanged = settings.listen["video"]["fullscreen"];
|
||||
|
||||
auto functor = [](const JsonNode &newState){
|
||||
GH.dispatchMainThread([](){
|
||||
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
|
||||
GH.onScreenResize();
|
||||
});
|
||||
};
|
||||
|
||||
resChanged(functor);
|
||||
fsChanged(functor);
|
||||
|
||||
inGuiThread.reset(new bool(true));
|
||||
|
||||
while(1) //main SDL events loop
|
||||
|
@ -10,13 +10,10 @@
|
||||
#pragma once
|
||||
|
||||
struct SDL_Texture;
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
struct SDL_Surface;
|
||||
|
||||
extern SDL_Texture * screenTexture;
|
||||
|
||||
extern SDL_Window * mainWindow;
|
||||
extern SDL_Renderer * mainRenderer;
|
||||
|
||||
extern SDL_Surface *screen; // main screen surface
|
||||
|
@ -183,7 +183,10 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player)
|
||||
if (player != playerID && LOCPLINT == this)
|
||||
{
|
||||
waitWhileDialog();
|
||||
adventureInt->onEnemyTurnStarted(player);
|
||||
|
||||
bool isHuman = cb->getStartInfo()->playerInfos.count(player) && cb->getStartInfo()->playerInfos.at(player).isControlledByHuman();
|
||||
|
||||
adventureInt->onEnemyTurnStarted(player, isHuman);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1097,7 +1100,8 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
|
||||
if (pom.size() > 1)
|
||||
charperline = 50;
|
||||
GH.windows().createAndPushWindow<CSelWindow>(text, playerID, charperline, intComps, pom, askID);
|
||||
intComps[0]->clickLeft(true, false);
|
||||
intComps[0]->clickPressed(GH.getCursorPosition());
|
||||
intComps[0]->clickReleased(GH.getCursorPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1314,11 +1318,8 @@ void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanc
|
||||
GH.windows().createAndPushWindow<CExchangeWindow>(hero1, hero2, query);
|
||||
}
|
||||
|
||||
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
void CPlayerInterface::beforeObjectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
|
||||
//redraw minimap if owner changed
|
||||
if (sop->what == ObjProperty::OWNER)
|
||||
{
|
||||
const CGObjectInstance * obj = cb->getObj(sop->id);
|
||||
@ -1328,13 +1329,34 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
auto town = static_cast<const CGTownInstance *>(obj);
|
||||
|
||||
if(obj->tempOwner == playerID)
|
||||
localState->addOwnedTown(town);
|
||||
else
|
||||
{
|
||||
localState->removeOwnedTown(town);
|
||||
adventureInt->onTownChanged(town);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adventureInt->onTownChanged(town);
|
||||
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
|
||||
if (sop->what == ObjProperty::OWNER)
|
||||
{
|
||||
const CGObjectInstance * obj = cb->getObj(sop->id);
|
||||
|
||||
if(obj->ID == Obj::TOWN)
|
||||
{
|
||||
auto town = static_cast<const CGTownInstance *>(obj);
|
||||
|
||||
if(obj->tempOwner == playerID)
|
||||
{
|
||||
localState->addOwnedTown(town);
|
||||
adventureInt->onTownChanged(town);
|
||||
}
|
||||
}
|
||||
|
||||
//redraw minimap if owner changed
|
||||
std::set<int3> pos = obj->getBlockedPos();
|
||||
std::unordered_set<int3> upos(pos.begin(), pos.end());
|
||||
adventureInt->onMapTilesChanged(upos);
|
||||
|
@ -144,6 +144,7 @@ protected: // Call-ins from server, should not be called directly, but only via
|
||||
void requestRealized(PackageApplied *pa) override;
|
||||
void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) override;
|
||||
void centerView (int3 pos, int focusTime) override;
|
||||
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void objectPropertyChanged(const SetObjectProperty * sop) override;
|
||||
void objectRemoved(const CGObjectInstance *obj) override;
|
||||
void objectRemovedAfter() override;
|
||||
|
@ -128,4 +128,5 @@ public:
|
||||
virtual void visitBattleStackMoved(BattleStackMoved & pack) override;
|
||||
virtual void visitBattleAttack(BattleAttack & pack) override;
|
||||
virtual void visitStartAction(StartAction & pack) override;
|
||||
};
|
||||
virtual void visitSetObjectProperty(SetObjectProperty & pack) override;
|
||||
};
|
||||
|
@ -611,6 +611,20 @@ void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
|
||||
logNetwork->warn("We received InfoWindow for not our player...");
|
||||
}
|
||||
|
||||
void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
|
||||
{
|
||||
//inform all players that see this object
|
||||
for(auto it = cl.playerint.cbegin(); it != cl.playerint.cend(); ++it)
|
||||
{
|
||||
if(gs.isVisible(gs.getObjInstance(pack.id), it->first))
|
||||
callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::beforeObjectPropertyChanged, &pack);
|
||||
}
|
||||
|
||||
// invalidate section of map view with our object and force an update with new flag color
|
||||
if (pack.what == ObjProperty::OWNER)
|
||||
CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
|
||||
}
|
||||
|
||||
void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
|
||||
{
|
||||
//inform all players that see this object
|
||||
@ -620,12 +634,9 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
|
||||
callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::objectPropertyChanged, &pack);
|
||||
}
|
||||
|
||||
// invalidate section of map view with our object and force an update with new flag color
|
||||
if (pack.what == ObjProperty::OWNER)
|
||||
{
|
||||
// invalidate section of map view with our object and force an update with new flag color
|
||||
CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
|
||||
CGI->mh->onObjectInstantAdd(gs.getObjInstance(pack.id));
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyClientNetPackVisitor::visitHeroLevelUp(HeroLevelUp & pack)
|
||||
|
@ -83,8 +83,11 @@ void AdventureMapInterface::onAudioPaused()
|
||||
|
||||
void AdventureMapInterface::onHeroMovementStarted(const CGHeroInstance * hero)
|
||||
{
|
||||
widget->getInfoBar()->popAll();
|
||||
widget->getInfoBar()->showSelection();
|
||||
if (shortcuts->optionMapViewActive())
|
||||
{
|
||||
widget->getInfoBar()->popAll();
|
||||
widget->getInfoBar()->showSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void AdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
|
||||
@ -137,6 +140,9 @@ void AdventureMapInterface::deactivate()
|
||||
{
|
||||
CIntObject::deactivate();
|
||||
CCS->curh->set(Cursor::Map::POINTER);
|
||||
|
||||
if(LOCPLINT)
|
||||
LOCPLINT->cingconsole->deactivate();
|
||||
}
|
||||
|
||||
void AdventureMapInterface::showAll(Canvas & to)
|
||||
@ -309,16 +315,15 @@ void AdventureMapInterface::onHotseatWaitStarted(PlayerColor playerID)
|
||||
setState(EAdventureState::HOTSEAT_WAIT);
|
||||
}
|
||||
|
||||
void AdventureMapInterface::onEnemyTurnStarted(PlayerColor playerID)
|
||||
void AdventureMapInterface::onEnemyTurnStarted(PlayerColor playerID, bool isHuman)
|
||||
{
|
||||
if(settings["session"]["spectate"].Bool())
|
||||
return;
|
||||
|
||||
mapAudio->onEnemyTurnStarted();
|
||||
widget->getMinimap()->setAIRadar(true);
|
||||
widget->getMinimap()->setAIRadar(!isHuman);
|
||||
widget->getInfoBar()->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
|
||||
setState(EAdventureState::ENEMY_TURN);
|
||||
|
||||
}
|
||||
|
||||
void AdventureMapInterface::setState(EAdventureState state)
|
||||
@ -333,17 +338,8 @@ void AdventureMapInterface::adjustActiveness()
|
||||
bool widgetMustBeActive = isActive() && shortcuts->optionSidePanelActive();
|
||||
bool mapViewMustBeActive = isActive() && (shortcuts->optionMapViewActive());
|
||||
|
||||
if (widgetMustBeActive && !widget->isActive())
|
||||
widget->activate();
|
||||
|
||||
if (!widgetMustBeActive && widget->isActive())
|
||||
widget->deactivate();
|
||||
|
||||
if (mapViewMustBeActive && !widget->getMapView()->isActive())
|
||||
widget->getMapView()->activate();
|
||||
|
||||
if (!mapViewMustBeActive && widget->getMapView()->isActive())
|
||||
widget->getMapView()->deactivate();
|
||||
widget->setInputEnabled(widgetMustBeActive);
|
||||
widget->getMapView()->setInputEnabled(mapViewMustBeActive);
|
||||
}
|
||||
|
||||
void AdventureMapInterface::onCurrentPlayerChanged(PlayerColor playerID)
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
void onHotseatWaitStarted(PlayerColor playerID);
|
||||
|
||||
/// Called by PlayerInterface when AI or remote human player starts his turn
|
||||
void onEnemyTurnStarted(PlayerColor playerID);
|
||||
void onEnemyTurnStarted(PlayerColor playerID, bool isHuman);
|
||||
|
||||
/// Called by PlayerInterface when local human player starts his turn
|
||||
void onPlayerTurnStarted(PlayerColor playerID);
|
||||
|
@ -402,7 +402,7 @@ bool AdventureMapShortcuts::optionCanViewQuests()
|
||||
|
||||
bool AdventureMapShortcuts::optionCanToggleLevel()
|
||||
{
|
||||
return optionInMapView() && LOCPLINT->cb->getMapSize().z > 0;
|
||||
return optionInMapView() && LOCPLINT->cb->getMapSize().z > 1;
|
||||
}
|
||||
|
||||
bool AdventureMapShortcuts::optionMapLevelSurface()
|
||||
|
@ -34,7 +34,7 @@ CInGameConsole::CInGameConsole()
|
||||
: CIntObject(KEYBOARD | TIME | TEXTINPUT)
|
||||
, prevEntDisp(-1)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
void CInGameConsole::showAll(Canvas & to)
|
||||
@ -96,7 +96,7 @@ void CInGameConsole::print(const std::string & txt)
|
||||
|
||||
auto splitText = CMessage::breakText(txt, maxWidth, FONT_MEDIUM);
|
||||
|
||||
for (auto const & entry : splitText)
|
||||
for(const auto & entry : splitText)
|
||||
texts.push_back({entry, 0});
|
||||
|
||||
while(texts.size() > maxDisplayedTexts)
|
||||
@ -104,6 +104,27 @@ void CInGameConsole::print(const std::string & txt)
|
||||
}
|
||||
|
||||
GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
|
||||
CCS->soundh->playSound("CHAT");
|
||||
}
|
||||
|
||||
bool CInGameConsole::captureThisKey(EShortcut key)
|
||||
{
|
||||
if (enteredText.empty())
|
||||
return false;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case EShortcut::GLOBAL_ACCEPT:
|
||||
case EShortcut::GLOBAL_CANCEL:
|
||||
case EShortcut::GAME_ACTIVATE_CONSOLE:
|
||||
case EShortcut::GLOBAL_BACKSPACE:
|
||||
case EShortcut::MOVE_UP:
|
||||
case EShortcut::MOVE_DOWN:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CInGameConsole::keyPressed (EShortcut key)
|
||||
@ -111,18 +132,18 @@ void CInGameConsole::keyPressed (EShortcut key)
|
||||
if (LOCPLINT->cingconsole != this)
|
||||
return;
|
||||
|
||||
if(!captureAllKeys && key != EShortcut::GAME_ACTIVATE_CONSOLE)
|
||||
if(enteredText.empty() && key != EShortcut::GAME_ACTIVATE_CONSOLE)
|
||||
return; //because user is not entering any text
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case EShortcut::GLOBAL_CANCEL:
|
||||
if(captureAllKeys)
|
||||
if(!enteredText.empty())
|
||||
endEnteringText(false);
|
||||
break;
|
||||
|
||||
case EShortcut::GAME_ACTIVATE_CONSOLE:
|
||||
if(captureAllKeys)
|
||||
if(!enteredText.empty())
|
||||
endEnteringText(false);
|
||||
else
|
||||
startEnteringText();
|
||||
@ -130,15 +151,10 @@ void CInGameConsole::keyPressed (EShortcut key)
|
||||
|
||||
case EShortcut::GLOBAL_ACCEPT:
|
||||
{
|
||||
if(!enteredText.empty() && captureAllKeys)
|
||||
if(!enteredText.empty())
|
||||
{
|
||||
bool anyTextExceptCaret = enteredText.size() > 1;
|
||||
endEnteringText(anyTextExceptCaret);
|
||||
|
||||
if(anyTextExceptCaret)
|
||||
{
|
||||
CCS->soundh->playSound("CHAT");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -195,8 +211,9 @@ void CInGameConsole::textInputed(const std::string & inputtedText)
|
||||
if (LOCPLINT->cingconsole != this)
|
||||
return;
|
||||
|
||||
if(!captureAllKeys || enteredText.empty())
|
||||
if(enteredText.empty())
|
||||
return;
|
||||
|
||||
enteredText.resize(enteredText.size()-1);
|
||||
|
||||
enteredText += inputtedText;
|
||||
@ -215,14 +232,10 @@ void CInGameConsole::startEnteringText()
|
||||
if (!isActive())
|
||||
return;
|
||||
|
||||
if (captureAllKeys)
|
||||
return;
|
||||
|
||||
assert(currentStatusBar.expired());//effectively, nullptr check
|
||||
|
||||
currentStatusBar = GH.statusbar();
|
||||
|
||||
captureAllKeys = true;
|
||||
enteredText = "_";
|
||||
|
||||
GH.statusbar()->setEnteringMode(true);
|
||||
@ -231,7 +244,6 @@ void CInGameConsole::startEnteringText()
|
||||
|
||||
void CInGameConsole::endEnteringText(bool processEnteredText)
|
||||
{
|
||||
captureAllKeys = false;
|
||||
prevEntDisp = -1;
|
||||
if(processEnteredText)
|
||||
{
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
void keyPressed(EShortcut key) override;
|
||||
void textInputed(const std::string & enteredText) override;
|
||||
void textEdited(const std::string & enteredText) override;
|
||||
bool captureThisKey(EShortcut key) override;
|
||||
|
||||
void startEnteringText();
|
||||
void endEnteringText(bool processEnteredText);
|
||||
|
@ -271,20 +271,17 @@ void CInfoBar::tick(uint32_t msPassed)
|
||||
}
|
||||
}
|
||||
|
||||
void CInfoBar::clickLeft(tribool down, bool previousState)
|
||||
void CInfoBar::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
if(state == HERO || state == TOWN)
|
||||
showGameStatus();
|
||||
else if(state == GAME)
|
||||
showDate();
|
||||
else
|
||||
popComponents(true);
|
||||
}
|
||||
if(state == HERO || state == TOWN)
|
||||
showGameStatus();
|
||||
else if(state == GAME)
|
||||
showDate();
|
||||
else
|
||||
popComponents(true);
|
||||
}
|
||||
|
||||
void CInfoBar::showPopupWindow()
|
||||
void CInfoBar::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
CRClickPopup::createAndPush(CGI->generaltexth->allTexts[109]);
|
||||
}
|
||||
|
@ -154,8 +154,8 @@ private:
|
||||
|
||||
void tick(uint32_t msPassed) override;
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
|
||||
void playNewDaySound();
|
||||
|
@ -40,25 +40,22 @@ CList::CListItem::CListItem(CList * Parent)
|
||||
|
||||
CList::CListItem::~CListItem() = default;
|
||||
|
||||
void CList::CListItem::showPopupWindow()
|
||||
void CList::CListItem::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
showTooltip();
|
||||
}
|
||||
|
||||
void CList::CListItem::clickLeft(tribool down, bool previousState)
|
||||
void CList::CListItem::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down == true)
|
||||
//second click on already selected item
|
||||
if(parent->selected == this->shared_from_this())
|
||||
{
|
||||
//second click on already selected item
|
||||
if(parent->selected == this->shared_from_this())
|
||||
{
|
||||
open();
|
||||
}
|
||||
else
|
||||
{
|
||||
//first click - switch selection
|
||||
parent->select(this->shared_from_this());
|
||||
}
|
||||
open();
|
||||
}
|
||||
else
|
||||
{
|
||||
//first click - switch selection
|
||||
parent->select(this->shared_from_this());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ protected:
|
||||
CListItem(CList * parent);
|
||||
~CListItem();
|
||||
|
||||
void showPopupWindow() override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
void onSelect(bool on);
|
||||
|
||||
|
@ -143,13 +143,12 @@ void CMinimap::gesturePanning(const Point & initialPosition, const Point & curre
|
||||
moveAdvMapSelection(currentPosition);
|
||||
}
|
||||
|
||||
void CMinimap::clickLeft(tribool down, bool previousState)
|
||||
void CMinimap::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
moveAdvMapSelection(GH.getCursorPosition());
|
||||
moveAdvMapSelection(cursorPosition);
|
||||
}
|
||||
|
||||
void CMinimap::showPopupWindow()
|
||||
void CMinimap::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
CRClickPopup::createAndPush(CGI->generaltexth->zelp[291].second);
|
||||
}
|
||||
@ -231,7 +230,7 @@ void CMinimap::setAIRadar(bool on)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CMinimap::updateTiles(std::unordered_set<int3> positions)
|
||||
void CMinimap::updateTiles(const std::unordered_set<int3> & positions)
|
||||
{
|
||||
if(minimap)
|
||||
{
|
||||
|
@ -44,8 +44,8 @@ class CMinimap : public CIntObject
|
||||
int level;
|
||||
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
void mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
|
||||
@ -68,6 +68,6 @@ public:
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
|
||||
void updateTiles(std::unordered_set<int3> positions);
|
||||
void updateTiles(const std::unordered_set<int3> & positions);
|
||||
};
|
||||
|
||||
|
@ -184,7 +184,7 @@ void BattleFieldController::createHeroes()
|
||||
void BattleFieldController::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
||||
{
|
||||
if (!on && pos.isInside(finalPosition))
|
||||
clickLeft(false, false);
|
||||
clickPressed(finalPosition);
|
||||
}
|
||||
|
||||
void BattleFieldController::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
||||
@ -213,18 +213,15 @@ void BattleFieldController::mouseMoved(const Point & cursorPosition, const Point
|
||||
owner.actionsController->onHoverEnded();
|
||||
}
|
||||
|
||||
void BattleFieldController::clickLeft(tribool down, bool previousState)
|
||||
void BattleFieldController::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(!down)
|
||||
{
|
||||
BattleHex selectedHex = getHoveredHex();
|
||||
BattleHex selectedHex = getHoveredHex();
|
||||
|
||||
if (selectedHex != BattleHex::INVALID)
|
||||
owner.actionsController->onHexLeftClicked(selectedHex);
|
||||
}
|
||||
if (selectedHex != BattleHex::INVALID)
|
||||
owner.actionsController->onHexLeftClicked(selectedHex);
|
||||
}
|
||||
|
||||
void BattleFieldController::showPopupWindow()
|
||||
void BattleFieldController::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
BattleHex selectedHex = getHoveredHex();
|
||||
|
||||
|
@ -100,8 +100,8 @@ class BattleFieldController : public CIntObject
|
||||
void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void activate() override;
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
|
@ -121,6 +121,8 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
|
||||
{
|
||||
Settings full = settings.write["video"]["fullscreen"];
|
||||
full->Bool() = !full->Bool();
|
||||
|
||||
GH.onScreenResize();
|
||||
return;
|
||||
}
|
||||
else if(ev.type == SDL_USEREVENT)
|
||||
|
@ -33,6 +33,12 @@ void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_TRUE)
|
||||
{
|
||||
if (key.keysym.sym >= ' ' && key.keysym.sym < 0x80)
|
||||
return; // printable character - will be handled as text input
|
||||
}
|
||||
|
||||
assert(key.state == SDL_PRESSED);
|
||||
|
||||
if(key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool())
|
||||
@ -77,6 +83,12 @@ void InputSourceKeyboard::handleEventKeyUp(const SDL_KeyboardEvent & key)
|
||||
if(key.repeat != 0)
|
||||
return; // ignore periodic event resends
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_TRUE)
|
||||
{
|
||||
if (key.keysym.sym >= ' ' && key.keysym.sym < 0x80)
|
||||
return; // printable character - will be handled as text input
|
||||
}
|
||||
|
||||
assert(key.state == SDL_RELEASED);
|
||||
|
||||
auto shortcutsVector = GH.shortcuts().translateKeycode(key.keysym.sym);
|
||||
|
@ -18,6 +18,12 @@
|
||||
#include "../gui/MouseButton.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_hints.h>
|
||||
|
||||
InputSourceMouse::InputSourceMouse()
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||
}
|
||||
|
||||
void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motion)
|
||||
{
|
||||
|
@ -24,6 +24,8 @@ class InputSourceMouse
|
||||
Point middleClickPosition;
|
||||
int mouseButtonsMask = 0;
|
||||
public:
|
||||
InputSourceMouse();
|
||||
|
||||
void handleEventMouseMotion(const SDL_MouseMotionEvent & current);
|
||||
void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current);
|
||||
void handleEventMouseWheel(const SDL_MouseWheelEvent & current);
|
||||
|
@ -14,20 +14,17 @@
|
||||
#include "../CMT.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/EventDispatcher.h"
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../renderSDL/SDL_Extensions.h"
|
||||
|
||||
#include "../../lib/Rect.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_render.h>
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
# include <dispatch/dispatch.h>
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
# include "ios/utils.h"
|
||||
#endif
|
||||
|
||||
void InputSourceText::handleEventTextInput(const SDL_TextInputEvent & text)
|
||||
{
|
||||
GH.events().dispatchTextInput(text.text);
|
||||
@ -40,30 +37,15 @@ void InputSourceText::handleEventTextEditing(const SDL_TextEditingEvent & text)
|
||||
|
||||
void InputSourceText::startTextInput(const Rect & whereInput)
|
||||
{
|
||||
|
||||
#ifdef VCMI_APPLE
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
|
||||
// TODO ios: looks like SDL bug actually, try fixing there
|
||||
auto renderer = SDL_GetRenderer(mainWindow);
|
||||
float scaleX, scaleY;
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
||||
SDL_RenderGetViewport(renderer, &viewport);
|
||||
Rect rectInScreenCoordinates = GH.screenHandler().convertLogicalPointsToWindow(whereInput);
|
||||
SDL_Rect textInputRect = CSDL_Ext::toSDL(rectInScreenCoordinates);
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
const auto nativeScale = iOS_utils::screenScale();
|
||||
scaleX /= nativeScale;
|
||||
scaleY /= nativeScale;
|
||||
#endif
|
||||
|
||||
SDL_Rect rectInScreenCoordinates;
|
||||
rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX;
|
||||
rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY;
|
||||
rectInScreenCoordinates.w = whereInput.w * scaleX;
|
||||
rectInScreenCoordinates.h = whereInput.h * scaleY;
|
||||
|
||||
SDL_SetTextInputRect(&rectInScreenCoordinates);
|
||||
SDL_SetTextInputRect(&textInputRect);
|
||||
|
||||
if (SDL_IsTextInputActive() == SDL_FALSE)
|
||||
{
|
||||
|
@ -22,6 +22,12 @@
|
||||
#include "../gui/MouseButton.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
|
||||
#if defined(VCMI_ANDROID)
|
||||
#include "../../lib/CAndroidVMHelper.h"
|
||||
#elif defined(VCMI_IOS)
|
||||
#include "../ios/utils.h"
|
||||
#endif
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_hints.h>
|
||||
#include <SDL_timer.h>
|
||||
@ -32,6 +38,7 @@ InputSourceTouch::InputSourceTouch()
|
||||
params.useRelativeMode = settings["general"]["userRelativePointer"].Bool();
|
||||
params.relativeModeSpeedFactor = settings["general"]["relativePointerSpeedMultiplier"].Float();
|
||||
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
||||
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
|
||||
|
||||
if (params.useRelativeMode)
|
||||
state = TouchState::RELATIVE_MODE;
|
||||
@ -100,6 +107,7 @@ void InputSourceTouch::handleEventFingerDown(const SDL_TouchFingerEvent & tfinge
|
||||
{
|
||||
// FIXME: better place to update potentially changed settings?
|
||||
params.longTouchTimeMilliseconds = settings["general"]["longTouchTimeMilliseconds"].Float();
|
||||
params.hapticFeedbackEnabled = settings["general"]["hapticFeedback"].Bool();
|
||||
|
||||
lastTapTimeTicks = tfinger.timestamp;
|
||||
|
||||
@ -215,6 +223,7 @@ void InputSourceTouch::handleUpdate()
|
||||
if (currentTime > lastTapTimeTicks + params.longTouchTimeMilliseconds)
|
||||
{
|
||||
GH.events().dispatchShowPopup(GH.getCursorPosition());
|
||||
hapticFeedback();
|
||||
|
||||
if (GH.windows().isTopWindowPopup())
|
||||
state = TouchState::TAP_DOWN_LONG;
|
||||
@ -287,3 +296,14 @@ void InputSourceTouch::emitPinchEvent(const SDL_TouchFingerEvent & tfinger)
|
||||
if (distanceOld > params.pinchSensitivityThreshold)
|
||||
GH.events().dispatchGesturePinch(lastTapPosition, distanceNew / distanceOld);
|
||||
}
|
||||
|
||||
void InputSourceTouch::hapticFeedback() {
|
||||
if(params.hapticFeedbackEnabled) {
|
||||
#if defined(VCMI_ANDROID)
|
||||
CAndroidVMHelper vmHelper;
|
||||
vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "hapticFeedback");
|
||||
#elif defined(VCMI_IOS)
|
||||
iOS_utils::hapticFeedback();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,8 @@ struct TouchInputParameters
|
||||
uint32_t pinchSensitivityThreshold = 10;
|
||||
|
||||
bool useRelativeMode = false;
|
||||
|
||||
bool hapticFeedbackEnabled = false;
|
||||
};
|
||||
|
||||
/// Class that handles touchscreen input from SDL events
|
||||
@ -94,6 +96,8 @@ class InputSourceTouch
|
||||
|
||||
void emitPanningEvent(const SDL_TouchFingerEvent & tfinger);
|
||||
void emitPinchEvent(const SDL_TouchFingerEvent & tfinger);
|
||||
|
||||
void hapticFeedback();
|
||||
|
||||
public:
|
||||
InputSourceTouch();
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "CGuiHandler.h"
|
||||
#include "WindowHandler.h"
|
||||
#include "EventDispatcher.h"
|
||||
#include "Shortcut.h"
|
||||
#include "../render/Canvas.h"
|
||||
#include "../windows/CMessage.h"
|
||||
@ -20,18 +21,13 @@
|
||||
CIntObject::CIntObject(int used_, Point pos_):
|
||||
parent_m(nullptr),
|
||||
parent(parent_m),
|
||||
type(0)
|
||||
redrawParent(false),
|
||||
inputEnabled(true),
|
||||
used(used_),
|
||||
recActions(GH.defActionsDef),
|
||||
defActions(GH.defActionsDef),
|
||||
pos(pos_, Point())
|
||||
{
|
||||
captureAllKeys = false;
|
||||
used = used_;
|
||||
|
||||
recActions = defActions = GH.defActionsDef;
|
||||
|
||||
pos.x = pos_.x;
|
||||
pos.y = pos_.y;
|
||||
pos.w = 0;
|
||||
pos.h = 0;
|
||||
|
||||
if(GH.captureChildren)
|
||||
GH.createdObj.front()->addChild(this, true);
|
||||
}
|
||||
@ -76,7 +72,11 @@ void CIntObject::activate()
|
||||
if (isActive())
|
||||
return;
|
||||
|
||||
activateEvents(used | GENERAL);
|
||||
if (inputEnabled)
|
||||
activateEvents(used | GENERAL);
|
||||
else
|
||||
activateEvents(GENERAL);
|
||||
|
||||
assert(isActive());
|
||||
|
||||
if(defActions & ACTIVATE)
|
||||
@ -102,7 +102,7 @@ void CIntObject::deactivate()
|
||||
|
||||
void CIntObject::addUsedEvents(ui16 newActions)
|
||||
{
|
||||
if (isActive())
|
||||
if (isActive() && inputEnabled)
|
||||
activateEvents(~used & newActions);
|
||||
used |= newActions;
|
||||
}
|
||||
@ -141,6 +141,32 @@ void CIntObject::setEnabled(bool on)
|
||||
disable();
|
||||
}
|
||||
|
||||
void CIntObject::setInputEnabled(bool on)
|
||||
{
|
||||
if (inputEnabled == on)
|
||||
return;
|
||||
|
||||
inputEnabled = on;
|
||||
|
||||
if (isActive())
|
||||
{
|
||||
assert((used & GENERAL) == 0);
|
||||
|
||||
if (on)
|
||||
activateEvents(used);
|
||||
else
|
||||
deactivateEvents(used);
|
||||
}
|
||||
|
||||
for(auto & elem : children)
|
||||
elem->setInputEnabled(on);
|
||||
}
|
||||
|
||||
void CIntObject::setRedrawParent(bool on)
|
||||
{
|
||||
redrawParent = on;
|
||||
}
|
||||
|
||||
void CIntObject::fitToScreen(int borderWidth, bool propagate)
|
||||
{
|
||||
Point newPos = pos.topLeft();
|
||||
@ -181,6 +207,9 @@ void CIntObject::addChild(CIntObject * child, bool adjustPosition)
|
||||
if(adjustPosition)
|
||||
child->moveBy(pos.topLeft(), adjustPosition);
|
||||
|
||||
if (inputEnabled != child->inputEnabled)
|
||||
child->setInputEnabled(inputEnabled);
|
||||
|
||||
if (!isActive() && child->isActive())
|
||||
child->deactivate();
|
||||
if (isActive()&& !child->isActive())
|
||||
@ -210,7 +239,7 @@ void CIntObject::redraw()
|
||||
//it should fix glitches when called by inactive elements located below active window
|
||||
if (isActive())
|
||||
{
|
||||
if (parent_m && (type & REDRAW_PARENT))
|
||||
if (parent_m && redrawParent)
|
||||
{
|
||||
parent_m->redraw();
|
||||
}
|
||||
@ -266,7 +295,7 @@ const Rect & CIntObject::center(const Point & p, bool propagate)
|
||||
|
||||
bool CIntObject::captureThisKey(EShortcut key)
|
||||
{
|
||||
return captureAllKeys;
|
||||
return false;
|
||||
}
|
||||
|
||||
CKeyShortcut::CKeyShortcut()
|
||||
@ -284,7 +313,7 @@ void CKeyShortcut::keyPressed(EShortcut key)
|
||||
if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed)
|
||||
{
|
||||
shortcutPressed = true;
|
||||
clickLeft(true, false);
|
||||
clickPressed(GH.getCursorPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,7 +322,7 @@ void CKeyShortcut::keyReleased(EShortcut key)
|
||||
if( assignedKey == key && assignedKey != EShortcut::NONE && shortcutPressed)
|
||||
{
|
||||
shortcutPressed = false;
|
||||
clickLeft(false, true);
|
||||
clickReleased(GH.getCursorPosition());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,11 +47,10 @@ class CIntObject : public IShowActivatable, public AEventsReceiver //interface o
|
||||
//non-const versions of fields to allow changing them in CIntObject
|
||||
CIntObject *parent_m; //parent object
|
||||
|
||||
public:
|
||||
//redraw parent flag - this int may be semi-transparent and require redraw of parent window
|
||||
enum {REDRAW_PARENT=8};
|
||||
int type; //bin flags using etype
|
||||
bool inputEnabled;
|
||||
bool redrawParent;
|
||||
|
||||
public:
|
||||
std::vector<CIntObject *> children;
|
||||
|
||||
/// read-only parent access. May not be a "clean" solution but allows some compatibility
|
||||
@ -63,10 +62,7 @@ public:
|
||||
CIntObject(int used=0, Point offset=Point());
|
||||
virtual ~CIntObject();
|
||||
|
||||
//keyboard handling
|
||||
bool captureAllKeys; //if true, only this object should get info about pressed keys
|
||||
|
||||
bool captureThisKey(EShortcut key) override; //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
|
||||
bool captureThisKey(EShortcut key) override;
|
||||
|
||||
void addUsedEvents(ui16 newActions);
|
||||
void removeUsedEvents(ui16 newActions);
|
||||
@ -82,6 +78,13 @@ public:
|
||||
/// deactivates or activates UI element based on flag
|
||||
void setEnabled(bool on);
|
||||
|
||||
/// Block (or allow) all user input, e.g. mouse/keyboard/touch without hiding element
|
||||
void setInputEnabled(bool on);
|
||||
|
||||
/// Mark this input as one that requires parent redraw on update,
|
||||
/// for example if current control might have semi-transparent elements and requires redrawing of background
|
||||
void setRedrawParent(bool on);
|
||||
|
||||
// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
|
||||
// usually used automatically by parent
|
||||
void activate() override;
|
||||
|
@ -63,7 +63,9 @@ void EventDispatcher::dispatchTimer(uint32_t msPassed)
|
||||
EventReceiversList hlp = timeinterested;
|
||||
for (auto & elem : hlp)
|
||||
{
|
||||
if(!vstd::contains(timeinterested,elem)) continue;
|
||||
if(!vstd::contains(timeinterested,elem))
|
||||
continue;
|
||||
|
||||
elem->tick(msPassed);
|
||||
}
|
||||
}
|
||||
@ -126,23 +128,23 @@ void EventDispatcher::dispatchMouseDoubleClick(const Point & position)
|
||||
|
||||
if(i->receiveEvent(position, AEventsReceiver::DOUBLECLICK))
|
||||
{
|
||||
i->clickDouble();
|
||||
i->clickDouble(position);
|
||||
doubleClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!doubleClicked)
|
||||
handleLeftButtonClick(true);
|
||||
handleLeftButtonClick(position, true);
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatchMouseLeftButtonPressed(const Point & position)
|
||||
{
|
||||
handleLeftButtonClick(true);
|
||||
handleLeftButtonClick(position, true);
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatchMouseLeftButtonReleased(const Point & position)
|
||||
{
|
||||
handleLeftButtonClick(false);
|
||||
handleLeftButtonClick(position, false);
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatchShowPopup(const Point & position)
|
||||
@ -153,10 +155,10 @@ void EventDispatcher::dispatchShowPopup(const Point & position)
|
||||
if(!vstd::contains(rclickable, i))
|
||||
continue;
|
||||
|
||||
if( !i->receiveEvent(GH.getCursorPosition(), AEventsReceiver::LCLICK))
|
||||
if( !i->receiveEvent(position, AEventsReceiver::LCLICK))
|
||||
continue;
|
||||
|
||||
i->showPopupWindow();
|
||||
i->showPopupWindow(position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +170,7 @@ void EventDispatcher::dispatchClosePopup(const Point & position)
|
||||
assert(!GH.windows().isTopWindowPopup());
|
||||
}
|
||||
|
||||
void EventDispatcher::handleLeftButtonClick(bool isPressed)
|
||||
void EventDispatcher::handleLeftButtonClick(const Point & position, bool isPressed)
|
||||
{
|
||||
auto hlp = lclickable;
|
||||
for(auto & i : hlp)
|
||||
@ -176,20 +178,23 @@ void EventDispatcher::handleLeftButtonClick(bool isPressed)
|
||||
if(!vstd::contains(lclickable, i))
|
||||
continue;
|
||||
|
||||
auto prev = i->isMouseLeftButtonPressed();
|
||||
|
||||
if(!isPressed)
|
||||
i->mouseClickedState = isPressed;
|
||||
|
||||
if( i->receiveEvent(GH.getCursorPosition(), AEventsReceiver::LCLICK))
|
||||
if( i->receiveEvent(position, AEventsReceiver::LCLICK))
|
||||
{
|
||||
if(isPressed)
|
||||
i->mouseClickedState = isPressed;
|
||||
i->clickLeft(isPressed, prev);
|
||||
i->clickPressed(position);
|
||||
|
||||
if (i->mouseClickedState && !isPressed)
|
||||
i->clickReleased(position);
|
||||
|
||||
i->mouseClickedState = isPressed;
|
||||
}
|
||||
else if(!isPressed)
|
||||
else
|
||||
{
|
||||
i->clickLeft(boost::logic::indeterminate, prev);
|
||||
if(i->mouseClickedState && !isPressed)
|
||||
{
|
||||
i->mouseClickedState = isPressed;
|
||||
i->clickCancel(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class EventDispatcher
|
||||
EventReceiversList textInterested;
|
||||
EventReceiversList panningInterested;
|
||||
|
||||
void handleLeftButtonClick(bool isPressed);
|
||||
void handleLeftButtonClick(const Point & position, bool isPressed);
|
||||
|
||||
|
||||
template<typename Functor>
|
||||
|
@ -15,7 +15,6 @@ VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class EventDispatcher;
|
||||
enum class EShortcut;
|
||||
using boost::logic::tribool;
|
||||
|
||||
/// Class that is capable of subscribing and receiving input events
|
||||
/// Acts as base class for all UI elements
|
||||
@ -34,9 +33,18 @@ protected:
|
||||
/// Deactivates particular events for this UI element. Uses unnamed enum from this class
|
||||
void deactivateEvents(ui16 what);
|
||||
|
||||
virtual void clickLeft(tribool down, bool previousState) {}
|
||||
virtual void showPopupWindow() {}
|
||||
virtual void clickDouble() {}
|
||||
/// allows capturing key input so it will be delivered only to this element
|
||||
virtual bool captureThisKey(EShortcut key) = 0;
|
||||
|
||||
/// If true, event of selected type in selected position will be processed by this element
|
||||
virtual bool receiveEvent(const Point & position, int eventType) const= 0;
|
||||
|
||||
public:
|
||||
virtual void clickPressed(const Point & cursorPosition) {}
|
||||
virtual void clickReleased(const Point & cursorPosition) {}
|
||||
virtual void clickCancel(const Point & cursorPosition) {}
|
||||
virtual void showPopupWindow(const Point & cursorPosition) {}
|
||||
virtual void clickDouble(const Point & cursorPosition) {}
|
||||
|
||||
/// Called when user pans screen by specified distance
|
||||
virtual void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) {}
|
||||
@ -62,11 +70,6 @@ protected:
|
||||
|
||||
virtual void tick(uint32_t msPassed) {}
|
||||
|
||||
virtual bool captureThisKey(EShortcut key) = 0;
|
||||
|
||||
/// If true, event of selected type in selected position will be processed by this element
|
||||
virtual bool receiveEvent(const Point & position, int eventType) const= 0;
|
||||
|
||||
public:
|
||||
AEventsReceiver();
|
||||
virtual ~AEventsReceiver() = default;
|
||||
|
@ -493,7 +493,7 @@ public:
|
||||
InterfaceLayoutWidget::InterfaceLayoutWidget()
|
||||
:CIntObject()
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildLayout(const JsonNode & config)
|
||||
|
@ -28,98 +28,14 @@
|
||||
|
||||
@implementation SDLViewObserver
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||
[object removeObserver:self forKeyPath:keyPath];
|
||||
|
||||
UIView * view = [object valueForKeyPath:keyPath];
|
||||
|
||||
auto longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
longPress.minimumPressDuration = 0.2;
|
||||
[view addGestureRecognizer:longPress];
|
||||
|
||||
auto pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
|
||||
[view addGestureRecognizer:pinch];
|
||||
}
|
||||
|
||||
#pragma mark - Gestures
|
||||
|
||||
- (void)handleLongPress:(UIGestureRecognizer *)gesture {
|
||||
// send RMB click
|
||||
SDL_EventType mouseButtonType;
|
||||
switch (gesture.state)
|
||||
{
|
||||
case UIGestureRecognizerStateBegan:
|
||||
mouseButtonType = SDL_MOUSEBUTTONDOWN;
|
||||
break;
|
||||
case UIGestureRecognizerStateEnded:
|
||||
mouseButtonType = SDL_MOUSEBUTTONUP;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
auto renderer = SDL_GetRenderer(mainWindow);
|
||||
float scaleX, scaleY;
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
||||
SDL_RenderGetViewport(renderer, &viewport);
|
||||
|
||||
auto touchedPoint = [gesture locationInView:gesture.view];
|
||||
auto screenScale = UIScreen.mainScreen.nativeScale;
|
||||
Sint32 x = (int)touchedPoint.x * screenScale / scaleX - viewport.x;
|
||||
Sint32 y = (int)touchedPoint.y * screenScale / scaleY - viewport.y;
|
||||
|
||||
SDL_Event rmbEvent;
|
||||
rmbEvent.button = (SDL_MouseButtonEvent){
|
||||
.type = mouseButtonType,
|
||||
.button = SDL_BUTTON_RIGHT,
|
||||
.clicks = 1,
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
SDL_PushEvent(&rmbEvent);
|
||||
|
||||
// small hack to prevent cursor jumping
|
||||
if (mouseButtonType == SDL_MOUSEBUTTONUP)
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.025 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
SDL_Event motionEvent;
|
||||
motionEvent.motion = (SDL_MouseMotionEvent){
|
||||
.type = SDL_MOUSEMOTION,
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
SDL_PushEvent(&motionEvent);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)handlePinch:(UIGestureRecognizer *)gesture {
|
||||
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
|
||||
return;
|
||||
[GameChatKeyboardHandler sendKeyEventWithKeyCode:SDLK_SPACE];
|
||||
}
|
||||
|
||||
#pragma mark - UIGestureRecognizerDelegate
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||
return [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int startSDL(int argc, char * argv[], BOOL startManually)
|
||||
{
|
||||
@autoreleasepool {
|
||||
auto observer = [SDLViewObserver new];
|
||||
observer.gameChatHandler = [GameChatKeyboardHandler new];
|
||||
|
||||
id __block sdlWindowCreationObserver = [NSNotificationCenter.defaultCenter addObserverForName:UIWindowDidBecomeKeyNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:sdlWindowCreationObserver];
|
||||
sdlWindowCreationObserver = nil;
|
||||
|
||||
UIWindow * sdlWindow = note.object;
|
||||
[sdlWindow.rootViewController addObserver:observer forKeyPath:NSStringFromSelector(@selector(view)) options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}];
|
||||
id textFieldObserver = [NSNotificationCenter.defaultCenter addObserverForName:UITextFieldTextDidEndEditingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
|
||||
removeFocusFromActiveInput();
|
||||
}];
|
||||
|
@ -15,4 +15,6 @@ double screenScale();
|
||||
|
||||
void showLoadingIndicator();
|
||||
void hideLoadingIndicator();
|
||||
|
||||
void hapticFeedback();
|
||||
}
|
||||
|
@ -43,4 +43,10 @@ void hideLoadingIndicator()
|
||||
[indicator removeFromSuperview];
|
||||
indicator = nil;
|
||||
}
|
||||
|
||||
void hapticFeedback()
|
||||
{
|
||||
auto hapticGen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
||||
[hapticGen impactOccurred];
|
||||
}
|
||||
}
|
||||
|
@ -499,23 +499,19 @@ void CBonusSelection::CRegion::updateState()
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusSelection::CRegion::clickLeft(tribool down, bool previousState)
|
||||
void CBonusSelection::CRegion::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
//select if selectable & clicked inside our graphic
|
||||
if(indeterminate(down))
|
||||
return;
|
||||
|
||||
if(!down && selectable && !graphicsNotSelected->getSurface()->isTransparent(GH.getCursorPosition() - pos.topLeft()))
|
||||
if(selectable && !graphicsNotSelected->getSurface()->isTransparent(cursorPosition - pos.topLeft()))
|
||||
{
|
||||
CSH->setCampaignMap(idOfMapAndRegion);
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusSelection::CRegion::showPopupWindow()
|
||||
void CBonusSelection::CRegion::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
// FIXME: For some reason "down" is only ever contain indeterminate_value
|
||||
auto text = CSH->si->campState->scenario(idOfMapAndRegion).regionText;
|
||||
if(!graphicsNotSelected->getSurface()->isTransparent(GH.getCursorPosition() - pos.topLeft()) && text.size())
|
||||
if(!graphicsNotSelected->getSurface()->isTransparent(cursorPosition - pos.topLeft()) && text.size())
|
||||
{
|
||||
CRClickPopup::createAndPush(text);
|
||||
}
|
||||
|
@ -47,8 +47,8 @@ public:
|
||||
public:
|
||||
CRegion(CampaignScenarioID id, bool accessible, bool selectable, const CampaignRegions & campDsc);
|
||||
void updateState();
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
};
|
||||
|
||||
void createBonusesIcons();
|
||||
|
@ -36,10 +36,10 @@ CSavingScreen::CSavingScreen()
|
||||
localMi->mapHeader = std::unique_ptr<CMapHeader>(new CMapHeader(*LOCPLINT->cb->getMapHeader()));
|
||||
|
||||
tabSel = std::make_shared<SelectionTab>(screenType);
|
||||
curTab = tabSel;
|
||||
tabSel->toggleMode();
|
||||
|
||||
tabSel->callOnSelect = std::bind(&CSavingScreen::changeSelection, this, _1);
|
||||
tabSel->toggleMode();
|
||||
curTab = tabSel;
|
||||
|
||||
buttonStart = std::make_shared<CButton>(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], std::bind(&CSavingScreen::saveGame, this), EShortcut::LOBBY_SAVE_GAME);
|
||||
}
|
||||
|
||||
@ -62,6 +62,7 @@ void CSavingScreen::changeSelection(std::shared_ptr<CMapInfo> to)
|
||||
|
||||
localMi = to;
|
||||
card->changeSelection();
|
||||
card->redraw();
|
||||
}
|
||||
|
||||
void CSavingScreen::saveGame()
|
||||
|
@ -115,7 +115,7 @@ InfoCard::InfoCard()
|
||||
: showChat(true)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
CIntObject::type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos.x += 393;
|
||||
pos.y += 6;
|
||||
|
||||
@ -310,8 +310,7 @@ CChatBox::CChatBox(const Rect & rect)
|
||||
{
|
||||
OBJ_CONSTRUCTION;
|
||||
pos += rect.topLeft();
|
||||
captureAllKeys = true;
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
|
||||
const int height = static_cast<int>(graphics->fonts[FONT_SMALL]->getLineHeight());
|
||||
inputBox = std::make_shared<CTextInput>(Rect(0, rect.h - height, rect.w, height), EFonts::FONT_SMALL, 0);
|
||||
@ -378,7 +377,7 @@ void CFlagBox::recreate()
|
||||
}
|
||||
}
|
||||
|
||||
void CFlagBox::showPopupWindow()
|
||||
void CFlagBox::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(SEL->getMapInfo())
|
||||
GH.windows().createAndPushWindow<CFlagBoxTooltipBox>(iconsTeamFlags);
|
||||
|
@ -135,7 +135,7 @@ class CFlagBox : public CIntObject
|
||||
public:
|
||||
CFlagBox(const Rect & rect);
|
||||
void recreate();
|
||||
void showPopupWindow() override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void showTeamsPopup();
|
||||
|
||||
class CFlagBoxTooltipBox : public CWindowObject
|
||||
|
@ -432,7 +432,7 @@ void OptionsTab::SelectedBox::update()
|
||||
subtitle->setText(getName());
|
||||
}
|
||||
|
||||
void OptionsTab::SelectedBox::showPopupWindow()
|
||||
void OptionsTab::SelectedBox::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
// cases when we do not need to display a message
|
||||
if(settings.castle == -2 && CPlayerSettingsHelper::type == TOWN)
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
std::shared_ptr<CLabel> subtitle;
|
||||
|
||||
SelectedBox(Point position, PlayerSettings & settings, SelType type);
|
||||
void showPopupWindow() override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void scrollBy(int distance) override;
|
||||
|
||||
void update();
|
||||
|
@ -370,7 +370,7 @@ TemplatesDropBox::ListItem::ListItem(const JsonNode & config, TemplatesDropBox &
|
||||
pos.w = w->pos.w;
|
||||
pos.h = w->pos.h;
|
||||
}
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::updateItem(int idx, const CRmgTemplate * _item)
|
||||
@ -406,18 +406,17 @@ void TemplatesDropBox::ListItem::hover(bool on)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::clickLeft(tribool down, bool previousState)
|
||||
void TemplatesDropBox::ListItem::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down && isHovered())
|
||||
{
|
||||
if(isHovered())
|
||||
dropBox.setTemplate(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
dropBox.clickLeft(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplatesDropBox::ListItem::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
dropBox.clickPressed(cursorPosition);
|
||||
dropBox.clickReleased(cursorPosition);
|
||||
}
|
||||
|
||||
TemplatesDropBox::TemplatesDropBox(RandomMapTab & randomMapTab, int3 size):
|
||||
InterfaceObjectConfigurable(LCLICK | HOVER),
|
||||
@ -471,9 +470,17 @@ void TemplatesDropBox::sliderMove(int slidPos)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void TemplatesDropBox::clickLeft(tribool down, bool previousState)
|
||||
bool TemplatesDropBox::receiveEvent(const Point & position, int eventType) const
|
||||
{
|
||||
if (!pos.isInside(GH.getCursorPosition()))
|
||||
if (eventType == LCLICK)
|
||||
return true; // we want drop box to close when clicking outside drop box borders
|
||||
|
||||
return CIntObject::receiveEvent(position, eventType);
|
||||
}
|
||||
|
||||
void TemplatesDropBox::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if (!pos.isInside(cursorPosition))
|
||||
{
|
||||
assert(GH.windows().isTopWindow(this));
|
||||
GH.windows().popWindows(1);
|
||||
|
@ -62,7 +62,8 @@ class TemplatesDropBox : public InterfaceObjectConfigurable
|
||||
void updateItem(int index, const CRmgTemplate * item = nullptr);
|
||||
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
};
|
||||
|
||||
friend struct ListItem;
|
||||
@ -70,7 +71,8 @@ class TemplatesDropBox : public InterfaceObjectConfigurable
|
||||
public:
|
||||
TemplatesDropBox(RandomMapTab & randomMapTab, int3 size);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void setTemplate(const CRmgTemplate *);
|
||||
|
||||
private:
|
||||
|
@ -179,7 +179,7 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
|
||||
break;
|
||||
case ESelectionScreen::campaignList:
|
||||
tabTitle = CGI->generaltexth->allTexts[726];
|
||||
type |= REDRAW_PARENT; // we use parent background so we need to make sure it's will be redrawn too
|
||||
setRedrawParent(true); // we use parent background so we need to make sure it's will be redrawn too
|
||||
pos.w = parent->pos.w;
|
||||
pos.h = parent->pos.h;
|
||||
pos.x += 3;
|
||||
@ -270,22 +270,20 @@ void SelectionTab::toggleMode()
|
||||
redraw();
|
||||
}
|
||||
|
||||
void SelectionTab::clickLeft(tribool down, bool previousState)
|
||||
void SelectionTab::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
int line = getLine();
|
||||
int line = getLine();
|
||||
|
||||
if(line != -1)
|
||||
{
|
||||
select(line);
|
||||
}
|
||||
#ifdef VCMI_IOS
|
||||
// focus input field if clicked inside it
|
||||
else if(inputName && inputName->isActive() && inputNameRect.isInside(GH.getCursorPosition()))
|
||||
inputName->giveFocus();
|
||||
#endif
|
||||
if(line != -1)
|
||||
{
|
||||
select(line);
|
||||
}
|
||||
#ifdef VCMI_IOS
|
||||
// focus input field if clicked inside it
|
||||
else if(inputName && inputName->isActive() && inputNameRect.isInside(cursorPosition))
|
||||
inputName->giveFocus();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void SelectionTab::keyPressed(EShortcut key)
|
||||
@ -317,12 +315,12 @@ void SelectionTab::keyPressed(EShortcut key)
|
||||
select((int)selectionPos - slider->getValue() + moveBy);
|
||||
}
|
||||
|
||||
void SelectionTab::clickDouble()
|
||||
void SelectionTab::clickDouble(const Point & cursorPosition)
|
||||
{
|
||||
if(getLine() != -1) //double clicked scenarios list
|
||||
{
|
||||
(static_cast<CLobbyScreen *>(parent))->buttonStart->clickLeft(true, false);
|
||||
(static_cast<CLobbyScreen *>(parent))->buttonStart->clickLeft(false, true);
|
||||
(static_cast<CLobbyScreen *>(parent))->buttonStart->clickPressed(cursorPosition);
|
||||
(static_cast<CLobbyScreen *>(parent))->buttonStart->clickReleased(cursorPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,7 +417,9 @@ void SelectionTab::select(int position)
|
||||
auto filename = *CResourceHandler::get("local")->getResourceName(ResourceID(curItems[py]->fileURI, EResType::CLIENT_SAVEGAME));
|
||||
inputName->setText(filename.stem().string());
|
||||
}
|
||||
|
||||
updateListItems();
|
||||
redraw();
|
||||
if(callOnSelect)
|
||||
callOnSelect(curItems[py]);
|
||||
}
|
||||
@ -457,10 +457,21 @@ void SelectionTab::updateListItems()
|
||||
}
|
||||
}
|
||||
|
||||
int SelectionTab::getLine()
|
||||
bool SelectionTab::receiveEvent(const Point & position, int eventType) const
|
||||
{
|
||||
// FIXME: widget should instead have well-defined pos so events will be filtered using standard routine
|
||||
return getLine(position - pos.topLeft()) != -1;
|
||||
}
|
||||
|
||||
int SelectionTab::getLine() const
|
||||
{
|
||||
Point clickPos = GH.getCursorPosition() - pos.topLeft();
|
||||
return getLine(clickPos);
|
||||
}
|
||||
|
||||
int SelectionTab::getLine(const Point & clickPos) const
|
||||
{
|
||||
int line = -1;
|
||||
Point clickPos = GH.getCursorPosition() - pos.topLeft();
|
||||
|
||||
// Ignore clicks on save name area
|
||||
int maxPosY;
|
||||
|
@ -65,10 +65,10 @@ public:
|
||||
SelectionTab(ESelectionScreen Type);
|
||||
void toggleMode();
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void keyPressed(EShortcut key) override;
|
||||
|
||||
void clickDouble() override;
|
||||
void clickDouble(const Point & cursorPosition) override;
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
|
||||
void filter(int size, bool selectFirst = false); //0 - all
|
||||
void sortBy(int criteria);
|
||||
@ -77,7 +77,8 @@ public:
|
||||
void selectAbs(int position); //position: absolute position in curItems vector
|
||||
void sliderMove(int slidPos);
|
||||
void updateListItems();
|
||||
int getLine();
|
||||
int getLine() const;
|
||||
int getLine(const Point & position) const;
|
||||
void selectFileName(std::string fname);
|
||||
std::shared_ptr<CMapInfo> getSelectedMapInfo() const;
|
||||
void rememberCurrentSelection();
|
||||
|
@ -141,13 +141,10 @@ void CCampaignScreen::CCampaignButton::show(Canvas & to)
|
||||
}
|
||||
}
|
||||
|
||||
void CCampaignScreen::CCampaignButton::clickLeft(tribool down, bool previousState)
|
||||
void CCampaignScreen::CCampaignButton::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
CCS->videoh->close();
|
||||
CMainMenu::openCampaignLobby(campFile);
|
||||
}
|
||||
CCS->videoh->close();
|
||||
CMainMenu::openCampaignLobby(campFile);
|
||||
}
|
||||
|
||||
void CCampaignScreen::CCampaignButton::hover(bool on)
|
||||
|
@ -40,7 +40,7 @@ private:
|
||||
std::string video; // the resource name of the video
|
||||
std::string hoverText;
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
|
||||
public:
|
||||
|
@ -95,7 +95,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
|
||||
menuNameToEntry.push_back("credits");
|
||||
|
||||
tabs = std::make_shared<CTabbedInt>(std::bind(&CMenuScreen::createTab, this, _1));
|
||||
tabs->type |= REDRAW_PARENT;
|
||||
tabs->setRedrawParent(true);
|
||||
}
|
||||
|
||||
std::shared_ptr<CIntObject> CMenuScreen::createTab(size_t index)
|
||||
@ -248,7 +248,7 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
|
||||
CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos = parent->pos;
|
||||
|
||||
for(const JsonNode & node : config["images"].Vector())
|
||||
@ -258,7 +258,7 @@ CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
|
||||
{
|
||||
buttons.push_back(createButton(parent, node));
|
||||
buttons.back()->hoverable = true;
|
||||
buttons.back()->type |= REDRAW_PARENT;
|
||||
buttons.back()->setRedrawParent(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,10 +52,10 @@ void CPrologEpilogVideo::show(Canvas & to)
|
||||
text->showAll(to); // blit text over video, if needed
|
||||
|
||||
if(text->textSize.y + 100 < positionCounter / 5)
|
||||
clickLeft(false, false);
|
||||
clickPressed(GH.getCursorPosition());
|
||||
}
|
||||
|
||||
void CPrologEpilogVideo::clickLeft(tribool down, bool previousState)
|
||||
void CPrologEpilogVideo::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
close();
|
||||
CCS->soundh->stopSound(voiceSoundHandle);
|
||||
|
@ -26,6 +26,6 @@ class CPrologEpilogVideo : public CWindowObject
|
||||
public:
|
||||
CPrologEpilogVideo(CampaignScenarioPrologEpilog _spe, std::function<void()> callback);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void show(Canvas & to) override;
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ CreditsScreen::CreditsScreen(Rect rect)
|
||||
{
|
||||
pos.w = rect.w;
|
||||
pos.h = rect.h;
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
auto textFile = CResourceHandler::get()->load(ResourceID("DATA/CREDITS.TXT"))->readAll();
|
||||
std::string text((char *)textFile.first.get(), textFile.second);
|
||||
@ -43,10 +43,10 @@ void CreditsScreen::show(Canvas & to)
|
||||
|
||||
//end of credits, close this screen
|
||||
if(credits->textSize.y + 600 < positionCounter / 2)
|
||||
clickLeft(false, false);
|
||||
clickPressed(GH.getCursorPosition());
|
||||
}
|
||||
|
||||
void CreditsScreen::clickLeft(tribool down, bool previousState)
|
||||
void CreditsScreen::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
CTabbedInt * menu = dynamic_cast<CTabbedInt *>(parent);
|
||||
assert(menu);
|
||||
|
@ -21,5 +21,5 @@ class CreditsScreen : public CIntObject
|
||||
public:
|
||||
CreditsScreen(Rect rect);
|
||||
void show(Canvas & to) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
};
|
||||
|
@ -145,16 +145,8 @@ void MapRendererTerrain::renderTile(IMapRendererContext & context, Canvas & targ
|
||||
|
||||
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex);
|
||||
|
||||
if(mapTile.terType->getId() == ETerrainId::LAVA)
|
||||
{
|
||||
image->shiftPalette(246, 9, context.terrainImageIndex(9));
|
||||
}
|
||||
|
||||
if(mapTile.terType->getId() == ETerrainId::WATER)
|
||||
{
|
||||
image->shiftPalette(229, 12, context.terrainImageIndex(12));
|
||||
image->shiftPalette(242, 14, context.terrainImageIndex(14));
|
||||
}
|
||||
for( auto const & element : mapTile.terType->paletteAnimation)
|
||||
image->shiftPalette(element.start, element.length, context.terrainImageIndex(element.length));
|
||||
|
||||
target.draw(image, Point(0, 0));
|
||||
}
|
||||
@ -163,7 +155,7 @@ uint8_t MapRendererTerrain::checksum(IMapRendererContext & context, const int3 &
|
||||
{
|
||||
const TerrainTile & mapTile = context.getMapTile(coordinates);
|
||||
|
||||
if(mapTile.terType->getId() == ETerrainId::LAVA || mapTile.terType->getId() == ETerrainId::WATER)
|
||||
if(!mapTile.terType->paletteAnimation.empty())
|
||||
return context.terrainImageIndex(250);
|
||||
return 0xff - 1;
|
||||
}
|
||||
@ -188,23 +180,8 @@ void MapRendererRiver::renderTile(IMapRendererContext & context, Canvas & target
|
||||
|
||||
const auto & image = storage.find(terrainIndex, rotationIndex, imageIndex);
|
||||
|
||||
if(mapTile.riverType->getId() == River::WATER_RIVER)
|
||||
{
|
||||
image->shiftPalette(183, 12, context.terrainImageIndex(12));
|
||||
image->shiftPalette(195, 6, context.terrainImageIndex(6));
|
||||
}
|
||||
|
||||
if(mapTile.riverType->getId() == River::MUD_RIVER)
|
||||
{
|
||||
image->shiftPalette(228, 12, context.terrainImageIndex(12));
|
||||
image->shiftPalette(183, 6, context.terrainImageIndex(6));
|
||||
image->shiftPalette(240, 6, context.terrainImageIndex(6));
|
||||
}
|
||||
|
||||
if(mapTile.riverType->getId() == River::LAVA_RIVER)
|
||||
{
|
||||
image->shiftPalette(240, 9, context.terrainImageIndex(9));
|
||||
}
|
||||
for( auto const & element : mapTile.riverType->paletteAnimation)
|
||||
image->shiftPalette(element.start, element.length, context.terrainImageIndex(element.length));
|
||||
|
||||
target.draw(image, Point(0, 0));
|
||||
}
|
||||
@ -213,9 +190,7 @@ uint8_t MapRendererRiver::checksum(IMapRendererContext & context, const int3 & c
|
||||
{
|
||||
const TerrainTile & mapTile = context.getMapTile(coordinates);
|
||||
|
||||
if(mapTile.riverType->getId() == River::WATER_RIVER ||
|
||||
mapTile.riverType->getId() == River::MUD_RIVER ||
|
||||
mapTile.riverType->getId() == River::LAVA_RIVER)
|
||||
if(!mapTile.riverType->paletteAnimation.empty())
|
||||
return context.terrainImageIndex(250);
|
||||
return 0xff-1;
|
||||
}
|
||||
|
@ -90,7 +90,6 @@ void MapView::show(Canvas & to)
|
||||
|
||||
MapView::MapView(const Point & offset, const Point & dimensions)
|
||||
: BasicMapView(offset, dimensions)
|
||||
, isSwiping(false)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
actions = std::make_shared<MapViewActions>(*this, model);
|
||||
@ -110,21 +109,15 @@ void MapView::onMapLevelSwitched()
|
||||
|
||||
void MapView::onMapScrolled(const Point & distance)
|
||||
{
|
||||
if(!isSwiping)
|
||||
if(!isGesturing())
|
||||
controller->setViewCenter(model->getMapViewCenter() + distance, model->getLevel());
|
||||
}
|
||||
|
||||
void MapView::onMapSwiped(const Point & viewPosition)
|
||||
{
|
||||
isSwiping = true;
|
||||
controller->setViewCenter(model->getMapViewCenter() + viewPosition, model->getLevel());
|
||||
}
|
||||
|
||||
void MapView::onMapSwipeEnded()
|
||||
{
|
||||
isSwiping = false;
|
||||
}
|
||||
|
||||
void MapView::onCenteredTile(const int3 & tile)
|
||||
{
|
||||
controller->setViewCenter(tile);
|
||||
|
@ -48,8 +48,6 @@ class MapView : public BasicMapView
|
||||
{
|
||||
std::shared_ptr<MapViewActions> actions;
|
||||
|
||||
bool isSwiping;
|
||||
|
||||
public:
|
||||
void show(Canvas & to) override;
|
||||
|
||||
@ -64,9 +62,6 @@ public:
|
||||
/// Moves current view to specified position, in pixels
|
||||
void onMapSwiped(const Point & viewPosition);
|
||||
|
||||
/// Ends swiping mode and allows normal map scrolling once again
|
||||
void onMapSwipeEnded();
|
||||
|
||||
/// Moves current view to specified tile
|
||||
void onCenteredTile(const int3 & tile);
|
||||
|
||||
|
@ -41,23 +41,17 @@ void MapViewActions::setContext(const std::shared_ptr<IMapRendererContext> & con
|
||||
this->context = context;
|
||||
}
|
||||
|
||||
void MapViewActions::clickLeft(tribool down, bool previousState)
|
||||
void MapViewActions::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(indeterminate(down))
|
||||
return;
|
||||
|
||||
if(down == false)
|
||||
return;
|
||||
|
||||
int3 tile = model->getTileAtPoint(GH.getCursorPosition() - pos.topLeft());
|
||||
int3 tile = model->getTileAtPoint(cursorPosition - pos.topLeft());
|
||||
|
||||
if(context->isInMap(tile))
|
||||
adventureInt->onTileLeftClicked(tile);
|
||||
}
|
||||
|
||||
void MapViewActions::showPopupWindow()
|
||||
void MapViewActions::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
int3 tile = model->getTileAtPoint(GH.getCursorPosition() - pos.topLeft());
|
||||
int3 tile = model->getTileAtPoint(cursorPosition - pos.topLeft());
|
||||
|
||||
if(context->isInMap(tile))
|
||||
adventureInt->onTileRightClicked(tile);
|
||||
|
@ -31,8 +31,8 @@ public:
|
||||
|
||||
void setContext(const std::shared_ptr<IMapRendererContext> & context);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void gesturePinch(const Point & centerPosition, double lastUpdateFactor) override;
|
||||
void hover(bool on) override;
|
||||
|
@ -185,9 +185,16 @@ void MapViewController::tick(uint32_t timeDelta)
|
||||
fadingInContext->progress = std::min( 1.0, fadingInContext->progress);
|
||||
}
|
||||
|
||||
if (adventureContext)
|
||||
adventureContext->animationTime += timeDelta;
|
||||
|
||||
updateState();
|
||||
}
|
||||
|
||||
void MapViewController::updateState()
|
||||
{
|
||||
if(adventureContext)
|
||||
{
|
||||
adventureContext->animationTime += timeDelta;
|
||||
adventureContext->settingsSessionSpectate = settings["session"]["spectate"].Bool();
|
||||
adventureContext->settingsAdventureObjectAnimation = settings["adventure"]["objectAnimation"].Bool();
|
||||
adventureContext->settingsAdventureTerrainAnimation = settings["adventure"]["terrainAnimation"].Bool();
|
||||
@ -511,6 +518,7 @@ void MapViewController::activateAdventureContext(uint32_t animationTime)
|
||||
adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
|
||||
adventureContext->animationTime = animationTime;
|
||||
context = adventureContext;
|
||||
updateState();
|
||||
}
|
||||
|
||||
void MapViewController::activateAdventureContext()
|
||||
|
@ -74,6 +74,7 @@ private:
|
||||
void onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
|
||||
|
||||
void resetContext();
|
||||
void updateState();
|
||||
|
||||
public:
|
||||
MapViewController(std::shared_ptr<MapViewModel> model, std::shared_ptr<MapViewCache> view);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class Point;
|
||||
class Rect;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class IScreenHandler
|
||||
@ -33,4 +34,7 @@ public:
|
||||
|
||||
/// Returns <min, max> range of possible values for screen scaling percentage
|
||||
virtual std::tuple<int, int> getSupportedScalingRange() const = 0;
|
||||
|
||||
/// Converts provided rect from logical coordinates into coordinates within window, accounting for scaling and viewport
|
||||
virtual Rect convertLogicalPointsToWindow(const Rect & input) const = 0;
|
||||
};
|
||||
|
@ -22,10 +22,14 @@
|
||||
#include "../lib/CAndroidVMHelper.h"
|
||||
#endif
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
# include "ios/utils.h"
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
// TODO: should be made into a private members of ScreenHandler
|
||||
SDL_Window * mainWindow = nullptr;
|
||||
static SDL_Window * mainWindow = nullptr;
|
||||
SDL_Renderer * mainRenderer = nullptr;
|
||||
SDL_Texture * screenTexture = nullptr;
|
||||
SDL_Surface * screen = nullptr; //main screen surface
|
||||
@ -42,28 +46,70 @@ std::tuple<int, int> ScreenHandler::getSupportedScalingRange() const
|
||||
// arbitrary limit on *downscaling*. Allow some downscaling, if requested by user. Should be generally limited to 100+ for all but few devices
|
||||
static const double minimalScaling = 50;
|
||||
|
||||
Point renderResolution = getPreferredRenderingResolution();
|
||||
double maximalScalingWidth = 100.0 * renderResolution.x / minResolution.x;
|
||||
double maximalScalingHeight = 100.0 * renderResolution.y / minResolution.y;
|
||||
Point renderResolution = getActualRenderResolution();
|
||||
double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
|
||||
Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
|
||||
|
||||
double maximalScalingWidth = 100.0 * availableResolution.x / minResolution.x;
|
||||
double maximalScalingHeight = 100.0 * availableResolution.y / minResolution.y;
|
||||
double maximalScaling = std::min(maximalScalingWidth, maximalScalingHeight);
|
||||
|
||||
return { minimalScaling, maximalScaling };
|
||||
}
|
||||
|
||||
Rect ScreenHandler::convertLogicalPointsToWindow(const Rect & input) const
|
||||
{
|
||||
Rect result;
|
||||
|
||||
// FIXME: use SDL_RenderLogicalToWindow instead? Needs to be tested on ios
|
||||
|
||||
float scaleX, scaleY;
|
||||
SDL_Rect viewport;
|
||||
SDL_RenderGetScale(mainRenderer, &scaleX, &scaleY);
|
||||
SDL_RenderGetViewport(mainRenderer, &viewport);
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
// TODO ios: looks like SDL bug actually, try fixing there
|
||||
const auto nativeScale = iOS_utils::screenScale();
|
||||
scaleX /= nativeScale;
|
||||
scaleY /= nativeScale;
|
||||
#endif
|
||||
|
||||
result.x = (viewport.x + input.x) * scaleX;
|
||||
result.y = (viewport.y + input.y) * scaleY;
|
||||
result.w = input.w * scaleX;
|
||||
result.h = input.h * scaleY;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Point ScreenHandler::getPreferredLogicalResolution() const
|
||||
{
|
||||
Point renderResolution = getPreferredRenderingResolution();
|
||||
Point renderResolution = getActualRenderResolution();
|
||||
double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
|
||||
Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
|
||||
|
||||
auto [minimalScaling, maximalScaling] = getSupportedScalingRange();
|
||||
|
||||
int userScaling = settings["video"]["resolution"]["scaling"].Integer();
|
||||
int scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
|
||||
|
||||
Point logicalResolution = renderResolution * 100.0 / scaling;
|
||||
Point logicalResolution = availableResolution * 100.0 / scaling;
|
||||
|
||||
return logicalResolution;
|
||||
}
|
||||
|
||||
Point ScreenHandler::getPreferredRenderingResolution() const
|
||||
Point ScreenHandler::getActualRenderResolution() const
|
||||
{
|
||||
assert(mainRenderer != nullptr);
|
||||
|
||||
Point result;
|
||||
SDL_GetRendererOutputSize(mainRenderer, &result.x, &result.y);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Point ScreenHandler::getPreferredWindowResolution() const
|
||||
{
|
||||
if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED)
|
||||
{
|
||||
@ -178,11 +224,14 @@ void ScreenHandler::updateWindowState()
|
||||
{
|
||||
case EWindowMode::FULLSCREEN_EXCLUSIVE:
|
||||
{
|
||||
// for some reason, VCMI fails to switch from FULLSCREEN_BORDERLESS_WINDOWED to FULLSCREEN_EXCLUSIVE directly
|
||||
// Switch to windowed mode first to avoid this bug
|
||||
SDL_SetWindowFullscreen(mainWindow, 0);
|
||||
SDL_SetWindowFullscreen(mainWindow, SDL_WINDOW_FULLSCREEN);
|
||||
|
||||
SDL_DisplayMode mode;
|
||||
SDL_GetDesktopDisplayMode(displayIndex, &mode);
|
||||
Point resolution = getPreferredRenderingResolution();
|
||||
Point resolution = getPreferredWindowResolution();
|
||||
|
||||
mode.w = resolution.x;
|
||||
mode.h = resolution.y;
|
||||
@ -200,7 +249,7 @@ void ScreenHandler::updateWindowState()
|
||||
}
|
||||
case EWindowMode::WINDOWED:
|
||||
{
|
||||
Point resolution = getPreferredRenderingResolution();
|
||||
Point resolution = getPreferredWindowResolution();
|
||||
SDL_SetWindowFullscreen(mainWindow, 0);
|
||||
SDL_SetWindowSize(mainWindow, resolution.x, resolution.y);
|
||||
SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex));
|
||||
@ -290,7 +339,7 @@ SDL_Window * ScreenHandler::createWindowImpl(Point dimensions, int flags, bool c
|
||||
SDL_Window * ScreenHandler::createWindow()
|
||||
{
|
||||
#ifndef VCMI_MOBILE
|
||||
Point dimensions = getPreferredRenderingResolution();
|
||||
Point dimensions = getPreferredWindowResolution();
|
||||
|
||||
switch(getPreferredWindowMode())
|
||||
{
|
||||
@ -350,7 +399,7 @@ void ScreenHandler::validateSettings()
|
||||
{
|
||||
//we only check that our desired window size fits on screen
|
||||
int displayIndex = getPreferredDisplayIndex();
|
||||
Point resolution = getPreferredRenderingResolution();
|
||||
Point resolution = getPreferredWindowResolution();
|
||||
|
||||
SDL_DisplayMode mode;
|
||||
|
||||
@ -368,7 +417,7 @@ void ScreenHandler::validateSettings()
|
||||
if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_EXCLUSIVE)
|
||||
{
|
||||
auto legalOptions = getSupportedResolutions();
|
||||
Point selectedResolution = getPreferredRenderingResolution();
|
||||
Point selectedResolution = getPreferredWindowResolution();
|
||||
|
||||
if(!vstd::contains(legalOptions, selectedResolution))
|
||||
{
|
||||
@ -476,7 +525,7 @@ void ScreenHandler::clearScreen()
|
||||
|
||||
std::vector<Point> ScreenHandler::getSupportedResolutions() const
|
||||
{
|
||||
int displayID = SDL_GetWindowDisplayIndex(mainWindow);
|
||||
int displayID = getPreferredDisplayIndex();
|
||||
return getSupportedResolutions(displayID);
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,17 @@ enum class EWindowMode
|
||||
};
|
||||
|
||||
/// This class is responsible for management of game window and its main rendering surface
|
||||
class ScreenHandler : public IScreenHandler
|
||||
class ScreenHandler final : public IScreenHandler
|
||||
{
|
||||
/// Dimensions of target surfaces/textures, this value is what game logic views as screen size
|
||||
Point getPreferredLogicalResolution() const;
|
||||
|
||||
/// Dimensions of output window, if different from logicalResolution SDL will perform scaling
|
||||
/// This value is what player views as window size
|
||||
Point getPreferredRenderingResolution() const;
|
||||
Point getPreferredWindowResolution() const;
|
||||
|
||||
/// Dimensions of render output, usually same as window size except for high-DPI screens on macOS / iOS
|
||||
Point getActualRenderResolution() const;
|
||||
|
||||
EWindowMode getPreferredWindowMode() const;
|
||||
|
||||
@ -86,4 +89,5 @@ public:
|
||||
std::vector<Point> getSupportedResolutions() const final;
|
||||
std::vector<Point> getSupportedResolutions(int displayIndex) const;
|
||||
std::tuple<int, int> getSupportedScalingRange() const final;
|
||||
Rect convertLogicalPointsToWindow(const Rect & input) const final;
|
||||
};
|
||||
|
@ -167,39 +167,48 @@ void CButton::onButtonClicked()
|
||||
callback();
|
||||
}
|
||||
|
||||
void CButton::clickLeft(tribool down, bool previousState)
|
||||
void CButton::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
if (down)
|
||||
if (getState() != PRESSED)
|
||||
{
|
||||
if (getState() != PRESSED)
|
||||
{
|
||||
if (!soundDisabled)
|
||||
CCS->soundh->playSound(soundBase::button);
|
||||
setState(PRESSED);
|
||||
if (!soundDisabled)
|
||||
CCS->soundh->playSound(soundBase::button);
|
||||
setState(PRESSED);
|
||||
|
||||
if (actOnDown)
|
||||
onButtonClicked();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getState() == PRESSED)
|
||||
{
|
||||
if(hoverable && isHovered())
|
||||
setState(HIGHLIGHTED);
|
||||
else
|
||||
setState(NORMAL);
|
||||
|
||||
if (!actOnDown && previousState && (down == false))
|
||||
onButtonClicked();
|
||||
}
|
||||
if (actOnDown)
|
||||
onButtonClicked();
|
||||
}
|
||||
}
|
||||
|
||||
void CButton::showPopupWindow()
|
||||
void CButton::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
if (getState() == PRESSED)
|
||||
{
|
||||
if(hoverable && isHovered())
|
||||
setState(HIGHLIGHTED);
|
||||
else
|
||||
setState(NORMAL);
|
||||
|
||||
if (!actOnDown)
|
||||
onButtonClicked();
|
||||
}
|
||||
}
|
||||
|
||||
void CButton::clickCancel(const Point & cursorPosition)
|
||||
{
|
||||
if (getState() == PRESSED)
|
||||
{
|
||||
if(hoverable && isHovered())
|
||||
setState(HIGHLIGHTED);
|
||||
else
|
||||
setState(NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void CButton::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(helpBox.size()) //there is no point to show window with nothing inside...
|
||||
CRClickPopup::createAndPush(helpBox);
|
||||
@ -331,11 +340,16 @@ void CToggleBase::setEnabled(bool enabled)
|
||||
// for overrides
|
||||
}
|
||||
|
||||
void CToggleBase::setSelectedSilent(bool on)
|
||||
{
|
||||
selected = on;
|
||||
doSelect(on);
|
||||
}
|
||||
|
||||
void CToggleBase::setSelected(bool on)
|
||||
{
|
||||
bool changed = (on != selected);
|
||||
selected = on;
|
||||
doSelect(on);
|
||||
setSelectedSilent(on);
|
||||
if (changed)
|
||||
callback(on);
|
||||
}
|
||||
@ -377,7 +391,7 @@ void CToggleButton::setEnabled(bool enabled)
|
||||
setState(enabled ? NORMAL : BLOCKED);
|
||||
}
|
||||
|
||||
void CToggleButton::clickLeft(tribool down, bool previousState)
|
||||
void CToggleButton::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
// force refresh
|
||||
hover(false);
|
||||
@ -386,22 +400,41 @@ void CToggleButton::clickLeft(tribool down, bool previousState)
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
if (down && canActivate())
|
||||
if (canActivate())
|
||||
{
|
||||
CCS->soundh->playSound(soundBase::button);
|
||||
setState(PRESSED);
|
||||
}
|
||||
}
|
||||
|
||||
if(previousState)//mouse up
|
||||
void CToggleButton::clickReleased(const Point & cursorPosition)
|
||||
{
|
||||
// force refresh
|
||||
hover(false);
|
||||
hover(true);
|
||||
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
if (getState() == PRESSED && canActivate())
|
||||
{
|
||||
if(down == false && getState() == PRESSED && canActivate())
|
||||
{
|
||||
onButtonClicked();
|
||||
setSelected(!selected);
|
||||
}
|
||||
else
|
||||
doSelect(selected); // restore
|
||||
onButtonClicked();
|
||||
setSelected(!selected);
|
||||
}
|
||||
else
|
||||
doSelect(selected); // restore
|
||||
}
|
||||
|
||||
void CToggleButton::clickCancel(const Point & cursorPosition)
|
||||
{
|
||||
// force refresh
|
||||
hover(false);
|
||||
hover(true);
|
||||
|
||||
if(isBlocked())
|
||||
return;
|
||||
|
||||
doSelect(selected);
|
||||
}
|
||||
|
||||
void CToggleGroup::addCallback(std::function<void(int)> callback)
|
||||
|
@ -102,8 +102,10 @@ public:
|
||||
void setPlayerColor(PlayerColor player);
|
||||
|
||||
/// CIntObject overrides
|
||||
void showPopupWindow() override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void clickCancel(const Point & cursorPosition) override;
|
||||
void hover (bool on) override;
|
||||
void showAll(Canvas & to) override;
|
||||
|
||||
@ -136,6 +138,9 @@ public:
|
||||
/// Changes selection to "on", and calls callback
|
||||
void setSelected(bool on);
|
||||
|
||||
/// Changes selection to "on" without calling callback
|
||||
void setSelectedSilent(bool on);
|
||||
|
||||
void addCallback(std::function<void(bool)> callback);
|
||||
|
||||
/// Set whether the toggle is currently enabled for user to use, this is only inplemented in ToggleButton, not for other toggles yet.
|
||||
@ -151,7 +156,10 @@ class CToggleButton : public CButton, public CToggleBase
|
||||
public:
|
||||
CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
|
||||
CFunctionList<void(bool)> Callback = 0, EShortcut key = {}, bool playerColoredButton = false );
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void clickReleased(const Point & cursorPosition) override;
|
||||
void clickCancel(const Point & cursorPosition) override;
|
||||
|
||||
// bring overrides into scope
|
||||
//using CButton::addCallback;
|
||||
|
@ -67,11 +67,6 @@ CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art)
|
||||
pos.w = pos.h = 44;
|
||||
}
|
||||
|
||||
void CArtPlace::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
LRClickableAreaWTextComp::clickLeft(down, previousState);
|
||||
}
|
||||
|
||||
const CArtifactInstance * CArtPlace::getArt()
|
||||
{
|
||||
return ourArt;
|
||||
@ -121,16 +116,16 @@ void CCommanderArtPlace::returnArtToHeroCallback()
|
||||
}
|
||||
}
|
||||
|
||||
void CCommanderArtPlace::clickLeft(tribool down, bool previousState)
|
||||
void CCommanderArtPlace::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(ourArt && text.size() && down)
|
||||
if(ourArt && text.size())
|
||||
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.commanderWindow.artifactMessage"), [this]() { returnArtToHeroCallback(); }, []() {});
|
||||
}
|
||||
|
||||
void CCommanderArtPlace::showPopupWindow()
|
||||
void CCommanderArtPlace::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(ourArt && text.size())
|
||||
CArtPlace::showPopupWindow();
|
||||
CArtPlace::showPopupWindow(cursorPosition);
|
||||
}
|
||||
|
||||
void CCommanderArtPlace::setArtifact(const CArtifactInstance * art)
|
||||
@ -183,16 +178,13 @@ bool CHeroArtPlace::isMarked() const
|
||||
return marked;
|
||||
}
|
||||
|
||||
void CHeroArtPlace::clickLeft(tribool down, bool previousState)
|
||||
void CHeroArtPlace::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down || !previousState)
|
||||
return;
|
||||
|
||||
if(leftClickCallback)
|
||||
leftClickCallback(*this);
|
||||
}
|
||||
|
||||
void CHeroArtPlace::showPopupWindow()
|
||||
void CHeroArtPlace::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(rightClickCallback)
|
||||
rightClickCallback(*this);
|
||||
@ -236,11 +228,11 @@ void CHeroArtPlace::addCombinedArtInfo(std::map<const CArtifact*, int> & arts)
|
||||
text += "{" + combinedArt.first->getNameTranslated() + "}";
|
||||
if(arts.size() == 1)
|
||||
{
|
||||
for(const auto part : *combinedArt.first->constituents)
|
||||
for(const auto part : combinedArt.first->getConstituents())
|
||||
artList += "\n" + part->getNameTranslated();
|
||||
}
|
||||
text += " (" + boost::str(boost::format("%d") % combinedArt.second) + " / " +
|
||||
boost::str(boost::format("%d") % combinedArt.first->constituents->size()) + ")" + artList;
|
||||
boost::str(boost::format("%d") % combinedArt.first->getConstituents().size()) + ")" + artList;
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,9 +282,9 @@ bool ArtifactUtilsClient::askToDisassemble(const CGHeroInstance * hero, const Ar
|
||||
const auto art = hero->getArt(slot);
|
||||
assert(art);
|
||||
|
||||
if(art->canBeDisassembled())
|
||||
if(art->isCombined())
|
||||
{
|
||||
if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->constituents->size() - 1))
|
||||
if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->getConstituents().size() - 1))
|
||||
return false;
|
||||
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
|
@ -41,7 +41,6 @@ protected:
|
||||
|
||||
public:
|
||||
CArtPlace(Point position, const CArtifactInstance * Art = nullptr);
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
const CArtifactInstance * getArt();
|
||||
|
||||
virtual void setArtifact(const CArtifactInstance * art)=0;
|
||||
@ -58,8 +57,8 @@ protected:
|
||||
|
||||
public:
|
||||
CCommanderArtPlace(Point position, const CGHeroInstance * commanderOwner, ArtifactPosition artSlot, const CArtifactInstance * Art = nullptr);
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void setArtifact(const CArtifactInstance * art) override;
|
||||
};
|
||||
|
||||
@ -77,8 +76,8 @@ public:
|
||||
bool isLocked();
|
||||
void selectSlot(bool on);
|
||||
bool isMarked() const;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void showAll(Canvas & to) override;
|
||||
void setArtifact(const CArtifactInstance * art) override;
|
||||
void addCombinedArtInfo(std::map<const CArtifact*, int> & arts);
|
||||
|
@ -98,13 +98,10 @@ void CArtifactsOfHeroAltar::deleteFromVisible(const CArtifactInstance * artInst)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(artInst->canBeDisassembled())
|
||||
for(const auto & part : artInst->getPartsInfo())
|
||||
{
|
||||
for(const auto & part : dynamic_cast<const CCombinedArtifactInstance*>(artInst)->constituentsInfo)
|
||||
{
|
||||
if(part.slot != ArtifactPosition::PRE_FIRST)
|
||||
getArtPlace(part.slot)->setArtifact(nullptr);
|
||||
}
|
||||
if(part.slot != ArtifactPosition::PRE_FIRST)
|
||||
getArtPlace(part.slot)->setArtifact(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
@ -257,14 +257,14 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit
|
||||
{
|
||||
artPlace->lockSlot(slotInfo->locked);
|
||||
artPlace->setArtifact(slotInfo->artifact);
|
||||
if(!slotInfo->artifact->canBeDisassembled())
|
||||
if(!slotInfo->artifact->isCombined())
|
||||
{
|
||||
// If the artifact is part of at least one combined artifact, add additional information
|
||||
std::map<const CArtifact*, int> arts;
|
||||
for(const auto combinedArt : slotInfo->artifact->artType->constituentOf)
|
||||
for(const auto combinedArt : slotInfo->artifact->artType->getPartOf())
|
||||
{
|
||||
arts.insert(std::pair(combinedArt, 0));
|
||||
for(const auto part : *combinedArt->constituents)
|
||||
for(const auto part : combinedArt->getConstituents())
|
||||
if(artSet.hasArt(part->getId(), true))
|
||||
arts.at(combinedArt)++;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/NetPacksBase.h"
|
||||
#include "../../lib/CArtHandler.h"
|
||||
#include "../../lib/CArtifactInstance.h"
|
||||
|
||||
CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize, EFonts font):
|
||||
perDay(false)
|
||||
@ -169,16 +170,12 @@ std::string CComponent::getDescription()
|
||||
case artifact:
|
||||
{
|
||||
auto artID = ArtifactID(subtype);
|
||||
std::unique_ptr<CArtifactInstance> art;
|
||||
if (artID != ArtifactID::SPELL_SCROLL)
|
||||
auto description = VLC->arth->objects[artID]->getDescriptionTranslated();
|
||||
if(artID == ArtifactID::SPELL_SCROLL)
|
||||
{
|
||||
art.reset(ArtifactUtils::createNewArtifactInstance(artID));
|
||||
ArtifactUtils::insertScrrollSpellName(description, SpellID(val));
|
||||
}
|
||||
else
|
||||
{
|
||||
art.reset(ArtifactUtils::createScroll(SpellID(val)));
|
||||
}
|
||||
return art->getDescription();
|
||||
return description;
|
||||
}
|
||||
case experience: return CGI->generaltexth->allTexts[241];
|
||||
case spell: return (*CGI->spellh)[subtype]->getDescriptionTranslated(val);
|
||||
@ -258,19 +255,16 @@ void CComponent::setSurface(std::string defName, int imgPos)
|
||||
image = std::make_shared<CAnimImage>(defName, imgPos);
|
||||
}
|
||||
|
||||
void CComponent::showPopupWindow()
|
||||
void CComponent::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(!getDescription().empty())
|
||||
CRClickPopup::createAndPush(getDescription());
|
||||
}
|
||||
|
||||
void CSelectableComponent::clickLeft(tribool down, bool previousState)
|
||||
void CSelectableComponent::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if (down)
|
||||
{
|
||||
if(onSelect)
|
||||
onSelect();
|
||||
}
|
||||
if(onSelect)
|
||||
onSelect();
|
||||
}
|
||||
|
||||
void CSelectableComponent::init()
|
||||
@ -281,7 +275,7 @@ void CSelectableComponent::init()
|
||||
CSelectableComponent::CSelectableComponent(const Component &c, std::function<void()> OnSelect):
|
||||
CComponent(c),onSelect(OnSelect)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
init();
|
||||
}
|
||||
@ -289,7 +283,7 @@ CSelectableComponent::CSelectableComponent(const Component &c, std::function<voi
|
||||
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
|
||||
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
init();
|
||||
}
|
||||
@ -466,7 +460,7 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CComponent>> _component
|
||||
betweenRows(betweenRows),
|
||||
componentsInRow(componentsInRow)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos = position + pos.topLeft();
|
||||
placeComponents(false);
|
||||
}
|
||||
@ -484,7 +478,7 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>>
|
||||
betweenRows(betweenRows),
|
||||
componentsInRow(componentsInRow)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos = position + pos.topLeft();
|
||||
placeComponents(true);
|
||||
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large, EFonts font = FONT_SMALL);
|
||||
CComponent(const Component &c, ESize imageSize=large, EFonts font = FONT_SMALL);
|
||||
|
||||
void showPopupWindow() override; //call-in
|
||||
void showPopupWindow(const Point & cursorPosition) override; //call-in
|
||||
};
|
||||
|
||||
/// component that can be selected or deselected
|
||||
@ -79,7 +79,7 @@ public:
|
||||
void showAll(Canvas & to) override;
|
||||
void select(bool on);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override; //call-in
|
||||
void clickPressed(const Point & cursorPosition) override; //call-in
|
||||
CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr);
|
||||
CSelectableComponent(const Component & c, std::function<void()> OnSelect = nullptr);
|
||||
};
|
||||
|
@ -285,7 +285,7 @@ bool CGarrisonSlot::mustForceReselection() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGarrisonSlot::showPopupWindow()
|
||||
void CGarrisonSlot::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(creature)
|
||||
{
|
||||
@ -293,10 +293,8 @@ void CGarrisonSlot::showPopupWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void CGarrisonSlot::clickLeft(tribool down, bool previousState)
|
||||
void CGarrisonSlot::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
{
|
||||
bool refr = false;
|
||||
const CGarrisonSlot * selection = owner->getSelection();
|
||||
|
||||
@ -349,7 +347,6 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
|
||||
hover(false);
|
||||
hover(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGarrisonSlot::update()
|
||||
|
@ -58,8 +58,8 @@ public:
|
||||
bool our() const;
|
||||
SlotID getSlot() const { return ID; }
|
||||
bool ally() const;
|
||||
void showPopupWindow() override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void update();
|
||||
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, EGarrisonType Upg=EGarrisonType::UP, const CStackInstance * creature_ = nullptr);
|
||||
|
||||
|
@ -200,7 +200,7 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
|
||||
return;
|
||||
}
|
||||
if(artPlace.text.size())
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow();
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(GH.getCursorPosition());
|
||||
}
|
||||
}
|
||||
// Altar window, Market window right click handler
|
||||
@ -209,7 +209,7 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMarket>>)
|
||||
{
|
||||
if(artPlace.getArt() && artPlace.text.size())
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow();
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(GH.getCursorPosition());
|
||||
}
|
||||
}, artSetWeak.value());
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ CreatureCostBox::CreatureCostBox(Rect position, std::string titleText)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos = position + pos.topLeft();
|
||||
|
||||
title = std::make_shared<CLabel>(pos.w/2, 10, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, titleText);
|
||||
|
@ -50,14 +50,12 @@ CHoverableArea::~CHoverableArea()
|
||||
{
|
||||
}
|
||||
|
||||
void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
|
||||
void LRClickableAreaWText::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(!down && previousState && !text.empty())
|
||||
{
|
||||
if(!text.empty())
|
||||
LOCPLINT->showInfoDialog(text);
|
||||
}
|
||||
}
|
||||
void LRClickableAreaWText::showPopupWindow()
|
||||
void LRClickableAreaWText::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if (!text.empty())
|
||||
CRClickPopup::createAndPush(text);
|
||||
@ -85,13 +83,10 @@ void LRClickableAreaWText::init()
|
||||
addUsedEvents(LCLICK | SHOW_POPUP | HOVER);
|
||||
}
|
||||
|
||||
void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
|
||||
void LRClickableAreaWTextComp::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if((!down) && previousState)
|
||||
{
|
||||
std::vector<std::shared_ptr<CComponent>> comp(1, createComponent());
|
||||
LOCPLINT->showInfoDialog(text, comp);
|
||||
}
|
||||
std::vector<std::shared_ptr<CComponent>> comp(1, createComponent());
|
||||
LOCPLINT->showInfoDialog(text, comp);
|
||||
}
|
||||
|
||||
LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType)
|
||||
@ -108,7 +103,7 @@ std::shared_ptr<CComponent> LRClickableAreaWTextComp::createComponent() const
|
||||
return std::shared_ptr<CComponent>();
|
||||
}
|
||||
|
||||
void LRClickableAreaWTextComp::showPopupWindow()
|
||||
void LRClickableAreaWTextComp::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(auto comp = createComponent())
|
||||
{
|
||||
@ -116,7 +111,7 @@ void LRClickableAreaWTextComp::showPopupWindow()
|
||||
return;
|
||||
}
|
||||
|
||||
LRClickableAreaWText::showPopupWindow(); //only if with-component variant not occurred
|
||||
LRClickableAreaWText::showPopupWindow(cursorPosition); //only if with-component variant not occurred
|
||||
}
|
||||
|
||||
CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero)
|
||||
@ -134,9 +129,9 @@ CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero)
|
||||
portrait = std::make_shared<CAnimImage>("PortraitsLarge", hero->portrait);
|
||||
}
|
||||
|
||||
void CHeroArea::clickLeft(tribool down, bool previousState)
|
||||
void CHeroArea::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(hero && (!down) && previousState)
|
||||
if(hero)
|
||||
LOCPLINT->openHeroWindow(hero);
|
||||
}
|
||||
|
||||
@ -148,9 +143,9 @@ void CHeroArea::hover(bool on)
|
||||
GH.statusbar()->clear();
|
||||
}
|
||||
|
||||
void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
|
||||
void LRClickableAreaOpenTown::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(town && (!down) && previousState)
|
||||
if(town)
|
||||
{
|
||||
LOCPLINT->openTownWindow(town);
|
||||
if ( type == 2 )
|
||||
|
@ -48,8 +48,8 @@ public:
|
||||
virtual ~LRClickableAreaWText();
|
||||
void init();
|
||||
|
||||
virtual void clickLeft(tribool down, bool previousState) override;
|
||||
virtual void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
};
|
||||
|
||||
/// base class for hero/town/garrison tooltips
|
||||
@ -135,7 +135,7 @@ class CHeroArea: public CIntObject
|
||||
public:
|
||||
CHeroArea(int x, int y, const CGHeroInstance * _hero);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
};
|
||||
|
||||
@ -143,10 +143,11 @@ public:
|
||||
class LRClickableAreaWTextComp: public LRClickableAreaWText
|
||||
{
|
||||
public:
|
||||
int type;
|
||||
int baseType;
|
||||
int bonusValue;
|
||||
virtual void clickLeft(tribool down, bool previousState) override;
|
||||
virtual void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
|
||||
LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
|
||||
std::shared_ptr<CComponent> createComponent() const;
|
||||
@ -157,7 +158,7 @@ class LRClickableAreaOpenTown: public LRClickableAreaWTextComp
|
||||
{
|
||||
public:
|
||||
const CGTownInstance * town;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
LRClickableAreaOpenTown(const Rect & Pos, const CGTownInstance * Town);
|
||||
};
|
||||
|
||||
|
@ -138,6 +138,9 @@ void CListBox::reset()
|
||||
|
||||
void CListBox::resize(size_t newSize)
|
||||
{
|
||||
if (totalSize == newSize)
|
||||
return;
|
||||
|
||||
totalSize = newSize;
|
||||
if (slider)
|
||||
slider->setAmount((int)totalSize);
|
||||
|
@ -121,24 +121,28 @@ void CSlider::scrollTo(int to)
|
||||
moved(to);
|
||||
}
|
||||
|
||||
void CSlider::clickLeft(tribool down, bool previousState)
|
||||
void CSlider::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down && !slider->isBlocked())
|
||||
if(!slider->isBlocked())
|
||||
{
|
||||
double pw = 0;
|
||||
double rw = 0;
|
||||
if(getOrientation() == Orientation::HORIZONTAL)
|
||||
{
|
||||
pw = GH.getCursorPosition().x-pos.x-25;
|
||||
pw = cursorPosition.x-pos.x-25;
|
||||
rw = pw / static_cast<double>(pos.w - 48);
|
||||
}
|
||||
else
|
||||
{
|
||||
pw = GH.getCursorPosition().y-pos.y-24;
|
||||
pw = cursorPosition.y-pos.y-24;
|
||||
rw = pw / (pos.h-48);
|
||||
}
|
||||
|
||||
slider->clickLeft(true, slider->isMouseLeftButtonPressed());
|
||||
// click on area covered by buttons -> ignore, will be handled by left/right buttons
|
||||
if (!vstd::iswithin(rw, 0, 1))
|
||||
return;
|
||||
|
||||
slider->clickPressed(cursorPosition);
|
||||
scrollTo((int)(rw * positions + 0.5));
|
||||
return;
|
||||
}
|
||||
@ -214,6 +218,10 @@ CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int
|
||||
pos.h = totalw;
|
||||
}
|
||||
|
||||
// for horizontal sliders that act as values selection - add keyboard event to receive left/right click
|
||||
if (getOrientation() == Orientation::HORIZONTAL)
|
||||
addUsedEvents(KEYBOARD);
|
||||
|
||||
updateSliderPos();
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
void keyPressed(EShortcut key) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
void showAll(Canvas & to) override;
|
||||
|
@ -47,7 +47,7 @@ void CLabel::showAll(Canvas & to)
|
||||
CLabel::CLabel(int x, int y, EFonts Font, ETextAlignment Align, const SDL_Color & Color, const std::string & Text)
|
||||
: CTextContainer(Align, Font, Color), text(Text)
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
autoRedraw = true;
|
||||
pos.x += x;
|
||||
pos.y += y;
|
||||
@ -299,7 +299,7 @@ CTextBox::CTextBox(std::string Text, const Rect & rect, int SliderStyle, EFonts
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
|
||||
label = std::make_shared<CMultiLineLabel>(rect, Font, Align, Color);
|
||||
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos.x += rect.x;
|
||||
pos.y += rect.y;
|
||||
pos.h = rect.h;
|
||||
@ -446,13 +446,10 @@ void CGStatusBar::show(Canvas & to)
|
||||
showAll(to);
|
||||
}
|
||||
|
||||
void CGStatusBar::clickLeft(tribool down, bool previousState)
|
||||
void CGStatusBar::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(!down)
|
||||
{
|
||||
if(LOCPLINT && LOCPLINT->cingconsole->isActive())
|
||||
LOCPLINT->cingconsole->startEnteringText();
|
||||
}
|
||||
if(LOCPLINT && LOCPLINT->cingconsole->isActive())
|
||||
LOCPLINT->cingconsole->startEnteringText();
|
||||
}
|
||||
|
||||
void CGStatusBar::activate()
|
||||
@ -492,10 +489,9 @@ CTextInput::CTextInput(const Rect & Pos, EFonts font, const CFunctionList<void(c
|
||||
cb(CB),
|
||||
CFocusable(std::make_shared<CKeyboardFocusListener>(this))
|
||||
{
|
||||
type |= REDRAW_PARENT;
|
||||
setRedrawParent(true);
|
||||
pos.h = Pos.h;
|
||||
pos.w = Pos.w;
|
||||
captureAllKeys = true;
|
||||
background.reset();
|
||||
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||
|
||||
@ -511,7 +507,6 @@ CTextInput::CTextInput(const Rect & Pos, const Point & bgOffset, const std::stri
|
||||
pos.h = Pos.h;
|
||||
pos.w = Pos.w;
|
||||
|
||||
captureAllKeys = true;
|
||||
OBJ_CONSTRUCTION;
|
||||
background = std::make_shared<CPicture>(bgName, bgOffset.x, bgOffset.y);
|
||||
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||
@ -525,7 +520,6 @@ CTextInput::CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf)
|
||||
:CFocusable(std::make_shared<CKeyboardFocusListener>(this))
|
||||
{
|
||||
pos += Pos.topLeft();
|
||||
captureAllKeys = true;
|
||||
OBJ_CONSTRUCTION;
|
||||
background = std::make_shared<CPicture>(srf, Pos);
|
||||
pos.w = background->pos.w;
|
||||
@ -564,9 +558,9 @@ std::string CTextInput::visibleText()
|
||||
return focus ? text + newText + "_" : text;
|
||||
}
|
||||
|
||||
void CTextInput::clickLeft(tribool down, bool previousState)
|
||||
void CTextInput::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down && !focus)
|
||||
if(!focus)
|
||||
giveFocus();
|
||||
}
|
||||
|
||||
@ -620,17 +614,6 @@ void CTextInput::setText(const std::string & nText, bool callCb)
|
||||
cb(text);
|
||||
}
|
||||
|
||||
bool CTextInput::captureThisKey(EShortcut key)
|
||||
{
|
||||
if(key == EShortcut::GLOBAL_RETURN)
|
||||
return false;
|
||||
|
||||
if (!focus)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTextInput::textInputed(const std::string & enteredText)
|
||||
{
|
||||
if(!focus)
|
||||
|
@ -138,7 +138,7 @@ class CGStatusBar : public CLabel, public std::enable_shared_from_this<CGStatusB
|
||||
protected:
|
||||
Point getBorderSize() override;
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
|
||||
public:
|
||||
~CGStatusBar();
|
||||
@ -224,10 +224,10 @@ public:
|
||||
CTextInput(const Rect & Pos, const Point & bgOffset, const std::string & bgName, const CFunctionList<void(const std::string &)> & CB);
|
||||
CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf);
|
||||
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void keyPressed(EShortcut key) override;
|
||||
|
||||
bool captureThisKey(EShortcut key) override;
|
||||
//bool captureThisKey(EShortcut key) override;
|
||||
|
||||
void textInputed(const std::string & enteredText) override;
|
||||
void textEdited(const std::string & enteredText) override;
|
||||
|
@ -134,16 +134,16 @@ void CBuildingRect::hover(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
void CBuildingRect::clickLeft(tribool down, bool previousState)
|
||||
void CBuildingRect::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(previousState && getBuilding() && area && !down && (parent->selectedBuilding==this))
|
||||
if(getBuilding() && area && (parent->selectedBuilding==this))
|
||||
{
|
||||
auto building = getBuilding();
|
||||
parent->buildingClicked(building->bid, building->subId, building->upgrade);
|
||||
}
|
||||
}
|
||||
|
||||
void CBuildingRect::showPopupWindow()
|
||||
void CBuildingRect::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if((!area) || (this!=parent->selectedBuilding) || getBuilding() == nullptr)
|
||||
return;
|
||||
@ -377,37 +377,35 @@ void CHeroGSlot::hover(bool on)
|
||||
GH.statusbar()->write(temp);
|
||||
}
|
||||
|
||||
void CHeroGSlot::clickLeft(tribool down, bool previousState)
|
||||
void CHeroGSlot::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
std::shared_ptr<CHeroGSlot> other = upg ? owner->garrisonedHero : owner->visitingHero;
|
||||
if(!down)
|
||||
|
||||
owner->garr->setSplittingMode(false);
|
||||
owner->garr->selectSlot(nullptr);
|
||||
|
||||
if(hero && isSelected())
|
||||
{
|
||||
owner->garr->setSplittingMode(false);
|
||||
owner->garr->selectSlot(nullptr);
|
||||
|
||||
if(hero && isSelected())
|
||||
{
|
||||
setHighlight(false);
|
||||
LOCPLINT->openHeroWindow(hero);
|
||||
}
|
||||
else if(other->hero && other->isSelected())
|
||||
{
|
||||
owner->swapArmies();
|
||||
}
|
||||
else if(hero)
|
||||
{
|
||||
setHighlight(true);
|
||||
owner->garr->selectSlot(nullptr);
|
||||
redraw();
|
||||
}
|
||||
|
||||
//refresh statusbar
|
||||
hover(false);
|
||||
hover(true);
|
||||
setHighlight(false);
|
||||
LOCPLINT->openHeroWindow(hero);
|
||||
}
|
||||
else if(other->hero && other->isSelected())
|
||||
{
|
||||
owner->swapArmies();
|
||||
}
|
||||
else if(hero)
|
||||
{
|
||||
setHighlight(true);
|
||||
owner->garr->selectSlot(nullptr);
|
||||
redraw();
|
||||
}
|
||||
|
||||
//refresh statusbar
|
||||
hover(false);
|
||||
hover(true);
|
||||
}
|
||||
|
||||
void CHeroGSlot::showPopupWindow()
|
||||
void CHeroGSlot::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(hero)
|
||||
{
|
||||
@ -800,7 +798,7 @@ void CCastleBuildings::enterBlacksmith(ArtifactID artifactID)
|
||||
bool possible = LOCPLINT->cb->getResourceAmount(EGameResID::GOLD) >= price;
|
||||
if(possible)
|
||||
{
|
||||
for(auto slot : art->possibleSlots.at(ArtBearer::HERO))
|
||||
for(auto slot : art->getPossibleSlots().at(ArtBearer::HERO))
|
||||
{
|
||||
if(hero->getArt(slot) == nullptr)
|
||||
{
|
||||
@ -1057,17 +1055,14 @@ void CCreaInfo::hover(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
void CCreaInfo::clickLeft(tribool down, bool previousState)
|
||||
void CCreaInfo::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(previousState && (!down))
|
||||
int offset = LOCPLINT->castleInt? (-87) : 0;
|
||||
auto recruitCb = [=](CreatureID id, int count)
|
||||
{
|
||||
int offset = LOCPLINT->castleInt? (-87) : 0;
|
||||
auto recruitCb = [=](CreatureID id, int count)
|
||||
{
|
||||
LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
|
||||
};
|
||||
GH.windows().createAndPushWindow<CRecruitmentWindow>(town, level, town, recruitCb, offset);
|
||||
}
|
||||
LOCPLINT->cb->recruitCreatures(town, town->getUpperArmy(), id, count, level);
|
||||
};
|
||||
GH.windows().createAndPushWindow<CRecruitmentWindow>(town, level, town, recruitCb, offset);
|
||||
}
|
||||
|
||||
std::string CCreaInfo::genGrowthText()
|
||||
@ -1081,7 +1076,7 @@ std::string CCreaInfo::genGrowthText()
|
||||
return descr;
|
||||
}
|
||||
|
||||
void CCreaInfo::showPopupWindow()
|
||||
void CCreaInfo::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if (showAvailable)
|
||||
GH.windows().createAndPushWindow<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
|
||||
@ -1133,7 +1128,7 @@ void CTownInfo::hover(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
void CTownInfo::showPopupWindow()
|
||||
void CTownInfo::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(building)
|
||||
{
|
||||
@ -1160,7 +1155,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
|
||||
updateShadow();
|
||||
|
||||
garr = std::make_shared<CGarrisonInt>(305, 387, 4, Point(0,96), town->getUpperArmy(), town->visitingHero);
|
||||
garr->type |= REDRAW_PARENT;
|
||||
garr->setRedrawParent(true);
|
||||
|
||||
heroes = std::make_shared<HeroSlots>(town, Point(241, 387), Point(241, 483), garr, true);
|
||||
title = std::make_shared<CLabel>(85, 387, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());
|
||||
@ -1379,13 +1374,12 @@ void CHallInterface::CBuildingBox::hover(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
void CHallInterface::CBuildingBox::clickLeft(tribool down, bool previousState)
|
||||
void CHallInterface::CBuildingBox::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(previousState && (!down))
|
||||
GH.windows().createAndPushWindow<CBuildWindow>(town,building,state,0);
|
||||
GH.windows().createAndPushWindow<CBuildWindow>(town,building,state,0);
|
||||
}
|
||||
|
||||
void CHallInterface::CBuildingBox::showPopupWindow()
|
||||
void CHallInterface::CBuildingBox::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
GH.windows().createAndPushWindow<CBuildWindow>(town,building,state,1);
|
||||
}
|
||||
@ -1740,10 +1734,9 @@ void CFortScreen::RecruitArea::creaturesChangedEventHandler()
|
||||
}
|
||||
}
|
||||
|
||||
void CFortScreen::RecruitArea::clickLeft(tribool down, bool previousState)
|
||||
void CFortScreen::RecruitArea::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(!down && previousState)
|
||||
LOCPLINT->castleInt->builds->enterDwelling(level);
|
||||
LOCPLINT->castleInt->builds->enterDwelling(level);
|
||||
}
|
||||
|
||||
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
|
||||
@ -1796,13 +1789,12 @@ CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell)
|
||||
pos = image->pos;
|
||||
}
|
||||
|
||||
void CMageGuildScreen::Scroll::clickLeft(tribool down, bool previousState)
|
||||
void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
|
||||
LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
|
||||
}
|
||||
|
||||
void CMageGuildScreen::Scroll::showPopupWindow()
|
||||
void CMageGuildScreen::Scroll::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
CRClickPopup::createAndPush(spell->getDescriptionTranslated(0), std::make_shared<CComponent>(CComponent::spell, spell->id));
|
||||
}
|
||||
|
@ -66,8 +66,8 @@ public:
|
||||
CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str);
|
||||
bool operator<(const CBuildingRect & p2) const;
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void mouseMoved (const Point & cursorPosition, const Point & lastUpdateDistance) override;
|
||||
bool receiveEvent(const Point & position, int eventType) const override;
|
||||
void tick(uint32_t msPassed) override;
|
||||
@ -112,8 +112,8 @@ public:
|
||||
void set(const CGHeroInstance * newHero);
|
||||
|
||||
void hover (bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void deactivate() override;
|
||||
};
|
||||
|
||||
@ -192,8 +192,8 @@ public:
|
||||
|
||||
void update();
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
bool getShowAvailable();
|
||||
};
|
||||
|
||||
@ -208,7 +208,7 @@ public:
|
||||
CTownInfo(int posX, int posY, const CGTownInstance * town, bool townHall);
|
||||
|
||||
void hover(bool on) override;
|
||||
void showPopupWindow() override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
};
|
||||
|
||||
/// Class which manages the castle window
|
||||
@ -274,8 +274,8 @@ class CHallInterface : public CStatusbarWindow
|
||||
public:
|
||||
CBuildingBox(int x, int y, const CGTownInstance * Town, const CBuilding * Building);
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
};
|
||||
const CGTownInstance * town;
|
||||
|
||||
@ -346,7 +346,7 @@ class CFortScreen : public CStatusbarWindow
|
||||
|
||||
void creaturesChangedEventHandler();
|
||||
void hover(bool on) override;
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
};
|
||||
std::shared_ptr<CLabel> title;
|
||||
std::vector<std::shared_ptr<RecruitArea>> recAreas;
|
||||
@ -371,8 +371,8 @@ class CMageGuildScreen : public CStatusbarWindow
|
||||
|
||||
public:
|
||||
Scroll(Point position, const CSpell *Spell);
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void showPopupWindow() override;
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
};
|
||||
std::shared_ptr<CPicture> window;
|
||||
|
@ -114,10 +114,9 @@ void CCommanderSkillIcon::setObject(std::shared_ptr<CIntObject> newObject)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CCommanderSkillIcon::clickLeft(tribool down, bool previousState)
|
||||
void CCommanderSkillIcon::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(down)
|
||||
callback();
|
||||
callback();
|
||||
}
|
||||
|
||||
static std::string skillToFile(int skill, int level, bool selected)
|
||||
@ -588,7 +587,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
auto art = parent->info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT);
|
||||
if(art)
|
||||
{
|
||||
parent->stackArtifactIcon = std::make_shared<CAnimImage>("ARTIFACT", art->artType->iconIndex, 0, pos.x, pos.y);
|
||||
parent->stackArtifactIcon = std::make_shared<CAnimImage>("ARTIFACT", art->artType->getIconIndex(), 0, pos.x, pos.y);
|
||||
parent->stackArtifactHelp = std::make_shared<LRClickableAreaWTextComp>(Rect(pos, Point(44, 44)), CComponent::artifact);
|
||||
parent->stackArtifactHelp->type = art->artType->getId();
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user