Mouse over & click on text

Hi all,

I am preparing a dialog system for an adventure game and

I needed a way of changing the color of a text and clicking on a
text. DirectButton and onScreenText did not allow me to do that, or
I did not find how to do it. So, I looked for another solution:

import sys

import direct.directbase.DirectStart
from pandac.PandaModules        import *
from direct.gui.OnscreenText    import OnscreenText
from direct.gui.DirectGui       import *
from direct.task                import Task 
from direct.showbase            import DirectObject


class Rectangle:
    def __init__(self):
        self.data = [0, 0, 0, 0]

    def set(self, x1, y1, x2, y2):
        self.data[0] = x1
        self.data[1] = y1
        self.data[2] = x2
        self.data[3] = y2

    def isInto(self, position):
        if not isinstance(position, Point3):
            raise "Position parameter is not of Point3 type"

        if (self.data[0] < position.getX() and position.getX() < self.data[2]) \
            and (self.data[1] < position.getY() and position.getY() < self.data[3]):
            return True
        else:
            return False

    def __str__(self):
        return "Rectangle: [%f, %f - %f, %f]" % \
                (self.data[0],self.data[1],self.data[2],self.data[3])
                

text = TextNode('node name') 
text.setText("Every day in every way I'm getting better and better.") 
text.setTextColor(1, 0.5, 0.5, 1) 
text.setWordwrap(10.0)    # In screen units
text.setAlign(TextNode.ACenter)
# TextNode.ALeft, TextNode.ACenter, or TextNode.ARight


text.setFrameColor(0, 0, 1, 1) 
text.setFrameAsMargin(0.1, 0.1, 0.1, 0.1)

# left, right, bottom, top 
#text.setFrameActual(-0.1, 16.0, -1.0, 0.2) 

#Show in the screen
textNodePath = aspect2d.attachNewNode(text)  

# By default scale = 1.0
myScale = 0.07
textNodePath.setScale(myScale)
textNodePath.setPos(0.0, 0.0, 0.0)

box = text.getFrameActual()
## print box

## print "get.isFrameAsMargin() = ",text.isFrameAsMargin()
## print "get.frameAsSet() = ", text.getFrameAsSet()

rec = Rectangle()

l = box[0] 
r = box[1]
b = box[2]
t = box[3]

#rec.set(l, b, r, t)
#print rec

# Position of the frame in rende2d coordinates space
ll = render2d.getRelativePoint(textNodePath, Point3(l, 0, b))
ur = render2d.getRelativePoint(textNodePath, Point3(r, 0, t))
#rec.set(ll[0], ll[2], ur[0], ur[2])
rec.set(ll.getX(), ll.getZ(), ur.getX(), ur.getZ())
#print rec

p1 = OnscreenText(text = 'll', 
                  pos = (box[0] * myScale, box[2] * myScale), 
                  scale = myScale)
p2 = OnscreenText(text = 'ur', 
                  pos = (box[1] * myScale, box[3] * myScale), 
                  scale = myScale)

# It returns the coordinates of the mouse in the render2d
# coordinates space
def getMousePosition():
    p = None
    
    if base.mouseWatcherNode.hasMouse(): 
        x=base.mouseWatcherNode.getMouseX() 
        y=base.mouseWatcherNode.getMouseY()
        
        # Set as Rectangle class expected it
        p = Point3(x,y,0)
        
        # Convert to aspect2d
        #p1 = aspect2d.getRelativePoint(render2d, p)
        #print p1
    
    return p
        
def exampleTask(task): 
    # Get mouse position
    p = getMousePosition()
    
    if p != None:
        #print p
        if rec.isInto(p):
            #print "Into"
            # Change the color of the text
            text.setTextColor(0.5, 1.0, 0.5, 1)
        else:
            #print "Not into"
            text.setTextColor(1, 0.5, 0.5, 1)

    ## if task.time > 15.0: 
        ## print "Task done"
        ## return Task.done 
    
    return Task.cont

class Hello(DirectObject.DirectObject):
    def __init__(self):
        self.accept('mouse1', self.printHello)
        self.accept('q', self.exit)
        
    def printHello(self):
        # Get mouse position
        p = getMousePosition()
        
        if p != None:
            if rec.isInto(p):
                print 'click on text'
                
    def exit(self):
        print "exit"
        sys.exit(0)
    
h = Hello()

taskMgr.add(exampleTask, 'MyTaskName') 

run()
 Regards.
 Alberto

Actually there is a lot simpler fire-and-forget solution, simply by taking advantage of DirectButton. Its dict holds valuable things :smiley:

DB = DirectButton(
         text="Every day in every way I'm getting better and better.",
         text_fg=(1, 0.5, 0.5, 1), frameColor=(0,0,0,0),
         text_wordwrap=10,
         scale=.07, pos=(0,0,.5),
         #command=,
         )
# text0 : normal
# text1 : pressed
# text2 : rollover
# text3 : disabled
for t in ('text1','text2'):
    DB._DirectGuiBase__componentInfo[t][0].setColor(0.5, 1.0, 0.5, 1)

I’ve used it [HERE].