changing mousewatcher depending on position

hello!

look at this image:

i have set up a displayregion for the 3dview

self.pandaDR = base.win.getDisplayRegion(1)
self.pandaDR.setDimensions(l,r,b,t)

so far so good, now i have my 3dstuff rendered into the red window.
my mouse must now be mapped to that region:

base.mouseWatcherNode.setDisplayRegion(self.pandaDR)

that works nice.
but now i can’t click the buttons.
i want to have the mouse mapped to the 3dview, if my mouse is over the 3dview, but when i move out of the 3dview, the mouse should then use the gui(aspect2d)-displayregion, which is displayregion(2), i think.

do you know what i mean?
it’s maybe a noob question, but i can’t figure out how to set the mousewatcher depending on where the mouse is acting…

greetz, kampfgnu

Hmm, I don’t know if this works, but you can always try it:

if(not base.mouseWatcherNode.hasMouse()):
  base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(0))
elif(base.mouseWatcherNode.getMouseX()>=self.pandaDR.getLeft() and base.mouseWatcherNode.getMouseX()<= self.pandaDR.getRight() and base.mouseWatcherNode.getMouseY()>=self.pandaDR.getBottom() and base.mouseWatcherNode.getMouseY()<=self.pandaDR.getTop()):
  base.mouseWatcherNode.setDisplayRegion(self.pandaDR)

i tried that before… the problem is, that the mousewatcher always has values from -1 to 1 for X and Y.
so, if i change the mousewatchernode-displayregion to another, it still has values from -1 to 1.

do you know what i mean?

or maybe can i create a second mousewatcher for my aspect2d stuff?

i have no other ideas in how to solve that problem.

please give me some advice.

greets

you probably just have to convert using the your region coordinates and the -1 to 1 of mouse watcher.

i hope i get you right, i tried this ,please move slowy between the screens, you can write a while between for a short brake or something like that - but it should work :wink: ->

greetz
dirk :wink:

#mouseWATCHER dirk hochegger 2008
#switching  DISPLAYS

import direct.directbase.DirectStart
from direct.showbase import DirectObject

import buttons

left = 0
right = .5
bottom = 0
top = .5

screenL = 1
screenR = 1
screenB = 1
screenT = 1

set1 = 0
set2 = 0

check = 0

class display (DirectObject.DirectObject):
    def __init__(self):
        base.setBackgroundColor(0, 0, 0)
        obj = loader.loadModel("cube")
        obj.reparentTo(render)
        obj.setPos(0,10,0)
        base.camNode.setActive(0)
        base.makeCamera(base.win, displayRegion = (left, right, bottom, top))
        self.screen = base.win.getDisplayRegion(1) 
        self.screen.setDimensions(left, right, bottom, top)

        
        
        def mouse(task):

            
            global x
            x = base.mouseWatcherNode.getMouseX()
            global y
            y = base.mouseWatcherNode.getMouseY()
            
            if x < 0 and y < 0:
                print "mouse IN"
                global set1
                global set2
                global check1
                set1 = 1
                set2 = 0
            
            
            
            if set1 == 1:
                base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(1))
                check = 1
                print check
                if x > .9 or y > .9:
                    print "change DISPLAY"
                    global set2
                    global set1
                    set2 = 1  
                    set1 = 0

            
                
            if set2 == 1:
                base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(0))
                check = 0
                global set2
                global set1
                set2 = 1  
                set1 = 0
                print check
            
            print x
            print y
            
            return task.cont
        taskMgr.add(mouse,"mouseTask")
        

            

d = display()
run()
        

you can use a brake for the switching or like i done in this code -> just changed the tollerance area…

#mouseWATCH node dirk hochegger 2008
#switching between DISPLAYS

import direct.directbase.DirectStart
from direct.showbase import DirectObject

import buttons

left = 0
right = .5
bottom = 0
top = .5

screenL = 1
screenR = 1
screenB = 1
screenT = 1

set1 = 0
set2 = 0

check = 0

class display (DirectObject.DirectObject):
    def __init__(self):
        base.setBackgroundColor(0, 0, 0)
        obj = loader.loadModel("cube")
        obj.reparentTo(render)
        obj.setPos(0,10,0)
        base.camNode.setActive(0)
        base.makeCamera(base.win, displayRegion = (left, right, bottom, top))
        self.screen = base.win.getDisplayRegion(1) 
        self.screen.setDimensions(left, right, bottom, top)

        
        
        def mouse(task):

            
            global x
            x = base.mouseWatcherNode.getMouseX()
            global y
            y = base.mouseWatcherNode.getMouseY()
            
            
            
            if x < -.1 and y < -.1:
                print "mouse IN"
                global set1
                global set2
                global check1
                set1 = 1
                set2 = 0
            
            
            
            
            
            if set1 == 1:
                base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(1))
                check = 1
                print check
                if x > .9 or y > .9:
                    
                    print "change DISPLAY"
                    global set2
                    global set1
                    set2 = 1  
                    set1 = 0

            
                
            if set2 == 1:
                base.mouseWatcherNode.setDisplayRegion(base.win.getDisplayRegion(0))
                check = 0
                global set2
                global set1
                set2 = 1  
                set1 = 0
                print check
            
            print x
            print y
            
            return task.cont
        taskMgr.add(mouse,"mouseTask")
        

            

d = display()
run()
        

still not buttons.py

:unamused: where is your imaginations power??? :wink:

import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.OnscreenImage import OnscreenImage 
from direct.gui.DirectGui import *



class buttons (DirectObject.DirectObject):
    def __init__ (self):
        
        print "loading the damn buttons are you happy now???"
        
        self.bttnSP = DirectButton(image = "button.tif",command = self.button, scale = (.2, .05, .05), relief = None)
        self.bttnSP.setTransparency(1)    
        self.bttnSP.setPos(0, 0, 0)
    
    def button (self):
        print "happy button check check ;)"

b = buttons()

button.tif ?

hmmm looks like a workaround.
isn’t there another way to get that thing to work?

isn’t it possible to have a mousewatcher mapped to the whole window (for the aspect2d stuff) and a second one for the little 3d window?

its making me crazy…

anyway…thanks dirk!

If you still want -1~1 range (or do you want 0~1 ? ) relative to whole screen, so what’s the point of setting the displayreg for mousewatcher ?
Moreover, if you set the mouse watcher’s displayreg to another one, all DirectGui stuff will use it too. It means if you have a button in the middle of the screen, after altering mouse watcher’s displayreg, that button would respond to a click in the middle of the displayreg. Haven’t you noticed that ?

If you only need to block mouse interface if the mouse get off the region, it’s easy. I only need to use modifier buttons when it’s outside the region (on Windows, meta blocks it all the way, while on Mac, alt does the job, I hope). There are also some low-level enter-leave events for mouse region. You just need to create a button to match the region’s size and catch the events.

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.gui.DirectGui import *
import sys

def a2d2DR(reg):
    asp=base.getAspectRatio()
    return ( asp*(reg[0]*2.-1), asp*(reg[1]*2.-1), reg[2]*2.-1,reg[3]*2.-1 )

def toggleModifiers(status):
#     base.mouseInterfaceNode.requireButton(KeyboardButton.control(), status)
#     base.mouseInterfaceNode.requireButton(KeyboardButton.shift(), status)
    base.mouseInterfaceNode.requireButton(KeyboardButton.alt(), status)
    base.mouseInterfaceNode.requireButton(KeyboardButton.meta(), status)


class World(DirectObject):
  def __init__(self):
      self.accept('escape',sys.exit)

      reg=(.5,1,.5,1)
      base.camNode.setActive(0)
      base.makeCamera(base.win, displayRegion = reg)

      smi=loader.loadModel('smiley')
      smi.reparentTo(render)

      camera.setY(-3)
      mat=Mat4(camera.getMat())
      mat.invertInPlace()
      base.mouseInterfaceNode.setMat(mat)
      
      for b in range(5):
          DirectButton(text='BUTTON',scale=.1,pos=(0,0,-.1-.15*b))

      self.DRprobe=DirectButton( 
                            rolloverSound=None,clickSound=None,
                            frameSize=a2d2DR(reg), frameColor=(0,0,0,0),
                            suppressMouse=0,suppressKeys=0 )
      self.accept(DGG.ENTER+self.DRprobe.guiId,self.intoDR1)
      self.accept(DGG.EXIT+self.DRprobe.guiId,self.offDR1)

#       messenger.toggleVerbose()
      base.mouseWatcherNode.showRegions(render2d,'gui-popup',0)
      self.offDR1(0)
      
  def intoDR1(self,m):
      toggleModifiers(False)
      print 'intoDR1'
  def offDR1(self,m):
      toggleModifiers(True)
      print 'offDR1'

World() 
run()

bottom line : what’s your detailed clear goal exactly ? So far, you only tell us your scenario.

thanks for your response, i will check this out.

to my scenario:

i am trying to make a virtual museum, where you can walk around in its rooms, clicking objects like an image or so, and then get detailed infos about the object (i want to hide the 3dview then, and show a screen with the image, detail infos and so on).

thats the detailview (no 3dview displayed here)

when you click on the button “back to 3d”, again, i want my mainscreen (3dview and some buttons like in the image in my first post)

i have a 3dworld with some collisionobjects.
i want these objects to be touched, when i move the mouse over them.
but as long as the mouse is mapped to the “whole window”, the coords of the collisionobjects do behave like they too are placed at the whole window.
lets say i have a collisionobject at the middle of the 3dviewscreen, then the collision happens, when i move the mouse to the middle of the “whole window”.
thats why i need to map the mouse to the 3dregion, because then, the collision really happens when i move the mouse to the middle of my 3dview.

but: i also have some gui elements that i want to click sometimes. as long as the mouse is mapped to the 3dregion, a button in the left bottom corner of the whole window only can be clicked at the left bottom corner of the 3dview (as you mentioned in you post above), and thats the problem.

now i want to either have 2 mousewatchers, one listening for the gui-elements (where i maybe should disable 3dinteraction) and a second one listening to the 3dview(where i disable guiinteraction), or i need to switch the mousewatchers displayregion, depending on where the mouse is moving around.

i hope i could explain you my scenario.

greets

There you go ! Why didn’t you say it in the beginning ?
If that’s what you need, it’s whole lot easier. You can live without messing around with mouse watcher’s display region at all. :laughing:
You only need to apply some transform to your collision ray, as much as the 3d display region transform, relative to render2d. I created a dummy node under render2d to ease the transform calc.

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.interval.IntervalGlobal import *
from direct.gui.DirectGui import *
import sys


class World(DirectObject):
  def __init__(self):
      self.accept('escape',sys.exit)
      self.accept('mouse1',self.pickObj)

      self.pickerNode = CollisionNode('mouseRay')
      self.pickerRay = CollisionRay()               #Make our ray
      self.pickerNode.addSolid(self.pickerRay)      #Add it to the collision node
      #Everything to be picked will use bit 1. This way if we were doing other
      #collision we could seperate it
      self.pickerNode.setFromCollideMask(BitMask32.bit(1))
      #Attach that node to the camera since the ray will need to be positioned
      #relative to it
      self.pickerNP = camera.attachNewNode(self.pickerNode)

      self.pq     = CollisionHandlerQueue()         #Make a handler
      self.picker = CollisionTraverser()            #Make a traverser
      self.picker.addCollider(self.pickerNP, self.pq)
      
      self.picked=None
      self.pickedIval=None

      reg=(.5,1,.5,1)
      self.DR1dummy=render2d.attachNewNode('DR1dummy')
      self.DR1dummy.setPos(reg[0]+reg[1]-1,0,reg[2]+reg[3]-1)
      self.DR1dummy.setScale(reg[1]-reg[0],1,reg[3]-reg[2])
      print self.DR1dummy.pPrintString()
      
      base.camNode.setActive(0)
      base.makeCamera(base.win, displayRegion = reg)

      num=7
      for x in range(num):
          smi=loader.loadModel('smiley')
          smi.reparentTo(render)
          smi.setPos(x-(num-1)*.5,0,.75*(x-(num-1)*.5))
          smi.setScale(.5)
          smi.setCollideMask(BitMask32.bit(1))

      for b in range(5):
          DirectButton(text='BUTTON',scale=.1,pos=(0,0,-.1-.15*b))

      camera.setY(-6)
      base.disableMouse()
      # highlight the active mouse regions
      base.mouseWatcherNode.showRegions(render2d,'gui-popup',0)

  def pickObj(self):
      if not base.mouseWatcherNode.hasMouse(): return
      mpos = base.mouseWatcherNode.getMouse() # MOUSE POS RELATIVE TO RENDER2D
      # MAKE IT RELATIVE TO THE DUMMY NODE WHOSE TRANSFORM REPRESENTS
      # THE 3D DISPLAY REGION'S RELATIVE TRANSFORM TO RENDER2D
      mpos=self.DR1dummy.getRelativePoint(render2d,Point3(mpos[0],0,mpos[1]))
      if not(-1<mpos[0]<1 and -1<mpos[2]<1): # OUTSIDE 3D DISPLAY REGION
         print 'YOU CLICKED OUTSIDE THE 3D DISPLAY REGION'
         return 

      #Set the position of the ray based on the mouse position
      self.pickerRay.setFromLens(base.camNode, mpos[0], mpos[2])

      self.picker.traverse(render)
      if self.pq.getNumEntries() > 0:
         #if we have hit something, sort the hits so that the closest
         #is first, and highlight that node
         self.pq.sortEntries()
         if self.picked!=None:
            self.picked.clearColorScale()
            self.pickedIval.setT(0) # somehow clearToInitial() didn't work
            self.pickedIval.pause()
            self.pickedIval=None
         self.picked=self.pq.getEntry(0).getIntoNodePath().getParent()
         self.picked.setColorScale(1,0,0,1)
         self.pickedIval=self.picked.hprInterval(1,Vec3(360,0,0))
         self.pickedIval.loop()
         

World() 
run()

Click on the smileys. see if I broke something.

:laughing:
yes, for that cartoon scenario i would also go the way with collisions rays :smiley:

btw. why you used two mousewatchers??? that would make no sense :wink:

but its very curious im doing also 3d galleries :smiley:

maybe i know u??? :stuck_out_tongue:

ynjh_jo, thank you very very very much for the code and your tips and comments and all…!
you are my god :smiley:
thats exactly the thing i need, now everything is just perfect.
thanks again!

ditus, it’s very funny you do the same stuff.
but do you really use your code above to get things working?
i think that would make loads of troubles everywhere in the program…
better ask ynjh_jo, he is the man.

greets, kampfgnu

p.s.: thanks thanks thanks

oh yes im using my code to make things working lol

you think???

you should find a programmer like me (if you not already did) :laughing:

i figured out a other workflow,without a collisionray, if you set a direct button as your background it works also :wink: ,thats it :wink: and it works fine :wink:

renderstates:
0 = backgrnd
1 = buttons
2 = viewport

here a example for the other way… without collisionrays

run.py

#dhochegger 2008
import direct.directbase.DirectStart
from direct.showbase import DirectObject

#display order

import background
import buttons
import 3Dview

run()

background.py

#dhochegger2008
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.DirectGui import *

scale = .5
count = 4
class BACKGROUND (DirectObject.DirectObject):
    def __init__ (self):
            Xratio = float(scale / 3.0000+scale)            
            print "X->",Xratio

            background = DirectButton(image = "bckgrnd.tif",pressEffect = 0,pos = (.65,0,0), command = self.background,rolloverSound = "",clickSound = "", relief = None)
            background.setTransparency(1)    
            background.setScale(Xratio,0,.98)
            
            background1 = DirectButton(image = "bckgrnd.tif",pressEffect = 0,pos = (-.65,0,.48), command = self.background,rolloverSound = "",clickSound = "", relief = None)
            background1.setTransparency(1)    
            background1.setScale(Xratio,0,.5)           
                 
    def background (self):
        print "BACKGROUND.."

ba = BACKGROUND()

3Dview.py

#dhochegger 2008
import direct.directbase.DirectStart
from direct.showbase import DirectObject
left = 0
right = .5
bottom = 0
top = .5
class display (DirectObject.DirectObject):
    def __init__(self):

        base.setBackgroundColor(0, 0, 0)
        obj = loader.loadModel("cube")
        obj.reparentTo(render)
        obj.setPos(0,10,0)
        base.camNode.setActive(0)
        base.makeCamera(base.win, displayRegion = (left, right, bottom, top))
        
d = display()
run()

buttons.py

#dhochegger 2008
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.DirectGui import *
from pandac.PandaModules import Point3,Vec3,Vec4
from direct.interval.LerpInterval import LerpFunc
from direct.interval.IntervalGlobal import * 
import sys
count = 4
class buttons (DirectObject.DirectObject):
    def __init__ (self):        
        XX = 0
        for x in range(count):
            XX += .15
            button = DirectButton(image = "button.tif", command = self.button, scale = (.2, .05, .05),rolloverSound = "", relief = None)
            button.setTransparency(1)    
            button.setPos(.65, 0,  -.1-XX)       
            X1=button.colorScaleInterval( .5,Vec4(1,1,1,1),Vec4(1,1,1,0) )
            X2=button.colorScaleInterval( 1.5,Vec4(1,1,1,0) )  
            Sequence( X1,Wait(.1),X2 ).loop()
    def button (self):
        print "happy button check check ;)"
b = buttons()