Updating Canvas pos (DirectScrolledFrame)

I’ve got myself a DirectScrolledFrame (DSF). Using the scroll bars to move the canvas works fine. Now I want to use the mouse to drag around the canvas. That works fine using:

	mpos = base.mouseWatcherNode.getMouse()
	self.mousepos = [Point3(0,0,0),Point3(mpos[0],0,mpos[1])]

def moveCanvas(self, task):
	del self.mousepos[0]
	diffpos = self.mousepos[0] - self.mousepos[1]
	self.Starmap.getCanvas().setPos(self.Starmap.getCanvas().getPos() - Point3(diffpos[0],0,diffpos[2]))

The problem is using setPos() the scroll bars are not updated. They stick at the default position where they were created.

Is one supposed to use setPos()? Or is one supposed to manipulate the




attributes of the DSF? When I try to do so in a task, the canvas just jiggles around when I click&drag. Seems to me that every frame the canvas is positioned, but then canvas snaps back to the default position.

Hmm, I don’t know. What happens if you call frame.guiItem.recompute() immediately after adjusting the slider positions? Or what happens if you adjust the slider positions and also set the canvas directly?


Interesting. Adding that line the DSF does not move anymore at all. Propably snapping back into it’s default position, even though that’s not visible, as in a jiggling.

Being able to drag around the Canvas is kinda important here. This better works.

“This better works?” What do you mean, are you challenging me to a fight if it doesn’t?

The DirectScrolledFrame wasn’t built with this kind of movement in mind, so it’s not surprising that it doesn’t work on the first attempt. However, I am certain it can be made to work. But that might require diving into the underlying code to figure out what it’s doing. You’re certainly welcome to do this–all of the Panda source code is available to you.


No reason to get snippy. That might be the first time that I see you react in this way, normally you are on the contrary overly polite. I honestly don’t see what could have ticked you off here. Please keep in mind that most people here are not native English speakers so there’s lot of imprecision and “lost in translation” going on here. I propably just forgot a smiley behind my sentence.

What I meant to say is that this feature has to work in my game exactly as described, since that is how the older games, that I am building upon, worked. Writing “This better works” I wanted to encourage you to convey information that you might have hold back until then thinking I might just work around the problem.

I am not one of those thinking that free to use, hobby-ish software should be error-free, self-explanatory and supported 24/7. I am also not one of those saying that just because I am too stupid to use a piece of software there must be a bug. Yet it seems plausible to me that there is a bug in DirectScrolledFrame, that causes the frame to jump back into it’s default position, since most Panda developers seem to forgo DirectGUI elements and instead go for other GUI systems. That’s why it seems plausible to me that there are undiscovered bugs. You maybe having experience using DirectGUI might know about there problems.

I did take a look at the DSF code. Notice that my struggle with that element of Panda goes way back, when I tried to figure how the DSF is culled. Problem I just don’t understand the DirectGUI code, not now, not back then. There seem to be three or four layers here with calls going up and down.

A solution to my problem might be to ditch the DSF and use a non-scrolled frame. Just use a DirectFrame as a window to a larger DirectFrame and move that frame around not by scroll bars but by the mouse. But then I am back to the 2010 problem mentioned above: How to clip the larger underlying frame I have no idea.

My apologies. I’ve been under a bit of stress lately, but that’s no excuse for me to be testy.

I think what you are trying to do with the DSF hasn’t been planned as a feature from the beginning, so the existing code is fighting you. If you can give me a few days, I should be able to take a look at how we can fix it.


I did it right, and you were wrong. :smiley:
I don’t set canvas pos, but only the scrollbars pos. I just need to set the canvas position to range ratio to the scrollbars’ values.
Though it’d be better indeed to also have canvas to scrollbars sync, currently it’s only scrollbars to canvas.

from panda3d.core import Point3, TextNode, Vec3
from direct.gui.DirectGui import *
import direct.directbase.DirectStart

DSF = DirectScrolledFrame(
  frameSize = (-.5,1,-.7,.5),
#   frameSize = (0,1,0,1),
#   scale = .7, pos = (0,0,.2)
DSFcanvas = DSF.getCanvas()
DSFcanvasParent = DSFcanvas.getParent()

for t in range(33):
    ot = OnscreenText('-'+str(t)*30, pos=(-1,.95-.06*t), scale=.05, align=TextNode.ALeft)

# The default canvas position is not (0,0,0), it depends on the frameSize.

# Call renderFrame() before querying the position, or else it won't be updated.
# Only calling DSF.guiItem.recompute() gives imprecise position.
# DSF.guiItem.recompute()
DSFcanvasDefaultPos = DSFcanvas.getPos()

# Must know the canvas position range
DSF['horizontalScroll_value'] = DSF['verticalScroll_value'] = 1
DSFcanvasRange = DSFcanvasDefaultPos-DSFcanvas.getPos()
DSFcanvasRange[0] = abs(DSFcanvasRange[0])
DSFcanvasRange[2] = abs(DSFcanvasRange[2])
DSF['horizontalScroll_value'] = DSF['verticalScroll_value'] = 0
print DSFcanvasDefaultPos, DSFcanvasRange

def startScroll():
    m = base.mouseWatcherNode.getMouse()
    m = DSFcanvasParent.getRelativePoint(render2d, Point3(m[0],0,m[1]))
    fs = DSF['frameSize']
    if fs[0]<m[0]<fs[1] and fs[2]<m[2]<fs[3]:
       task = taskMgr.add(scroll, 'scrolltask')
       task.startMouse= m
       task.canvasOrigPos = DSFcanvas.getPos() - DSFcanvasDefaultPos
       base.accept('mouse1-up', taskMgr.remove, [task])
def scroll(task):
    m = base.mouseWatcherNode.getMouse()
    m = DSFcanvasParent.getRelativePoint(render2d, Point3(m[0],0,m[1]))
    canvasPos = task.canvasOrigPos + (m - task.startMouse)
    DSF['horizontalScroll_value'] = -canvasPos[0]/DSFcanvasRange[0]
    DSF['verticalScroll_value'] = canvasPos[2]/DSFcanvasRange[2]
    return task.cont

base.accept('mouse1', startScroll)

Oh my god … that works. Once again you did it :slight_smile:

Interesting. At some point I had something similar for the scroll bars, something like (pseudo-code):

DSF["horizontalScroll_value] = 0.5 +/- newValue

As far as I understand you are doing two key things that I hadn’t thought of. The one thing is the renderFrame() thing, the other the canvasRange thing. But yeah, the latter makes sense. I just assumed 0.5+/-0.5 here, but no, depends on the relative node.

Also very clever how you pass the


thing. That the stuff I don’t think of, that’s why I had

poses = []

to calculate the mouse change from frame to frame.

I will sooner or later post a video of this and other things working. Thanks again!

The renderFrame() call is only needed if you need to get the default pos before calling run(). If you get it eg. in startScoll(), you don’t need renderFrame().