setImageButton Help

1984plusplus

Chieftain
Joined
May 23, 2011
Messages
59
I'm trying to use the setImageButton function to add a button for a new screen to the main interface. Mimicking the code for the other buttons, I managed to make it show up and determine that iData1 is apparently what's responsible for what happens when you click the button. Where do I add the code to make a new iData1 entry that opens the new window? I've already added the necessary code for the new screen to CvScreenEnums.py and CvScreensInterface.py.

void setImageButton ( string szName, string szAttachTo, string szTexture, int iX, int iY, int iWidth, int iHeight, WidgetTypes eWidgetType, int iData1, int iData2 )
 
Each widget has 3 variables you can set to tell what the widget is, Those are "WidgetTypes eWidgetType, int iData1, int iData2". Actions with the widget (like clicking it) goes through CvDLLWidgetData.cpp where some widget types have special meaning.

Let's assume you use a widget with no special meaning like WIDGET_GENERAL. That will allow a pure python implementation.

Somewhere in the screen there should be
PHP:
def handleInput (self, inputClass):
Here you need to identify if it is your widget. It can be done with code like this:
PHP:
if (inputClass.getNotifyCode() == NotifyCode.NOTIFY_CLICKED):
  if (inputClass.getButtonType() == WidgetTypes.WIDGET_GENERAL):
    if (inputClass.getData1() == X and inputClass.getData2() == Y):
If you set X and Y to something, which ensures that it is your widget and you know no other widget will use that iData combo, then you know it's your widget and that it has been clicked. You can then add the code you want to do whatever you want the button to do.

Elsewhere in the file, there is a function called
PHP:
def getWidgetHelp(self, argsList):
       iScreen, eWidgetType, iData1, iData2, bOption = argsList
If you make this one return a string, this string will show up as tooltip. I recommend you to use getText instead of hardcoding the string as this will allow translators to translate the help text.
 
Thanks, that was exactly what I needed. Now there's only one issue left. How do you go about adding a new keyboard command to open the new window? Is it possible to bump the Financial Advisor to be shift F2 and use F2 for the new screen?
 
Thanks, that was exactly what I needed. Now there's only one issue left. How do you go about adding a new keyboard command to open the new window? Is it possible to bump the Financial Advisor to be shift F2 and use F2 for the new screen?
It has been on my TODO list for quite a while to figure out the answer to that precise question (or in general: how to assign hotkeys to opening new windows). I figured since I will have to research this eventually, I might as well do it now that there is a question about it.

It works like this:
First you add a new hotkey combo to units/control infos xml. Be aware that the vanilla indexes are hardcoded, meaning you add to the end. Changing the order of vanilla entries will mess up the game.

You set the button widget to WidgetTypes.WIDGET_ACTION. iData1 is then set to the index from the control xml (use GC.getInfoTypeForString)

In the DLL file CvGameInterface.cpp, the function CvGame::doControl(ControlTypes eControl) will be called where the only argument is what you put in iData1. Make it open a screen. (look at CONTROL_FINANCIAL_SCREEN or similar)

In CvScreenInferface.py, add your screen and a show command.

I haven't tested this, but I suspect CvGame::doControl is called on both mouse click and whenever the hotkey combo is pressed.
 
So, to be clear, I'll need to edit the SDK to add a new keyboard shortcut? That's further down the rabbit hole than I'm looking to go at this point. Nonetheless, thanks for all the help.
 
Thanks, that was exactly what I needed. Now there's only one issue left. How do you go about adding a new keyboard command to open the new window? Is it possible to bump the Financial Advisor to be shift F2 and use F2 for the new screen?

So, to be clear, I'll need to edit the SDK to add a new keyboard shortcut? That's further down the rabbit hole than I'm looking to go at this point. Nonetheless, thanks for all the help.

No need to edit the DLL, you can modify the keybindings for such screens (and several other things) in /Assets/XML/Units/Civ4ControlInfos.xml.
 
No need to edit the DLL, you can modify the keybindings for such screens (and several other things) in /Assets/XML/Units/Civ4ControlInfos.xml.
First you add a new hotkey combo to units/control infos xml. Be aware that the vanilla indexes are hardcoded, meaning you add to the end. Changing the order of vanilla entries will mess up the game.
Looks like we agree on that part. The question is how to tell the game that you want to open a certain screen when you press CONTROL_OPEN_MY_MOD_SCREEN. From what I can tell, it ends up calling CvGame::doControl and that function contains a switch where default doesn't do anything other than asserting.

If hotkey actions can be added without modding CvGame::doControl, do tell.
 
Looks like we agree on that part. The question is how to tell the game that you want to open a certain screen when you press CONTROL_OPEN_MY_MOD_SCREEN. From what I can tell, it ends up calling CvGame::doControl and that function contains a switch where default doesn't do anything other than asserting.

If hotkey actions can be added without modding CvGame::doControl, do tell.

It's done via onKbdEvent() in CvEventManager.py. An example from my mod:

PHP:
        if eventType == self.EventKeyDown:
            # Use 'if' instead of 'elif' or keys will not be detected
            theKey = int(key)
            CvCameraControls.g_CameraControls.handleInput(theKey)

            # Tenets Advisor
            if theKey == int(InputTypes.KB_F8) and not self.bShift:
                CvScreensInterface.showTenetsScreen()
                return 1
 
PHP:
    def onKbdEvent(self, argsList):
       'keypress handler - return 1 if the event was consumed'
Looks like there is more to this than first meets the eye. Presumably consuming the event means it will not do anything else with the event in question. This begs the question: what happens next if you return 0? What about handleInput in the different screens? They can contain code like
PHP:
if (inputClass.getNotifyCode() == NotifyCode.NOTIFY_CHARACTER):
This tells that a character has been clicked as well as if shift, alt and control is down. Clearly that's some keyboard reading as well. handleInput too can return 1 to consume the event. Also where is CvGame::doControl() in all this?

Being able to add a hotkey to opening the screen answers the question and that should be good enough. Still I can't help wondering what we could do with a complete understanding of how keyboard inputs are read.
 
Back
Top Bottom