2017-07-13 10:26:03 +02:00
/*
* InfoWindows . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2014-07-15 10:14:49 +03:00
# include "StdInc.h"
# include "InfoWindows.h"
2022-09-18 14:47:49 +02:00
# include "CAdvmapInterface.h"
2014-07-15 10:14:49 +03:00
# include "../CBitmapHandler.h"
# include "../Graphics.h"
# include "../CGameInfo.h"
# include "../CPlayerInterface.h"
# include "../CMessage.h"
# include "../CMusicHandler.h"
# include "../widgets/CComponent.h"
# include "../widgets/MiscWidgets.h"
# include "../gui/SDL_Pixels.h"
# include "../gui/SDL_Extensions.h"
# include "../gui/CGuiHandler.h"
# include "../gui/CCursorHandler.h"
# include "../battle/CBattleInterface.h"
# include "../battle/CBattleInterfaceClasses.h"
# include "../../CCallback.h"
# include "../../lib/CGameState.h"
# include "../../lib/CConfigHandler.h"
# include "../../lib/CondSh.h"
# include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
# include "../../lib/mapObjects/CGHeroInstance.h"
# include "../../lib/mapObjects/CGTownInstance.h"
# include "../../lib/mapObjects/MiscObjects.h"
void CSimpleWindow : : show ( SDL_Surface * to )
{
if ( bitmap )
blitAt ( bitmap , pos . x , pos . y , to ) ;
}
CSimpleWindow : : ~ CSimpleWindow ( )
{
if ( bitmap )
{
SDL_FreeSurface ( bitmap ) ;
bitmap = nullptr ;
}
}
void CSelWindow : : selectionChange ( unsigned to )
{
for ( unsigned i = 0 ; i < components . size ( ) ; i + + )
{
2018-04-07 13:34:11 +02:00
auto pom = std : : dynamic_pointer_cast < CSelectableComponent > ( components [ i ] ) ;
2014-07-15 10:14:49 +03:00
if ( ! pom )
continue ;
pom - > select ( i = = to ) ;
}
redraw ( ) ;
}
2018-04-07 13:34:11 +02:00
CSelWindow : : CSelWindow ( const std : : string & Text , PlayerColor player , int charperline , const std : : vector < std : : shared_ptr < CSelectableComponent > > & comps , const std : : vector < std : : pair < std : : string , CFunctionList < void ( ) > > > & Buttons , QueryID askID )
2014-07-15 10:14:49 +03:00
{
2018-04-07 13:34:11 +02:00
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
2014-07-15 10:14:49 +03:00
ID = askID ;
2014-09-05 21:13:58 +03:00
for ( int i = 0 ; i < Buttons . size ( ) ; i + + )
2014-07-15 10:14:49 +03:00
{
2018-04-07 13:34:11 +02:00
buttons . push_back ( std : : make_shared < CButton > ( Point ( 0 , 0 ) , Buttons [ i ] . first , CButton : : tooltip ( ) , Buttons [ i ] . second ) ) ;
2014-09-05 21:13:58 +03:00
if ( ! i & & askID . getNum ( ) > = 0 )
buttons . back ( ) - > addCallback ( std : : bind ( & CSelWindow : : madeChoice , this ) ) ;
buttons [ i ] - > addCallback ( std : : bind ( & CInfoWindow : : close , this ) ) ; //each button will close the window apart from call-defined actions
2014-07-15 10:14:49 +03:00
}
2018-04-07 13:34:11 +02:00
text = std : : make_shared < CTextBox > ( Text , Rect ( 0 , 0 , 250 , 100 ) , 0 , FONT_MEDIUM , CENTER , Colors : : WHITE ) ;
2014-07-15 10:14:49 +03:00
buttons . front ( ) - > assignedKeys . insert ( SDLK_RETURN ) ; //first button - reacts on enter
buttons . back ( ) - > assignedKeys . insert ( SDLK_ESCAPE ) ; //last button - reacts on escape
2014-09-05 21:13:58 +03:00
if ( buttons . size ( ) > 1 & & askID . getNum ( ) > = 0 ) //cancel button functionality
{
buttons . back ( ) - > addCallback ( [ askID ] ( ) {
LOCPLINT - > cb . get ( ) - > selectionMade ( 0 , askID ) ;
} ) ;
//buttons.back()->addCallback(std::bind(&CCallback::selectionMade, LOCPLINT->cb.get(), 0, askID));
}
2014-07-15 10:14:49 +03:00
for ( int i = 0 ; i < comps . size ( ) ; i + + )
{
2018-04-07 13:34:11 +02:00
comps [ i ] - > recActions = 255 - DISPOSE ;
addChild ( comps [ i ] . get ( ) ) ;
2014-07-15 10:14:49 +03:00
components . push_back ( comps [ i ] ) ;
2014-08-09 15:14:31 +03:00
comps [ i ] - > onSelect = std : : bind ( & CSelWindow : : selectionChange , this , i ) ;
2014-07-15 10:14:49 +03:00
if ( i < 9 )
comps [ i ] - > assignedKeys . insert ( SDLK_1 + i ) ;
}
CMessage : : drawIWindow ( this , Text , player ) ;
}
void CSelWindow : : madeChoice ( )
{
if ( ID . getNum ( ) < 0 )
return ;
int ret = - 1 ;
for ( int i = 0 ; i < components . size ( ) ; i + + )
{
2018-04-07 13:34:11 +02:00
if ( std : : dynamic_pointer_cast < CSelectableComponent > ( components [ i ] ) - > selected )
2014-07-15 10:14:49 +03:00
{
ret = i ;
}
}
LOCPLINT - > cb - > selectionMade ( ret + 1 , ID ) ;
}
2018-04-07 13:34:11 +02:00
CInfoWindow : : CInfoWindow ( std : : string Text , PlayerColor player , const TCompsInfo & comps , const TButtonsInfo & Buttons )
2014-07-15 10:14:49 +03:00
{
2018-04-07 13:34:11 +02:00
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
2014-07-15 10:14:49 +03:00
type | = BLOCK_ADV_HOTKEYS ;
ID = QueryID ( - 1 ) ;
for ( auto & Button : Buttons )
{
2018-04-07 13:34:11 +02:00
std : : shared_ptr < CButton > button = std : : make_shared < CButton > ( Point ( 0 , 0 ) , Button . first , CButton : : tooltip ( ) , std : : bind ( & CInfoWindow : : close , this ) ) ;
2018-03-17 06:23:22 +02:00
button - > setBorderColor ( Colors : : METALLIC_GOLD ) ;
2014-08-03 14:16:19 +03:00
button - > addCallback ( Button . second ) ; //each button will close the window apart from call-defined actions
2014-07-15 10:14:49 +03:00
buttons . push_back ( button ) ;
}
2018-04-07 13:34:11 +02:00
text = std : : make_shared < CTextBox > ( Text , Rect ( 0 , 0 , 250 , 100 ) , 0 , FONT_MEDIUM , CENTER , Colors : : WHITE ) ;
2014-07-15 10:14:49 +03:00
if ( ! text - > slider )
{
text - > resize ( text - > label - > textSize ) ;
}
if ( buttons . size ( ) )
{
buttons . front ( ) - > assignedKeys . insert ( SDLK_RETURN ) ; //first button - reacts on enter
buttons . back ( ) - > assignedKeys . insert ( SDLK_ESCAPE ) ; //last button - reacts on escape
}
for ( auto & comp : comps )
{
2018-04-07 13:34:11 +02:00
comp - > recActions = 0xff & ~ DISPOSE ;
addChild ( comp . get ( ) ) ;
2014-07-15 10:14:49 +03:00
comp - > recActions & = ~ ( SHOWALL | UPDATE ) ;
components . push_back ( comp ) ;
}
2018-04-07 13:34:11 +02:00
2014-07-15 10:14:49 +03:00
CMessage : : drawIWindow ( this , Text , player ) ;
}
CInfoWindow : : CInfoWindow ( )
{
ID = QueryID ( - 1 ) ;
}
void CInfoWindow : : close ( )
{
2018-07-25 00:36:48 +02:00
WindowBase : : close ( ) ;
2014-07-15 10:14:49 +03:00
if ( LOCPLINT )
LOCPLINT - > showingDialog - > setn ( false ) ;
}
void CInfoWindow : : show ( SDL_Surface * to )
{
CIntObject : : show ( to ) ;
}
2018-04-07 13:34:11 +02:00
CInfoWindow : : ~ CInfoWindow ( ) = default ;
2014-07-15 10:14:49 +03:00
void CInfoWindow : : showAll ( SDL_Surface * to )
{
CSimpleWindow : : show ( to ) ;
CIntObject : : showAll ( to ) ;
}
2018-04-07 13:34:11 +02:00
void CInfoWindow : : showInfoDialog ( const std : : string & text , const TCompsInfo & components , PlayerColor player )
2014-07-15 10:14:49 +03:00
{
2018-07-25 00:36:48 +02:00
GH . pushInt ( CInfoWindow : : create ( text , player , components ) ) ;
2014-07-15 10:14:49 +03:00
}
2018-04-07 13:34:11 +02:00
void CInfoWindow : : showYesNoDialog ( const std : : string & text , const TCompsInfo & components , const CFunctionList < void ( ) > & onYes , const CFunctionList < void ( ) > & onNo , PlayerColor player )
2014-07-15 10:14:49 +03:00
{
assert ( ! LOCPLINT | | LOCPLINT - > showingDialog - > get ( ) ) ;
std : : vector < std : : pair < std : : string , CFunctionList < void ( ) > > > pom ;
pom . push_back ( std : : pair < std : : string , CFunctionList < void ( ) > > ( " IOKAY.DEF " , 0 ) ) ;
pom . push_back ( std : : pair < std : : string , CFunctionList < void ( ) > > ( " ICANCEL.DEF " , 0 ) ) ;
2018-07-25 00:36:48 +02:00
std : : shared_ptr < CInfoWindow > temp = std : : make_shared < CInfoWindow > ( text , player , components , pom ) ;
2014-11-12 22:45:48 +02:00
temp - > buttons [ 0 ] - > addCallback ( onYes ) ;
temp - > buttons [ 1 ] - > addCallback ( onNo ) ;
2014-07-15 10:14:49 +03:00
GH . pushInt ( temp ) ;
}
2018-07-25 00:36:48 +02:00
std : : shared_ptr < CInfoWindow > CInfoWindow : : create ( const std : : string & text , PlayerColor playerID , const TCompsInfo & components )
2014-07-15 10:14:49 +03:00
{
std : : vector < std : : pair < std : : string , CFunctionList < void ( ) > > > pom ;
pom . push_back ( std : : pair < std : : string , CFunctionList < void ( ) > > ( " IOKAY.DEF " , 0 ) ) ;
2018-07-25 00:36:48 +02:00
return std : : make_shared < CInfoWindow > ( text , playerID , components , pom ) ;
2014-07-15 10:14:49 +03:00
}
std : : string CInfoWindow : : genText ( std : : string title , std : : string description )
{
return std : : string ( " { " ) + title + " } " + " \n \n " + description ;
}
CInfoPopup : : CInfoPopup ( SDL_Surface * Bitmap , int x , int y , bool Free )
: free ( Free ) , bitmap ( Bitmap )
{
init ( x , y ) ;
}
2017-07-15 13:08:20 +02:00
CInfoPopup : : CInfoPopup ( SDL_Surface * Bitmap , const Point & p , EAlignment alignment , bool Free )
2014-07-15 10:14:49 +03:00
: free ( Free ) , bitmap ( Bitmap )
{
switch ( alignment )
{
case BOTTOMRIGHT :
init ( p . x - Bitmap - > w , p . y - Bitmap - > h ) ;
break ;
case CENTER :
init ( p . x - Bitmap - > w / 2 , p . y - Bitmap - > h / 2 ) ;
break ;
case TOPLEFT :
init ( p . x , p . y ) ;
break ;
default :
assert ( 0 ) ; //not implemented
}
}
CInfoPopup : : CInfoPopup ( SDL_Surface * Bitmap , bool Free )
{
CCS - > curh - > hide ( ) ;
free = Free ;
bitmap = Bitmap ;
if ( bitmap )
{
pos . x = screen - > w / 2 - bitmap - > w / 2 ;
pos . y = screen - > h / 2 - bitmap - > h / 2 ;
pos . h = bitmap - > h ;
pos . w = bitmap - > w ;
}
}
void CInfoPopup : : close ( )
{
if ( free )
SDL_FreeSurface ( bitmap ) ;
2018-07-25 00:36:48 +02:00
WindowBase : : close ( ) ;
2014-07-15 10:14:49 +03:00
}
void CInfoPopup : : show ( SDL_Surface * to )
{
blitAt ( bitmap , pos . x , pos . y , to ) ;
}
CInfoPopup : : ~ CInfoPopup ( )
{
CCS - > curh - > show ( ) ;
}
void CInfoPopup : : init ( int x , int y )
{
CCS - > curh - > hide ( ) ;
pos . x = x ;
pos . y = y ;
pos . h = bitmap - > h ;
pos . w = bitmap - > w ;
// Put the window back on screen if necessary
vstd : : amax ( pos . x , 0 ) ;
vstd : : amax ( pos . y , 0 ) ;
vstd : : amin ( pos . x , screen - > w - bitmap - > w ) ;
vstd : : amin ( pos . y , screen - > h - bitmap - > h ) ;
}
void CRClickPopup : : clickRight ( tribool down , bool previousState )
{
if ( down )
return ;
close ( ) ;
}
void CRClickPopup : : close ( )
{
2018-07-25 00:36:48 +02:00
WindowBase : : close ( ) ;
2014-07-15 10:14:49 +03:00
}
void CRClickPopup : : createAndPush ( const std : : string & txt , const CInfoWindow : : TCompsInfo & comps )
{
PlayerColor player = LOCPLINT ? LOCPLINT - > playerID : PlayerColor ( 1 ) ; //if no player, then use blue
2017-06-03 07:25:10 +02:00
if ( settings [ " session " ] [ " spectate " ] . Bool ( ) ) //TODO: there must be better way to implement this
player = PlayerColor ( 1 ) ;
2014-07-15 10:14:49 +03:00
2018-07-25 00:36:48 +02:00
auto temp = std : : make_shared < CInfoWindow > ( txt , player , comps ) ;
2014-07-15 10:14:49 +03:00
temp - > center ( Point ( GH . current - > motion ) ) ; //center on mouse
2021-03-21 12:43:01 +02:00
# ifdef VCMI_IOS
// TODO: enable also for android?
temp - > moveBy ( { 0 , - temp - > pos . h / 2 } ) ;
# endif
2014-07-15 10:14:49 +03:00
temp - > fitToScreen ( 10 ) ;
2018-07-25 00:36:48 +02:00
GH . pushIntT < CRClickPopupInt > ( temp ) ;
2014-07-15 10:14:49 +03:00
}
2018-04-07 13:34:11 +02:00
void CRClickPopup : : createAndPush ( const std : : string & txt , std : : shared_ptr < CComponent > component )
2014-07-15 10:14:49 +03:00
{
CInfoWindow : : TCompsInfo intComps ;
intComps . push_back ( component ) ;
createAndPush ( txt , intComps ) ;
}
2018-07-25 00:36:48 +02:00
void CRClickPopup : : createAndPush ( const CGObjectInstance * obj , const Point & p , EAlignment alignment )
2014-07-15 10:14:49 +03:00
{
2018-07-25 00:36:48 +02:00
auto iWin = createInfoWin ( p , obj ) ; //try get custom infowindow for this obj
2014-07-15 10:14:49 +03:00
if ( iWin )
2018-07-25 00:36:48 +02:00
{
2014-07-15 10:14:49 +03:00
GH . pushInt ( iWin ) ;
2018-07-25 00:36:48 +02:00
}
2014-07-15 10:14:49 +03:00
else
{
2018-07-25 00:36:48 +02:00
if ( adventureInt - > curHero ( ) )
2014-07-15 10:14:49 +03:00
CRClickPopup : : createAndPush ( obj - > getHoverText ( adventureInt - > curHero ( ) ) ) ;
else
CRClickPopup : : createAndPush ( obj - > getHoverText ( LOCPLINT - > playerID ) ) ;
}
}
CRClickPopup : : CRClickPopup ( )
{
addUsedEvents ( RCLICK ) ;
}
CRClickPopup : : ~ CRClickPopup ( )
{
}
2018-07-25 00:36:48 +02:00
CRClickPopupInt : : CRClickPopupInt ( std : : shared_ptr < CIntObject > our )
2014-07-15 10:14:49 +03:00
{
CCS - > curh - > hide ( ) ;
2018-07-25 00:36:48 +02:00
defActions = SHOWALL | UPDATE ;
our - > recActions = defActions ;
2014-07-15 10:14:49 +03:00
inner = our ;
2018-07-25 00:36:48 +02:00
addChild ( our . get ( ) , false ) ;
2014-07-15 10:14:49 +03:00
}
CRClickPopupInt : : ~ CRClickPopupInt ( )
{
CCS - > curh - > show ( ) ;
}
Point CInfoBoxPopup : : toScreen ( Point p )
{
vstd : : abetween ( p . x , adventureInt - > terrain . pos . x + 100 , adventureInt - > terrain . pos . x + adventureInt - > terrain . pos . w - 100 ) ;
vstd : : abetween ( p . y , adventureInt - > terrain . pos . y + 100 , adventureInt - > terrain . pos . y + adventureInt - > terrain . pos . h - 100 ) ;
return p ;
}
2018-04-07 13:34:11 +02:00
CInfoBoxPopup : : CInfoBoxPopup ( Point position , const CGTownInstance * town )
: CWindowObject ( RCLICK_POPUP | PLAYER_COLORED , " TOWNQVBK " , toScreen ( position ) )
2014-07-15 10:14:49 +03:00
{
InfoAboutTown iah ;
2015-02-06 16:36:09 +02:00
LOCPLINT - > cb - > getTownInfo ( town , iah , adventureInt - > selection ) ; //todo: should this be nearest hero?
2014-07-15 10:14:49 +03:00
2018-04-07 13:34:11 +02:00
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
tooltip = std : : make_shared < CTownTooltip > ( Point ( 9 , 10 ) , iah ) ;
2014-07-15 10:14:49 +03:00
}
2018-04-07 13:34:11 +02:00
CInfoBoxPopup : : CInfoBoxPopup ( Point position , const CGHeroInstance * hero )
: CWindowObject ( RCLICK_POPUP | PLAYER_COLORED , " HEROQVBK " , toScreen ( position ) )
2014-07-15 10:14:49 +03:00
{
InfoAboutHero iah ;
2015-02-06 16:36:09 +02:00
LOCPLINT - > cb - > getHeroInfo ( hero , iah , adventureInt - > selection ) ; //todo: should this be nearest hero?
2014-07-15 10:14:49 +03:00
2018-04-07 13:34:11 +02:00
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
tooltip = std : : make_shared < CHeroTooltip > ( Point ( 9 , 10 ) , iah ) ;
2014-07-15 10:14:49 +03:00
}
2018-04-07 13:34:11 +02:00
CInfoBoxPopup : : CInfoBoxPopup ( Point position , const CGGarrison * garr )
: CWindowObject ( RCLICK_POPUP | PLAYER_COLORED , " TOWNQVBK " , toScreen ( position ) )
2014-07-15 10:14:49 +03:00
{
InfoAboutTown iah ;
LOCPLINT - > cb - > getTownInfo ( garr , iah ) ;
2018-04-07 13:34:11 +02:00
OBJECT_CONSTRUCTION_CAPTURING ( 255 - DISPOSE ) ;
tooltip = std : : make_shared < CArmyTooltip > ( Point ( 9 , 10 ) , iah ) ;
2014-07-15 10:14:49 +03:00
}
2018-07-25 00:36:48 +02:00
std : : shared_ptr < WindowBase > CRClickPopup : : createInfoWin ( Point position , const CGObjectInstance * specific ) //specific=0 => draws info about selected town/hero
2014-07-15 10:14:49 +03:00
{
2015-02-06 14:41:26 +02:00
if ( nullptr = = specific )
2014-07-15 10:14:49 +03:00
specific = adventureInt - > selection ;
2018-04-07 13:34:11 +02:00
2015-02-06 14:41:26 +02:00
if ( nullptr = = specific )
{
logGlobal - > error ( " createInfoWin: no object to describe " ) ;
return nullptr ;
2018-04-07 13:34:11 +02:00
}
2014-07-15 10:14:49 +03:00
switch ( specific - > ID )
{
case Obj : : HERO :
2018-07-25 00:36:48 +02:00
return std : : make_shared < CInfoBoxPopup > ( position , dynamic_cast < const CGHeroInstance * > ( specific ) ) ;
2014-07-15 10:14:49 +03:00
case Obj : : TOWN :
2018-07-25 00:36:48 +02:00
return std : : make_shared < CInfoBoxPopup > ( position , dynamic_cast < const CGTownInstance * > ( specific ) ) ;
2014-07-15 10:14:49 +03:00
case Obj : : GARRISON :
case Obj : : GARRISON2 :
2018-07-25 00:36:48 +02:00
return std : : make_shared < CInfoBoxPopup > ( position , dynamic_cast < const CGGarrison * > ( specific ) ) ;
2014-07-15 10:14:49 +03:00
default :
2018-07-25 00:36:48 +02:00
return std : : shared_ptr < WindowBase > ( ) ;
2014-07-15 10:14:49 +03:00
}
}