00001 import BigWorld
00002 import GUI
00003 from functools import partial
00004 from Utils import clipSize
00005 from bwdebug import ERROR_MSG
00006
00007 import PyGUIBase
00008 from Window import Window
00009
00010
00011 class ToolTipInfo( object ):
00012
00013 def __init__( self, component = None, templateName = None, infoDictionary = {}, infoArea = None,
00014 delayType = None, placement = None ):
00015 if templateName:
00016 self.templateName = templateName
00017 self.infoDictionary = infoDictionary
00018 self.infoArea = infoArea
00019 self.delayType = delayType
00020 self.placement = placement
00021
00022
00023 def onLoad( self, dataSection ):
00024 self.templateName = dataSection._templateName.asString
00025
00026 self.infoDictionary = {}
00027 if dataSection.has_key( "items" ):
00028 itemsDataSection = dataSection._items
00029 for key, value in itemsDataSection.items():
00030 self.infoDictionary[ key ] = value.asString
00031
00032 self.infoArea = None
00033 if dataSection.has_key( "infoArea" ):
00034 infoArea = [0,0,0,0]
00035 infoAreaDataSection = dataSection._infoArea
00036 infoArea[0] = infoAreaDataSection.readFloat( "top" )
00037 infoArea[1] = infoAreaDataSection.readFloat( "left" )
00038 infoArea[2] = infoAreaDataSection.readFloat( "bottom" )
00039 infoArea[3] = infoAreaDataSection.readFloat( "right" )
00040 self.infoArea = tuple( infoArea )
00041
00042 self.delayType = None
00043 if dataSection.has_key( "delayType" ):
00044 if dataSection._delayType.asString == 'delay':
00045 self.delayType = ToolTip.DELAYED_TOOL_TIP
00046 else:
00047 self.delayType = ToolTip.IMMEDIATE_TOOL_TIP
00048
00049 self.placement = None
00050 if dataSection.has_key( "placement" ):
00051 self.placement = dataSection._placement.asString
00052
00053
00054 def onSave( self, dataSection ):
00055 dataSection.writeString( "templateName", self.templateName )
00056
00057 if len( self.infoDictionary ) > 0:
00058 itemsDataSection = dataSection.createSection( "items" )
00059 for key, value in self.infoDictionary.iteritems():
00060 itemsDataSection.writeString( key, value )
00061
00062 if self.infoArea:
00063 infoAreaDataSection = dataSection.createSection( "items" )
00064 infoAreaDataSection.writeFloat( "top", self.infoArea[0] )
00065 infoAreaDataSection.writeFloat( "left", self.infoArea[1] )
00066 infoAreaDataSection.writeFloat( "bottom", self.infoArea[2] )
00067 infoAreaDataSection.writeFloat( "right", self.infoArea[3] )
00068
00069 if self.delayType:
00070 delayString = 'delay' if self.delayType == ToolTip.DELAYED_TOOL_TIP else 'immediate'
00071 dataSection.writeString( "delayType", delayString)
00072
00073 if self.placement:
00074 dataSection.writeString( "placement", self.placement)
00075
00076
00077 class ToolTip( Window ):
00078
00079 IMMEDIATE_TOOL_TIP = 1
00080 DELAYED_TOOL_TIP = 2
00081
00082 PLACE_BELOW = 'below'
00083 PLACE_ABOVE = 'above'
00084 PLACE_LEFT = 'left'
00085 PLACE_RIGHT = 'right'
00086
00087 DELAY_TIME = 0.5
00088 GAP_SIZE = 0.01
00089
00090 def __init__( self, component ):
00091 Window.__init__( self, component )
00092 self.items = []
00093
00094
00095 def setupToolTip( self, toolTipInfo, infoArea ):
00096 self.toolTipInfo = toolTipInfo
00097 self.infoArea = infoArea
00098
00099 items = {}
00100 for item in self.items:
00101 items[ item ] = ''
00102 for key, value in toolTipInfo.infoDictionary.items():
00103 items[ key ] = value
00104
00105 for key, value in items.items():
00106 try:
00107 component = getattr( self.component, key )
00108 except AttributeError:
00109 continue
00110
00111 if isinstance( component, GUI.Text ):
00112 component.text = value
00113 else:
00114 component.textureName = value
00115
00116 self.doLayout( None )
00117
00118
00119 def onSave( self, dataSection ):
00120 Window.onSave( self, dataSection )
00121 if len( self.items ) > 0:
00122 itemSection = dataSection.createSection( "items" )
00123 for item in self.items:
00124 itemSection.createSection( item )
00125
00126
00127 def onLoad( self, dataSection ):
00128 Window.onLoad( self, dataSection )
00129 if dataSection.has_key( "items" ):
00130 itemSection = dataSection._items
00131 for item in itemSection.keys():
00132 self.items.append( item )
00133
00134
00135 def doLayout( self, parent ):
00136 mousePos = GUI.mcursor().position
00137 placement = self.toolTipInfo.placement if self.toolTipInfo.placement else ToolTip.PLACE_ABOVE
00138 zorder = self.component.position.z
00139 self.component.position = self.getToolTipPosition( mousePos, self.infoArea, placement )
00140 self.component.position.z = zorder
00141
00142
00143 def getToolTipPosition( self, mousePos, infoArea, placement ):
00144 '''Returns a position to place the ToolTip window in self.toolTipGUI so it is outside the info
00145 area positioned according to placement's hint'''
00146 width, height = clipSize( self.component )
00147
00148 if placement == ToolTip.PLACE_BELOW:
00149 position = [mousePos[0], infoArea[3] - ToolTip.GAP_SIZE - height / 2]
00150 elif placement == ToolTip.PLACE_ABOVE:
00151 position = [mousePos[0], infoArea[1] + ToolTip.GAP_SIZE + height / 2]
00152 elif placement == ToolTip.PLACE_LEFT:
00153 position = [infoArea[0] - ToolTip.GAP_SIZE - width / 2, mousePos[1]]
00154 elif placement == ToolTip.PLACE_RIGHT:
00155 position = [infoArea[2] + ToolTip.GAP_SIZE + width / 2, mousePos[1]]
00156
00157 if position[0] - width / 2 < -1.0:
00158
00159 if placement == ToolTip.PLACE_LEFT:
00160 position[0] = infoArea[2] + ToolTip.GAP_SIZE + width / 2
00161 else:
00162 position[0] = -1.0 + ToolTip.GAP_SIZE + width / 2
00163 elif position[0] + width / 2 > 1.0:
00164
00165 if placement == ToolTip.PLACE_RIGHT:
00166 position[0] = infoArea[0] - ToolTip.GAP_SIZE - width / 2
00167 else:
00168 position[0] = 1.0 - ToolTip.GAP_SIZE - width / 2
00169 if position[1] - height / 2 < -1.0:
00170
00171 if placement == ToolTip.PLACE_BELOW:
00172 position[1] = infoArea[1] + ToolTip.GAP_SIZE + height / 2
00173 else:
00174 position[1] = -1.0 + ToolTip.GAP_SIZE + height / 2
00175 elif position[1] + height / 2 > 1.0:
00176
00177 if placement == ToolTip.PLACE_ABOVE:
00178 position[1] = infoArea[3] - ToolTip.GAP_SIZE - height / 2
00179 else:
00180 position[1] = 1.0 - ToolTip.GAP_SIZE - height / 2
00181
00182 return (position[0], position[1], 0.0)
00183
00184
00185 class ToolTipManager( object ):
00186
00187 instance = None
00188
00189 def __init__( self, rootGUI, zorder ):
00190 self.rootGUI = rootGUI
00191 self.toolTipZOrder = zorder
00192 self.toolTipGUIs = {}
00193 self.toolTipGUI = None
00194 self.infoAreaTop = 0
00195 self.infoAreaLeft = 0
00196 self.infoAreaBottom = 0
00197 self.infoAreaRight = 0
00198 self.showToolTipCallback = None
00199
00200 assert( ToolTipManager.instance == None )
00201 ToolTipManager.instance = self
00202
00203
00204 def addToolTipTemplate( self, templateName, guiFileName ):
00205 if not self.toolTipGUIs.has_key( templateName ):
00206 toolTipGUI = GUI.load( guiFileName )
00207 toolTipGUI.horizontalAnchor = 'CENTER'
00208 toolTipGUI.verticalAnchor = 'CENTER'
00209 toolTipGUI.horizontalPositionMode = 'CLIP'
00210 toolTipGUI.verticalPositionMode = 'CLIP'
00211 toolTipGUI.position.z = self.toolTipZOrder
00212 self.toolTipGUIs[ templateName ] = toolTipGUI
00213 return self.toolTipGUIs[ templateName ]
00214
00215
00216 def setupToolTip( self, component, toolTipInfo ):
00217 if not self.toolTipGUIs.has_key( toolTipInfo.templateName ):
00218 ERROR_MSG( "Setting up tool tip with missing template '%s'" % (toolTipInfo.templateName,) )
00219 return
00220
00221
00222 if self.toolTipGUI != self.toolTipGUIs[ toolTipInfo.templateName ] and self.toolTipGUI in self.rootGUI.children:
00223 self.rootGUI.delChild( self.toolTipGUI )
00224 self.toolTipGUI = None
00225
00226 if toolTipInfo.infoArea:
00227 infoArea = toolTipInfo.infoArea
00228 else:
00229 infoArea = (0.0, 0.0, component.width, component.height)
00230 (self.infoAreaLeft, self.infoAreaTop) = component.localToScreen( (infoArea[0], infoArea[1]) )
00231 (self.infoAreaRight, self.infoAreaBottom) = component.localToScreen( (infoArea[2], infoArea[3]) )
00232
00233 showFunction = partial( self._showToolTip, component, toolTipInfo )
00234
00235 if self.showToolTipCallback is not None:
00236 BigWorld.cancelCallback( self.showToolTipCallback )
00237 self.showToolTipCallback = None
00238
00239 if toolTipInfo.delayType and toolTipInfo.delayType == ToolTip.IMMEDIATE_TOOL_TIP:
00240 showFunction()
00241 self.showToolTipCallback = None
00242 else:
00243 self.showToolTipCallback = BigWorld.callback( ToolTip.DELAY_TIME, showFunction )
00244
00245
00246 def handleMouseEvent( self, dx, dy, dz ):
00247 if self.showToolTipCallback or self.toolTipGUI:
00248 mpos = GUI.mcursor().position
00249 if mpos.x < self.infoAreaLeft or mpos.x > self.infoAreaRight or mpos.y < self.infoAreaBottom or mpos.y > self.infoAreaTop:
00250
00251 if self.toolTipGUI:
00252 self.rootGUI.delChild( self.toolTipGUI )
00253 self.toolTipGUI = None
00254
00255 if self.showToolTipCallback:
00256 BigWorld.cancelCallback( self.showToolTipCallback )
00257 self.showToolTipCallback = None
00258 self.toolTipGUI = None
00259
00260
00261 def _showToolTip( self, component, toolTipInfo ):
00262 self.toolTipGUI = self.toolTipGUIs[ toolTipInfo.templateName ]
00263 self.showToolTipCallback = None
00264 infoArea = (self.infoAreaLeft, self.infoAreaTop, self.infoAreaRight, self.infoAreaBottom)
00265 self.toolTipGUI.script.setupToolTip( toolTipInfo, infoArea )
00266 self.rootGUI.addChild( self.toolTipGUI )
00267
00268