class Main(ShowBase,  ConfigFSM):
    def __init__(self):
        self.loadingText = None
        self.saveFolderPath = './saves/'
        self.appName = appName
        ShowBase.__init__(self)
        self.textEngine = TextEngine(base.messenger.send)
        self.mapData = MapsModel()
        self.gameData = GameModel(self.saveFolderPath)
        ConfigFSM.__init__(self)
        self.disableMouse()
        self.callLoadingScreen()

        self.request("StartMenu")
        # self.request("RPGField")
        # self.request("Cutscene")

    def callLoadingScreen(self):
        self.loadingText = DirectFrame(
            frameSize=(base.a2dLeft, base.a2dRight,
                       base.a2dBottom, base.a2dTop),
            frameColor=(0, 0, 0, 1.0))

        txt = OnscreenText("Loading...", 1, fg=(1, 1, 1, 1), pos=(
            0, 0), align=TextNode.ACenter, scale=.07, mayChange=1)
        txt.reparentTo(self.loadingText)
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()

    def removeLoadingScreen(self):
        if self.loadingText:
            self.loadingText.removeNode()
        self.loadingText = None
Esempio n. 2
0
class Main(ShowBase, ConfigFSM):
    def __init__(self, appName):
        self.appName = appName
        self.loadingText = None
        ShowBase.__init__(self)
        ConfigFSM.__init__(self)
        self.request('StartMenu')

    def callLoadingScreen(self):
        self.loadingText = DirectFrame(
            frameSize=(base.a2dLeft, base.a2dRight,
                       base.a2dBottom, base.a2dTop),
            frameColor=(0, 0, 0, 1.0))

        txt = OnscreenText("Loading...", 1, fg=(1, 1, 1, 1), pos=(
            0, 0), align=TextNode.ACenter, scale=.07, mayChange=1)
        txt.reparentTo(self.loadingText)
        base.graphicsEngine.renderFrame()
        base.graphicsEngine.renderFrame()

    def removeLoadingScreen(self):
        if self.loadingText:
            self.loadingText.removeNode()
        self.loadingText = None
class GUIDialog:
    def __init__(self):
        self.mainFrame = DirectFrame(frameColor=(0, 0, 0, 0.5),
                                     borderWidth=(10, 10),
                                     frameSize=(-2, 2, -1, -0.45))
        self.textIndex = 0
        self.isCalling = False
        self.frameText = None
        self.frameActor = None
        self.frameChoices = None
        self.textList = []
        self.hide()

    def setLabel(self, labelName):
        base.textEngine.setTextLabel(labelName)
        self.textList = base.textEngine.getDialogue()
        self.processLine(self.textList[self.textIndex])

    def processLine(self, line):
        if line['type'] == 'text':
            self.dialogueLine(line)
        elif line['type'] == 'menu':
            self.choiceLine(line)

    def choiceLine(self, lineObj):
        self.setFrameText(lineObj['text'])
        self.setFrameChoices(lineObj)
        self.show()

    def dialogueLine(self, lineObj):
        self.setFrameActor(lineObj['actor'])
        self.setFrameText(lineObj['line'])
        self.show()

    def showMessage(self, txt):
        self.setFrameText(txt)
        self.show()

    def setFrameChoices(self, lineObj):
        base.resetButtons()
        if self.frameChoices:
            self.frameChoices.quit()

        optionsList = lineObj['options']
        self.frameChoices = GUIDialogOptions(optionsList)
        self.frameChoices.reparentTo(self.mainFrame)
        taskMgr.add(self.frameChoices.readKeys, "readKeysTask")
        for option in optionsList:
            index = optionsList.index(option)
            base.accept("TextChoice-{}".format(index), self.chooseOption,
                        [lineObj, index])

    def destroyFrameChoices(self, optionsList):
        self.frameChoices.quit()
        self.frameChoices = None
        taskMgr.remove("readKeysTask")
        for option in optionsList:
            index = optionsList.index(option)
            base.ignore("TextChoice-{}".format(index))

    def chooseOption(self, lineObj, index):
        base.textEngine.chooseFromMenu(lineObj, index)
        self.destroyFrameChoices(lineObj['options'])
        self.textList = base.textEngine.getDialogue()
        self.textIndex = 0
        self.processLine(self.textList[self.textIndex])

    def setFrameActor(self, text):
        if self.frameActor:
            self.frameActor.detach_node()
        self.frameActor = OnscreenText(text=text,
                                       pos=(-1.2, -0.55),
                                       scale=0.07,
                                       wordwrap=35,
                                       mayChange=False,
                                       align=TextNode.ALeft,
                                       fg=(1, 1, 1, 1),
                                       shadow=(0, 0, 0, 1),
                                       shadowOffset=(0.05, 0.05))
        self.frameActor.reparentTo(self.mainFrame)

    def setFrameText(self, text):
        if self.frameText:
            self.frameText.detach_node()
        self.frameText = OnscreenText(text=text,
                                      pos=(-1.2, -0.65),
                                      scale=0.07,
                                      wordwrap=35,
                                      mayChange=False,
                                      align=TextNode.ALeft,
                                      fg=(1, 1, 1, 1),
                                      shadow=(0, 0, 0, 1),
                                      shadowOffset=(0.05, 0.05))
        self.frameText.reparentTo(self.mainFrame)

    def show(self):
        self.mainFrame.show()

    def hide(self):
        self.mainFrame.hide()
        if self.frameText:
            self.frameText.detach_node()
        if self.frameActor:
            self.frameActor.detach_node()
        self.textIndex = 0
        self.frameText = None

    def next(self):
        if not self.isCalling:
            self.isCalling = True
            taskMgr.doMethodLater(.1, self.nextText, 'Next Text')

    def nextText(self, task):
        if self.textIndex < len(self.textList) - 1:
            self.textIndex += 1
            self.processLine(self.textList[self.textIndex])
        else:
            self.hide()

        self.isCalling = False
        return task.done

    @property
    def isShowing(self):
        return self.frameText != None

    @property
    def isChoices(self):
        return self.frameChoices != None

    def reparentTo(self, target):
        self.mainFrame.reparentTo(target)

    def removeNode(self):
        self.mainFrame.removeNode()
Esempio n. 4
0
class FileDialog(DirectObject):
    def __init__(self, title, initial_status, callback):
        self.frmLeft = -.7
        self.frmBottom = -.12
        self.frmRight = .7
        self.frmTop = .12

        self.frmWidth = self.frmRight - self.frmLeft
        self.frmHeight = self.frmTop - self.frmBottom

        self.title = title
        self.initial_status = initial_status
        self.callback = callback

        self.result = None
        self.done = 0

    def activate(self):
        # create main dialog frame
        # Note: frame position references the CENTER of the frame
        self.frm = DirectFrame(pos=(0, 0, 0),
                               frameSize=(self.frmLeft, self.frmRight,
                                          self.frmBottom, self.frmTop),
                               relief=DGG.RIDGE,
                               borderWidth=(0.01, 0.01),
                               frameColor=(0.6, 0.6, 0.6, 1.0))

        self.frm.reparentTo(base.aspect2d)

        # Note: wonderfully enough, label position on the other hand
        # references the CENTER of the LEFT border of the label!
        titleLabel = DirectLabel(text=self.title,
                                 scale=0.04,
                                 frameColor=(0.5, 0.5, 0.5, 1),
                                 relief=DGG.RIDGE,
                                 borderWidth=(0.01, 0.01),
                                 text_align=TextNode.ALeft)

        titleLabel.setPos(-self.frmWidth / 2 + .02, 0,
                          self.frmHeight / 2 - .045)
        titleLabel.reparentTo(self.frm)

        sc = .04
        self.dir_edit_field = DirectEntry(
            text='',  # prompt text
            scale=sc,
            frameColor=(0.65, 0.65, 0.65, 1),
            command=self.setText,
            width=32,
            numLines=1,
            focus=1,
            focusInCommand=self.efFocusIn,
        )

        self.dir_edit_field.setPos(-self.frmWidth / 2 + .02, 0,
                                   self.frmHeight / 2 - .13)
        self.dir_edit_field.reparentTo(self.frm)

        self.statusLabel = DirectLabel(
            text=self.initial_status,
            scale=0.04,
            frameColor=(0.6, 0.6, 0.6, 1),
            # relief = DGG.RIDGE,
            # borderWidth = (0.01, 0.01),
            text_align=TextNode.ALeft)

        self.statusLabel.setPos(-self.frmWidth / 2 + .02, 0,
                                self.frmHeight / 2 - .2)
        self.statusLabel.reparentTo(self.frm)

    # call this if you need to run a form before your mainloop starts steppping the taskMgr
    def run(self):
        while self.done != 1:
            taskMgr.step()

        taskMgr.step(
        )  # once more to make the last output from the dialog visible
        # while we load a zone
        self.frm.removeNode()

    def end(self):
        self.frm.removeNode()

    # callback function to set  text: called by the Panda3d taskMgr when the user
    # has entered something into the DirectEntry widget
    def setText(self, textEntered):
        print 'dir_edit_field::setText:', textEntered
        self.done = self.callback(textEntered)
        if self.done != 1:
            self.dir_edit_field['focus'] = 1

    #clear the text
    def efFocusIn(self):
        print 'focus in'
        self.dir_edit_field.enterText('')

    def setStatus(self, status):
        self.statusLabel['text'] = status
Esempio n. 5
0
class FileDialog(DirectObject):

    def __init__(self, title, initial_status, callback):
        self.frmLeft = -.7
        self.frmBottom = -.12
        self.frmRight = .7
        self.frmTop = .12
        
        self.frmWidth = self.frmRight - self.frmLeft
        self.frmHeight = self.frmTop - self.frmBottom
        
        self.title = title
        self.initial_status = initial_status
        self.callback = callback
        
        self.result = None
        self.done = 0
            
            
    def activate(self):
        # create main dialog frame
        # Note: frame position references the CENTER of the frame
        self.frm = DirectFrame(
            pos = (0,0,0),
            frameSize = (self.frmLeft, self.frmRight,self.frmBottom, self.frmTop),
            relief = DGG.RIDGE,
            borderWidth = (0.01, 0.01),
            frameColor = (0.6, 0.6, 0.6, 1.0))
        
        self.frm.reparentTo(base.aspect2d)
        
        # Note: wonderfully enough, label position on the other hand
        # references the CENTER of the LEFT border of the label!
        titleLabel = DirectLabel(text = self.title,
            scale = 0.04,
            frameColor = (0.5, 0.5, 0.5, 1),
            relief = DGG.RIDGE,
            borderWidth = (0.01, 0.01),
            text_align = TextNode.ALeft)
            
        titleLabel.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.045)
        titleLabel.reparentTo(self.frm)
        
        sc = .04     
        self.dir_edit_field = DirectEntry(
            text = '',      # prompt text
            scale = sc,
            frameColor = (0.65, 0.65, 0.65, 1),
            command=self.setText,
            width = 32,
            numLines = 1,
            focus = 1,
            focusInCommand=self.efFocusIn,
            )

        self.dir_edit_field.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.13)
        self.dir_edit_field.reparentTo(self.frm)

        self.statusLabel = DirectLabel(text = self.initial_status,
            scale = 0.04,
            frameColor = (0.6, 0.6, 0.6, 1),
            # relief = DGG.RIDGE,
            # borderWidth = (0.01, 0.01),
            text_align = TextNode.ALeft)
            
        self.statusLabel.setPos(-self.frmWidth/2+.02, 0, self.frmHeight/2-.2)
        self.statusLabel.reparentTo(self.frm)

    # call this if you need to run a form before your mainloop starts steppping the taskMgr
    def run(self):
        while self.done != 1:
            taskMgr.step()

        taskMgr.step()          # once more to make the last output from the dialog visible
                                # while we load a zone
        self.frm.removeNode()

    def end(self):
        self.frm.removeNode()
        

    # callback function to set  text: called by the Panda3d taskMgr when the user
    # has entered something into the DirectEntry widget
    def setText(self, textEntered):
        print 'dir_edit_field::setText:', textEntered
        self.done = self.callback(textEntered)
        if self.done != 1:
            self.dir_edit_field['focus'] = 1

                
    #clear the text
    def efFocusIn(self):
        print 'focus in'
        self.dir_edit_field.enterText('')
        
    def setStatus(self, status):
        self.statusLabel['text'] = status
class IMenu(metaclass=abc.ABCMeta):
    def __init__(self, frame=None):
        self.hasLoaded = False
        self.menuVerticalChoicesList = [
            {"event": "Example-Event", "text": "Override this"}]
        self.menuVerticalChoice = [0]
        self.menuHorizontalChoices = [
            {"event": "Example-Event", "text": "Override this"}]
        self.menuHorizontalChoice = [0]
        self.menuVerticalButtons = []
        self.menuHorizontalButtons = []
        self.isButtonUp = True
        self.init_frame(frame)

    def init_frame(self, frame):
        if frame:
            self.frameMain = frame
        else:
            self.frameMain = DirectFrame(
                frameSize=(base.a2dLeft, base.a2dRight,
                           base.a2dBottom, base.a2dTop),
                frameColor=(0, 0, 0, 0.0))

    def show(self):
        self.frameMain.show()

    def hide(self):
        self.frameMain.hide()

    def quit(self):
        self.frameMain.removeNode()

    def readKeys(self, task):
        keysPressed = sum(base.directionMap.values())

        if keysPressed == 0:
            self.isButtonUp = True

            if base.commandMap["confirm"]:
                self.menuVerticalEvent()
                base.messenger.send("playConfirm")
            elif base.commandMap["cancel"]:
                self.cancelCommand()
                base.messenger.send("playCancel")

            base.resetButtons()
            return task.cont

        if not self.isButtonUp:
            return task.cont

        if base.directionMap["up"]:
            self.navigateChoice(-1, self.menuVerticalChoice,
                                self.menuVerticalChoicesList)
            self.isButtonUp = False
        elif base.directionMap["down"]:
            self.navigateChoice(1, self.menuVerticalChoice,
                                self.menuVerticalChoicesList)
            self.isButtonUp = False
        elif base.directionMap["left"]:
            self.navigateChoice(-1, self.menuHorizontalChoice,
                                self.menuHorizontalChoices)
            self.isButtonUp = False
            self.menuHorizontalEvent()
        elif base.directionMap["right"]:
            self.navigateChoice(1, self.menuHorizontalChoice,
                                self.menuHorizontalChoices)
            self.isButtonUp = False
            self.menuHorizontalEvent()

        base.resetButtons()
        return task.cont

    def navigateChoice(self, value, choice, choiceList):
        choice[0] += value

        if choice[0] < 0:
            choice[0] = len(choiceList) - 1
        elif choice[0] > len(choiceList) - 1:
            choice[0] = 0

        self.updateCheckbuttons()

    def updateCheckbuttons(self):
        for btn in self.menuVerticalButtons:
            index = self.menuVerticalButtons.index(btn)
            isPressed = index == self.menuVerticalChoice[0]
            btn["indicatorValue"] = isPressed
            btn.setIndicatorValue()

        for btn in self.menuHorizontalButtons:
            index = self.menuHorizontalButtons.index(btn)
            isPressed = index == self.menuHorizontalChoice[0]
            btn["indicatorValue"] = isPressed
            btn.setIndicatorValue()

    def menuVerticalEvent(self):
        base.messenger.send(
            self.menuVerticalChoicesList[self.menuVerticalChoice[0]]["event"])

    def menuHorizontalEvent(self):
        base.messenger.send(
            self.menuHorizontalChoices[self.menuHorizontalChoice[0]]["event"])

    def createVerticalButtons(self):
        for btn in self.menuVerticalChoicesList:
            index = self.menuVerticalChoicesList.index(btn)
            self.createButton(
                btn['text'],
                index,
                [btn['event']])

    @abc.abstractmethod
    def createButton(self, text, index, eventArgs):
        raise NotImplementedError('subclass must define this method')

    @abc.abstractmethod
    def cancelCommand(self):
        raise NotImplementedError('subclass must define this method')
Esempio n. 7
0
class GuiButton2:
    def __init__(self, hugpos, offset, aspect, plane, name):
        self.enabled = True
        self.name = name
        
        self.frame = DirectFrame(   relief = DGG.FLAT
                                  , frameColor = (0, 0, 0, 0)
                                  , scale = 1
                                  , frameSize = (-0.3, 0.3, -0.3, 0.3) ) #32/600=0.05333
        self.frame.setScale(0.0533)
        
        self.imageObject = OnscreenImage(image = name+".png", pos = (0, 0, 0))
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)
        self.imageObject.setAlphaScale(1) 
        self.imageObject.reparentTo(self.frame)
        
        self.hugpos = hugpos
        self.offset = offset
        self.redraw(aspect)

    def redraw(self, aspect, flag="wide"):
        if self.hugpos == "top":
            p = base.a2dTopLeft.getPos()#@UndefinedVariable
            p.setX(p.getX() + self.offset.getX() + 0.05)
            p.setZ(p.getZ() + self.offset.getZ() - GUI_TOP_OFFSET - 0.05)
        elif self.hugpos == "bottom":
            p = base.a2dBottomLeft.getPos()#@UndefinedVariable
            p.setX(p.getX() + self.offset.getX() + 0.05)
            p.setZ(p.getZ() + self.offset.getZ() + GUI_BOTTOM_OFFSET - 0.05)
        elif self.hugpos == "right":
            p = base.a2dBottomRight.getPos()#@UndefinedVariable
            p.setX(p.getX() + self.offset.getX() + 0.05)
            p.setZ(p.getZ() + self.offset.getZ() + GUI_BOTTOM_OFFSET - 0.05)
        self.frame.setPos(p)
        if flag == "wide":
            posx, posy = self.frame.getTightBounds()
            self.pos_min_x = posx.getX() / aspect
            self.pos_min_y = posx.getZ()
            self.pos_max_x = posy.getX() / aspect
            self.pos_max_y = posy.getZ()
        elif flag == "tall":
            posx, posy = self.frame.getTightBounds()
            self.pos_min_x = posx.getX()
            self.pos_min_y = posx.getZ() / aspect
            self.pos_max_x = posy.getX()
            self.pos_max_y = posy.getZ() / aspect
            
    def turnOn(self):
        self.imageObject.setImage(self.name+"_on.png")#@UndefinedVariable
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)
        
    def turnOff(self):
        self.imageObject.setImage(self.name+".png")#@UndefinedVariable
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)    
            
    def enable(self):
        self.imageObject.setImage(self.name+".png")#@UndefinedVariable
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)
        self.enabled = True
        
    def disable(self):
        self.imageObject.setImage("empty.png")#@UndefinedVariable
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)
        self.enabled = False
            
    def removeNode(self):
        self.frame.removeNode()   
        
    def setAbility(self, ability):
        self.name = ability
        self.imageObject.setImage(self.name+".png")
        self.imageObject.setTransparency(TransparencyAttrib.MAlpha)
        self.imageObject.setAlphaScale(1) 
Esempio n. 8
0
class DirectWindow( DirectFrame ):
  def __init__( self
              , pos         = ( -.5, .5)
              , title       = 'Title'
              , bgColor  = (.5,.5,.5,1)
              , buttonColor = (1,1,1,1) #( .6, .6, .6, 1 )
              #, minSize     = ( .5, .5 )
              #, maxSize     = ( 1, 1 )
              , minWindowSize = (0,0)
              , maxWindowSize = (10000,10000)
              , virtualSize = (1,1)
              , windowBorderTextureFiles = [ DEFAULT_TITLE_TEXTURE_LEFT
                                       , DEFAULT_TITLE_TEXTURE_CENTER
                                       , DEFAULT_TITLE_TEXTURE_RIGHT
                                       , DEFAULT_RESIZE_GEOM ]
              , windowBorderGeomFiles = [ DEFAULT_TITLE_GEOM_RIGHT ]
              , windowColors    = [ ( 1, 1, 1, 1 )
                                  , ( 1, 1, 1, 1 )
                                  , ( 1, 1, 1, 1 )
                                  , ( 1, 1, 1, 1 ) ]
              , borderSize = 0.01
              , dragbarSize = 0.05
              , parent=None):
    self.windowPos = pos
    self.minWindowSize = minWindowSize
    self.maxWindowSize = maxWindowSize
    self.virtualSize = virtualSize
    self.borderSize = borderSize
    self.dragbarSize = dragbarSize
    
    if parent is None:
      parent=aspect2d
    self.parent=parent
    
    self.previousSize = (10,10)
    self.collapsed = False
    
    # maybe we should check if aspect2d doesnt already contain the aspect2dMouseNode
    self.mouseNode = self.parent.attachNewNode( 'aspect2dMouseNode', sort = 999999 )
    taskMgr.add( self.mouseNodeTask, 'mouseNodeTask' )
    
    windowBorderTextures = list()
    for windowBorder in windowBorderTextureFiles:
      if windowBorder is not None:
        mdlFile = loader.loadTexture(windowBorder)
        windowBorderTextures.append(mdlFile)
      else:
        windowBorderTextures.append(None)
    windowBorderGeoms = list()
    for windowGeom in windowBorderGeomFiles:
      if windowGeom is not None:
        mdlFile = loader.loadModel(windowGeom)
        mdls = ( mdlFile.find('**/**-default'),
                 mdlFile.find('**/**-click'),
                 mdlFile.find('**/**-rollover'),
                 mdlFile.find('**/**-disabled') )
        windowBorderGeoms.append(mdls)
      else:
        windowBorderGeoms.append((None,None,None,None,),)
    
    # the main window we want to move around
    self.parentWindow = DirectFrame(
      parent=self.parent, pos=(self.windowPos[0], 0, self.windowPos[1]),
      #frameSize=# is defined in resize
      scale=(1, 1, -1),
      frameColor=bgColor,
      borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, )
    
    # header of the window (drag&drop with it)
    # the title part of the window, drag around to move the window
    self.headerParent = DirectButton(
        parent=self.parentWindow, pos=(0, 0, 0), 
        #frameSize=# is defined in resize
        scale=(1, 1, self.dragbarSize),
        frameColor=(1, 1, 1, 1), 
        borderWidth=(0, 0), relief=DGG.FLAT, )
    self.headerParent.bind(DGG.B1PRESS,self.startWindowDrag)
    # images in the headerParent
    self.headerCenter = DirectFrame(
        parent=self.headerParent, pos=(0, 0, 1),
        #frameSize=# is defined in resize
        scale=(1,1,-1),
        frameColor=windowColors[1], frameTexture=windowBorderTextures[1],
        borderWidth=(0, 0), relief=DGG.FLAT, )
    self.headerLeft = DirectFrame(
        parent=self.headerParent, pos=(0, 0, 1),
        frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1),
        frameColor=windowColors[0], frameTexture=windowBorderTextures[0],
        borderWidth=(0, 0), relief=DGG.FLAT, )
    # collapse button
    self.headerRight = DirectButton(
        parent=self.headerParent, #pos=# is defined in resize
        frameSize=(0, self.dragbarSize, 0, 1), scale=(1,1,-1),
        frameColor=windowColors[2], #frameTexture=windowBorderTextures[2],
        borderWidth=(0, 0), relief=DGG.FLAT,
        command=self.toggleCollapsed,
        geom=windowBorderGeoms[0], geom_scale=(self.dragbarSize,1,1) )
    # the resize button of the window
    self.resizeButton = DirectButton(
        parent=self.parentWindow, pos=(1-self.dragbarSize, 0, 1),
        frameSize=(0, 1, 0, 1), scale=(self.dragbarSize,1,-self.dragbarSize),
        frameColor=windowColors[3], frameTexture=windowBorderTextures[3],
        borderWidth=(0, 0), relief=DGG.FLAT, sortOrder=1, )
    self.resizeButton.bind(DGG.B1PRESS,self.startResizeDrag)
    # text in the center of the window
    text = TextNode('WindowTitleTextNode')
    text.setText(title)
    text.setAlign(TextNode.ACenter)
    text.setTextColor( 0, 0, 0, 1 )
    text.setShadow(0.05, 0.05)
    text.setShadowColor( 1, 1, 1, 1 )
    self.textNodePath = self.headerCenter.attachNewNode(text)
    self.textNodePath.setPos(.5,0,.3)
    self.textNodePath.setScale(0.8*self.dragbarSize,1,0.8)
    
    if Y_INVERTED:
      scale = (1,1,-1)
    else:
      scale = (1,1,1)
    # the content part of the window, put stuff beneath
    # contentWindow.getCanvas() to put it into it
    self.contentWindow = DirectScrolledFrame(
        parent       = self.parentWindow,
        #pos          = # is defined in resize
        scale        = scale,
        canvasSize   = (0,self.virtualSize[0],0,self.virtualSize[1]),
        frameColor   = buttonColor,
        relief       = DGG.RAISED,
        borderWidth  = (0,0),
        verticalScroll_frameSize                = [0,self.dragbarSize,0,1],
        verticalScroll_frameTexture             = loader.loadTexture( 'rightBorder.png' ),
        verticalScroll_incButton_frameTexture   = loader.loadTexture( 'scrollDown.png' ),
        verticalScroll_decButton_frameTexture   = loader.loadTexture( 'scrollDown.png' ),
        verticalScroll_thumb_frameTexture       = loader.loadTexture( 'scrollBar.png' ),
        horizontalScroll_frameSize              = [0,1,0,self.dragbarSize],
        horizontalScroll_frameTexture           = loader.loadTexture( 'bottomBorder.png' ),
        horizontalScroll_incButton_frameTexture = loader.loadTexture( 'scrollDown.png' ),
        horizontalScroll_decButton_frameTexture = loader.loadTexture( 'scrollDown.png' ),
        horizontalScroll_thumb_frameTexture     = loader.loadTexture( 'scrollBar.png' ),
      )
    # child we attach should be inside the window
    DirectFrame.__init__( self,
        parent       = self.contentWindow.getCanvas(),
        pos          = (0,0,self.virtualSize[1]),
        scale        = (1,1,1),
        frameSize    = ( 0, self.virtualSize[0]+2*self.borderSize, 0, self.virtualSize[1] ),
        #frameColor   = (0,0,0,1),
        relief       = DGG.RIDGE,
        borderWidth  = (0,0),
        )
    self.initialiseoptions(DirectWindow)
    
    # offset then clicking on the resize button from the mouse to the resizebutton
    # position, required to calculate the position / scaling
    self.offset = None
    self.resizeButtonTaskName = "resizeTask-%s" % str(hash(self))
    
    # do sizing of the window to virtualSize
    #self.resize( self.virtualSize[0]+2*self.borderSize
    #           , self.virtualSize[1]+self.dragbarSize+2*self.borderSize )
    self.resize(10,10)
  
  # a task that keeps a node at the position of the mouse-cursor
  def mouseNodeTask(self, task):
    if WindowManager.hasMouse():
      x=WindowManager.getMouseX()
      y=WindowManager.getMouseY()
      # the mouse position is read relative to render2d, so set it accordingly
      self.mouseNode.setPos( render2d, x, 0, y )
    return task.cont
  
  # dragging functions
  def startWindowDrag( self, param ):
    self.parentWindow.wrtReparentTo( self.mouseNode )
    self.ignoreAll()
    self.accept( 'mouse1-up', self.stopWindowDrag )
  def stopWindowDrag( self, param=None ):
    # this could be called even after the window has been destroyed
    #if self:
    # this is called 2 times (bug), so make sure it's not already parented to aspect2d
    if self.parentWindow.getParent() != self.parent:
      self.parentWindow.wrtReparentTo(self.parent)
    self.ignoreAll()
  
  # resize functions
  def startResizeDrag(self, param):
    self.offset = self.resizeButton.getPos(aspect2d) - self.mouseNode.getPos(aspect2d)
    taskMgr.remove( self.resizeButtonTaskName )
    taskMgr.add( self.resizeButtonTask, self.resizeButtonTaskName )
    self.accept( 'mouse1-up', self.stopResizeDrag,['x'] )
  def resize(self,windowX,windowY):
    # limit max/min size of the window
    maxX = min(self.maxWindowSize[0], self.virtualSize[0]+2*self.borderSize)
    minX = max( self.dragbarSize*3, self.minWindowSize[0])
    windowWidth = min( maxX, max( minX, windowX ) )
    maxY = min( self.maxWindowSize[1], self.virtualSize[1]+self.dragbarSize+2*self.borderSize )
    minY = max( self.dragbarSize*4, self.minWindowSize[1])
    windowHeight = min( maxY, max( minY, windowY ) )
    if self.collapsed:
      windowHeight = 2*self.dragbarSize+2*self.borderSize
      windowWidth = windowWidth
      self.contentWindow.hide()
      # store changed window width only
      self.previousSize = windowWidth, self.previousSize[1]
    else:
      self.contentWindow.show()
      self.previousSize = windowWidth, windowHeight
    # set the window size
    self.headerParent['frameSize'] = (0, windowWidth, 0, 1)
    self.headerCenter['frameSize'] = (0, windowWidth, 0, 1)
    self.parentWindow['frameSize'] = (0, windowWidth, 0, windowHeight)
    self.contentWindow['frameSize'] = (0, windowWidth-self.borderSize*2, 0, windowHeight-self.dragbarSize-2*self.borderSize)
    self.contentWindow.setPos(self.borderSize,0,windowHeight-self.borderSize)
    self.headerRight.setPos(windowWidth-self.dragbarSize, 0, 1)
    self.textNodePath.setPos(windowWidth/2.,0,.3)
    self.resizeButton.setPos(windowWidth-self.dragbarSize, 0, windowHeight)
  def resizeButtonTask(self, task=None):
    mPos = self.mouseNode.getPos(self.parentWindow)
    # max height, the smaller of (given maxWindowSize and real size of content and borders
    windowX = mPos.getX() + self.offset.getX() + self.dragbarSize
    windowY = mPos.getZ() - self.offset.getZ()
    self.resize(windowX,windowY)
    return task.cont
  def stopResizeDrag(self, param):
    taskMgr.remove( self.resizeButtonTaskName )
    self.ignoreAll()
  
  
  # a bugfix for a wrong implementation
  def detachNode( self ):
    self.parentWindow.detachNode()
    #self. = None
    #DirectFrame.detachNode( self )
  def removeNode( self ):
    self.parentWindow.removeNode()
    #DirectFrame.removeNode( self )
  
  def toggleCollapsed(self,state=None):
    if state is None:
      state=not self.collapsed
    if state:
      self.collapse()
    else:
      self.uncollapse()
  def collapse(self):
    self.collapsed = True
    self.resize(*self.previousSize)
  def uncollapse(self):
    self.collapsed = False
    self.resize(*self.previousSize)