diff --git a/src/fheroes2/castle/buildinginfo.cpp b/src/fheroes2/castle/buildinginfo.cpp index c17e3f22c8..118319f95f 100644 --- a/src/fheroes2/castle/buildinginfo.cpp +++ b/src/fheroes2/castle/buildinginfo.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -34,7 +34,6 @@ #include "castle_building_info.h" #include "cursor.h" #include "dialog.h" -#include "game_hotkeys.h" #include "icn.h" #include "localevent.h" #include "m82.h" @@ -543,42 +542,21 @@ bool BuildingInfo::DialogBuyBuilding( bool buttons ) const return false; } - const bool isEvilInterface = Settings::Get().isEvilInterfaceEnabled(); - const int buttonOkayIcnID = isEvilInterface ? ICN::UNIFORM_EVIL_OKAY_BUTTON : ICN::UNIFORM_GOOD_OKAY_BUTTON; - - pos.x = dialogRoi.x; - pos.y = dialogRoi.y + dialogRoi.height - fheroes2::AGG::GetICN( buttonOkayIcnID, 0 ).height(); - - fheroes2::Button buttonOkay( pos.x, pos.y, buttonOkayIcnID, 0, 1 ); - - const int buttonCancelIcnID = isEvilInterface ? ICN::UNIFORM_EVIL_CANCEL_BUTTON : ICN::UNIFORM_GOOD_CANCEL_BUTTON; - - pos.x = dialogRoi.x + dialogRoi.width - fheroes2::AGG::GetICN( buttonCancelIcnID, 0 ).width(); - pos.y = dialogRoi.y + dialogRoi.height - fheroes2::AGG::GetICN( buttonCancelIcnID, 0 ).height(); - fheroes2::Button buttonCancel( pos.x, pos.y, buttonCancelIcnID, 0, 1 ); + fheroes2::ButtonGroup buttonGroup( dialogRoi, Dialog::OK | Dialog::CANCEL ); + fheroes2::ButtonBase & buttonOkay = buttonGroup.button( 0 ); + const fheroes2::ButtonBase & buttonCancel = buttonGroup.button( 1 ); if ( BuildingStatus::ALLOW_BUILD != castle.CheckBuyBuilding( _buildingType ) ) { buttonOkay.disable(); } - buttonOkay.draw(); - buttonCancel.draw(); - + buttonGroup.draw(); display.render(); while ( le.HandleEvents() ) { - if ( buttonOkay.isEnabled() ) { - buttonOkay.drawOnState( le.isMouseLeftButtonPressedInArea( buttonOkay.area() ) ); - } - - buttonCancel.drawOnState( le.isMouseLeftButtonPressedInArea( buttonCancel.area() ) ); - - if ( buttonOkay.isEnabled() && ( Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_OKAY ) || le.MouseClickLeft( buttonOkay.area() ) ) ) { - return true; - } - - if ( Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_CANCEL ) || le.MouseClickLeft( buttonCancel.area() ) ) { - break; + const int result = buttonGroup.processEvents(); + if ( result != Dialog::ZERO ) { + return result == Dialog::OK; } if ( le.isMouseRightButtonPressedInArea( buttonOkay.area() ) ) { diff --git a/src/fheroes2/castle/castle_town.cpp b/src/fheroes2/castle/castle_town.cpp index 80cbda65d8..2f43bff537 100644 --- a/src/fheroes2/castle/castle_town.cpp +++ b/src/fheroes2/castle/castle_town.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -126,38 +126,22 @@ int Castle::DialogBuyHero( const Heroes * hero ) const rbs.SetPos( dialogRoi.x, pos.y + heroDescriptionText.height( fheroes2::boxAreaWidthPx ) + spacer ); rbs.Redraw(); - const bool isEvilInterface = Settings::Get().isEvilInterfaceEnabled(); - const int okayButtonIcnID = isEvilInterface ? ICN::UNIFORM_EVIL_OKAY_BUTTON : ICN::UNIFORM_GOOD_OKAY_BUTTON; - - pos.y = dialogRoi.y + dialogRoi.height - fheroes2::AGG::GetICN( okayButtonIcnID, 0 ).height(); - fheroes2::Button buttonOkay( dialogRoi.x, pos.y, okayButtonIcnID, 0, 1 ); + fheroes2::ButtonGroup buttonGroup( dialogRoi, Dialog::OK | Dialog::CANCEL ); + fheroes2::ButtonBase & buttonOkay = buttonGroup.button( 0 ); + const fheroes2::ButtonBase & buttonCancel = buttonGroup.button( 1 ); if ( !AllowBuyHero() ) { buttonOkay.disable(); } - const int cancelButtonIcnID = isEvilInterface ? ICN::UNIFORM_EVIL_CANCEL_BUTTON : ICN::UNIFORM_GOOD_CANCEL_BUTTON; - - pos.x = dialogRoi.x + dialogRoi.width - fheroes2::AGG::GetICN( cancelButtonIcnID, 0 ).width(); - pos.y = dialogRoi.y + dialogRoi.height - fheroes2::AGG::GetICN( cancelButtonIcnID, 0 ).height(); - fheroes2::Button buttonCancel( pos.x, pos.y, cancelButtonIcnID, 0, 1 ); - - buttonOkay.draw(); - buttonCancel.draw(); - + buttonGroup.draw(); display.render(); LocalEvent & le = LocalEvent::Get(); while ( le.HandleEvents() ) { - buttonOkay.drawOnState( le.isMouseLeftButtonPressedInArea( buttonOkay.area() ) ); - buttonCancel.drawOnState( le.isMouseLeftButtonPressedInArea( buttonCancel.area() ) ); - - if ( buttonOkay.isEnabled() && ( le.MouseClickLeft( buttonOkay.area() ) || Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_OKAY ) ) ) { - return Dialog::OK; - } - - if ( le.MouseClickLeft( buttonCancel.area() ) || Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_CANCEL ) ) { - break; + const int result = buttonGroup.processEvents(); + if ( result != Dialog::ZERO ) { + return result; } if ( le.isMouseRightButtonPressedInArea( heroPortraitArea ) ) { diff --git a/src/fheroes2/dialog/dialog_buyboat.cpp b/src/fheroes2/dialog/dialog_buyboat.cpp index 54afe4e15d..160615f9bb 100644 --- a/src/fheroes2/dialog/dialog_buyboat.cpp +++ b/src/fheroes2/dialog/dialog_buyboat.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2019 - 2024 * + * Copyright (C) 2019 - 2025 * * * * Free Heroes2 Engine: http://sourceforge.net/projects/fheroes2 * * Copyright (C) 2009 by Andrey Afletdinov * @@ -24,7 +24,6 @@ #include "agg_image.h" #include "cursor.h" #include "dialog.h" // IWYU pragma: associated -#include "game_hotkeys.h" #include "icn.h" #include "image.h" #include "localevent.h" @@ -32,7 +31,6 @@ #include "payment.h" #include "resource.h" #include "screen.h" -#include "settings.h" #include "translations.h" #include "ui_button.h" #include "ui_text.h" @@ -41,8 +39,6 @@ int Dialog::BuyBoat( bool enable ) { fheroes2::Display & display = fheroes2::Display::instance(); - const bool isEvilInterface = Settings::Get().isEvilInterfaceEnabled(); - // setup cursor const CursorRestorer cursorRestorer( true, Cursor::POINTER ); @@ -71,43 +67,24 @@ int Dialog::BuyBoat( bool enable ) rbs.Redraw(); // buttons - const int buttonOkayICN = isEvilInterface ? ICN::UNIFORM_EVIL_OKAY_BUTTON : ICN::UNIFORM_GOOD_OKAY_BUTTON; - dst_pt.x = box_rt.x; - dst_pt.y = box_rt.y + box_rt.height - fheroes2::AGG::GetICN( buttonOkayICN, 0 ).height(); - fheroes2::Button buttonOkay( dst_pt.x, dst_pt.y, buttonOkayICN, 0, 1 ); - - const int buttonCancelICN = isEvilInterface ? ICN::UNIFORM_EVIL_CANCEL_BUTTON : ICN::UNIFORM_GOOD_CANCEL_BUTTON; - - dst_pt.x = box_rt.x + box_rt.width - fheroes2::AGG::GetICN( buttonCancelICN, 0 ).width(); - dst_pt.y = box_rt.y + box_rt.height - fheroes2::AGG::GetICN( buttonCancelICN, 0 ).height(); - fheroes2::Button buttonCancel( dst_pt.x, dst_pt.y, buttonCancelICN, 0, 1 ); + fheroes2::ButtonGroup buttonGroup( box_rt, Dialog::OK | Dialog::CANCEL ); + fheroes2::ButtonBase & buttonOkay = buttonGroup.button( 0 ); if ( !enable ) { buttonOkay.press(); buttonOkay.disable(); } - buttonOkay.draw(); - buttonCancel.draw(); - + buttonGroup.draw(); display.render(); LocalEvent & le = LocalEvent::Get(); // message loop while ( le.HandleEvents() ) { - if ( buttonOkay.isEnabled() ) { - buttonOkay.drawOnState( le.isMouseLeftButtonPressedInArea( buttonOkay.area() ) ); - } - - buttonCancel.drawOnState( le.isMouseLeftButtonPressedInArea( buttonCancel.area() ) ); - - if ( buttonOkay.isEnabled() && ( Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_OKAY ) || le.MouseClickLeft( buttonOkay.area() ) ) ) { - return Dialog::OK; - } - - if ( Game::HotKeyPressEvent( Game::HotKeyEvent::DEFAULT_CANCEL ) || le.MouseClickLeft( buttonCancel.area() ) ) { - return Dialog::CANCEL; + const int result = buttonGroup.processEvents(); + if ( result != Dialog::ZERO ) { + return result; } } diff --git a/src/fheroes2/gui/ui_button.cpp b/src/fheroes2/gui/ui_button.cpp index 887c600139..d2476b980a 100644 --- a/src/fheroes2/gui/ui_button.cpp +++ b/src/fheroes2/gui/ui_button.cpp @@ -1,6 +1,6 @@ /*************************************************************************** * fheroes2: https://github.com/ihhub/fheroes2 * - * Copyright (C) 2020 - 2024 * + * Copyright (C) 2020 - 2025 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -425,37 +425,58 @@ namespace fheroes2 Point offset; switch ( buttonTypes ) { - case Dialog::YES | Dialog::NO: - offset.x = area.x; - offset.y = area.y + area.height - AGG::GetICN( buttonYesIcnID, 0 ).height(); + case Dialog::YES | Dialog::NO: { + const Sprite & yesButtonSprite = AGG::GetICN( buttonYesIcnID, 0 ); + const Sprite & noButtonSprite = AGG::GetICN( buttonNoIcnID, 0 ); + + const int32_t horizontalFreeSpace = area.width - yesButtonSprite.width() - noButtonSprite.width(); + const int32_t padding = horizontalFreeSpace / 4; + assert( horizontalFreeSpace > 0 ); + + offset.x = area.x + padding; + offset.y = area.y + area.height - yesButtonSprite.height(); createButton( offset.x, offset.y, buttonYesIcnID, 0, 1, Dialog::YES ); - offset.x = area.x + area.width - AGG::GetICN( buttonNoIcnID, 0 ).width(); - offset.y = area.y + area.height - AGG::GetICN( buttonNoIcnID, 0 ).height(); + offset.x = area.x + area.width - noButtonSprite.width() - padding; + offset.y = area.y + area.height - noButtonSprite.height(); createButton( offset.x, offset.y, buttonNoIcnID, 0, 1, Dialog::NO ); break; + } - case Dialog::OK | Dialog::CANCEL: - offset.x = area.x; - offset.y = area.y + area.height - AGG::GetICN( buttonOkayIcnID, 0 ).height(); + case Dialog::OK | Dialog::CANCEL: { + const Sprite & okayButtonSprite = AGG::GetICN( buttonOkayIcnID, 0 ); + const Sprite & cancelButtonSprite = AGG::GetICN( buttonCancelIcnID, 0 ); + const int32_t horizontalFreeSpace = area.width - okayButtonSprite.width() - cancelButtonSprite.width(); + const int32_t padding = horizontalFreeSpace / 4; + assert( horizontalFreeSpace > 0 ); + + offset.x = area.x + padding; + offset.y = area.y + area.height - okayButtonSprite.height(); createButton( offset.x, offset.y, buttonOkayIcnID, 0, 1, Dialog::OK ); - offset.x = area.x + area.width - AGG::GetICN( buttonCancelIcnID, 0 ).width(); - offset.y = area.y + area.height - AGG::GetICN( buttonCancelIcnID, 0 ).height(); + offset.x = area.x + area.width - cancelButtonSprite.width() - padding; + offset.y = area.y + area.height - cancelButtonSprite.height(); createButton( offset.x, offset.y, buttonCancelIcnID, 0, 1, Dialog::CANCEL ); break; + } - case Dialog::OK: - offset.x = area.x + ( area.width - AGG::GetICN( buttonOkayIcnID, 0 ).width() ) / 2; - offset.y = area.y + area.height - AGG::GetICN( buttonOkayIcnID, 0 ).height(); + case Dialog::OK: { + const Sprite & okayButtonSprite = AGG::GetICN( buttonOkayIcnID, 0 ); + + offset.x = area.x + ( area.width - okayButtonSprite.width() ) / 2; + offset.y = area.y + area.height - okayButtonSprite.height(); createButton( offset.x, offset.y, buttonOkayIcnID, 0, 1, Dialog::OK ); break; + } - case Dialog::CANCEL: - offset.x = area.x + ( area.width - AGG::GetICN( buttonCancelIcnID, 0 ).width() ) / 2; - offset.y = area.y + area.height - AGG::GetICN( buttonCancelIcnID, 0 ).height(); + case Dialog::CANCEL: { + const Sprite & cancelButtonSprite = AGG::GetICN( buttonCancelIcnID, 0 ); + + offset.x = area.x + ( area.width - cancelButtonSprite.width() ) / 2; + offset.y = area.y + area.height - cancelButtonSprite.height(); createButton( offset.x, offset.y, buttonCancelIcnID, 0, 1, Dialog::CANCEL ); break; + } default: break;