-
Notifications
You must be signed in to change notification settings - Fork 37
Widget creation
A widget is a graphic element displayed on your screen, either purely decorative, or with acction and information attached
Long story short : WidgetTypes.GENERAL
has neither meaning nor behaviour attached.
The main advantage of WidgetTypes.GENERAL is that it doesn't bind the graphical component to a predetermined behaviour when clicked, hovered, or dragged and dropped.
This feature becomes an issue when we want a component to have the same behaviour across all screens, or having access to state not exposed via the Python API. It forces to make calls that are slow, forces to duplicate game logic on both Python script and C++. All of this is explained in issue #929
In our example, we will create the widget for Tax Information, the one displayed at the top of Africa and Europe
Its name will be WIDGET_HELP_TAX_CALCULATION
The path of the file within the mod is Assets/XML/GlobalTypes.xml
The best practice is to add as the last element of the list.
Most of the declarative work takes place in CvDLLWidgetData.cpp
template<> // This lines tells the compiler we use a fully defined template
class WidgetContainer<WIDGET_HELP_TAX_CALCULATION> : public WidgetData
{
public:
WidgetContainer(const CvWidgetDataStruct widgetDataStruct)
: eColonyPlayer((PlayerTypes)widgetDataStruct.m_iData1)
, bForceDetailedInfo(widgetDataStruct.m_iData2 == 1) //If set to 1, will display the detailed info, regardless of hidden variable display option
{}
const PlayerTypes eColonyPlayer;
const bool bForceDetailedInfo;
void parseHelp(CvWStringBuffer& szBuffer) const
{
CvPlayerAI& kColony = GET_PLAYER(eColonyPlayer);
CvPlayerAI& kKing = *kColony.getParentPlayer();
const bool bNoHidden = GC.getGameINLINE().isOption(GAMEOPTION_NO_MORE_VARIABLES_HIDDEN);
if (bNoHidden || bForceDetailedInfo)
{
const int chancePerThousand = kKing.getTaxRaiseChance();
szBuffer.append(gDLL->getText("TXT_KEY_TAX_BAR",
kKing.getFullYieldScore(), //apply the Global Ratio
kKing.getTaxThresold(), // get a comparable quantity
GC.getYieldInfo(YIELD_TRADE_GOODS).getChar(),
chancePerThousand / 10, chancePerThousand % 10,
GLOBAL_DEFINE_TAX_RATE_RETAINED_FRACTION
));
}
else
{
const CvWString st = gDLL->getText("TXT_KEY_MISC_TAX_RATE",
kColony.getTaxRate(),
kColony.NBMOD_GetMaxTaxRate());
// st.ToUpper?
szBuffer.append(st);
}
}
};
the first lines are the most crucial to understand of all this work.
And then edit the WidgetData::getNew
method to explicitely include this new templated class
WidgetData* WidgetData::getNew(const CvWidgetDataStruct& widgetData)
{
switch (widgetData.m_eWidgetType)
{
case WIDGET_PEDIA_JUMP_TO_UNIT: return new WidgetContainer<WIDGET_PEDIA_JUMP_TO_UNIT>(widgetData);
case WIDGET_HELP_TAX_CALCULATION: return new WidgetContainer<WIDGET_HELP_TAX_CALCULATION >(widgetData); //New ! Shiny!
}
return NULL;
}
When placing graphical elements with python calls, there are 3 parameters at the end.
screen.setText(self.getNextWidgetName(), "Background", szTaxRate, CvUtil.FONT_RIGHT_JUSTIFY,
self.XResolution - CyInterface().determineWidth(szExit) - self.STANDARD_MARGIN * 2, self.STANDARD_MARGIN, 0, FontTypes.TITLE_FONT,
WidgetTypes.WIDGET_HELP_TAX_CALCULATION, self.player_id, -1 ) # here
Doing so will attach the behaviour of the C++ class we defined above to this zone of text.