View Full Version : handleInput in CvMainInterface.py
The Great Apple Mar 30, 2006, 12:48 PM What I'm trying to do is to get custom mouseover info showing when I mouseover an action button (using the action buttons mod). Now the info is quite easy to do - what I'm having trouble doing is getting the handleInput function in CvMainInterface.py to recognise when the mouse is over the button.
I've done a bit of testing with the function, and it seems that it is only fired when you actually select an item such as the end turn button... which is not when I want it to be fired.
I notice poking through other screens that the handleInput functions on them seem to handle a lot more inputs then the main interface screen - including "LISTBOX_ITEM_SELECTED", "NOTIFY_CURSOR_MOVE_OFF", and "NOTIFY_CURSOR_MOVE_ON", all of which sounds like they might be the ones I want.... but I can't work out how to get by buttons to fire the input when the curser moves on or off in the first place.
Any ideas?
TheLopez Mar 30, 2006, 01:26 PM Honestly, I don't think it's possible right now for the main interface. I fought this for about 3 days straight, literally.
I think this might be a "wait till the SDK comes around."
SimCutie Mar 30, 2006, 03:54 PM I think that the handleInput() is useless for triggering action on mouse over button. You should use update() which is called on every 0.25 sec intervals.
In CvMainInterface.update(), getcoods where mouse is on. (Using CyIntarfcae. getMousePos() which returns mouse screen coordinates in pixel (X, Y) then compare it with button rectangle postition..
Dirty hack may be..
I think that WIDGET_XXX or (WIDGET_ACTION, iAction argument) of the button is the key.
If you can add new WIDGET_XXX, or new action type, then you can specify new mouse over handler for the button. for WIDGET_ACTION, new text for on-screen help string.
The action numer/ help string of specific WIDGET_ACTION is secified in CvMissionInfo.xml, CvAutomationInfo.xml and various XML files. Most of them we can not add new entry unless we can modify "CvEnum.h" :C++ header file.
12monkeys Mar 30, 2006, 04:13 PM I think it's possible to get these mouse over events in main interface, but only in you change the widget type of the related object.
In my (still not released) Plot List Enhancements I was only able to get this mouse over for th eplot list buttons, by changing the widget type from WIDGET_PLOT_LIST to WIDGET_GENERAL. This prevents the standard widget type consumes to consume the event.
EDIT : I was also able to use the mouse over events in my Modified Special Domestic Advisor.
The Great Apple Mar 30, 2006, 04:14 PM I think that the handleInput() is useless to triggering action on mouse over plots. You should use update() which is called on every 0.25 sec intervals.
In CvMainInterface.update(), get plot where mouse is on. (Using CyIntarfcae. getMouseOverPlot() which returns *CyPlot struct), and find out what is in the plot. (Using CyPlot.getUnit(), getNumUnits(), getPlotCity(), etc etc...
If some thing of your interest is on the plot, then add the action button.I want to find which selection button the mouse is over, not the plot.
I could do it a really long winded way because I can work out where all the buttons are, and then if one is under the pointer at any specific time. Not really what I wanted to do, but it'd probably work.
Does anybody know what the fDelta argument on the update function is? I had assumed it was the time between the two updates.
The Great Apple Mar 30, 2006, 04:14 PM I think it's possible to get these mouse over events in main interface, but only in you change the widget type of the related object.
In my (still not released) Plot List Enhancements I was only able to get this mouse over for th eplot list buttons, by changing the widget type from WIDGET_PLOT_LIST to WIDGET_GENERAL. This prevents the standard widget type consumes to consume the event.
EDIT : I was also able to use the mouse over events in my Modified Special Domestic Advisor.
Fantastic - I'll have a go.
The Great Apple Mar 30, 2006, 04:25 PM Nope - didn't work. Not only did inputHandler not get called, but the button didn't do what it was meant to do anymore.
12monkeys Mar 30, 2006, 04:33 PM Mmhh. If the inputHandler works for the NOTIFY_CLICKED event before, I assume that the object naming the interface input map was Ok as well.
What type of objects you want to get the event for? I managed to get it work for a check box ( screen.addCheckBoxGFC() ) with WidgetTypes.WIDGET_GENERAL.
Are you trying to get that event for an existing or an added interface object?
The Great Apple Mar 30, 2006, 04:40 PM Mmhh. If the inputHandler works for the NOTIFY_CLICKED event before, I assume that the object naming the interface input map was Ok as well.
What type of objects you want to get the event for? I managed to get it work for a check box ( screen.addCheckBoxGFC() ) with WidgetTypes.WIDGET_GENERAL.
Are you trying to get that event for an existing or an added interface object?
An added object to an existing parent object...
First using screen.addMultiListControlGFC then using screen.appendMultiListButton several times to add the separate buttons.
12monkeys Mar 30, 2006, 05:13 PM An added object to an existing parent object...
First using screen.addMultiListControlGFC then using screen.appendMultiListButton several times to add the separate buttons.
I had a short look in that action button mod. I think the problem is, that those added action buttons don't pass the CvActionButtonsGameUtils.cannotHandleAction() method, if they don't have the widget type WIDGET_ACTION. Thats the reason why you loose your handler. A solution for this may be to add a handler in the main interface itself.
The possible reason why you don't get a mouse over event, could be that the event handler for those buttons is not part of the main interface but of the game core. This multi list button container is kind a special thing.
I had similar effects with the plot list buttons. Because the plot list is also bit of high integrated into game core, I had to change widget type to prevent the game core mixing everything up. As a side effect I switched off the mouse over info, which forces me to reprogram it. It was not my major intention to do so.
I'm afraid, you have to made a similar decision. If you want to change the mouse over info for the action buttons, you may have to write your own handler for the actions when you click such a button. You have to do that not only for your added ones, you have to do that for all possible action buttons.
Most of the actions can be pictured with CyGroup.pushMissions() (except the grouping stuff, this will hard to do, maybe its even impossible!). It could be a high price you have to pay.
As an alternative, you sould try to seperate those added buttons from the standard action buttons by creating your own container.
No good news I'm afraid.
The Great Apple Mar 30, 2006, 05:18 PM No good news I'm afraid.Right... I'll do the pointer finding method. It'll be cruder but alot easier - and I'm feeling lazy.
talchas Mar 30, 2006, 06:27 PM As an alternative, you sould try to seperate those added buttons from the standard action buttons by creating your own container.
I believe I have some commented out examples of how this could be done in my Spell mod. It added images (that act like buttons) above the normal interface and could handle stuff for them in handleInput.
The Great Apple Mar 31, 2006, 06:09 AM I believe I have some commented out examples of how this could be done in my Spell mod. It added images (that act like buttons) above the normal interface and could handle stuff for them in handleInput.Unfortunetly then you don't get all the nice things like the flashing pulse.
I've managed to implement it by finding the mouse pointer. Seems to be working fairly smoothly.
TheLopez Mar 31, 2006, 06:11 AM Unfortunetly then you don't get all the nice things like the flashing pulse.
I've managed to implement it by finding the mouse pointer. Seems to be working fairly smoothly.
Do you have any code you care to share with us yet?
The Great Apple Mar 31, 2006, 06:23 AM Do you have any code you care to share with us yet?
Unfortunetly it's a tiny bit specific. The button positions I've used aren't the default button positions, as I had to fiddle them so that they'd fit inside the interface image I was using.
I am also yet to fiddle with the ActionButton class to tie text to the button. Getting there :p
12monkeys Mar 31, 2006, 08:16 AM Unfortunetly it's a tiny bit specific. The button positions I've used aren't the default button positions, as I had to fiddle them so that they'd fit inside the interface image I was using.
I am also yet to fiddle with the ActionButton class to tie text to the button. Getting there :p
Are you retrieveing the mouse position with CyInterface.getMousePos(), checking if the resulting x,y-coord is over one of your square button objects? Is that correct?
TheLopez Mar 31, 2006, 08:42 AM When are you checking the mouse position? Every update?
The Great Apple Mar 31, 2006, 08:56 AM Yes - checking it every update and tracking the mouse position. Have to be quite careful not to put too much load on it, and it seems to be holding up alright.
The only problem I have is the lack of dropshadow on the multiline text. I think I may have to split it into several single-line text pieces to get it to work.
12monkeys Mar 31, 2006, 09:43 AM Yes - checking it every update and tracking the mouse position. Have to be quite careful not to put too much load on it, and it seems to be holding up alright.
you may reduce the load by splitting it :
option 1 : doing a scan on each button each 2nd or 3rd update
option 2 : doing a scan on half of the button one update and the second half next update.
Of course, this makes only sense, if the logic to split the load is not to complex.
TheLopez Mar 31, 2006, 09:55 AM you may reduce the load by splitting it :
option 1 : doing a scan on each button each 2nd or 3rd update
option 2 : doing a scan on half of the button one update and the second half next update.
Of course, this makes only sense, if the logic to split the load is not to complex.
The problem with this logic is that you could possibly get some flickering in the interface.
The Great Apple Mar 31, 2006, 11:17 AM you may reduce the load by splitting it :
option 1 : doing a scan on each button each 2nd or 3rd update
option 2 : doing a scan on half of the button one update and the second half next update.
Of course, this makes only sense, if the logic to split the load is not to complex.I've just run a few tests.
It would appear update triggers about 7 times every second (~ every 0.14 seconds), rather than 4 times as mentioned earlier, though it's not quite fixed - mousing over the end turn button pops it up to 0.3 seconds for example. I think it's based on how quick you computer is, and when playing it's probably even faster (I have loads of background apps open at the moment).
The method I'm using takes about 0.015 seconds when it runs fully through, but almost always it's cut a bit early - it only runs fully through if the mouse moves onto the button.
Not really worth the effort then, IMO.
12monkeys Mar 31, 2006, 04:36 PM I've just run a few tests.
It would appear update triggers about 7 times every second (~ every 0.14 seconds), rather than 4 times as mentioned earlier, though it's not quite fixed - mousing over the end turn button pops it up to 0.3 seconds for example. I think it's based on how quick you computer is, and when playing it's probably even faster (I have loads of background apps open at the moment).
The method I'm using takes about 0.015 seconds when it runs fully through, but almost always it's cut a bit early - it only runs fully through if the mouse moves onto the button.
Not really worth the effort then, IMO.
You're right. No need to do somthing here.
BTW: if you're still looking for the dropshadow, I found a way to get it. Just display the text in black color with one pixel shift on x and y-axis before you set the text.
The result looks the same as the one in game, which makes me think they doing it exactly this way in the game core.
TheLopez Mar 31, 2006, 04:43 PM Code damnit, I need code :D
12monkeys Mar 31, 2006, 05:08 PM Here is some code:
# text to display
szText = "Hello!\nThis code example is dedicated to TheLopez\nHave Fun!"
# create shadow text
szTextBlack = localText.changeTextColor(szText, gc.getInfoTypeForString("COLOR_BLACK"))
# display shadow text at position x+1, y+1
screen.addMultilineText( "TEXT_SHADOW", szTextBlack, X+1, Y+1, 100, 100, \
WidgetTypes.WIDGET_GENERAL, -1, -1, CvUtil.FONT_LEFT_JUSTIFY)
# display text at position x, y
screen.addMultilineText( "TEXT", szText, X, Y, 100, 100, \
WidgetTypes.WIDGET_GENERAL, -1, -1, CvUtil.FONT_LEFT_JUSTIFY)
In case you have some color information within the text to display, you have to remove it in the shadow text before you make it black. You can use that function here :
def removeColor(szText):
# replace color start sequence
while szText.find("<color=") != -1:
iStartPos = szText.find("<color=")
iEndPos = szText.find(">", iStartPos)
szText = szText[:iStartPos]+szText[iEndPos+1:]
# replace color end sequence
szText = szText.replace("</color>", "")
return szText
12monkeys Mar 31, 2006, 05:40 PM @TGA : you said you're using the CyInterface().getMousePos() function for reading the x,y coords of the mouse cursor. How do you managed to split the resulting tuple into x and y positions. When I do this, I always get the python error "object not indexable" or something like that. Example :
tMousePos = CyInterface().getMousePos()
x = tMousePos[0]
y = tMousePos[1]
The second line produces the error. Can you or anybody else give me a hint, please?
TheLopez Mar 31, 2006, 05:45 PM 12monkeys, I was looking for TGA code, I know how to set color for text already, I do it in the merc mod.
Here from http://sthurlow.com/cvDocs/cvDoc/CyInterface.htm:
getMousePos(...) - POINT getMousePos() - returns the mouse coords
from the POINT def:
http://sthurlow.com/cvDocs/cvDoc/POINT.htm
Here's how to unpack it.
(x,y) = CyInterface().getMousePos().x,CyInterface().getMou sePos().y
12monkeys Mar 31, 2006, 05:57 PM 12monkeys, I was looking for TGA code, I know how to set color for text already, I do it in the merc mod.
Here from http://sthurlow.com/cvDocs/cvDoc/CyInterface.htm:
getMousePos(...) - POINT getMousePos() - returns the mouse coords
from the POINT def:
http://sthurlow.com/cvDocs/cvDoc/POINT.htm
Here's how to unpack it.
(x,y) = CyInterface().getMousePos().x,CyInterface().getMou sePos().y
I don't speak about the text color, I speak about a drop shadow of displayed text. The text color is only a method to get the drop shadow.
I know sturlows and I know that definition. But, to be honest, I don't understand that stuff, because I don't know the syntax. What I was in need of, was syntax example. Thank you for that!
The Great Apple Mar 31, 2006, 06:41 PM 12monkeys, I was looking for TGA code, I know how to set color for text already, I do it in the merc mod.
Okies - just finished ironing out a glitch where the text would be the wrong size.
It's rather long, and I shamelessly stole some stuff from 12monkeys domestic advisor, as well as this thread.
Also, as I warned before, alot of it won't be relavent - all the calculations for finding where the button would be would be alot easier with standard selection button positioning, and quite a bit of it would be completely different... so I'm not sure how useful posting this will be to you.
def update(self, fDelta):
screen = CyGInterfaceScreen( "MainInterface", CvScreenEnums.MAIN_INTERFACE )
pHeadSelectedUnit = CyInterface().getHeadSelectedUnit()
bComplete = False
global g_ActionInfoIsUp
# This code is for mouseover info on the custom buttons
if (pHeadSelectedUnit and not CyEngine().isGlobeviewUp() and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_HIDE_ALL and CyInterface().getShowInterface() != InterfaceVisibility.INTERFACE_MINIMAP_ONLY):
global g_ActionListOverflow
# Find out our resolution
xResolution = screen.getXResolution()
yResolution = screen.getYResolution()
mouseX = CyInterface().getMousePos().x
mouseY = CyInterface().getMousePos().y
# This is the area the big box the selection boxes can be in is
if ((yResolution - 160 - (57 * g_ActionListOverflow)) < mouseY < yResolution) and (296 < mouseX < (xResolution - 296)):
# Don't check the default buttons
numDefaults = len(CyInterface().getActionsToShow())
defaultPositions = []
bContinue = True
if numDefaults > 18:
return
while bContinue:
for Y in range(2):
for X in range (9):
if len(defaultPositions) < numDefaults:
defaultPositions.append((X, Y))
else:
bContinue = False
# Getting the button spacing/sizing
### THIS SIZING IS SPECIFIC TO MY INTERFACE ###
realWidth = xResolution - 592 - ((xResolution - 592)/11.5)
buttonSpacing = int(realWidth/8.7)
buttonSize = int(realWidth/9) - 4
notDefaults = []
addedButtons = ActionButtons.getButtons(pHeadSelectedUnit)
numAddedButtons = len(addedButtons)
iCount = 0
for iY in range(3):
for iX in range (9):
if (iCount < numAddedButtons) and ((iX, iY) not in defaultPositions):
buttonXmin = (296 + (xResolution - 592)/33 + (iX * buttonSpacing))
if (buttonXmin) <= mouseX <= (buttonXmin + buttonSize):
buttonYmin = yResolution - 107 + (57 * (iY - g_ActionListOverflow - 1)) + (48 - buttonSize)/2 # Dunno why there it is g_ActionListOverflow - 1. Too tired to work it out. It works though
if (buttonYmin) <= mouseY <= (buttonYmin + buttonSize):
if g_ActionInfoIsUp == iCount:
return
bComplete = True
szHelpText = "<font=2>"
szHelpText += "<color=100,225,255>"
szHelpText += u"%s" %addedButtons[iCount].getType()
szHelpText += "</color>"
szHelpText += u"\n"
szHelpText += u"%s" %addedButtons[iCount].getText()
szHelpText += "</font>"
# calculate panel heigth by examining the to be dispalyed text
# seperate the text into the chapters : everything between the line feeds
lChapters = szHelpText.split("\n")
nLines = 0
for iLoop in range(len(lChapters)):
# one line for each "\n"
nLines += 1
# another line for each n characters per chapter
nLines += int(CyInterface().determineWidth( lChapters[iLoop] )/259)
# transform the lines into pixels
yOffset = int(nLines*18)
szTextBlack = szHelpText
while szTextBlack.find("<color=") != -1:
iStartPos = szTextBlack.find("<color=")
iEndPos = szTextBlack.find(">", iStartPos)
szTextBlack = szTextBlack[:iStartPos]+szTextBlack[iEndPos+1:]
# replace color end sequence
szTextBlack = szTextBlack.replace("</color>", "")
szTextBlack = localText.changeTextColor(szTextBlack, gc.getInfoTypeForString("COLOR_BLACK"))
screen.addPanel( "MouseoverTextPanel", u"", u"", True, False, \
7, yResolution - 182 - yOffset, 269, yOffset + 10, \
PanelStyles.PANEL_STYLE_HUD_HELP )
screen.addMultilineText( "MouseoverTextShadow", szTextBlack, \
7 + 1 + 1, yResolution - 178 + 1 - yOffset, \
269 - 10, yOffset + 4, \
WidgetTypes.WIDGET_HELP_SELECTED, -1, -1, CvUtil.FONT_LEFT_JUSTIFY)
screen.addMultilineText( "MouseoverText", szHelpText, \
7 + 1, yResolution - 178 - yOffset, \
269 - 10, yOffset +4, \
WidgetTypes.WIDGET_HELP_SELECTED, -1, -1, CvUtil.FONT_LEFT_JUSTIFY)
screen.show( "MouseoverTextPanel" )
screen.show( "MouseoverTextShadow" )
screen.show( "MouseoverText" )
g_ActionInfoIsUp = iCount
#CyInterface().addImmediateMessage("Mouse is over custom button", "")
iCount += 1
if not (bComplete):
screen.hide("MouseoverTextPanel")
screen.hide( "MouseoverTextShadow" )
screen.hide("MouseoverText")
g_ActionInfoIsUp = -1
#CyInterface().addImmediateMessage("Mouse is NOT over custom button", "")
return
Basically, it first checks to see if there is a selection box, then if the mouse is over it, and then if the mouse is over a custom button. Finally, it adds the message if the message for that button isn't already up.
Probably should have had a few sub-functions. I think it would be better to define the panel in def interfaceScreen along with all the others as well, and only resize it in this code.
EDIT: g_ActionListOverflow just in case you are wondering is a variable calculated when the selection buttons are updated to dynamically change the positioning/size of the bottom bar.
EDIT 2: I forgot to mention that you'll also have to fiddle with the action buttons class so as to include a description.
EDIT 3: The third and final... I hope. There is also a small bug which means that sometimes default info is displayed from the terrain beneath as well as the button for a small amount of time. Looks a bit daft, but only occurs for an instant. Perhaps could be fixed by fiddling with the panel's widget.
EDIT 4: This has to be a record. I've just realised the way I've done the default button removal may be far from optimal. Too late to fix and test now - need sleep.
TheLopez Mar 31, 2006, 09:17 PM Wow, great work TGA.
SimCutie Mar 31, 2006, 10:35 PM Good work! Now action button can have on screen mouse over help or mosuse over handler..
And for (X,y) syntax is ....
tMousePos = CyInterface().getMousePos()
x = tMousePos[0]
y = tMousePos[1]
(x, y) = (tMousePos.x, tMousePos.y)
The Great Apple Apr 01, 2006, 05:05 AM Ignore this post
12monkeys Apr 01, 2006, 09:20 AM TGA : great job. :goodjob:
Thx for the mouse pos syntax, I really could use it.
I also like the CyInterface().determineWidth() function. It's a real improvement in this case. :goodjob:
|
|