CyGInterfaceScreen question

Vadus

pretend the impossible
Joined
Nov 23, 2003
Messages
374
Location
Northern Germany
Hi python pros,

I want to add a new button to the Civ4 Main-Interface, so I have to change the CvInterface.py . This class (or interface) uses an instance of CyGInterface.
So currently I have to get to know the CyGInterface Class, ... at least the
setButtonGFC( ) method.
( Because I want to add my Button in the CityScreen right under the "show only wonders to build" - button. And this selectionButtons are set with the setButtonGFC( ) method , see CvMainInterface.py line:289)

The API shows this signature :
Code:
setButtonGFC(...) - void ( string szName, wstring szText, string szTexture, 
                          int iX, int iY, int imageWidth, int imageHeight, 
                          WidgetTypes eWidgetType, 
                          int iData1, int iData2, 
                          ButtonStyles eStyle )
So my questions are :

1. What for a type is a 'wstring' in python ?
2. Refer the 2 iData params to the method, which is called, when this button was pressed ? If so, where can I find the implementation of this methods ? Mostly there are values from -1 to 2 consigned. :hmm:
If not, where and how do I have to implement the method for this new button ?

regards
 
Vadus said:
Hi python pros,

I want to add a new button to the Civ4 Main-Interface, so I have to change the CvInterface.py . This class (or interface) uses an instance of CyGInterface.
So currently I have to get to know the CyGInterface Class, ... at least the
setButtonGFC( ) method.
( Because I want to add my Button in the CityScreen right under the "show only wonders to build" - button. And this selectionButtons are set with the setButtonGFC( ) method , see CvMainInterface.py line:289)

The API shows this signature :
Code:
setButtonGFC(...) - void ( string szName, wstring szText, string szTexture, 
                          int iX, int iY, int imageWidth, int imageHeight, 
                          WidgetTypes eWidgetType, 
                          int iData1, int iData2, 
                          ButtonStyles eStyle )
Hmm, I used setImageButton, but maybe this is better.
So my questions are :

1. What for a type is a 'wstring' in python ?
Its a unicode string. It would look like this: u"String Text Here". The 'u' is what matters.
2. Refer the 2 iData params to the method, which is called, when this button was pressed ? If so, where can I find the implementation of this methods ? Mostly there are values from -1 to 2 consigned. :hmm:
The two iData parameters are passed in the inputData to handleInput on a click event. As long as you use the Python WidgetTypes enum value (I forget exactly what its called, WIDGETTYPES_PYTHON perhaps?) there shouldn't be any side effects.
If not, where and how do I have to implement the method for this new button ?

regards
add this to your handleInput procedure (its at the end):
Code:
		if( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED):
			###do something here
 
to 1.) the wstring seems to be the text to display when you move the mouse over the button. Just look in the CvMainInterface.py for the text "# Conscript button" for a sample

to 2.) look in the same file for the text "COMMERCE_PERCENT_CHANGE_INCREMENT". It seems to be, that with idata1 and idata2 you can pass a variable and an increment for it. Means, when you press the button, the variable in idata1 is incermented by idata2.

There are lot of sample implementations for those buttons, Just look in the main interface for the usage and try.
 
ok, many thanks for the fast answer :goodjob:

but now I decided to add a new ImageButton, because the ButtonGFC confuses me to much :crazyeye:

So I added a new Button next to the domestic advisor.

In the CvMainInterface I added the following lines (by copy paste and changing the domestic advisor button lines). I also added the lines for screen.show( ) , screen.hide( ) and so on. Everywhere where I found a line for the domestic advisor button ...
Code:
screen.setImageButton( "VadusAdvisorButton", "", 
                      iBtnX, iBtnY, iBtnWidth, iBtnWidth, 
                      WidgetTypes.WIDGET_ACTION, 
                      gc.getControlInfo(ControlTypes.CONTROL_UNITBOX_SCREEN).
                      getActionInfoIndex(), -1 )
screen.setStyle( "VadusAdvisorButton", 
                      "Button_HUDAdvisorDomestic_Style" )
screen.hide( "VadusAdvisorButton" )

I found the Entry for the controlType in XML/Units/CIV4ControlInfos.xml
... but why are button controls under units :rolleyes: .. however ..
I added there (by copy paste the domestic-advisor entry):
Code:
<ControlInfo>
  <Type>CONTROL_UNITBOX_SCREEN</Type>
  <Description>TXT_KEY_UNITBOX_TITLE</Description>
  <Help/>
  <HotKey>KB_U</HotKey>
  <bAltDown>0</bAltDown>
  <bShiftDown>0</bShiftDown>
  <bCtrlDown>0</bCtrlDown>
  <iHotKeyPriority>0</iHotKeyPriority>
  <HotKeyAlt/>
  <bAltDownAlt>0</bAltDownAlt>
  <bShiftDownAlt>0</bShiftDownAlt>
  <bCtrlDownAlt>0</bCtrlDownAlt>
  <iHotKeyPriorityAlt>0</iHotKeyPriorityAlt>
</ControlInfo>
I choosed KB_U , because there is no similar hotkey entry in this file.

The Description for this control is stored in XML/Text/CIV4GameTextInfos.xml
There I added the lines ( by using the corresponding domestic advisor template) :
Code:
<TEXT>
  <Tag>TXT_KEY_UNITBOX_TITLE</Tag>
  <English>My Unitbox</English>
  <French>Conseiller aux affaires int&#233;rieures</French>
  <German>Meine Einheitenkiste</German>
  <Italian>Consigliere interno</Italian>
  <Spanish>Consejero de Interior</Spanish>
  <Russian>Unit Sandbox</Russian>
  <Japanese>Unit Sandbox</Japanese>
  <Chinese>Unit Sandbox</Chinese>
</TEXT>

and now the strange behavior ingame :
When I take the same controlType like the domestic advisor for my unitbox-button ( in the CvMainInterface), the button will appear right next the domestic advisor button in the game. And it will also open the dom.adv. screen by pressing F1.
But when I use my new controlType "CONTROL_UNITBOX_SCREEN" , the hole interface of civ4 will disappear after starting a new game! :sad:
But the Hotkeys are still working. But by pressing the F1 key I get the VictoryScreen. And pressing the U-Key, I will get the domestic-advisor screen.:confused:
So I think, using the gc.getControlInfo(ControlTypes.CONTROL_UNITBOX_SCREEN).getActionInfoIndex() as iData1 param of the setImageButton( ) method will call somehow an internal method, which is linked to the ControlType. And because, there is no method defined for the type CONTROL_UNITBOX_SCREEN , this will cause an error...
But, if there is one : Which log-file is written ? In my .ini file of my mod, I have the following entrys:
Code:
; Debugging completely on
HidePythonExceptions = 0
ShowPythonDebugMsgs = 1
LoggingEnabled = 1
MessageLog = 1
But there are no messages in the Civ/log/ folder :hmm:
talchas said:
add this to your handleInput procedure (its at the end):
Code:
if( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED):
			###do something here
allright, but I think at this point I have to decide which button of the interface was pressed, haven't I ?
But how ? is there a method of inputClass ? or NotifyCode ?
 
Vadus said:
ok, many thanks for the fast answer :goodjob:

but now I decided to add a new ImageButton, because the ButtonGFC confuses me to much :crazyeye:

So I added a new Button next to the domestic advisor.

In the CvMainInterface I added the following lines (by copy paste and changing the domestic advisor button lines). I also added the lines for screen.show( ) , screen.hide( ) and so on. Everywhere where I found a line for the domestic advisor button ...
Code:
screen.setImageButton( "VadusAdvisorButton", "", 
                      iBtnX, iBtnY, iBtnWidth, iBtnWidth, 
                      WidgetTypes.WIDGET_ACTION, 
                      gc.getControlInfo(ControlTypes.CONTROL_UNITBOX_SCREEN).
                      getActionInfoIndex(), -1 )
screen.setStyle( "VadusAdvisorButton", 
                      "Button_HUDAdvisorDomestic_Style" )
screen.hide( "VadusAdvisorButton" )

I found the Entry for the controlType in XML/Units/CIV4ControlInfos.xml
... but why are button controls under units :rolleyes: .. however ..
I added there (by copy paste the domestic-advisor entry):
Code:
<ControlInfo>
  <Type>CONTROL_UNITBOX_SCREEN</Type>
  <Description>TXT_KEY_UNITBOX_TITLE</Description>
  <Help/>
  <HotKey>KB_U</HotKey>
  <bAltDown>0</bAltDown>
  <bShiftDown>0</bShiftDown>
  <bCtrlDown>0</bCtrlDown>
  <iHotKeyPriority>0</iHotKeyPriority>
  <HotKeyAlt/>
  <bAltDownAlt>0</bAltDownAlt>
  <bShiftDownAlt>0</bShiftDownAlt>
  <bCtrlDownAlt>0</bCtrlDownAlt>
  <iHotKeyPriorityAlt>0</iHotKeyPriorityAlt>
</ControlInfo>
I choosed KB_U , because there is no similar hotkey entry in this file.
You can't do this w/o the SDK, as the CONTROL_* things are in the C++.

instead add a line after line 1372 so that the area looks like this:
Code:
						iCount = iCount + 1
					screen.setImageButton( "t2",buttonImg , 40, yResolution - 180, 24, 24, WidgetTypes.WIDGET_GENERAL, -1, -1 )

		elif (CyInterface...
then replace handleInput with
Code:
	def handleInput (self, inputClass):
		if( inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED and inputClass.getFunctionName() == "t" and inputClass.getID() == 2):
			CyInterface().addImmediateMessage("button clicked","")
			return 1
		return 0
For some reason it seems to split "t2" into name "t" and ID 2. Instead you could probably use "MyThingamjig" and check for that as the FunctionName.
 
kewl ! works fine :) , thanks
I guess in 2 days I will have further questiones about building a new popup window, but fortunately there are already some mods with such a stuff

.. but it's line 1357 in the original CvMainInterface.py .. just for the other readers here ..
 
Vadus said:
kewl ! works find :) , thanks
I guess in 2 days I will have further questiones about building a new popup window, but fortunately there are already some mods with such a stuff

.. but it's line 1357 in the original CvMainInterface.py .. just for the other readers here ..
Oops, wrong version of CvMainInterface.py :blush:
 
Hi all,
another question about this topic:
Is it possible to find out, which unit-button of the cityscreen was pressed ( the number of that button) , if a unit-button was pressed (to build a unit ) ?
For example, if the settler is the first unit button of the city screen and I press this button to build the settler, I get somewhere, maybe from the handleInput method or even the EventManager, the information, that button number 0 was pressed.

The according code of setting the unitbuttons in CyGInterfaceScreen is :
Code:
# Units to construct
for i in range ( g_NumUnitClassInfos ):
	eLoopUnit = gc.getCivilizationInfo(
                         pHeadSelectedCity.getCivilizationType()
                         ).getCivilizationUnits(i)
					
	if (pHeadSelectedCity.canTrain(eLoopUnit, False, True) ):
		screen.appendMultiListButton( 
                          "BottomButtonContainer", 
                          gc.getUnitInfo(eLoopUnit).getButton(),
                          0, WidgetTypes.WIDGET_TRAIN, 
                          i, -1, False )
		screen.show( "BottomButtonContainer" )
						
		if ( not pHeadSelectedCity.canTrain(eLoopUnit, False, False) ):
			screen.disableMultiListButton( 
                                  "BottomButtonContainer", 
                                  0, iCount, 
                                  gc.getUnitInfo(eLoopUnit).getButton()
                         )
						
		iCount = iCount + 1

Well, I think because of the WidgetTypes.WIDGET_TRAIN setting, these buttons call an internal function when they where pressed.
Also to EventManagers onCityBuildingUnit only the values of city and unit-type are given :
Code:
def onCityBuildingUnit(self, argsList):
		'City begins building a unit'
		pCity = argsList[0]
		iUnitType = argsList[1]
		if (not self.__LOG_CITYBUILDING):
			return
		CvUtil.pyPrint("%s has begun building a %s" 
                       %(pCity.getName(),
                       gc.getUnitInfo(iUnitType).getDescription())
                 )

So, I see a possibility in changing the unit-buttons in the CyGInterfaceScreen from the type MultiListButton to ImageButton , because the ImageButton has it's own methodcall in the inputhandle method ( via the string attribute name of the imageButton ). Then I could give the buttonPosition over the iData1 param to the handleInput and call from there the cyCity.setUnitProduction( )
and CyGInterfaceScreen.updateCityScreen( ) , but I don't like this way .. :nono: because then I have change a lot only to get one int value .
Is there the possibility to get the position (or index ) of a MultiListButton ??
 
well, jeah .. to my proposed solution above :
I tried to add the unit-production buttons as ImageButtons, but let the others (buildings and wonders) as MultiListButton. Then I get this error I attached.
Perhaps this is the result of attaching an ImageButton to a MultiListControlGFC ( which is the panel with the production buttons of a city ) :sad:

So do I have still the chance to get the number of the production button, which was pressed ? :confused:


For info, if a firaxis developer is reading this (because such runtime errors should be unusually )

in CvMainInterface.py

Code:
# Units to construct

for vUnit in MyMod.MyMod().getUnits():
					
	if (pHeadSelectedCity.canTrain(vUnit.getType(), False, True) ):
		screen.attachImageButton( "BottomButtonContainer", "productionUnitButton", 
                                  gc.getUnitInfo(vUnit.getType()).getButton(), GenericButtonSizes.BUTTON_SIZE_CUSTOM,
                                  WidgetTypes.WIDGET_GENERAL, iCount, -1, False )
						
		screen.show( "BottomButtonContainer" )
						
		iCount = iCount + 1
						
iCount = 0

and in handleInput of CvMainInterface.py

Code:
def handleInput (self, inputClass):
	if (inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED 
        and inputClass.getFunctionName() == "productionUnitButton"):
		CyInterface().addImmediateMessage("unitBox clicked", "")
		return 1
 

Attachments

  • civError01.png
    civError01.png
    6.1 KB · Views: 56
did you try the approach of talchas described in this thread here?

I think he uses any event to analyze the pressed button. Same should work for the production button. You have to look in the code.
 
Back
Top Bottom